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