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