]> git.ozlabs.org Git - ppp.git/blob - pppd/utils.c
Makefile.am: Add explicit openssl directory to pppd include path
[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 #ifndef UNIT_TEST
333         case 'P':               /* print PPP packet */
334             bufinfo.ptr = buf;
335             bufinfo.len = buflen + 1;
336             p = va_arg(args, unsigned char *);
337             n = va_arg(args, int);
338             format_packet(p, n, vslp_printer, &bufinfo);
339             buf = bufinfo.ptr;
340             buflen = bufinfo.len - 1;
341             continue;
342 #endif
343         case 'B':
344             p = va_arg(args, unsigned char *);
345             for (n = prec; n > 0; --n) {
346                 c = *p++;
347                 if (fillch == ' ')
348                     OUTCHAR(' ');
349                 OUTCHAR(hexchars[(c >> 4) & 0xf]);
350                 OUTCHAR(hexchars[c & 0xf]);
351             }
352             continue;
353         default:
354             *buf++ = '%';
355             if (c != '%')
356                 --fmt;          /* so %z outputs %z etc. */
357             --buflen;
358             continue;
359         }
360         if (base != 0) {
361             str = num + sizeof(num);
362             *--str = 0;
363             while (str > num + neg) {
364                 *--str = hexchars[val % base];
365                 val = val / base;
366                 if (--prec <= 0 && val == 0)
367                     break;
368             }
369             switch (neg) {
370             case 1:
371                 *--str = '-';
372                 break;
373             case 2:
374                 *--str = 'x';
375                 *--str = '0';
376                 break;
377             }
378             len = num + sizeof(num) - 1 - str;
379         } else {
380             for (len = 0; len < buflen && (prec == -1 || len < prec); ++len)
381                 if (str[len] == 0)
382                     break;
383         }
384         if (width > 0) {
385             if (width > buflen)
386                 width = buflen;
387             if ((n = width - len) > 0) {
388                 buflen -= n;
389                 for (; n > 0; --n)
390                     *buf++ = fillch;
391             }
392         }
393         if (len > buflen)
394             len = buflen;
395         memcpy(buf, str, len);
396         buf += len;
397         buflen -= len;
398     }
399     *buf = 0;
400     return buf - buf0;
401 }
402
403 /*
404  * vslp_printer - used in processing a %P format
405  */
406 static void
407 vslp_printer(void *arg, char *fmt, ...)
408 {
409     int n;
410     va_list pvar;
411     struct buffer_info *bi;
412
413     va_start(pvar, fmt);
414
415     bi = (struct buffer_info *) arg;
416     n = vslprintf(bi->ptr, bi->len, fmt, pvar);
417     va_end(pvar);
418
419     bi->ptr += n;
420     bi->len -= n;
421 }
422
423 #ifdef unused
424 /*
425  * log_packet - format a packet and log it.
426  */
427
428 void
429 log_packet(u_char *p, int len, char *prefix, int level)
430 {
431         init_pr_log(prefix, level);
432         format_packet(p, len, pr_log, &level);
433         end_pr_log();
434 }
435 #endif /* unused */
436
437 #ifndef UNIT_TEST
438 /*
439  * format_packet - make a readable representation of a packet,
440  * calling `printer(arg, format, ...)' to output it.
441  */
442 static void
443 format_packet(u_char *p, int len, printer_func printer, void *arg)
444 {
445     int i, n;
446     u_short proto;
447     struct protent *protp;
448
449     if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
450         p += 2;
451         GETSHORT(proto, p);
452         len -= PPP_HDRLEN;
453         for (i = 0; (protp = protocols[i]) != NULL; ++i)
454             if (proto == protp->protocol)
455                 break;
456         if (protp != NULL) {
457             printer(arg, "[%s", protp->name);
458             n = (*protp->printpkt)(p, len, printer, arg);
459             printer(arg, "]");
460             p += n;
461             len -= n;
462         } else {
463             for (i = 0; (protp = protocols[i]) != NULL; ++i)
464                 if (proto == (protp->protocol & ~0x8000))
465                     break;
466             if (protp != 0 && protp->data_name != 0) {
467                 printer(arg, "[%s data]", protp->data_name);
468                 if (len > 8)
469                     printer(arg, "%.8B ...", p);
470                 else
471                     printer(arg, "%.*B", len, p);
472                 len = 0;
473             } else
474                 printer(arg, "[proto=0x%x]", proto);
475         }
476     }
477
478     if (len > 32)
479         printer(arg, "%.32B ...", p);
480     else
481         printer(arg, "%.*B", len, p);
482 }
483 #endif  /* UNIT_TEST */
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(const char *prefix, int level)
495 {
496         linep = line;
497         if (prefix != NULL) {
498                 strlcpy(line, prefix, sizeof(line));
499                 linep = line + strlen(line);
500         }
501         llevel = level;
502 }
503
504 void
505 end_pr_log(void)
506 {
507         if (linep != line) {
508                 *linep = 0;
509                 log_write(llevel, line);
510         }
511 }
512
513 /*
514  * pr_log - printer routine for outputting to syslog
515  */
516 void
517 pr_log(void *arg, char *fmt, ...)
518 {
519         int l, n;
520         va_list pvar;
521         char *p, *eol;
522         char buf[256];
523
524         va_start(pvar, fmt);
525
526         n = vslprintf(buf, sizeof(buf), fmt, pvar);
527         va_end(pvar);
528
529         p = buf;
530         eol = strchr(buf, '\n');
531         if (linep != line) {
532                 l = (eol == NULL)? n: eol - buf;
533                 if (linep + l < line + sizeof(line)) {
534                         if (l > 0) {
535                                 memcpy(linep, buf, l);
536                                 linep += l;
537                         }
538                         if (eol == NULL)
539                                 return;
540                         p = eol + 1;
541                         eol = strchr(p, '\n');
542                 }
543                 *linep = 0;
544                 log_write(llevel, line);
545                 linep = line;
546         }
547
548         while (eol != NULL) {
549                 *eol = 0;
550                 log_write(llevel, p);
551                 p = eol + 1;
552                 eol = strchr(p, '\n');
553         }
554
555         /* assumes sizeof(buf) <= sizeof(line) */
556         l = buf + n - p;
557         if (l > 0) {
558                 memcpy(line, p, n);
559                 linep = line + l;
560         }
561 }
562
563 /*
564  * print_string - print a readable representation of a string using
565  * printer.
566  */
567 void
568 print_string(char *p, int len, printer_func printer, void *arg)
569 {
570     int c;
571
572     printer(arg, "\"");
573     for (; len > 0; --len) {
574         c = *p++;
575         if (' ' <= c && c <= '~') {
576             if (c == '\\' || c == '"')
577                 printer(arg, "\\");
578             printer(arg, "%c", c);
579         } else {
580             switch (c) {
581             case '\n':
582                 printer(arg, "\\n");
583                 break;
584             case '\r':
585                 printer(arg, "\\r");
586                 break;
587             case '\t':
588                 printer(arg, "\\t");
589                 break;
590             default:
591                 printer(arg, "\\%.3o", (unsigned char) c);
592             }
593         }
594     }
595     printer(arg, "\"");
596 }
597
598 /*
599  * logit - does the hard work for fatal et al.
600  */
601 static void
602 logit(int level, char *fmt, va_list args)
603 {
604     char buf[1024];
605
606     vslprintf(buf, sizeof(buf), fmt, args);
607     log_write(level, buf);
608 }
609
610 #ifndef UNIT_TEST
611 static void
612 log_write(int level, char *buf)
613 {
614     syslog(level, "%s", buf);
615     if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) {
616         int n = strlen(buf);
617
618         if (n > 0 && buf[n-1] == '\n')
619             --n;
620         if (write(log_to_fd, buf, n) != n
621             || write(log_to_fd, "\n", 1) != 1)
622             log_to_fd = -1;
623     }
624 }
625 #else
626 static void
627 log_write(int level, char *buf)
628 {
629     printf("<%d>: %s\n", level, buf);
630 }
631 #endif
632
633 /*
634  * fatal - log an error message and die horribly.
635  */
636 void
637 fatal(char *fmt, ...)
638 {
639     va_list pvar;
640
641     va_start(pvar, fmt);
642
643     logit(LOG_ERR, fmt, pvar);
644     va_end(pvar);
645
646 #ifndef UNIT_TEST
647     die(1);                     /* as promised */
648 #else
649     exit(-1);
650 #endif
651 }
652
653 /*
654  * error - log an error message.
655  */
656 void
657 error(char *fmt, ...)
658 {
659     va_list pvar;
660
661     va_start(pvar, fmt);
662
663     logit(LOG_ERR, fmt, pvar);
664     va_end(pvar);
665     ++error_count;
666 }
667
668 /*
669  * warn - log a warning message.
670  */
671 void
672 warn(char *fmt, ...)
673 {
674     va_list pvar;
675
676     va_start(pvar, fmt);
677
678     logit(LOG_WARNING, fmt, pvar);
679     va_end(pvar);
680 }
681
682 /*
683  * notice - log a notice-level message.
684  */
685 void
686 notice(char *fmt, ...)
687 {
688     va_list pvar;
689
690     va_start(pvar, fmt);
691
692     logit(LOG_NOTICE, fmt, pvar);
693     va_end(pvar);
694 }
695
696 /*
697  * info - log an informational message.
698  */
699 void
700 info(char *fmt, ...)
701 {
702     va_list pvar;
703
704     va_start(pvar, fmt);
705
706     logit(LOG_INFO, fmt, pvar);
707     va_end(pvar);
708 }
709
710 /*
711  * dbglog - log a debug message.
712  */
713 void
714 dbglog(char *fmt, ...)
715 {
716     va_list pvar;
717
718     va_start(pvar, fmt);
719
720     logit(LOG_DEBUG, fmt, pvar);
721     va_end(pvar);
722 }
723
724 /*
725  * dump_packet - print out a packet in readable form if it is interesting.
726  * Assumes len >= PPP_HDRLEN.
727  */
728 void
729 dump_packet(const char *tag, unsigned char *p, int len)
730 {
731     int proto;
732
733     if (!debug)
734         return;
735
736     /*
737      * don't print LCP echo request/reply packets if debug <= 1
738      * and the link is up.
739      */
740     proto = (p[2] << 8) + p[3];
741     if (debug <= 1 && unsuccess == 0 && proto == PPP_LCP
742         && len >= PPP_HDRLEN + HEADERLEN) {
743         unsigned char *lcp = p + PPP_HDRLEN;
744         int l = (lcp[2] << 8) + lcp[3];
745
746         if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP)
747             && l >= HEADERLEN && l <= len - PPP_HDRLEN)
748             return;
749     }
750
751     dbglog("%s %P", tag, p, len);
752 }
753
754
755 #ifndef UNIT_TEST
756 /*
757  * complete_read - read a full `count' bytes from fd,
758  * unless end-of-file or an error other than EINTR is encountered.
759  */
760 ssize_t
761 complete_read(int fd, void *buf, size_t count)
762 {
763         size_t done;
764         ssize_t nb;
765         char *ptr = buf;
766
767         for (done = 0; done < count; ) {
768                 nb = read(fd, ptr, count - done);
769                 if (nb < 0) {
770                         if (errno == EINTR && !got_sigterm)
771                                 continue;
772                         return -1;
773                 }
774                 if (nb == 0)
775                         break;
776                 done += nb;
777                 ptr += nb;
778         }
779         return done;
780 }
781 #endif
782
783 /* Procedures for locking the serial device using a lock file. */
784 #ifndef LOCK_DIR
785 #ifdef __linux__
786 #define LOCK_DIR        "/var/lock"
787 #else
788 #ifdef SVR4
789 #define LOCK_DIR        "/var/spool/locks"
790 #else
791 #define LOCK_DIR        "/var/spool/lock"
792 #endif
793 #endif
794 #endif /* LOCK_DIR */
795
796 static char lock_file[MAXPATHLEN];
797
798 /*
799  * lock - create a lock file for the named device
800  */
801 int
802 lock(char *dev)
803 {
804 #ifdef LOCKLIB
805     int result;
806
807     result = mklock (dev, (void *) 0);
808     if (result == 0) {
809         strlcpy(lock_file, dev, sizeof(lock_file));
810         return 0;
811     }
812
813     if (result > 0)
814         notice("Device %s is locked by pid %d", dev, result);
815     else
816         error("Can't create lock file %s", lock_file);
817     return -1;
818
819 #else /* LOCKLIB */
820
821     char lock_buffer[12];
822     int fd, pid, n, siz;
823
824 #ifdef SVR4
825     struct stat sbuf;
826
827     if (stat(dev, &sbuf) < 0) {
828         error("Can't get device number for %s: %m", dev);
829         return -1;
830     }
831     if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
832         error("Can't lock %s: not a character device", dev);
833         return -1;
834     }
835     slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
836              LOCK_DIR, major(sbuf.st_dev),
837              major(sbuf.st_rdev), minor(sbuf.st_rdev));
838 #else
839     char *p;
840     char lockdev[MAXPATHLEN];
841
842     if ((p = strstr(dev, "dev/")) != NULL) {
843         dev = p + 4;
844         strncpy(lockdev, dev, MAXPATHLEN-1);
845         lockdev[MAXPATHLEN-1] = 0;
846         while ((p = strrchr(lockdev, '/')) != NULL) {
847             *p = '_';
848         }
849         dev = lockdev;
850     } else
851         if ((p = strrchr(dev, '/')) != NULL)
852             dev = p + 1;
853
854     slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
855 #endif
856
857     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
858         if (errno != EEXIST) {
859             error("Can't create lock file %s: %m", lock_file);
860             break;
861         }
862
863         /* Read the lock file to find out who has the device locked. */
864         fd = open(lock_file, O_RDONLY, 0);
865         if (fd < 0) {
866             if (errno == ENOENT) /* This is just a timing problem. */
867                 continue;
868             error("Can't open existing lock file %s: %m", lock_file);
869             break;
870         }
871 #ifndef LOCK_BINARY
872         n = read(fd, lock_buffer, 11);
873 #else
874         n = read(fd, &pid, sizeof(pid));
875 #endif /* LOCK_BINARY */
876         close(fd);
877         fd = -1;
878         if (n <= 0) {
879             error("Can't read pid from lock file %s", lock_file);
880             break;
881         }
882
883         /* See if the process still exists. */
884 #ifndef LOCK_BINARY
885         lock_buffer[n] = 0;
886         pid = atoi(lock_buffer);
887 #endif /* LOCK_BINARY */
888         if (pid == getpid())
889             return 1;           /* somebody else locked it for us */
890         if (pid == 0
891             || (kill(pid, 0) == -1 && errno == ESRCH)) {
892             if (unlink (lock_file) == 0) {
893                 notice("Removed stale lock on %s (pid %d)", dev, pid);
894                 continue;
895             }
896             warn("Couldn't remove stale lock on %s", dev);
897         } else
898             notice("Device %s is locked by pid %d", dev, pid);
899         break;
900     }
901
902     if (fd < 0) {
903         lock_file[0] = 0;
904         return -1;
905     }
906
907     pid = getpid();
908 #ifndef LOCK_BINARY
909     siz = 11;
910     slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
911     n = write (fd, lock_buffer, siz);
912 #else
913     siz = sizeof (pid);
914     n = write(fd, &pid, siz);
915 #endif
916     if (n != siz) {
917         error("Could not write pid to lock file when locking");
918     }
919     close(fd);
920     return 0;
921
922 #endif
923 }
924
925 /*
926  * relock - called to update our lockfile when we are about to detach,
927  * thus changing our pid (we fork, the child carries on, and the parent dies).
928  * Note that this is called by the parent, with pid equal to the pid
929  * of the child.  This avoids a potential race which would exist if
930  * we had the child rewrite the lockfile (the parent might die first,
931  * and another process could think the lock was stale if it checked
932  * between when the parent died and the child rewrote the lockfile).
933  */
934 int
935 relock(int pid)
936 {
937 #ifdef LOCKLIB
938     /* XXX is there a way to do this? */
939     return -1;
940 #else /* LOCKLIB */
941
942     int fd, n, siz;
943     char lock_buffer[12];
944
945     if (lock_file[0] == 0)
946         return -1;
947     fd = open(lock_file, O_WRONLY, 0);
948     if (fd < 0) {
949         error("Couldn't reopen lock file %s: %m", lock_file);
950         lock_file[0] = 0;
951         return -1;
952     }
953
954 #ifndef LOCK_BINARY
955     siz = 11;
956     slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
957     n = write (fd, lock_buffer, siz);
958 #else
959     siz = sizeof(pid);
960     n = write(fd, &pid, siz);
961 #endif /* LOCK_BINARY */
962     if (n != siz) {
963         error("Could not write pid to lock file when locking");
964     }
965     close(fd);
966     return 0;
967
968 #endif /* LOCKLIB */
969 }
970
971 /*
972  * unlock - remove our lockfile
973  */
974 void
975 unlock(void)
976 {
977     if (lock_file[0]) {
978 #ifdef LOCKLIB
979         (void) rmlock(lock_file, (void *) 0);
980 #else
981         unlink(lock_file);
982 #endif
983         lock_file[0] = 0;
984     }
985 }
986