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