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