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