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