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