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