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