Rtos API example

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 #if 0 /* unused (and wrong on LLP64 systems) */
00251     case 'p':
00252         val = (unsigned long) va_arg(args, void *);
00253         base = 16;
00254         neg = 2;
00255         break;
00256 #endif /* unused (and wrong on LLP64 systems) */
00257     case 's':
00258         str = va_arg(args, char *);
00259         break;
00260     case 'c':
00261         num[0] = va_arg(args, int);
00262         num[1] = 0;
00263         str = num;
00264         break;
00265 #if 0 /* do we always have strerror() in embedded ? */
00266     case 'm':
00267         str = strerror(errno);
00268         break;
00269 #endif /* do we always have strerror() in embedded ? */
00270     case 'I':
00271         ip = va_arg(args, u32_t);
00272         ip = lwip_ntohl(ip);
00273         ppp_slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff,
00274              (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
00275         str = num;
00276         break;
00277 #if 0 /* need port */
00278     case 't':
00279         time(&t);
00280         str = ctime(&t);
00281         str += 4;       /* chop off the day name */
00282         str[15] = 0;    /* chop off year and newline */
00283         break;
00284 #endif /* need port */
00285     case 'v':       /* "visible" string */
00286     case 'q':       /* quoted string */
00287         quoted = c == 'q';
00288         p = va_arg(args, unsigned char *);
00289         if (p == NULL)
00290         p = (const unsigned char *)"<NULL>";
00291         if (fillch == '0' && prec >= 0) {
00292         n = prec;
00293         } else {
00294         n = strlen((const char *)p);
00295         if (prec >= 0 && n > prec)
00296             n = prec;
00297         }
00298         while (n > 0 && buflen > 0) {
00299         c = *p++;
00300         --n;
00301         if (!quoted && c >= 0x80) {
00302             OUTCHAR('M');
00303             OUTCHAR('-');
00304             c -= 0x80;
00305         }
00306         if (quoted && (c == '"' || c == '\\'))
00307             OUTCHAR('\\');
00308         if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
00309             if (quoted) {
00310             OUTCHAR('\\');
00311             switch (c) {
00312             case '\t':  OUTCHAR('t');   break;
00313             case '\n':  OUTCHAR('n');   break;
00314             case '\b':  OUTCHAR('b');   break;
00315             case '\f':  OUTCHAR('f');   break;
00316             default:
00317                 OUTCHAR('x');
00318                 OUTCHAR(hexchars[c >> 4]);
00319                 OUTCHAR(hexchars[c & 0xf]);
00320             }
00321             } else {
00322             if (c == '\t')
00323                 OUTCHAR(c);
00324             else {
00325                 OUTCHAR('^');
00326                 OUTCHAR(c ^ 0x40);
00327             }
00328             }
00329         } else
00330             OUTCHAR(c);
00331         }
00332         continue;
00333 #if PRINTPKT_SUPPORT
00334     case 'P':       /* print PPP packet */
00335         bufinfo.ptr = buf;
00336         bufinfo.len = buflen + 1;
00337         p = va_arg(args, unsigned char *);
00338         n = va_arg(args, int);
00339         ppp_format_packet(p, n, ppp_vslp_printer, &bufinfo);
00340         buf = bufinfo.ptr;
00341         buflen = bufinfo.len - 1;
00342         continue;
00343 #endif /* PRINTPKT_SUPPORT */
00344     case 'B':
00345         p = va_arg(args, unsigned char *);
00346         for (n = prec; n > 0; --n) {
00347         c = *p++;
00348         if (fillch == ' ')
00349             OUTCHAR(' ');
00350         OUTCHAR(hexchars[(c >> 4) & 0xf]);
00351         OUTCHAR(hexchars[c & 0xf]);
00352         }
00353         continue;
00354     default:
00355         *buf++ = '%';
00356         if (c != '%')
00357         --fmt;      /* so %z outputs %z etc. */
00358         --buflen;
00359         continue;
00360     }
00361     if (base != 0) {
00362         str = num + sizeof(num);
00363         *--str = 0;
00364         while (str > num + neg) {
00365         *--str = hexchars[val % base];
00366         val = val / base;
00367         if (--prec <= 0 && val == 0)
00368             break;
00369         }
00370         switch (neg) {
00371         case 1:
00372         *--str = '-';
00373         break;
00374         case 2:
00375         *--str = 'x';
00376         *--str = '0';
00377         break;
00378         default:
00379         break;
00380         }
00381         len = num + sizeof(num) - 1 - str;
00382     } else {
00383         len = strlen(str);
00384         if (prec >= 0 && len > prec)
00385         len = prec;
00386     }
00387     if (width > 0) {
00388         if (width > buflen)
00389         width = buflen;
00390         if ((n = width - len) > 0) {
00391         buflen -= n;
00392         for (; n > 0; --n)
00393             *buf++ = fillch;
00394         }
00395     }
00396     if (len > buflen)
00397         len = buflen;
00398     memcpy(buf, str, len);
00399     buf += len;
00400     buflen -= len;
00401     }
00402     *buf = 0;
00403     return buf - buf0;
00404 }
00405 
00406 #if PRINTPKT_SUPPORT
00407 /*
00408  * vslp_printer - used in processing a %P format
00409  */
00410 static void ppp_vslp_printer(void *arg, const char *fmt, ...) {
00411     int n;
00412     va_list pvar;
00413     struct buffer_info *bi;
00414 
00415     va_start(pvar, fmt);
00416     bi = (struct buffer_info *) arg;
00417     n = ppp_vslprintf(bi->ptr, bi->len, fmt, pvar);
00418     va_end(pvar);
00419 
00420     bi->ptr += n;
00421     bi->len -= n;
00422 }
00423 #endif /* PRINTPKT_SUPPORT */
00424 
00425 #if 0 /* UNUSED */
00426 /*
00427  * log_packet - format a packet and log it.
00428  */
00429 
00430 void
00431 log_packet(p, len, prefix, level)
00432     u_char *p;
00433     int len;
00434     char *prefix;
00435     int level;
00436 {
00437     init_pr_log(prefix, level);
00438     ppp_format_packet(p, len, pr_log, &level);
00439     end_pr_log();
00440 }
00441 #endif /* UNUSED */
00442 
00443 #if PRINTPKT_SUPPORT
00444 /*
00445  * ppp_format_packet - make a readable representation of a packet,
00446  * calling `printer(arg, format, ...)' to output it.
00447  */
00448 static void ppp_format_packet(const u_char *p, int len,
00449         void (*printer) (void *, const char *, ...), void *arg) {
00450     int i, n;
00451     u_short proto;
00452     const struct protent *protp;
00453 
00454     if (len >= 2) {
00455     GETSHORT(proto, p);
00456     len -= 2;
00457     for (i = 0; (protp = protocols[i]) != NULL; ++i)
00458         if (proto == protp->protocol)
00459         break;
00460     if (protp != NULL) {
00461         printer(arg, "[%s", protp->name);
00462         n = (*protp->printpkt)(p, len, printer, arg);
00463         printer(arg, "]");
00464         p += n;
00465         len -= n;
00466     } else {
00467         for (i = 0; (protp = protocols[i]) != NULL; ++i)
00468         if (proto == (protp->protocol & ~0x8000))
00469             break;
00470         if (protp != 0 && protp->data_name != 0) {
00471         printer(arg, "[%s data]", protp->data_name);
00472         if (len > 8)
00473             printer(arg, "%.8B ...", p);
00474         else
00475             printer(arg, "%.*B", len, p);
00476         len = 0;
00477         } else
00478         printer(arg, "[proto=0x%x]", proto);
00479     }
00480     }
00481 
00482     if (len > 32)
00483     printer(arg, "%.32B ...", p);
00484     else
00485     printer(arg, "%.*B", len, p);
00486 }
00487 #endif /* PRINTPKT_SUPPORT */
00488 
00489 #if 0 /* UNUSED */
00490 /*
00491  * init_pr_log, end_pr_log - initialize and finish use of pr_log.
00492  */
00493 
00494 static char line[256];      /* line to be logged accumulated here */
00495 static char *linep;     /* current pointer within line */
00496 static int llevel;      /* level for logging */
00497 
00498 void
00499 init_pr_log(prefix, level)
00500      const char *prefix;
00501      int level;
00502 {
00503     linep = line;
00504     if (prefix != NULL) {
00505         ppp_strlcpy(line, prefix, sizeof(line));
00506         linep = line + strlen(line);
00507     }
00508     llevel = level;
00509 }
00510 
00511 void
00512 end_pr_log()
00513 {
00514     if (linep != line) {
00515         *linep = 0;
00516         ppp_log_write(llevel, line);
00517     }
00518 }
00519 
00520 /*
00521  * pr_log - printer routine for outputting to log
00522  */
00523 void
00524 pr_log (void *arg, const char *fmt, ...)
00525 {
00526     int l, n;
00527     va_list pvar;
00528     char *p, *eol;
00529     char buf[256];
00530 
00531     va_start(pvar, fmt);
00532     n = ppp_vslprintf(buf, sizeof(buf), fmt, pvar);
00533     va_end(pvar);
00534 
00535     p = buf;
00536     eol = strchr(buf, '\n');
00537     if (linep != line) {
00538         l = (eol == NULL)? n: eol - buf;
00539         if (linep + l < line + sizeof(line)) {
00540             if (l > 0) {
00541                 memcpy(linep, buf, l);
00542                 linep += l;
00543             }
00544             if (eol == NULL)
00545                 return;
00546             p = eol + 1;
00547             eol = strchr(p, '\n');
00548         }
00549         *linep = 0;
00550         ppp_log_write(llevel, line);
00551         linep = line;
00552     }
00553 
00554     while (eol != NULL) {
00555         *eol = 0;
00556         ppp_log_write(llevel, p);
00557         p = eol + 1;
00558         eol = strchr(p, '\n');
00559     }
00560 
00561     /* assumes sizeof(buf) <= sizeof(line) */
00562     l = buf + n - p;
00563     if (l > 0) {
00564         memcpy(line, p, n);
00565         linep = line + l;
00566     }
00567 }
00568 #endif /* UNUSED */
00569 
00570 /*
00571  * ppp_print_string - print a readable representation of a string using
00572  * printer.
00573  */
00574 void ppp_print_string(const u_char *p, int len, void (*printer) (void *, const char *, ...), void *arg) {
00575     int c;
00576 
00577     printer(arg, "\"");
00578     for (; len > 0; --len) {
00579     c = *p++;
00580     if (' ' <= c && c <= '~') {
00581         if (c == '\\' || c == '"')
00582         printer(arg, "\\");
00583         printer(arg, "%c", c);
00584     } else {
00585         switch (c) {
00586         case '\n':
00587         printer(arg, "\\n");
00588         break;
00589         case '\r':
00590         printer(arg, "\\r");
00591         break;
00592         case '\t':
00593         printer(arg, "\\t");
00594         break;
00595         default:
00596         printer(arg, "\\%.3o", (u8_t)c);
00597         /* no break */
00598         }
00599     }
00600     }
00601     printer(arg, "\"");
00602 }
00603 
00604 /*
00605  * ppp_logit - does the hard work for fatal et al.
00606  */
00607 static void ppp_logit(int level, const char *fmt, va_list args) {
00608 
00609     char buf[256];
00610 
00611     ppp_vslprintf(buf, sizeof(buf), fmt, args);
00612     ppp_log_write(level, buf);
00613 }
00614 
00615 static void ppp_log_write(int level, char *buf) {
00616     LWIP_UNUSED_ARG(level); /* necessary if PPPDEBUG is defined to an empty function */
00617     LWIP_UNUSED_ARG(buf);
00618     PPPDEBUG(level, ("%s\n", buf) );
00619 #if 0
00620     if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) {
00621     int n = strlen(buf);
00622 
00623     if (n > 0 && buf[n-1] == '\n')
00624         --n;
00625     if (write(log_to_fd, buf, n) != n
00626         || write(log_to_fd, "\n", 1) != 1)
00627         log_to_fd = -1;
00628     }
00629 #endif
00630 }
00631 
00632 /*
00633  * ppp_fatal - log an error message and die horribly.
00634  */
00635 void ppp_fatal(const char *fmt, ...) {
00636     va_list pvar;
00637 
00638     va_start(pvar, fmt);
00639     ppp_logit(LOG_ERR, fmt, pvar);
00640     va_end(pvar);
00641 
00642     LWIP_ASSERT("ppp_fatal", 0);   /* as promised */
00643 }
00644 
00645 /*
00646  * ppp_error - log an error message.
00647  */
00648 void ppp_error(const char *fmt, ...) {
00649     va_list pvar;
00650 
00651     va_start(pvar, fmt);
00652     ppp_logit(LOG_ERR, fmt, pvar);
00653     va_end(pvar);
00654 #if 0 /* UNUSED */
00655     ++error_count;
00656 #endif /* UNUSED */
00657 }
00658 
00659 /*
00660  * ppp_warn - log a warning message.
00661  */
00662 void ppp_warn(const char *fmt, ...) {
00663     va_list pvar;
00664 
00665     va_start(pvar, fmt);
00666     ppp_logit(LOG_WARNING, fmt, pvar);
00667     va_end(pvar);
00668 }
00669 
00670 /*
00671  * ppp_notice - log a notice-level message.
00672  */
00673 void ppp_notice(const char *fmt, ...) {
00674     va_list pvar;
00675 
00676     va_start(pvar, fmt);
00677     ppp_logit(LOG_NOTICE, fmt, pvar);
00678     va_end(pvar);
00679 }
00680 
00681 /*
00682  * ppp_info - log an informational message.
00683  */
00684 void ppp_info(const char *fmt, ...) {
00685     va_list pvar;
00686 
00687     va_start(pvar, fmt);
00688     ppp_logit(LOG_INFO, fmt, pvar);
00689     va_end(pvar);
00690 }
00691 
00692 /*
00693  * ppp_dbglog - log a debug message.
00694  */
00695 void ppp_dbglog(const char *fmt, ...) {
00696     va_list pvar;
00697 
00698     va_start(pvar, fmt);
00699     ppp_logit(LOG_DEBUG, fmt, pvar);
00700     va_end(pvar);
00701 }
00702 
00703 #if PRINTPKT_SUPPORT
00704 /*
00705  * ppp_dump_packet - print out a packet in readable form if it is interesting.
00706  * Assumes len >= PPP_HDRLEN.
00707  */
00708 void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len) {
00709     int proto;
00710 
00711     /*
00712      * don't print data packets, i.e. IPv4, IPv6, VJ, and compressed packets.
00713      */
00714     proto = (p[0] << 8) + p[1];
00715     if (proto < 0xC000 && (proto & ~0x8000) == proto)
00716     return;
00717 
00718     /*
00719      * don't print valid LCP echo request/reply packets if the link is up.
00720      */
00721     if (proto == PPP_LCP && pcb->phase == PPP_PHASE_RUNNING && len >= 2 + HEADERLEN) {
00722     unsigned char *lcp = p + 2;
00723     int l = (lcp[2] << 8) + lcp[3];
00724 
00725     if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP)
00726         && l >= HEADERLEN && l <= len - 2)
00727         return;
00728     }
00729 
00730     TRACE_TO_ASCII_HEX_DUMPF("PPP>", len, (char *) p);
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 */