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