Greg Steiert / pegasus_dev

Dependents:   blinky_max32630fthr

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_utils.c Source File

lwip_utils.c

00001 /*
00002  * utils.c - various utility functions used in pppd.
00003  *
00004  * Copyright (c) 1999-2002 Paul Mackerras. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *
00013  * 2. The name(s) of the authors of this software must not be used to
00014  *    endorse or promote products derived from this software without
00015  *    prior written permission.
00016  *
00017  * 3. Redistributions of any form whatsoever must retain the following
00018  *    acknowledgment:
00019  *    "This product includes software developed by Paul Mackerras
00020  *     <paulus@samba.org>".
00021  *
00022  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
00023  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00024  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
00025  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00026  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
00027  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
00028  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00029  */
00030 
00031 #include "netif/ppp/ppp_opts.h"
00032 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
00033 
00034 #if 0 /* UNUSED */
00035 #include <stdio.h>
00036 #include <ctype.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <unistd.h>
00040 #include <signal.h>
00041 #include <errno.h>
00042 #include <fcntl.h>
00043 #include <syslog.h>
00044 #include <netdb.h>
00045 #include <time.h>
00046 #include <utmp.h>
00047 #include <pwd.h>
00048 #include <sys/param.h>
00049 #include <sys/types.h>
00050 #include <sys/wait.h>
00051 #include <sys/time.h>
00052 #include <sys/resource.h>
00053 #include <sys/stat.h>
00054 #include <sys/socket.h>
00055 #include <netinet/in.h>
00056 #ifdef SVR4
00057 #include <sys/mkdev.h>
00058 #endif
00059 #endif /* UNUSED */
00060 
00061 #include <ctype.h>  /* isdigit() */
00062 
00063 #include "netif/ppp/ppp_impl.h"
00064 
00065 #include "netif/ppp/fsm.h"
00066 #include "netif/ppp/lcp.h"
00067 
00068 #if defined(SUNOS4)
00069 extern char *strerror();
00070 #endif
00071 
00072 static void ppp_logit(int level, const char *fmt, va_list args);
00073 static void ppp_log_write(int level, char *buf);
00074 #if PRINTPKT_SUPPORT
00075 static void ppp_vslp_printer(void *arg, const char *fmt, ...);
00076 static void ppp_format_packet(const u_char *p, int len,
00077         void (*printer) (void *, const char *, ...), void *arg);
00078 
00079 struct buffer_info {
00080     char *ptr;
00081     int len;
00082 };
00083 #endif /* PRINTPKT_SUPPORT */
00084 
00085 /*
00086  * ppp_strlcpy - like strcpy/strncpy, doesn't overflow destination buffer,
00087  * always leaves destination null-terminated (for len > 0).
00088  */
00089 size_t ppp_strlcpy(char *dest, const char *src, size_t len) {
00090     size_t ret = strlen(src);
00091 
00092     if (len != 0) {
00093     if (ret < len)
00094         strcpy(dest, src);
00095     else {
00096         strncpy(dest, src, len - 1);
00097         dest[len-1] = 0;
00098     }
00099     }
00100     return ret;
00101 }
00102 
00103 /*
00104  * ppp_strlcat - like strcat/strncat, doesn't overflow destination buffer,
00105  * always leaves destination null-terminated (for len > 0).
00106  */
00107 size_t ppp_strlcat(char *dest, const char *src, size_t len) {
00108     size_t dlen = strlen(dest);
00109 
00110     return dlen + ppp_strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0));
00111 }
00112 
00113 
00114 /*
00115  * ppp_slprintf - format a message into a buffer.  Like sprintf except we
00116  * also specify the length of the output buffer, and we handle
00117  * %m (error message), %v (visible string),
00118  * %q (quoted string), %t (current time) and %I (IP address) formats.
00119  * Doesn't do floating-point formats.
00120  * Returns the number of chars put into buf.
00121  */
00122 int ppp_slprintf(char *buf, int buflen, const char *fmt, ...) {
00123     va_list args;
00124     int n;
00125 
00126     va_start(args, fmt);
00127     n = ppp_vslprintf(buf, buflen, fmt, args);
00128     va_end(args);
00129     return n;
00130 }
00131 
00132 /*
00133  * ppp_vslprintf - like ppp_slprintf, takes a va_list instead of a list of args.
00134  */
00135 #define OUTCHAR(c)  (buflen > 0? (--buflen, *buf++ = (c)): 0)
00136 
00137 int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args) {
00138     int c, i, n;
00139     int width, prec, fillch;
00140     int base, len, neg, quoted;
00141     unsigned long val = 0;
00142     const char *f;
00143     char *str, *buf0;
00144     const unsigned char *p;
00145     char num[32];
00146 #if 0 /* need port */
00147     time_t t;
00148 #endif /* need port */
00149     u32_t ip;
00150     static char hexchars[] = "0123456789abcdef";
00151 #if PRINTPKT_SUPPORT
00152     struct buffer_info bufinfo;
00153 #endif /* PRINTPKT_SUPPORT */
00154 
00155     buf0 = buf;
00156     --buflen;
00157     while (buflen > 0) {
00158     for (f = fmt; *f != '%' && *f != 0; ++f)
00159         ;
00160     if (f > fmt) {
00161         len = f - fmt;
00162         if (len > buflen)
00163         len = buflen;
00164         memcpy(buf, fmt, len);
00165         buf += len;
00166         buflen -= len;
00167         fmt = f;
00168     }
00169     if (*fmt == 0)
00170         break;
00171     c = *++fmt;
00172     width = 0;
00173     prec = -1;
00174     fillch = ' ';
00175     if (c == '0') {
00176         fillch = '0';
00177         c = *++fmt;
00178     }
00179     if (c == '*') {
00180         width = va_arg(args, int);
00181         c = *++fmt;
00182     } else {
00183         while (isdigit(c)) {
00184         width = width * 10 + c - '0';
00185         c = *++fmt;
00186         }
00187     }
00188     if (c == '.') {
00189         c = *++fmt;
00190         if (c == '*') {
00191         prec = va_arg(args, int);
00192         c = *++fmt;
00193         } else {
00194         prec = 0;
00195         while (isdigit(c)) {
00196             prec = prec * 10 + c - '0';
00197             c = *++fmt;
00198         }
00199         }
00200     }
00201     str = 0;
00202     base = 0;
00203     neg = 0;
00204     ++fmt;
00205     switch (c) {
00206     case 'l':
00207         c = *fmt++;
00208         switch (c) {
00209         case 'd':
00210         val = va_arg(args, long);
00211         if ((long)val < 0) {
00212             neg = 1;
00213             val = (unsigned long)-(long)val;
00214         }
00215         base = 10;
00216         break;
00217         case 'u':
00218         val = va_arg(args, unsigned long);
00219         base = 10;
00220         break;
00221         default:
00222         OUTCHAR('%');
00223         OUTCHAR('l');
00224         --fmt;      /* so %lz outputs %lz etc. */
00225         continue;
00226         }
00227         break;
00228     case 'd':
00229         i = va_arg(args, int);
00230         if (i < 0) {
00231         neg = 1;
00232         val = -i;
00233         } else
00234         val = i;
00235         base = 10;
00236         break;
00237     case 'u':
00238         val = va_arg(args, unsigned int);
00239         base = 10;
00240         break;
00241     case 'o':
00242         val = va_arg(args, unsigned int);
00243         base = 8;
00244         break;
00245     case 'x':
00246     case 'X':
00247         val = va_arg(args, unsigned int);
00248         base = 16;
00249         break;
00250     case 'p':
00251         val = (unsigned long) va_arg(args, void *);
00252         base = 16;
00253         neg = 2;
00254         break;
00255     case 's':
00256         str = va_arg(args, char *);
00257         break;
00258     case 'c':
00259         num[0] = va_arg(args, int);
00260         num[1] = 0;
00261         str = num;
00262         break;
00263 #if 0 /* do we always have strerror() in embedded ? */
00264     case 'm':
00265         str = strerror(errno);
00266         break;
00267 #endif /* do we always have strerror() in embedded ? */
00268     case 'I':
00269         ip = va_arg(args, u32_t);
00270         ip = ntohl(ip);
00271         ppp_slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff,
00272              (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
00273         str = num;
00274         break;
00275 #if 0 /* need port */
00276     case 't':
00277         time(&t);
00278         str = ctime(&t);
00279         str += 4;       /* chop off the day name */
00280         str[15] = 0;    /* chop off year and newline */
00281         break;
00282 #endif /* need port */
00283     case 'v':       /* "visible" string */
00284     case 'q':       /* quoted string */
00285         quoted = c == 'q';
00286         p = va_arg(args, unsigned char *);
00287         if (p == NULL)
00288         p = (const unsigned char *)"<NULL>";
00289         if (fillch == '0' && prec >= 0) {
00290         n = prec;
00291         } else {
00292         n = strlen((const char *)p);
00293         if (prec >= 0 && n > prec)
00294             n = prec;
00295         }
00296         while (n > 0 && buflen > 0) {
00297         c = *p++;
00298         --n;
00299         if (!quoted && c >= 0x80) {
00300             OUTCHAR('M');
00301             OUTCHAR('-');
00302             c -= 0x80;
00303         }
00304         if (quoted && (c == '"' || c == '\\'))
00305             OUTCHAR('\\');
00306         if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
00307             if (quoted) {
00308             OUTCHAR('\\');
00309             switch (c) {
00310             case '\t':  OUTCHAR('t');   break;
00311             case '\n':  OUTCHAR('n');   break;
00312             case '\b':  OUTCHAR('b');   break;
00313             case '\f':  OUTCHAR('f');   break;
00314             default:
00315                 OUTCHAR('x');
00316                 OUTCHAR(hexchars[c >> 4]);
00317                 OUTCHAR(hexchars[c & 0xf]);
00318             }
00319             } else {
00320             if (c == '\t')
00321                 OUTCHAR(c);
00322             else {
00323                 OUTCHAR('^');
00324                 OUTCHAR(c ^ 0x40);
00325             }
00326             }
00327         } else
00328             OUTCHAR(c);
00329         }
00330         continue;
00331 #if PRINTPKT_SUPPORT
00332     case 'P':       /* print PPP packet */
00333         bufinfo.ptr = buf;
00334         bufinfo.len = buflen + 1;
00335         p = va_arg(args, unsigned char *);
00336         n = va_arg(args, int);
00337         ppp_format_packet(p, n, ppp_vslp_printer, &bufinfo);
00338         buf = bufinfo.ptr;
00339         buflen = bufinfo.len - 1;
00340         continue;
00341 #endif /* PRINTPKT_SUPPORT */
00342     case 'B':
00343         p = va_arg(args, unsigned char *);
00344         for (n = prec; n > 0; --n) {
00345         c = *p++;
00346         if (fillch == ' ')
00347             OUTCHAR(' ');
00348         OUTCHAR(hexchars[(c >> 4) & 0xf]);
00349         OUTCHAR(hexchars[c & 0xf]);
00350         }
00351         continue;
00352     default:
00353         *buf++ = '%';
00354         if (c != '%')
00355         --fmt;      /* so %z outputs %z etc. */
00356         --buflen;
00357         continue;
00358     }
00359     if (base != 0) {
00360         str = num + sizeof(num);
00361         *--str = 0;
00362         while (str > num + neg) {
00363         *--str = hexchars[val % base];
00364         val = val / base;
00365         if (--prec <= 0 && val == 0)
00366             break;
00367         }
00368         switch (neg) {
00369         case 1:
00370         *--str = '-';
00371         break;
00372         case 2:
00373         *--str = 'x';
00374         *--str = '0';
00375         break;
00376         default:
00377         break;
00378         }
00379         len = num + sizeof(num) - 1 - str;
00380     } else {
00381         len = strlen(str);
00382         if (prec >= 0 && len > prec)
00383         len = prec;
00384     }
00385     if (width > 0) {
00386         if (width > buflen)
00387         width = buflen;
00388         if ((n = width - len) > 0) {
00389         buflen -= n;
00390         for (; n > 0; --n)
00391             *buf++ = fillch;
00392         }
00393     }
00394     if (len > buflen)
00395         len = buflen;
00396     memcpy(buf, str, len);
00397     buf += len;
00398     buflen -= len;
00399     }
00400     *buf = 0;
00401     return buf - buf0;
00402 }
00403 
00404 #if PRINTPKT_SUPPORT
00405 /*
00406  * vslp_printer - used in processing a %P format
00407  */
00408 static void ppp_vslp_printer(void *arg, const char *fmt, ...) {
00409     int n;
00410     va_list pvar;
00411     struct buffer_info *bi;
00412 
00413     va_start(pvar, fmt);
00414     bi = (struct buffer_info *) arg;
00415     n = ppp_vslprintf(bi->ptr, bi->len, fmt, pvar);
00416     va_end(pvar);
00417 
00418     bi->ptr += n;
00419     bi->len -= n;
00420 }
00421 #endif /* PRINTPKT_SUPPORT */
00422 
00423 #if 0 /* UNUSED */
00424 /*
00425  * log_packet - format a packet and log it.
00426  */
00427 
00428 void
00429 log_packet(p, len, prefix, level)
00430     u_char *p;
00431     int len;
00432     char *prefix;
00433     int level;
00434 {
00435     init_pr_log(prefix, level);
00436     ppp_format_packet(p, len, pr_log, &level);
00437     end_pr_log();
00438 }
00439 #endif /* UNUSED */
00440 
00441 #if PRINTPKT_SUPPORT
00442 /*
00443  * ppp_format_packet - make a readable representation of a packet,
00444  * calling `printer(arg, format, ...)' to output it.
00445  */
00446 static void ppp_format_packet(const u_char *p, int len,
00447         void (*printer) (void *, const char *, ...), void *arg) {
00448     int i, n;
00449     u_short proto;
00450     const struct protent *protp;
00451 
00452     if (len >= 2) {
00453     GETSHORT(proto, p);
00454     len -= 2;
00455     for (i = 0; (protp = protocols[i]) != NULL; ++i)
00456         if (proto == protp->protocol)
00457         break;
00458     if (protp != NULL) {
00459         printer(arg, "[%s", protp->name);
00460         n = (*protp->printpkt)(p, len, printer, arg);
00461         printer(arg, "]");
00462         p += n;
00463         len -= n;
00464     } else {
00465         for (i = 0; (protp = protocols[i]) != NULL; ++i)
00466         if (proto == (protp->protocol & ~0x8000))
00467             break;
00468         if (protp != 0 && protp->data_name != 0) {
00469         printer(arg, "[%s data]", protp->data_name);
00470         if (len > 8)
00471             printer(arg, "%.8B ...", p);
00472         else
00473             printer(arg, "%.*B", len, p);
00474         len = 0;
00475         } else
00476         printer(arg, "[proto=0x%x]", proto);
00477     }
00478     }
00479 
00480     if (len > 32)
00481     printer(arg, "%.32B ...", p);
00482     else
00483     printer(arg, "%.*B", len, p);
00484 }
00485 #endif /* PRINTPKT_SUPPORT */
00486 
00487 #if 0 /* UNUSED */
00488 /*
00489  * init_pr_log, end_pr_log - initialize and finish use of pr_log.
00490  */
00491 
00492 static char line[256];      /* line to be logged accumulated here */
00493 static char *linep;     /* current pointer within line */
00494 static int llevel;      /* level for logging */
00495 
00496 void
00497 init_pr_log(prefix, level)
00498      const char *prefix;
00499      int level;
00500 {
00501     linep = line;
00502     if (prefix != NULL) {
00503         ppp_strlcpy(line, prefix, sizeof(line));
00504         linep = line + strlen(line);
00505     }
00506     llevel = level;
00507 }
00508 
00509 void
00510 end_pr_log()
00511 {
00512     if (linep != line) {
00513         *linep = 0;
00514         ppp_log_write(llevel, line);
00515     }
00516 }
00517 
00518 /*
00519  * pr_log - printer routine for outputting to log
00520  */
00521 void
00522 pr_log (void *arg, const char *fmt, ...)
00523 {
00524     int l, n;
00525     va_list pvar;
00526     char *p, *eol;
00527     char buf[256];
00528 
00529     va_start(pvar, fmt);
00530     n = ppp_vslprintf(buf, sizeof(buf), fmt, pvar);
00531     va_end(pvar);
00532 
00533     p = buf;
00534     eol = strchr(buf, '\n');
00535     if (linep != line) {
00536         l = (eol == NULL)? n: eol - buf;
00537         if (linep + l < line + sizeof(line)) {
00538             if (l > 0) {
00539                 memcpy(linep, buf, l);
00540                 linep += l;
00541             }
00542             if (eol == NULL)
00543                 return;
00544             p = eol + 1;
00545             eol = strchr(p, '\n');
00546         }
00547         *linep = 0;
00548         ppp_log_write(llevel, line);
00549         linep = line;
00550     }
00551 
00552     while (eol != NULL) {
00553         *eol = 0;
00554         ppp_log_write(llevel, p);
00555         p = eol + 1;
00556         eol = strchr(p, '\n');
00557     }
00558 
00559     /* assumes sizeof(buf) <= sizeof(line) */
00560     l = buf + n - p;
00561     if (l > 0) {
00562         memcpy(line, p, n);
00563         linep = line + l;
00564     }
00565 }
00566 #endif /* UNUSED */
00567 
00568 /*
00569  * ppp_print_string - print a readable representation of a string using
00570  * printer.
00571  */
00572 void ppp_print_string(const u_char *p, int len, void (*printer) (void *, const char *, ...), void *arg) {
00573     int c;
00574 
00575     printer(arg, "\"");
00576     for (; len > 0; --len) {
00577     c = *p++;
00578     if (' ' <= c && c <= '~') {
00579         if (c == '\\' || c == '"')
00580         printer(arg, "\\");
00581         printer(arg, "%c", c);
00582     } else {
00583         switch (c) {
00584         case '\n':
00585         printer(arg, "\\n");
00586         break;
00587         case '\r':
00588         printer(arg, "\\r");
00589         break;
00590         case '\t':
00591         printer(arg, "\\t");
00592         break;
00593         default:
00594         printer(arg, "\\%.3o", (u8_t)c);
00595         /* no break */
00596         }
00597     }
00598     }
00599     printer(arg, "\"");
00600 }
00601 
00602 /*
00603  * ppp_logit - does the hard work for fatal et al.
00604  */
00605 static void ppp_logit(int level, const char *fmt, va_list args) {
00606     char buf[1024];
00607 
00608     ppp_vslprintf(buf, sizeof(buf), fmt, args);
00609     ppp_log_write(level, buf);
00610 }
00611 
00612 static void ppp_log_write(int level, char *buf) {
00613     LWIP_UNUSED_ARG(level); /* necessary if PPPDEBUG is defined to an empty function */
00614     LWIP_UNUSED_ARG(buf);
00615     PPPDEBUG(level, ("%s\n", buf) );
00616 #if 0
00617     if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) {
00618     int n = strlen(buf);
00619 
00620     if (n > 0 && buf[n-1] == '\n')
00621         --n;
00622     if (write(log_to_fd, buf, n) != n
00623         || write(log_to_fd, "\n", 1) != 1)
00624         log_to_fd = -1;
00625     }
00626 #endif
00627 }
00628 
00629 /*
00630  * ppp_fatal - log an error message and die horribly.
00631  */
00632 void ppp_fatal(const char *fmt, ...) {
00633     va_list pvar;
00634 
00635     va_start(pvar, fmt);
00636     ppp_logit(LOG_ERR, fmt, pvar);
00637     va_end(pvar);
00638 
00639     LWIP_ASSERT("ppp_fatal", 0);   /* as promised */
00640 }
00641 
00642 /*
00643  * ppp_error - log an error message.
00644  */
00645 void ppp_error(const char *fmt, ...) {
00646     va_list pvar;
00647 
00648     va_start(pvar, fmt);
00649     ppp_logit(LOG_ERR, fmt, pvar);
00650     va_end(pvar);
00651 #if 0 /* UNUSED */
00652     ++error_count;
00653 #endif /* UNUSED */
00654 }
00655 
00656 /*
00657  * ppp_warn - log a warning message.
00658  */
00659 void ppp_warn(const char *fmt, ...) {
00660     va_list pvar;
00661 
00662     va_start(pvar, fmt);
00663     ppp_logit(LOG_WARNING, fmt, pvar);
00664     va_end(pvar);
00665 }
00666 
00667 /*
00668  * ppp_notice - log a notice-level message.
00669  */
00670 void ppp_notice(const char *fmt, ...) {
00671     va_list pvar;
00672 
00673     va_start(pvar, fmt);
00674     ppp_logit(LOG_NOTICE, fmt, pvar);
00675     va_end(pvar);
00676 }
00677 
00678 /*
00679  * ppp_info - log an informational message.
00680  */
00681 void ppp_info(const char *fmt, ...) {
00682     va_list pvar;
00683 
00684     va_start(pvar, fmt);
00685     ppp_logit(LOG_INFO, fmt, pvar);
00686     va_end(pvar);
00687 }
00688 
00689 /*
00690  * ppp_dbglog - log a debug message.
00691  */
00692 void ppp_dbglog(const char *fmt, ...) {
00693     va_list pvar;
00694 
00695     va_start(pvar, fmt);
00696     ppp_logit(LOG_DEBUG, fmt, pvar);
00697     va_end(pvar);
00698 }
00699 
00700 #if PRINTPKT_SUPPORT
00701 /*
00702  * ppp_dump_packet - print out a packet in readable form if it is interesting.
00703  * Assumes len >= PPP_HDRLEN.
00704  */
00705 void ppp_dump_packet(const char *tag, unsigned char *p, int len) {
00706     int proto;
00707 
00708     /*
00709      * don't print IPv4 and IPv6 packets.
00710      */
00711     proto = (p[0] << 8) + p[1];
00712     if (proto == PPP_IP)
00713     return;
00714 #if PPP_IPV6_SUPPORT
00715     if (proto == PPP_IPV6)
00716     return;
00717 #endif
00718 
00719     /*
00720      * don't print LCP echo request/reply packets if the link is up.
00721      */
00722     if (proto == PPP_LCP && len >= 2 + HEADERLEN) {
00723     unsigned char *lcp = p + 2;
00724     int l = (lcp[2] << 8) + lcp[3];
00725 
00726     if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP)
00727         && l >= HEADERLEN && l <= len - 2)
00728         return;
00729     }
00730 
00731     ppp_dbglog("%s %P", tag, p, len);
00732 }
00733 #endif /* PRINTPKT_SUPPORT */
00734 
00735 #if 0 /* Unused */
00736 
00737 /*
00738  * complete_read - read a full `count' bytes from fd,
00739  * unless end-of-file or an error other than EINTR is encountered.
00740  */
00741 ssize_t
00742 complete_read(int fd, void *buf, size_t count)
00743 {
00744     size_t done;
00745     ssize_t nb;
00746     char *ptr = buf;
00747 
00748     for (done = 0; done < count; ) {
00749         nb = read(fd, ptr, count - done);
00750         if (nb < 0) {
00751             if (errno == EINTR)
00752                 continue;
00753             return -1;
00754         }
00755         if (nb == 0)
00756             break;
00757         done += nb;
00758         ptr += nb;
00759     }
00760     return done;
00761 }
00762 
00763 /* Procedures for locking the serial device using a lock file. */
00764 #ifndef LOCK_DIR
00765 #ifdef __linux__
00766 #define LOCK_DIR    "/var/lock"
00767 #else
00768 #ifdef SVR4
00769 #define LOCK_DIR    "/var/spool/locks"
00770 #else
00771 #define LOCK_DIR    "/var/spool/lock"
00772 #endif
00773 #endif
00774 #endif /* LOCK_DIR */
00775 
00776 static char lock_file[MAXPATHLEN];
00777 
00778 /*
00779  * lock - create a lock file for the named device
00780  */
00781 int
00782 lock(dev)
00783     char *dev;
00784 {
00785 #ifdef LOCKLIB
00786     int result;
00787 
00788     result = mklock (dev, (void *) 0);
00789     if (result == 0) {
00790     ppp_strlcpy(lock_file, dev, sizeof(lock_file));
00791     return 0;
00792     }
00793 
00794     if (result > 0)
00795         ppp_notice("Device %s is locked by pid %d", dev, result);
00796     else
00797     ppp_error("Can't create lock file %s", lock_file);
00798     return -1;
00799 
00800 #else /* LOCKLIB */
00801 
00802     char lock_buffer[12];
00803     int fd, pid, n;
00804 
00805 #ifdef SVR4
00806     struct stat sbuf;
00807 
00808     if (stat(dev, &sbuf) < 0) {
00809     ppp_error("Can't get device number for %s: %m", dev);
00810     return -1;
00811     }
00812     if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
00813     ppp_error("Can't lock %s: not a character device", dev);
00814     return -1;
00815     }
00816     ppp_slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
00817          LOCK_DIR, major(sbuf.st_dev),
00818          major(sbuf.st_rdev), minor(sbuf.st_rdev));
00819 #else
00820     char *p;
00821     char lockdev[MAXPATHLEN];
00822 
00823     if ((p = strstr(dev, "dev/")) != NULL) {
00824     dev = p + 4;
00825     strncpy(lockdev, dev, MAXPATHLEN-1);
00826     lockdev[MAXPATHLEN-1] = 0;
00827     while ((p = strrchr(lockdev, '/')) != NULL) {
00828         *p = '_';
00829     }
00830     dev = lockdev;
00831     } else
00832     if ((p = strrchr(dev, '/')) != NULL)
00833         dev = p + 1;
00834 
00835     ppp_slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
00836 #endif
00837 
00838     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
00839     if (errno != EEXIST) {
00840         ppp_error("Can't create lock file %s: %m", lock_file);
00841         break;
00842     }
00843 
00844     /* Read the lock file to find out who has the device locked. */
00845     fd = open(lock_file, O_RDONLY, 0);
00846     if (fd < 0) {
00847         if (errno == ENOENT) /* This is just a timing problem. */
00848         continue;
00849         ppp_error("Can't open existing lock file %s: %m", lock_file);
00850         break;
00851     }
00852 #ifndef LOCK_BINARY
00853     n = read(fd, lock_buffer, 11);
00854 #else
00855     n = read(fd, &pid, sizeof(pid));
00856 #endif /* LOCK_BINARY */
00857     close(fd);
00858     fd = -1;
00859     if (n <= 0) {
00860         ppp_error("Can't read pid from lock file %s", lock_file);
00861         break;
00862     }
00863 
00864     /* See if the process still exists. */
00865 #ifndef LOCK_BINARY
00866     lock_buffer[n] = 0;
00867     pid = atoi(lock_buffer);
00868 #endif /* LOCK_BINARY */
00869     if (pid == getpid())
00870         return 1;       /* somebody else locked it for us */
00871     if (pid == 0
00872         || (kill(pid, 0) == -1 && errno == ESRCH)) {
00873         if (unlink (lock_file) == 0) {
00874         ppp_notice("Removed stale lock on %s (pid %d)", dev, pid);
00875         continue;
00876         }
00877         ppp_warn("Couldn't remove stale lock on %s", dev);
00878     } else
00879         ppp_notice("Device %s is locked by pid %d", dev, pid);
00880     break;
00881     }
00882 
00883     if (fd < 0) {
00884     lock_file[0] = 0;
00885     return -1;
00886     }
00887 
00888     pid = getpid();
00889 #ifndef LOCK_BINARY
00890     ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
00891     write (fd, lock_buffer, 11);
00892 #else
00893     write(fd, &pid, sizeof (pid));
00894 #endif
00895     close(fd);
00896     return 0;
00897 
00898 #endif
00899 }
00900 
00901 /*
00902  * relock - called to update our lockfile when we are about to detach,
00903  * thus changing our pid (we fork, the child carries on, and the parent dies).
00904  * Note that this is called by the parent, with pid equal to the pid
00905  * of the child.  This avoids a potential race which would exist if
00906  * we had the child rewrite the lockfile (the parent might die first,
00907  * and another process could think the lock was stale if it checked
00908  * between when the parent died and the child rewrote the lockfile).
00909  */
00910 int
00911 relock(pid)
00912     int pid;
00913 {
00914 #ifdef LOCKLIB
00915     /* XXX is there a way to do this? */
00916     return -1;
00917 #else /* LOCKLIB */
00918 
00919     int fd;
00920     char lock_buffer[12];
00921 
00922     if (lock_file[0] == 0)
00923     return -1;
00924     fd = open(lock_file, O_WRONLY, 0);
00925     if (fd < 0) {
00926     ppp_error("Couldn't reopen lock file %s: %m", lock_file);
00927     lock_file[0] = 0;
00928     return -1;
00929     }
00930 
00931 #ifndef LOCK_BINARY
00932     ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
00933     write (fd, lock_buffer, 11);
00934 #else
00935     write(fd, &pid, sizeof(pid));
00936 #endif /* LOCK_BINARY */
00937     close(fd);
00938     return 0;
00939 
00940 #endif /* LOCKLIB */
00941 }
00942 
00943 /*
00944  * unlock - remove our lockfile
00945  */
00946 void
00947 unlock()
00948 {
00949     if (lock_file[0]) {
00950 #ifdef LOCKLIB
00951     (void) rmlock(lock_file, (void *) 0);
00952 #else
00953     unlink(lock_file);
00954 #endif
00955     lock_file[0] = 0;
00956     }
00957 }
00958 
00959 #endif /* Unused */
00960 
00961 #endif /* PPP_SUPPORT */