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