• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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
strlcpy(dest,src,len)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
strlcat(dest,src,len)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
slprintf(char * buf,int buflen,char * fmt,...)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
vslprintf(buf,buflen,fmt,args)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
vslp_printer(void * arg,char * fmt,...)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
log_packet(p,len,prefix,level)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
format_packet(p,len,printer,arg)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
init_pr_log(prefix,level)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
end_pr_log()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
pr_log(void * arg,char * fmt,...)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
print_string(p,len,printer,arg)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
logit(level,fmt,args)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
log_write(level,buf)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
fatal(char * fmt,...)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
error(char * fmt,...)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
warn(char * fmt,...)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
notice(char * fmt,...)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
info(char * fmt,...)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
dbglog(char * fmt,...)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
dump_packet(const char * tag,unsigned char * p,int len)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
complete_read(int fd,void * buf,size_t count)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
lock(dev)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
relock(pid)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
unlock()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