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