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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 * 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