Home | History | Annotate | Download | only in pppd
      1 /*
      2  * utils.c - various utility functions used in pppd.
      3  *
      4  * Copyright (c) 1999-2002 Paul Mackerras. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  *
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  *
     13  * 2. The name(s) of the authors of this software must not be used to
     14  *    endorse or promote products derived from this software without
     15  *    prior written permission.
     16  *
     17  * 3. Redistributions of any form whatsoever must retain the following
     18  *    acknowledgment:
     19  *    "This product includes software developed by Paul Mackerras
     20  *     <paulus (at) samba.org>".
     21  *
     22  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
     23  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     24  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
     25  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     26  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     27  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     28  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     29  */
     30 
     31 #define RCSID	"$Id: utils.c,v 1.25 2008/06/03 12:06:37 paulus Exp $"
     32 
     33 #include <stdio.h>
     34 #include <ctype.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <unistd.h>
     38 #include <signal.h>
     39 #include <errno.h>
     40 #include <fcntl.h>
     41 #include <syslog.h>
     42 #include <netdb.h>
     43 #include <time.h>
     44 #include <utmp.h>
     45 #include <pwd.h>
     46 #include <sys/param.h>
     47 #include <sys/types.h>
     48 #include <sys/wait.h>
     49 #include <sys/time.h>
     50 #include <sys/resource.h>
     51 #include <sys/stat.h>
     52 #include <sys/socket.h>
     53 #include <netinet/in.h>
     54 #ifdef SVR4
     55 #include <sys/mkdev.h>
     56 #endif
     57 
     58 #include "pppd.h"
     59 #include "fsm.h"
     60 #include "lcp.h"
     61 
     62 static const char rcsid[] = RCSID;
     63 
     64 #if defined(SUNOS4)
     65 extern char *strerror();
     66 #endif
     67 
     68 static void logit __P((int, char *, va_list));
     69 static void log_write __P((int, char *));
     70 static void vslp_printer __P((void *, char *, ...));
     71 static void format_packet __P((u_char *, int, printer_func, void *));
     72 
     73 struct buffer_info {
     74     char *ptr;
     75     int len;
     76 };
     77 
     78 #if !defined(__ANDROID__)
     79 
     80 /*
     81  * strlcpy - like strcpy/strncpy, doesn't overflow destination buffer,
     82  * always leaves destination null-terminated (for len > 0).
     83  */
     84 size_t
     85 strlcpy(dest, src, len)
     86     char *dest;
     87     const char *src;
     88     size_t len;
     89 {
     90     size_t ret = strlen(src);
     91 
     92     if (len != 0) {
     93 	if (ret < len)
     94 	    strcpy(dest, src);
     95 	else {
     96 	    strncpy(dest, src, len - 1);
     97 	    dest[len-1] = 0;
     98 	}
     99     }
    100     return ret;
    101 }
    102 
    103 /*
    104  * strlcat - like strcat/strncat, doesn't overflow destination buffer,
    105  * always leaves destination null-terminated (for len > 0).
    106  */
    107 size_t
    108 strlcat(dest, src, len)
    109     char *dest;
    110     const char *src;
    111     size_t len;
    112 {
    113     size_t dlen = strlen(dest);
    114 
    115     return dlen + strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0));
    116 }
    117 #endif
    118 
    119 
    120 /*
    121  * slprintf - format a message into a buffer.  Like sprintf except we
    122  * also specify the length of the output buffer, and we handle
    123  * %m (error message), %v (visible string),
    124  * %q (quoted string), %t (current time) and %I (IP address) formats.
    125  * Doesn't do floating-point formats.
    126  * Returns the number of chars put into buf.
    127  */
    128 int
    129 slprintf __V((char *buf, int buflen, char *fmt, ...))
    130 {
    131     va_list args;
    132     int n;
    133 
    134 #if defined(__STDC__)
    135     va_start(args, fmt);
    136 #else
    137     char *buf;
    138     int buflen;
    139     char *fmt;
    140     va_start(args);
    141     buf = va_arg(args, char *);
    142     buflen = va_arg(args, int);
    143     fmt = va_arg(args, char *);
    144 #endif
    145     n = vslprintf(buf, buflen, fmt, args);
    146     va_end(args);
    147     return n;
    148 }
    149 
    150 /*
    151  * vslprintf - like slprintf, takes a va_list instead of a list of args.
    152  */
    153 #define OUTCHAR(c)	(buflen > 0? (--buflen, *buf++ = (c)): 0)
    154 
    155 int
    156 vslprintf(buf, buflen, fmt, args)
    157     char *buf;
    158     int buflen;
    159     char *fmt;
    160     va_list args;
    161 {
    162     int c, i, n;
    163     int width, prec, fillch;
    164     int base, len, neg, quoted;
    165     unsigned long val = 0;
    166     char *str, *f, *buf0;
    167     unsigned char *p;
    168     char num[32];
    169     time_t t;
    170     u_int32_t ip;
    171     static char hexchars[] = "0123456789abcdef";
    172     struct buffer_info bufinfo;
    173 
    174     buf0 = buf;
    175     --buflen;
    176     while (buflen > 0) {
    177 	for (f = fmt; *f != '%' && *f != 0; ++f)
    178 	    ;
    179 	if (f > fmt) {
    180 	    len = f - fmt;
    181 	    if (len > buflen)
    182 		len = buflen;
    183 	    memcpy(buf, fmt, len);
    184 	    buf += len;
    185 	    buflen -= len;
    186 	    fmt = f;
    187 	}
    188 	if (*fmt == 0)
    189 	    break;
    190 	c = *++fmt;
    191 	width = 0;
    192 	prec = -1;
    193 	fillch = ' ';
    194 	if (c == '0') {
    195 	    fillch = '0';
    196 	    c = *++fmt;
    197 	}
    198 	if (c == '*') {
    199 	    width = va_arg(args, int);
    200 	    c = *++fmt;
    201 	} else {
    202 	    while (isdigit(c)) {
    203 		width = width * 10 + c - '0';
    204 		c = *++fmt;
    205 	    }
    206 	}
    207 	if (c == '.') {
    208 	    c = *++fmt;
    209 	    if (c == '*') {
    210 		prec = va_arg(args, int);
    211 		c = *++fmt;
    212 	    } else {
    213 		prec = 0;
    214 		while (isdigit(c)) {
    215 		    prec = prec * 10 + c - '0';
    216 		    c = *++fmt;
    217 		}
    218 	    }
    219 	}
    220 	str = 0;
    221 	base = 0;
    222 	neg = 0;
    223 	++fmt;
    224 	switch (c) {
    225 	case 'l':
    226 	    c = *fmt++;
    227 	    switch (c) {
    228 	    case 'd':
    229 		val = va_arg(args, long);
    230 #if defined(__ANDROID__)
    231 		if ((long)val < 0) {
    232 		    neg = 1;
    233 		    val = (unsigned long)(-(long)val);
    234 		}
    235 #else
    236 		if (val < 0) {
    237 		    neg = 1;
    238 		    val = -val;
    239 		}
    240 #endif
    241 		base = 10;
    242 		break;
    243 	    case 'u':
    244 		val = va_arg(args, unsigned long);
    245 		base = 10;
    246 		break;
    247 	    default:
    248 		OUTCHAR('%');
    249 		OUTCHAR('l');
    250 		--fmt;		/* so %lz outputs %lz etc. */
    251 		continue;
    252 	    }
    253 	    break;
    254 	case 'd':
    255 	    i = va_arg(args, int);
    256 	    if (i < 0) {
    257 		neg = 1;
    258 		val = -i;
    259 	    } else
    260 		val = i;
    261 	    base = 10;
    262 	    break;
    263 	case 'u':
    264 	    val = va_arg(args, unsigned int);
    265 	    base = 10;
    266 	    break;
    267 	case 'o':
    268 	    val = va_arg(args, unsigned int);
    269 	    base = 8;
    270 	    break;
    271 	case 'x':
    272 	case 'X':
    273 	    val = va_arg(args, unsigned int);
    274 	    base = 16;
    275 	    break;
    276 	case 'p':
    277 	    val = (unsigned long) va_arg(args, void *);
    278 	    base = 16;
    279 	    neg = 2;
    280 	    break;
    281 	case 's':
    282 	    str = va_arg(args, char *);
    283 	    break;
    284 	case 'c':
    285 	    num[0] = va_arg(args, int);
    286 	    num[1] = 0;
    287 	    str = num;
    288 	    break;
    289 	case 'm':
    290 	    str = strerror(errno);
    291 	    break;
    292 	case 'I':
    293 	    ip = va_arg(args, u_int32_t);
    294 	    ip = ntohl(ip);
    295 	    slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff,
    296 		     (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
    297 	    str = num;
    298 	    break;
    299 	case 't':
    300 	    time(&t);
    301 	    str = ctime(&t);
    302 	    str += 4;		/* chop off the day name */
    303 	    str[15] = 0;	/* chop off year and newline */
    304 	    break;
    305 	case 'v':		/* "visible" string */
    306 	case 'q':		/* quoted string */
    307 	    quoted = c == 'q';
    308 	    p = va_arg(args, unsigned char *);
    309 	    if (p == NULL)
    310 		    p = (unsigned char *)"<NULL>";
    311 	    if (fillch == '0' && prec >= 0) {
    312 		n = prec;
    313 	    } else {
    314 		n = strlen((char *)p);
    315 		if (prec >= 0 && n > prec)
    316 		    n = prec;
    317 	    }
    318 	    while (n > 0 && buflen > 0) {
    319 		c = *p++;
    320 		--n;
    321 		if (!quoted && c >= 0x80) {
    322 		    OUTCHAR('M');
    323 		    OUTCHAR('-');
    324 		    c -= 0x80;
    325 		}
    326 		if (quoted && (c == '"' || c == '\\'))
    327 		    OUTCHAR('\\');
    328 		if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
    329 		    if (quoted) {
    330 			OUTCHAR('\\');
    331 			switch (c) {
    332 			case '\t':	OUTCHAR('t');	break;
    333 			case '\n':	OUTCHAR('n');	break;
    334 			case '\b':	OUTCHAR('b');	break;
    335 			case '\f':	OUTCHAR('f');	break;
    336 			default:
    337 			    OUTCHAR('x');
    338 			    OUTCHAR(hexchars[c >> 4]);
    339 			    OUTCHAR(hexchars[c & 0xf]);
    340 			}
    341 		    } else {
    342 			if (c == '\t')
    343 			    OUTCHAR(c);
    344 			else {
    345 			    OUTCHAR('^');
    346 			    OUTCHAR(c ^ 0x40);
    347 			}
    348 		    }
    349 		} else
    350 		    OUTCHAR(c);
    351 	    }
    352 	    continue;
    353 	case 'P':		/* print PPP packet */
    354 	    bufinfo.ptr = buf;
    355 	    bufinfo.len = buflen + 1;
    356 	    p = va_arg(args, unsigned char *);
    357 	    n = va_arg(args, int);
    358 	    format_packet(p, n, vslp_printer, &bufinfo);
    359 	    buf = bufinfo.ptr;
    360 	    buflen = bufinfo.len - 1;
    361 	    continue;
    362 	case 'B':
    363 	    p = va_arg(args, unsigned char *);
    364 	    for (n = prec; n > 0; --n) {
    365 		c = *p++;
    366 		if (fillch == ' ')
    367 		    OUTCHAR(' ');
    368 		OUTCHAR(hexchars[(c >> 4) & 0xf]);
    369 		OUTCHAR(hexchars[c & 0xf]);
    370 	    }
    371 	    continue;
    372 	default:
    373 	    *buf++ = '%';
    374 	    if (c != '%')
    375 		--fmt;		/* so %z outputs %z etc. */
    376 	    --buflen;
    377 	    continue;
    378 	}
    379 	if (base != 0) {
    380 	    str = num + sizeof(num);
    381 	    *--str = 0;
    382 	    while (str > num + neg) {
    383 		*--str = hexchars[val % base];
    384 		val = val / base;
    385 		if (--prec <= 0 && val == 0)
    386 		    break;
    387 	    }
    388 	    switch (neg) {
    389 	    case 1:
    390 		*--str = '-';
    391 		break;
    392 	    case 2:
    393 		*--str = 'x';
    394 		*--str = '0';
    395 		break;
    396 	    }
    397 	    len = num + sizeof(num) - 1 - str;
    398 	} else {
    399 	    len = strlen(str);
    400 	    if (prec >= 0 && len > prec)
    401 		len = prec;
    402 	}
    403 	if (width > 0) {
    404 	    if (width > buflen)
    405 		width = buflen;
    406 	    if ((n = width - len) > 0) {
    407 		buflen -= n;
    408 		for (; n > 0; --n)
    409 		    *buf++ = fillch;
    410 	    }
    411 	}
    412 	if (len > buflen)
    413 	    len = buflen;
    414 	memcpy(buf, str, len);
    415 	buf += len;
    416 	buflen -= len;
    417     }
    418     *buf = 0;
    419     return buf - buf0;
    420 }
    421 
    422 /*
    423  * vslp_printer - used in processing a %P format
    424  */
    425 static void
    426 vslp_printer __V((void *arg, char *fmt, ...))
    427 {
    428     int n;
    429     va_list pvar;
    430     struct buffer_info *bi;
    431 
    432 #if defined(__STDC__)
    433     va_start(pvar, fmt);
    434 #else
    435     void *arg;
    436     char *fmt;
    437     va_start(pvar);
    438     arg = va_arg(pvar, void *);
    439     fmt = va_arg(pvar, char *);
    440 #endif
    441 
    442     bi = (struct buffer_info *) arg;
    443     n = vslprintf(bi->ptr, bi->len, fmt, pvar);
    444     va_end(pvar);
    445 
    446     bi->ptr += n;
    447     bi->len -= n;
    448 }
    449 
    450 #ifdef unused
    451 /*
    452  * log_packet - format a packet and log it.
    453  */
    454 
    455 void
    456 log_packet(p, len, prefix, level)
    457     u_char *p;
    458     int len;
    459     char *prefix;
    460     int level;
    461 {
    462 	init_pr_log(prefix, level);
    463 	format_packet(p, len, pr_log, &level);
    464 	end_pr_log();
    465 }
    466 #endif /* unused */
    467 
    468 /*
    469  * format_packet - make a readable representation of a packet,
    470  * calling `printer(arg, format, ...)' to output it.
    471  */
    472 static void
    473 format_packet(p, len, printer, arg)
    474     u_char *p;
    475     int len;
    476     printer_func printer;
    477     void *arg;
    478 {
    479     int i, n;
    480     u_short proto;
    481     struct protent *protp;
    482 
    483     if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
    484 	p += 2;
    485 	GETSHORT(proto, p);
    486 	len -= PPP_HDRLEN;
    487 	for (i = 0; (protp = protocols[i]) != NULL; ++i)
    488 	    if (proto == protp->protocol)
    489 		break;
    490 	if (protp != NULL) {
    491 	    printer(arg, "[%s", protp->name);
    492 	    n = (*protp->printpkt)(p, len, printer, arg);
    493 	    printer(arg, "]");
    494 	    p += n;
    495 	    len -= n;
    496 	} else {
    497 	    for (i = 0; (protp = protocols[i]) != NULL; ++i)
    498 		if (proto == (protp->protocol & ~0x8000))
    499 		    break;
    500 	    if (protp != 0 && protp->data_name != 0) {
    501 		printer(arg, "[%s data]", protp->data_name);
    502 		if (len > 8)
    503 		    printer(arg, "%.8B ...", p);
    504 		else
    505 		    printer(arg, "%.*B", len, p);
    506 		len = 0;
    507 	    } else
    508 		printer(arg, "[proto=0x%x]", proto);
    509 	}
    510     }
    511 
    512     if (len > 32)
    513 	printer(arg, "%.32B ...", p);
    514     else
    515 	printer(arg, "%.*B", len, p);
    516 }
    517 
    518 /*
    519  * init_pr_log, end_pr_log - initialize and finish use of pr_log.
    520  */
    521 
    522 static char line[256];		/* line to be logged accumulated here */
    523 static char *linep;		/* current pointer within line */
    524 static int llevel;		/* level for logging */
    525 
    526 void
    527 init_pr_log(prefix, level)
    528      const char *prefix;
    529      int level;
    530 {
    531 	linep = line;
    532 	if (prefix != NULL) {
    533 		strlcpy(line, prefix, sizeof(line));
    534 		linep = line + strlen(line);
    535 	}
    536 	llevel = level;
    537 }
    538 
    539 void
    540 end_pr_log()
    541 {
    542 	if (linep != line) {
    543 		*linep = 0;
    544 		log_write(llevel, line);
    545 	}
    546 }
    547 
    548 /*
    549  * pr_log - printer routine for outputting to syslog
    550  */
    551 void
    552 pr_log __V((void *arg, char *fmt, ...))
    553 {
    554 	int l, n;
    555 	va_list pvar;
    556 	char *p, *eol;
    557 	char buf[256];
    558 
    559 #if defined(__STDC__)
    560 	va_start(pvar, fmt);
    561 #else
    562 	void *arg;
    563 	char *fmt;
    564 	va_start(pvar);
    565 	arg = va_arg(pvar, void *);
    566 	fmt = va_arg(pvar, char *);
    567 #endif
    568 
    569 	n = vslprintf(buf, sizeof(buf), fmt, pvar);
    570 	va_end(pvar);
    571 
    572 	p = buf;
    573 	eol = strchr(buf, '\n');
    574 	if (linep != line) {
    575 		l = (eol == NULL)? n: eol - buf;
    576 		if (linep + l < line + sizeof(line)) {
    577 			if (l > 0) {
    578 				memcpy(linep, buf, l);
    579 				linep += l;
    580 			}
    581 			if (eol == NULL)
    582 				return;
    583 			p = eol + 1;
    584 			eol = strchr(p, '\n');
    585 		}
    586 		*linep = 0;
    587 		log_write(llevel, line);
    588 		linep = line;
    589 	}
    590 
    591 	while (eol != NULL) {
    592 		*eol = 0;
    593 		log_write(llevel, p);
    594 		p = eol + 1;
    595 		eol = strchr(p, '\n');
    596 	}
    597 
    598 	/* assumes sizeof(buf) <= sizeof(line) */
    599 	l = buf + n - p;
    600 	if (l > 0) {
    601 		memcpy(line, p, n);
    602 		linep = line + l;
    603 	}
    604 }
    605 
    606 /*
    607  * print_string - print a readable representation of a string using
    608  * printer.
    609  */
    610 void
    611 print_string(p, len, printer, arg)
    612     char *p;
    613     int len;
    614     printer_func printer;
    615     void *arg;
    616 {
    617     int c;
    618 
    619     printer(arg, "\"");
    620     for (; len > 0; --len) {
    621 	c = *p++;
    622 	if (' ' <= c && c <= '~') {
    623 	    if (c == '\\' || c == '"')
    624 		printer(arg, "\\");
    625 	    printer(arg, "%c", c);
    626 	} else {
    627 	    switch (c) {
    628 	    case '\n':
    629 		printer(arg, "\\n");
    630 		break;
    631 	    case '\r':
    632 		printer(arg, "\\r");
    633 		break;
    634 	    case '\t':
    635 		printer(arg, "\\t");
    636 		break;
    637 	    default:
    638 		printer(arg, "\\%.3o", c);
    639 	    }
    640 	}
    641     }
    642     printer(arg, "\"");
    643 }
    644 
    645 /*
    646  * logit - does the hard work for fatal et al.
    647  */
    648 static void
    649 logit(level, fmt, args)
    650     int level;
    651     char *fmt;
    652     va_list args;
    653 {
    654     char buf[1024];
    655 
    656     vslprintf(buf, sizeof(buf), fmt, args);
    657     log_write(level, buf);
    658 }
    659 
    660 static void
    661 log_write(level, buf)
    662     int level;
    663     char *buf;
    664 {
    665     syslog(level, "%s", buf);
    666     if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) {
    667 	int n = strlen(buf);
    668 
    669 	if (n > 0 && buf[n-1] == '\n')
    670 	    --n;
    671 	if (write(log_to_fd, buf, n) != n
    672 	    || write(log_to_fd, "\n", 1) != 1)
    673 	    log_to_fd = -1;
    674     }
    675 }
    676 
    677 /*
    678  * fatal - log an error message and die horribly.
    679  */
    680 void
    681 fatal __V((char *fmt, ...))
    682 {
    683     va_list pvar;
    684 
    685 #if defined(__STDC__)
    686     va_start(pvar, fmt);
    687 #else
    688     char *fmt;
    689     va_start(pvar);
    690     fmt = va_arg(pvar, char *);
    691 #endif
    692 
    693     logit(LOG_ERR, fmt, pvar);
    694     va_end(pvar);
    695 
    696     die(1);			/* as promised */
    697 }
    698 
    699 /*
    700  * error - log an error message.
    701  */
    702 void
    703 error __V((char *fmt, ...))
    704 {
    705     va_list pvar;
    706 
    707 #if defined(__STDC__)
    708     va_start(pvar, fmt);
    709 #else
    710     char *fmt;
    711     va_start(pvar);
    712     fmt = va_arg(pvar, char *);
    713 #endif
    714 
    715     logit(LOG_ERR, fmt, pvar);
    716     va_end(pvar);
    717     ++error_count;
    718 }
    719 
    720 /*
    721  * warn - log a warning message.
    722  */
    723 void
    724 warn __V((char *fmt, ...))
    725 {
    726     va_list pvar;
    727 
    728 #if defined(__STDC__)
    729     va_start(pvar, fmt);
    730 #else
    731     char *fmt;
    732     va_start(pvar);
    733     fmt = va_arg(pvar, char *);
    734 #endif
    735 
    736     logit(LOG_WARNING, fmt, pvar);
    737     va_end(pvar);
    738 }
    739 
    740 /*
    741  * notice - log a notice-level message.
    742  */
    743 void
    744 notice __V((char *fmt, ...))
    745 {
    746     va_list pvar;
    747 
    748 #if defined(__STDC__)
    749     va_start(pvar, fmt);
    750 #else
    751     char *fmt;
    752     va_start(pvar);
    753     fmt = va_arg(pvar, char *);
    754 #endif
    755 
    756     logit(LOG_NOTICE, fmt, pvar);
    757     va_end(pvar);
    758 }
    759 
    760 /*
    761  * info - log an informational message.
    762  */
    763 void
    764 info __V((char *fmt, ...))
    765 {
    766     va_list pvar;
    767 
    768 #if defined(__STDC__)
    769     va_start(pvar, fmt);
    770 #else
    771     char *fmt;
    772     va_start(pvar);
    773     fmt = va_arg(pvar, char *);
    774 #endif
    775 
    776     logit(LOG_INFO, fmt, pvar);
    777     va_end(pvar);
    778 }
    779 
    780 /*
    781  * dbglog - log a debug message.
    782  */
    783 void
    784 dbglog __V((char *fmt, ...))
    785 {
    786     va_list pvar;
    787 
    788 #if defined(__STDC__)
    789     va_start(pvar, fmt);
    790 #else
    791     char *fmt;
    792     va_start(pvar);
    793     fmt = va_arg(pvar, char *);
    794 #endif
    795 
    796     logit(LOG_DEBUG, fmt, pvar);
    797     va_end(pvar);
    798 }
    799 
    800 /*
    801  * dump_packet - print out a packet in readable form if it is interesting.
    802  * Assumes len >= PPP_HDRLEN.
    803  */
    804 void
    805 dump_packet(const char *tag, unsigned char *p, int len)
    806 {
    807     int proto;
    808 
    809     if (!debug)
    810 	return;
    811 
    812     /*
    813      * don't print LCP echo request/reply packets if debug <= 1
    814      * and the link is up.
    815      */
    816     proto = (p[2] << 8) + p[3];
    817     if (debug <= 1 && unsuccess == 0 && proto == PPP_LCP
    818 	&& len >= PPP_HDRLEN + HEADERLEN) {
    819 	unsigned char *lcp = p + PPP_HDRLEN;
    820 	int l = (lcp[2] << 8) + lcp[3];
    821 
    822 	if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP)
    823 	    && l >= HEADERLEN && l <= len - PPP_HDRLEN)
    824 	    return;
    825     }
    826 
    827     dbglog("%s %P", tag, p, len);
    828 }
    829 
    830 /*
    831  * complete_read - read a full `count' bytes from fd,
    832  * unless end-of-file or an error other than EINTR is encountered.
    833  */
    834 ssize_t
    835 complete_read(int fd, void *buf, size_t count)
    836 {
    837 	size_t done;
    838 	ssize_t nb;
    839 	char *ptr = buf;
    840 
    841 	for (done = 0; done < count; ) {
    842 		nb = read(fd, ptr, count - done);
    843 		if (nb < 0) {
    844 			if (errno == EINTR)
    845 				continue;
    846 			return -1;
    847 		}
    848 		if (nb == 0)
    849 			break;
    850 		done += nb;
    851 		ptr += nb;
    852 	}
    853 	return done;
    854 }
    855 
    856 /* Procedures for locking the serial device using a lock file. */
    857 #ifndef LOCK_DIR
    858 #ifdef __linux__
    859 #define LOCK_DIR	"/var/lock"
    860 #else
    861 #ifdef SVR4
    862 #define LOCK_DIR	"/var/spool/locks"
    863 #else
    864 #define LOCK_DIR	"/var/spool/lock"
    865 #endif
    866 #endif
    867 #endif /* LOCK_DIR */
    868 
    869 static char lock_file[MAXPATHLEN];
    870 
    871 /*
    872  * lock - create a lock file for the named device
    873  */
    874 int
    875 lock(dev)
    876     char *dev;
    877 {
    878 #ifdef LOCKLIB
    879     int result;
    880 
    881     result = mklock (dev, (void *) 0);
    882     if (result == 0) {
    883 	strlcpy(lock_file, dev, sizeof(lock_file));
    884 	return 0;
    885     }
    886 
    887     if (result > 0)
    888         notice("Device %s is locked by pid %d", dev, result);
    889     else
    890 	error("Can't create lock file %s", lock_file);
    891     return -1;
    892 
    893 #else /* LOCKLIB */
    894 
    895     char lock_buffer[12];
    896     int fd, pid, n;
    897 
    898 #ifdef SVR4
    899     struct stat sbuf;
    900 
    901     if (stat(dev, &sbuf) < 0) {
    902 	error("Can't get device number for %s: %m", dev);
    903 	return -1;
    904     }
    905     if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
    906 	error("Can't lock %s: not a character device", dev);
    907 	return -1;
    908     }
    909     slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
    910 	     LOCK_DIR, major(sbuf.st_dev),
    911 	     major(sbuf.st_rdev), minor(sbuf.st_rdev));
    912 #else
    913     char *p;
    914     char lockdev[MAXPATHLEN];
    915 
    916     if ((p = strstr(dev, "dev/")) != NULL) {
    917 	dev = p + 4;
    918 	strncpy(lockdev, dev, MAXPATHLEN-1);
    919 	lockdev[MAXPATHLEN-1] = 0;
    920 	while ((p = strrchr(lockdev, '/')) != NULL) {
    921 	    *p = '_';
    922 	}
    923 	dev = lockdev;
    924     } else
    925 	if ((p = strrchr(dev, '/')) != NULL)
    926 	    dev = p + 1;
    927 
    928     slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
    929 #endif
    930 
    931     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
    932 	if (errno != EEXIST) {
    933 	    error("Can't create lock file %s: %m", lock_file);
    934 	    break;
    935 	}
    936 
    937 	/* Read the lock file to find out who has the device locked. */
    938 	fd = open(lock_file, O_RDONLY, 0);
    939 	if (fd < 0) {
    940 	    if (errno == ENOENT) /* This is just a timing problem. */
    941 		continue;
    942 	    error("Can't open existing lock file %s: %m", lock_file);
    943 	    break;
    944 	}
    945 #ifndef LOCK_BINARY
    946 	n = read(fd, lock_buffer, 11);
    947 #else
    948 	n = read(fd, &pid, sizeof(pid));
    949 #endif /* LOCK_BINARY */
    950 	close(fd);
    951 	fd = -1;
    952 	if (n <= 0) {
    953 	    error("Can't read pid from lock file %s", lock_file);
    954 	    break;
    955 	}
    956 
    957 	/* See if the process still exists. */
    958 #ifndef LOCK_BINARY
    959 	lock_buffer[n] = 0;
    960 	pid = atoi(lock_buffer);
    961 #endif /* LOCK_BINARY */
    962 	if (pid == getpid())
    963 	    return 1;		/* somebody else locked it for us */
    964 	if (pid == 0
    965 	    || (kill(pid, 0) == -1 && errno == ESRCH)) {
    966 	    if (unlink (lock_file) == 0) {
    967 		notice("Removed stale lock on %s (pid %d)", dev, pid);
    968 		continue;
    969 	    }
    970 	    warn("Couldn't remove stale lock on %s", dev);
    971 	} else
    972 	    notice("Device %s is locked by pid %d", dev, pid);
    973 	break;
    974     }
    975 
    976     if (fd < 0) {
    977 	lock_file[0] = 0;
    978 	return -1;
    979     }
    980 
    981     pid = getpid();
    982 #ifndef LOCK_BINARY
    983     slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
    984     write (fd, lock_buffer, 11);
    985 #else
    986     write(fd, &pid, sizeof (pid));
    987 #endif
    988     close(fd);
    989     return 0;
    990 
    991 #endif
    992 }
    993 
    994 /*
    995  * relock - called to update our lockfile when we are about to detach,
    996  * thus changing our pid (we fork, the child carries on, and the parent dies).
    997  * Note that this is called by the parent, with pid equal to the pid
    998  * of the child.  This avoids a potential race which would exist if
    999  * we had the child rewrite the lockfile (the parent might die first,
   1000  * and another process could think the lock was stale if it checked
   1001  * between when the parent died and the child rewrote the lockfile).
   1002  */
   1003 int
   1004 relock(pid)
   1005     int pid;
   1006 {
   1007 #ifdef LOCKLIB
   1008     /* XXX is there a way to do this? */
   1009     return -1;
   1010 #else /* LOCKLIB */
   1011 
   1012     int fd;
   1013     char lock_buffer[12];
   1014 
   1015     if (lock_file[0] == 0)
   1016 	return -1;
   1017     fd = open(lock_file, O_WRONLY, 0);
   1018     if (fd < 0) {
   1019 	error("Couldn't reopen lock file %s: %m", lock_file);
   1020 	lock_file[0] = 0;
   1021 	return -1;
   1022     }
   1023 
   1024 #ifndef LOCK_BINARY
   1025     slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
   1026     write (fd, lock_buffer, 11);
   1027 #else
   1028     write(fd, &pid, sizeof(pid));
   1029 #endif /* LOCK_BINARY */
   1030     close(fd);
   1031     return 0;
   1032 
   1033 #endif /* LOCKLIB */
   1034 }
   1035 
   1036 /*
   1037  * unlock - remove our lockfile
   1038  */
   1039 void
   1040 unlock()
   1041 {
   1042     if (lock_file[0]) {
   1043 #ifdef LOCKLIB
   1044 	(void) rmlock(lock_file, (void *) 0);
   1045 #else
   1046 	unlink(lock_file);
   1047 #endif
   1048 	lock_file[0] = 0;
   1049     }
   1050 }
   1051 
   1052