Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers utils.c Source File

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 "ppp_opts.h"
00032 #if PPP_SUPPORT /* don't build if not configured for use in ppp_opts.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 "ppp_impl.h"
00062 
00063 #include "fsm.h"
00064 #include "lcp.h"
00065 
00066 #if defined(SUNOS4)
00067 extern char *strerror();
00068 #endif
00069 
00070 static void ppp_logit(int level, const char *fmt, va_list args);
00071 static void ppp_log_write(int level, char *buf);
00072 #if PRINTPKT_SUPPORT
00073 static void ppp_vslp_printer(void *arg, const char *fmt, ...);
00074 static void ppp_format_packet(const u_char *p, int len,
00075         void (*printer) (void *, const char *, ...), void *arg);
00076 
00077 struct buffer_info {
00078     char *ptr;
00079     int len;
00080 };
00081 #endif /* PRINTPKT_SUPPORT */
00082 
00083 /*
00084  * ppp_strlcpy - like strcpy/strncpy, doesn't overflow destination buffer,
00085  * always leaves destination null-terminated (for len > 0).
00086  */
00087 size_t ppp_strlcpy(char *dest, const char *src, size_t len) {
00088     size_t ret = strlen(src);
00089 
00090     if (len != 0) {
00091     if (ret < len)
00092         strcpy(dest, src);
00093     else {
00094         strncpy(dest, src, len - 1);
00095         dest[len-1] = 0;
00096     }
00097     }
00098     return ret;
00099 }
00100 
00101 /*
00102  * ppp_strlcat - like strcat/strncat, doesn't overflow destination buffer,
00103  * always leaves destination null-terminated (for len > 0).
00104  */
00105 size_t ppp_strlcat(char *dest, const char *src, size_t len) {
00106     size_t dlen = strlen(dest);
00107 
00108     return dlen + ppp_strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0));
00109 }
00110 
00111 
00112 /*
00113  * ppp_slprintf - format a message into a buffer.  Like sprintf except we
00114  * also specify the length of the output buffer, and we handle
00115  * %m (error message), %v (visible string),
00116  * %q (quoted string), %t (current time) and %I (IP address) formats.
00117  * Doesn't do floating-point formats.
00118  * Returns the number of chars put into buf.
00119  */
00120 int ppp_slprintf(char *buf, int buflen, const char *fmt, ...) {
00121     va_list args;
00122     int n;
00123 
00124     va_start(args, fmt);
00125     n = ppp_vslprintf(buf, buflen, fmt, args);
00126     va_end(args);
00127     return n;
00128 }
00129 
00130 /*
00131  * ppp_vslprintf - like ppp_slprintf, takes a va_list instead of a list of args.
00132  */
00133 #define OUTCHAR(c)  (buflen > 0? (--buflen, *buf++ = (c)): 0)
00134 
00135 int ppp_vslprintf(char *buf, int buflen, const char *fmt, va_list args) {
00136     int c, i, n;
00137     int width, prec, fillch;
00138     int base, len, neg, quoted;
00139     unsigned long val = 0;
00140     const char *f;
00141     char *str, *buf0;
00142     const unsigned char *p;
00143     char num[32];
00144 #if 0 /* need port */
00145     time_t t;
00146 #endif /* need port */
00147     u32_t ip;
00148     static char hexchars[] = "0123456789abcdef";
00149 #if PRINTPKT_SUPPORT
00150     struct buffer_info bufinfo;
00151 #endif /* PRINTPKT_SUPPORT */
00152 
00153     buf0 = buf;
00154     --buflen;
00155     while (buflen > 0) {
00156     for (f = fmt; *f != '%' && *f != 0; ++f)
00157         ;
00158     if (f > fmt) {
00159         len = f - fmt;
00160         if (len > buflen)
00161         len = buflen;
00162         memcpy(buf, fmt, len);
00163         buf += len;
00164         buflen -= len;
00165         fmt = f;
00166     }
00167     if (*fmt == 0)
00168         break;
00169     c = *++fmt;
00170     width = 0;
00171     prec = -1;
00172     fillch = ' ';
00173     if (c == '0') {
00174         fillch = '0';
00175         c = *++fmt;
00176     }
00177     if (c == '*') {
00178         width = va_arg(args, int);
00179         c = *++fmt;
00180     } else {
00181         while (ppp_isdigit(c)) {
00182         width = width * 10 + c - '0';
00183         c = *++fmt;
00184         }
00185     }
00186     if (c == '.') {
00187         c = *++fmt;
00188         if (c == '*') {
00189         prec = va_arg(args, int);
00190         c = *++fmt;
00191         } else {
00192         prec = 0;
00193         while (ppp_isdigit(c)) {
00194             prec = prec * 10 + c - '0';
00195             c = *++fmt;
00196         }
00197         }
00198     }
00199     str = 0;
00200     base = 0;
00201     neg = 0;
00202     ++fmt;
00203     switch (c) {
00204     case 'l':
00205         c = *fmt++;
00206         switch (c) {
00207         case 'd':
00208         val = va_arg(args, long);
00209         if ((long)val < 0) {
00210             neg = 1;
00211             val = (unsigned long)-(long)val;
00212         }
00213         base = 10;
00214         break;
00215         case 'u':
00216         val = va_arg(args, unsigned long);
00217         base = 10;
00218         break;
00219         default:
00220         OUTCHAR('%');
00221         OUTCHAR('l');
00222         --fmt;      /* so %lz outputs %lz etc. */
00223         continue;
00224         }
00225         break;
00226     case 'd':
00227         i = va_arg(args, int);
00228         if (i < 0) {
00229         neg = 1;
00230         val = -i;
00231         } else
00232         val = i;
00233         base = 10;
00234         break;
00235     case 'u':
00236         val = va_arg(args, unsigned int);
00237         base = 10;
00238         break;
00239     case 'o':
00240         val = va_arg(args, unsigned int);
00241         base = 8;
00242         break;
00243     case 'x':
00244     case 'X':
00245         val = va_arg(args, unsigned int);
00246         base = 16;
00247         break;
00248 #if 0 /* unused (and wrong on LLP64 systems) */
00249     case 'p':
00250         val = (unsigned long) va_arg(args, void *);
00251         base = 16;
00252         neg = 2;
00253         break;
00254 #endif /* unused (and wrong on LLP64 systems) */
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 = ppp_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[256];
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     PPP_UNUSED_ARG(level); /* necessary if PPPDEBUG is defined to an empty function */
00614     PPP_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     PPP_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(ppp_pcb *pcb, const char *tag, unsigned char *p, int len) {
00706     int proto;
00707 
00708     /*
00709      * don't print data packets, i.e. IPv4, IPv6, VJ, and compressed packets.
00710      */
00711     proto = (p[0] << 8) + p[1];
00712     if (proto < 0xC000 && (proto & ~0x8000) == proto)
00713     return;
00714 
00715     /*
00716      * don't print valid LCP echo request/reply packets if the link is up.
00717      */
00718     if (proto == PPP_LCP && pcb->phase == PPP_PHASE_RUNNING && len >= 2 + HEADERLEN) {
00719     unsigned char *lcp = p + 2;
00720     int l = (lcp[2] << 8) + lcp[3];
00721 
00722     if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP)
00723         && l >= HEADERLEN && l <= len - 2)
00724         return;
00725     }
00726 
00727     TRACE_TO_ASCII_HEX_DUMPF("PPP>", len, (char *) p);
00728     ppp_dbglog("%s %P", tag, p, len);
00729 }
00730 #endif /* PRINTPKT_SUPPORT */
00731 
00732 #if 0 /* Unused */
00733 
00734 /*
00735  * complete_read - read a full `count' bytes from fd,
00736  * unless end-of-file or an error other than EINTR is encountered.
00737  */
00738 ssize_t
00739 complete_read(int fd, void *buf, size_t count)
00740 {
00741     size_t done;
00742     ssize_t nb;
00743     char *ptr = buf;
00744 
00745     for (done = 0; done < count; ) {
00746         nb = read(fd, ptr, count - done);
00747         if (nb < 0) {
00748             if (errno == EINTR)
00749                 continue;
00750             return -1;
00751         }
00752         if (nb == 0)
00753             break;
00754         done += nb;
00755         ptr += nb;
00756     }
00757     return done;
00758 }
00759 
00760 /* Procedures for locking the serial device using a lock file. */
00761 #ifndef LOCK_DIR
00762 #ifdef __linux__
00763 #define LOCK_DIR    "/var/lock"
00764 #else
00765 #ifdef SVR4
00766 #define LOCK_DIR    "/var/spool/locks"
00767 #else
00768 #define LOCK_DIR    "/var/spool/lock"
00769 #endif
00770 #endif
00771 #endif /* LOCK_DIR */
00772 
00773 static char lock_file[MAXPATHLEN];
00774 
00775 /*
00776  * lock - create a lock file for the named device
00777  */
00778 int
00779 lock(dev)
00780     char *dev;
00781 {
00782 #ifdef LOCKLIB
00783     int result;
00784 
00785     result = mklock (dev, (void *) 0);
00786     if (result == 0) {
00787     ppp_strlcpy(lock_file, dev, sizeof(lock_file));
00788     return 0;
00789     }
00790 
00791     if (result > 0)
00792         ppp_notice("Device %s is locked by pid %d", dev, result);
00793     else
00794     ppp_error("Can't create lock file %s", lock_file);
00795     return -1;
00796 
00797 #else /* LOCKLIB */
00798 
00799     char lock_buffer[12];
00800     int fd, pid, n;
00801 
00802 #ifdef SVR4
00803     struct stat sbuf;
00804 
00805     if (stat(dev, &sbuf) < 0) {
00806     ppp_error("Can't get device number for %s: %m", dev);
00807     return -1;
00808     }
00809     if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
00810     ppp_error("Can't lock %s: not a character device", dev);
00811     return -1;
00812     }
00813     ppp_slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
00814          LOCK_DIR, major(sbuf.st_dev),
00815          major(sbuf.st_rdev), minor(sbuf.st_rdev));
00816 #else
00817     char *p;
00818     char lockdev[MAXPATHLEN];
00819 
00820     if ((p = strstr(dev, "dev/")) != NULL) {
00821     dev = p + 4;
00822     strncpy(lockdev, dev, MAXPATHLEN-1);
00823     lockdev[MAXPATHLEN-1] = 0;
00824     while ((p = strrchr(lockdev, '/')) != NULL) {
00825         *p = '_';
00826     }
00827     dev = lockdev;
00828     } else
00829     if ((p = strrchr(dev, '/')) != NULL)
00830         dev = p + 1;
00831 
00832     ppp_slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
00833 #endif
00834 
00835     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
00836     if (errno != EEXIST) {
00837         ppp_error("Can't create lock file %s: %m", lock_file);
00838         break;
00839     }
00840 
00841     /* Read the lock file to find out who has the device locked. */
00842     fd = open(lock_file, O_RDONLY, 0);
00843     if (fd < 0) {
00844         if (errno == ENOENT) /* This is just a timing problem. */
00845         continue;
00846         ppp_error("Can't open existing lock file %s: %m", lock_file);
00847         break;
00848     }
00849 #ifndef LOCK_BINARY
00850     n = read(fd, lock_buffer, 11);
00851 #else
00852     n = read(fd, &pid, sizeof(pid));
00853 #endif /* LOCK_BINARY */
00854     close(fd);
00855     fd = -1;
00856     if (n <= 0) {
00857         ppp_error("Can't read pid from lock file %s", lock_file);
00858         break;
00859     }
00860 
00861     /* See if the process still exists. */
00862 #ifndef LOCK_BINARY
00863     lock_buffer[n] = 0;
00864     pid = atoi(lock_buffer);
00865 #endif /* LOCK_BINARY */
00866     if (pid == getpid())
00867         return 1;       /* somebody else locked it for us */
00868     if (pid == 0
00869         || (kill(pid, 0) == -1 && errno == ESRCH)) {
00870         if (unlink (lock_file) == 0) {
00871         ppp_notice("Removed stale lock on %s (pid %d)", dev, pid);
00872         continue;
00873         }
00874         ppp_warn("Couldn't remove stale lock on %s", dev);
00875     } else
00876         ppp_notice("Device %s is locked by pid %d", dev, pid);
00877     break;
00878     }
00879 
00880     if (fd < 0) {
00881     lock_file[0] = 0;
00882     return -1;
00883     }
00884 
00885     pid = getpid();
00886 #ifndef LOCK_BINARY
00887     ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
00888     write (fd, lock_buffer, 11);
00889 #else
00890     write(fd, &pid, sizeof (pid));
00891 #endif
00892     close(fd);
00893     return 0;
00894 
00895 #endif
00896 }
00897 
00898 /*
00899  * relock - called to update our lockfile when we are about to detach,
00900  * thus changing our pid (we fork, the child carries on, and the parent dies).
00901  * Note that this is called by the parent, with pid equal to the pid
00902  * of the child.  This avoids a potential race which would exist if
00903  * we had the child rewrite the lockfile (the parent might die first,
00904  * and another process could think the lock was stale if it checked
00905  * between when the parent died and the child rewrote the lockfile).
00906  */
00907 int
00908 relock(pid)
00909     int pid;
00910 {
00911 #ifdef LOCKLIB
00912     /* XXX is there a way to do this? */
00913     return -1;
00914 #else /* LOCKLIB */
00915 
00916     int fd;
00917     char lock_buffer[12];
00918 
00919     if (lock_file[0] == 0)
00920     return -1;
00921     fd = open(lock_file, O_WRONLY, 0);
00922     if (fd < 0) {
00923     ppp_error("Couldn't reopen lock file %s: %m", lock_file);
00924     lock_file[0] = 0;
00925     return -1;
00926     }
00927 
00928 #ifndef LOCK_BINARY
00929     ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
00930     write (fd, lock_buffer, 11);
00931 #else
00932     write(fd, &pid, sizeof(pid));
00933 #endif /* LOCK_BINARY */
00934     close(fd);
00935     return 0;
00936 
00937 #endif /* LOCKLIB */
00938 }
00939 
00940 /*
00941  * unlock - remove our lockfile
00942  */
00943 void
00944 unlock()
00945 {
00946     if (lock_file[0]) {
00947 #ifdef LOCKLIB
00948     (void) rmlock(lock_file, (void *) 0);
00949 #else
00950     unlink(lock_file);
00951 #endif
00952     lock_file[0] = 0;
00953     }
00954 }
00955 
00956 #endif /* Unused */
00957 
00958 #endif /* PPP_SUPPORT */