1 /* $NetBSD: utils.c,v 1.2 2013/11/28 22:33:42 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.2 2013/11/28 22:33:42 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 (fillch == '0' && prec >= 0) { 272 n = prec; 273 } else { 274 n = strlen((char *)p); 275 if (prec >= 0 && n > prec) 276 n = prec; 277 } 278 while (n > 0 && buflen > 0) { 279 c = *p++; 280 --n; 281 if (!quoted && c >= 0x80) { 282 OUTCHAR('M'); 283 OUTCHAR('-'); 284 c -= 0x80; 285 } 286 if (quoted && (c == '"' || c == '\\')) 287 OUTCHAR('\\'); 288 if (c < 0x20 || (0x7f <= c && c < 0xa0)) { 289 if (quoted) { 290 OUTCHAR('\\'); 291 switch (c) { 292 case '\t': OUTCHAR('t'); break; 293 case '\n': OUTCHAR('n'); break; 294 case '\b': OUTCHAR('b'); break; 295 case '\f': OUTCHAR('f'); break; 296 default: 297 OUTCHAR('x'); 298 OUTCHAR(hexchars[c >> 4]); 299 OUTCHAR(hexchars[c & 0xf]); 300 } 301 } else { 302 if (c == '\t') 303 OUTCHAR(c); 304 else { 305 OUTCHAR('^'); 306 OUTCHAR(c ^ 0x40); 307 } 308 } 309 } else 310 OUTCHAR(c); 311 } 312 continue; 313 case 'P': /* print PPP packet */ 314 bufinfo.ptr = buf; 315 bufinfo.len = buflen + 1; 316 p = va_arg(args, unsigned char *); 317 n = va_arg(args, int); 318 format_packet(p, n, vslp_printer, &bufinfo); 319 buf = bufinfo.ptr; 320 buflen = bufinfo.len - 1; 321 continue; 322 case 'B': 323 p = va_arg(args, unsigned char *); 324 for (n = prec; n > 0; --n) { 325 c = *p++; 326 if (fillch == ' ') 327 OUTCHAR(' '); 328 OUTCHAR(hexchars[(c >> 4) & 0xf]); 329 OUTCHAR(hexchars[c & 0xf]); 330 } 331 continue; 332 default: 333 *buf++ = '%'; 334 if (c != '%') 335 --fmt; /* so %z outputs %z etc. */ 336 --buflen; 337 continue; 338 } 339 if (base != 0) { 340 str = num + sizeof(num); 341 *--str = 0; 342 while (str > num + neg) { 343 *--str = hexchars[val % base]; 344 val = val / base; 345 if (--prec <= 0 && val == 0) 346 break; 347 } 348 switch (neg) { 349 case 1: 350 *--str = '-'; 351 break; 352 case 2: 353 *--str = 'x'; 354 *--str = '0'; 355 break; 356 } 357 len = num + sizeof(num) - 1 - str; 358 } else { 359 len = strlen(str); 360 if (prec >= 0 && len > prec) 361 len = prec; 362 } 363 if (width > 0) { 364 if (width > buflen) 365 width = buflen; 366 if ((n = width - len) > 0) { 367 buflen -= n; 368 for (; n > 0; --n) 369 *buf++ = fillch; 370 } 371 } 372 if (len > buflen) 373 len = buflen; 374 memcpy(buf, str, len); 375 buf += len; 376 buflen -= len; 377 } 378 *buf = 0; 379 return buf - buf0; 380 } 381 382 /* 383 * vslp_printer - used in processing a %P format 384 */ 385 static void 386 vslp_printer __V((void *arg, char *fmt, ...)) 387 { 388 int n; 389 va_list pvar; 390 struct buffer_info *bi; 391 392 #if defined(__STDC__) 393 va_start(pvar, fmt); 394 #else 395 void *arg; 396 char *fmt; 397 va_start(pvar); 398 arg = va_arg(pvar, void *); 399 fmt = va_arg(pvar, char *); 400 #endif 401 402 bi = (struct buffer_info *) arg; 403 n = vslprintf(bi->ptr, bi->len, fmt, pvar); 404 va_end(pvar); 405 406 bi->ptr += n; 407 bi->len -= n; 408 } 409 410 #ifdef unused 411 /* 412 * log_packet - format a packet and log it. 413 */ 414 415 void 416 log_packet(p, len, prefix, level) 417 u_char *p; 418 int len; 419 char *prefix; 420 int level; 421 { 422 init_pr_log(prefix, level); 423 format_packet(p, len, pr_log, &level); 424 end_pr_log(); 425 } 426 #endif /* unused */ 427 428 /* 429 * format_packet - make a readable representation of a packet, 430 * calling `printer(arg, format, ...)' to output it. 431 */ 432 static void 433 format_packet(p, len, printer, arg) 434 u_char *p; 435 int len; 436 printer_func printer; 437 void *arg; 438 { 439 int i, n; 440 u_short proto; 441 struct protent *protp; 442 443 if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) { 444 p += 2; 445 GETSHORT(proto, p); 446 len -= PPP_HDRLEN; 447 for (i = 0; (protp = protocols[i]) != NULL; ++i) 448 if (proto == protp->protocol) 449 break; 450 if (protp != NULL) { 451 printer(arg, "[%s", protp->name); 452 n = (*protp->printpkt)(p, len, printer, arg); 453 printer(arg, "]"); 454 p += n; 455 len -= n; 456 } else { 457 for (i = 0; (protp = protocols[i]) != NULL; ++i) 458 if (proto == (protp->protocol & ~0x8000)) 459 break; 460 if (protp != 0 && protp->data_name != 0) { 461 printer(arg, "[%s data]", protp->data_name); 462 if (len > 8) 463 printer(arg, "%.8B ...", p); 464 else 465 printer(arg, "%.*B", len, p); 466 len = 0; 467 } else 468 printer(arg, "[proto=0x%x]", proto); 469 } 470 } 471 472 if (len > 32) 473 printer(arg, "%.32B ...", p); 474 else 475 printer(arg, "%.*B", len, p); 476 } 477 478 /* 479 * init_pr_log, end_pr_log - initialize and finish use of pr_log. 480 */ 481 482 static char line[256]; /* line to be logged accumulated here */ 483 static char *linep; /* current pointer within line */ 484 static int llevel; /* level for logging */ 485 486 void 487 init_pr_log(prefix, level) 488 const char *prefix; 489 int level; 490 { 491 linep = line; 492 if (prefix != NULL) { 493 strlcpy(line, prefix, sizeof(line)); 494 linep = line + strlen(line); 495 } 496 llevel = level; 497 } 498 499 void 500 end_pr_log() 501 { 502 if (linep != line) { 503 *linep = 0; 504 log_write(llevel, line); 505 } 506 } 507 508 /* 509 * pr_log - printer routine for outputting to syslog 510 */ 511 void 512 pr_log __V((void *arg, char *fmt, ...)) 513 { 514 int l, n; 515 va_list pvar; 516 char *p, *eol; 517 char buf[256]; 518 519 #if defined(__STDC__) 520 va_start(pvar, fmt); 521 #else 522 void *arg; 523 char *fmt; 524 va_start(pvar); 525 arg = va_arg(pvar, void *); 526 fmt = va_arg(pvar, char *); 527 #endif 528 529 n = vslprintf(buf, sizeof(buf), fmt, pvar); 530 va_end(pvar); 531 532 p = buf; 533 eol = strchr(buf, '\n'); 534 if (linep != line) { 535 l = (eol == NULL)? n: eol - buf; 536 if (linep + l < line + sizeof(line)) { 537 if (l > 0) { 538 memcpy(linep, buf, l); 539 linep += l; 540 } 541 if (eol == NULL) 542 return; 543 p = eol + 1; 544 eol = strchr(p, '\n'); 545 } 546 *linep = 0; 547 log_write(llevel, line); 548 linep = line; 549 } 550 551 while (eol != NULL) { 552 *eol = 0; 553 log_write(llevel, p); 554 p = eol + 1; 555 eol = strchr(p, '\n'); 556 } 557 558 /* assumes sizeof(buf) <= sizeof(line) */ 559 l = buf + n - p; 560 if (l > 0) { 561 memcpy(line, p, n); 562 linep = line + l; 563 } 564 } 565 566 /* 567 * print_string - print a readable representation of a string using 568 * printer. 569 */ 570 void 571 print_string(p, len, printer, arg) 572 char *p; 573 int len; 574 printer_func printer; 575 void *arg; 576 { 577 int c; 578 579 printer(arg, "\""); 580 for (; len > 0; --len) { 581 c = *p++; 582 if (' ' <= c && c <= '~') { 583 if (c == '\\' || c == '"') 584 printer(arg, "\\"); 585 printer(arg, "%c", c); 586 } else { 587 switch (c) { 588 case '\n': 589 printer(arg, "\\n"); 590 break; 591 case '\r': 592 printer(arg, "\\r"); 593 break; 594 case '\t': 595 printer(arg, "\\t"); 596 break; 597 default: 598 printer(arg, "\\%.3o", c); 599 } 600 } 601 } 602 printer(arg, "\""); 603 } 604 605 /* 606 * logit - does the hard work for fatal et al. 607 */ 608 static void 609 logit(level, fmt, args) 610 int level; 611 char *fmt; 612 va_list args; 613 { 614 char buf[1024]; 615 616 vslprintf(buf, sizeof(buf), fmt, args); 617 log_write(level, buf); 618 } 619 620 static void 621 log_write(level, buf) 622 int level; 623 char *buf; 624 { 625 syslog(level, "%s", buf); 626 if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) { 627 int n = strlen(buf); 628 629 if (n > 0 && buf[n-1] == '\n') 630 --n; 631 if (write(log_to_fd, buf, n) != n 632 || write(log_to_fd, "\n", 1) != 1) 633 log_to_fd = -1; 634 } 635 } 636 637 /* 638 * fatal - log an error message and die horribly. 639 */ 640 void 641 fatal __V((char *fmt, ...)) 642 { 643 va_list pvar; 644 645 #if defined(__STDC__) 646 va_start(pvar, fmt); 647 #else 648 char *fmt; 649 va_start(pvar); 650 fmt = va_arg(pvar, char *); 651 #endif 652 653 logit(LOG_ERR, fmt, pvar); 654 va_end(pvar); 655 656 die(1); /* as promised */ 657 } 658 659 /* 660 * error - log an error message. 661 */ 662 void 663 error __V((char *fmt, ...)) 664 { 665 va_list pvar; 666 667 #if defined(__STDC__) 668 va_start(pvar, fmt); 669 #else 670 char *fmt; 671 va_start(pvar); 672 fmt = va_arg(pvar, char *); 673 #endif 674 675 logit(LOG_ERR, fmt, pvar); 676 va_end(pvar); 677 ++error_count; 678 } 679 680 /* 681 * warn - log a warning message. 682 */ 683 void 684 warn __V((char *fmt, ...)) 685 { 686 va_list pvar; 687 688 #if defined(__STDC__) 689 va_start(pvar, fmt); 690 #else 691 char *fmt; 692 va_start(pvar); 693 fmt = va_arg(pvar, char *); 694 #endif 695 696 logit(LOG_WARNING, fmt, pvar); 697 va_end(pvar); 698 } 699 700 /* 701 * notice - log a notice-level message. 702 */ 703 void 704 notice __V((char *fmt, ...)) 705 { 706 va_list pvar; 707 708 #if defined(__STDC__) 709 va_start(pvar, fmt); 710 #else 711 char *fmt; 712 va_start(pvar); 713 fmt = va_arg(pvar, char *); 714 #endif 715 716 logit(LOG_NOTICE, fmt, pvar); 717 va_end(pvar); 718 } 719 720 /* 721 * info - log an informational message. 722 */ 723 void 724 info __V((char *fmt, ...)) 725 { 726 va_list pvar; 727 728 #if defined(__STDC__) 729 va_start(pvar, fmt); 730 #else 731 char *fmt; 732 va_start(pvar); 733 fmt = va_arg(pvar, char *); 734 #endif 735 736 logit(LOG_INFO, fmt, pvar); 737 va_end(pvar); 738 } 739 740 /* 741 * dbglog - log a debug message. 742 */ 743 void 744 dbglog __V((char *fmt, ...)) 745 { 746 va_list pvar; 747 748 #if defined(__STDC__) 749 va_start(pvar, fmt); 750 #else 751 char *fmt; 752 va_start(pvar); 753 fmt = va_arg(pvar, char *); 754 #endif 755 756 logit(LOG_DEBUG, fmt, pvar); 757 va_end(pvar); 758 } 759 760 /* 761 * dump_packet - print out a packet in readable form if it is interesting. 762 * Assumes len >= PPP_HDRLEN. 763 */ 764 void 765 dump_packet(const char *tag, unsigned char *p, int len) 766 { 767 int proto; 768 769 if (!debug) 770 return; 771 772 /* 773 * don't print LCP echo request/reply packets if debug <= 1 774 * and the link is up. 775 */ 776 proto = (p[2] << 8) + p[3]; 777 if (debug <= 1 && unsuccess == 0 && proto == PPP_LCP 778 && len >= PPP_HDRLEN + HEADERLEN) { 779 unsigned char *lcp = p + PPP_HDRLEN; 780 int l = (lcp[2] << 8) + lcp[3]; 781 782 if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP) 783 && l >= HEADERLEN && l <= len - PPP_HDRLEN) 784 return; 785 } 786 787 dbglog("%s %P", tag, p, len); 788 } 789 790 /* 791 * complete_read - read a full `count' bytes from fd, 792 * unless end-of-file or an error other than EINTR is encountered. 793 */ 794 ssize_t 795 complete_read(int fd, void *buf, size_t count) 796 { 797 size_t done; 798 ssize_t nb; 799 char *ptr = buf; 800 801 for (done = 0; done < count; ) { 802 nb = read(fd, ptr, count - done); 803 if (nb < 0) { 804 if (errno == EINTR) 805 continue; 806 return -1; 807 } 808 if (nb == 0) 809 break; 810 done += nb; 811 ptr += nb; 812 } 813 return done; 814 } 815 816 /* Procedures for locking the serial device using a lock file. */ 817 #ifndef LOCK_DIR 818 #ifdef __linux__ 819 #define LOCK_DIR "/var/lock" 820 #else 821 #ifdef SVR4 822 #define LOCK_DIR "/var/spool/locks" 823 #else 824 #define LOCK_DIR "/var/spool/lock" 825 #endif 826 #endif 827 #endif /* LOCK_DIR */ 828 829 static char lock_file[MAXPATHLEN]; 830 831 /* 832 * lock - create a lock file for the named device 833 */ 834 int 835 lock(dev) 836 char *dev; 837 { 838 #ifdef LOCKLIB 839 int result; 840 841 result = mklock (dev, (void *) 0); 842 if (result == 0) { 843 strlcpy(lock_file, dev, sizeof(lock_file)); 844 return 0; 845 } 846 847 if (result > 0) 848 notice("Device %s is locked by pid %d", dev, result); 849 else 850 error("Can't create lock file %s", lock_file); 851 return -1; 852 853 #else /* LOCKLIB */ 854 855 char lock_buffer[12]; 856 int fd, pid, n; 857 858 #ifdef SVR4 859 struct stat sbuf; 860 861 if (stat(dev, &sbuf) < 0) { 862 error("Can't get device number for %s: %m", dev); 863 return -1; 864 } 865 if ((sbuf.st_mode & S_IFMT) != S_IFCHR) { 866 error("Can't lock %s: not a character device", dev); 867 return -1; 868 } 869 slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d", 870 LOCK_DIR, major(sbuf.st_dev), 871 major(sbuf.st_rdev), minor(sbuf.st_rdev)); 872 #else 873 char *p; 874 char lockdev[MAXPATHLEN]; 875 876 if ((p = strstr(dev, "dev/")) != NULL) { 877 dev = p + 4; 878 strncpy(lockdev, dev, MAXPATHLEN-1); 879 lockdev[MAXPATHLEN-1] = 0; 880 while ((p = strrchr(lockdev, '/')) != NULL) { 881 *p = '_'; 882 } 883 dev = lockdev; 884 } else 885 if ((p = strrchr(dev, '/')) != NULL) 886 dev = p + 1; 887 888 slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev); 889 #endif 890 891 while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { 892 if (errno != EEXIST) { 893 error("Can't create lock file %s: %m", lock_file); 894 break; 895 } 896 897 /* Read the lock file to find out who has the device locked. */ 898 fd = open(lock_file, O_RDONLY, 0); 899 if (fd < 0) { 900 if (errno == ENOENT) /* This is just a timing problem. */ 901 continue; 902 error("Can't open existing lock file %s: %m", lock_file); 903 break; 904 } 905 #ifndef LOCK_BINARY 906 n = read(fd, lock_buffer, 11); 907 #else 908 n = read(fd, &pid, sizeof(pid)); 909 #endif /* LOCK_BINARY */ 910 close(fd); 911 fd = -1; 912 if (n <= 0) { 913 error("Can't read pid from lock file %s", lock_file); 914 break; 915 } 916 917 /* See if the process still exists. */ 918 #ifndef LOCK_BINARY 919 lock_buffer[n] = 0; 920 pid = atoi(lock_buffer); 921 #endif /* LOCK_BINARY */ 922 if (pid == getpid()) 923 return 1; /* somebody else locked it for us */ 924 if (pid == 0 925 || (kill(pid, 0) == -1 && errno == ESRCH)) { 926 if (unlink (lock_file) == 0) { 927 notice("Removed stale lock on %s (pid %d)", dev, pid); 928 continue; 929 } 930 warn("Couldn't remove stale lock on %s", dev); 931 } else 932 notice("Device %s is locked by pid %d", dev, pid); 933 break; 934 } 935 936 if (fd < 0) { 937 lock_file[0] = 0; 938 return -1; 939 } 940 941 pid = getpid(); 942 #ifndef LOCK_BINARY 943 slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid); 944 write (fd, lock_buffer, 11); 945 #else 946 write(fd, &pid, sizeof (pid)); 947 #endif 948 close(fd); 949 return 0; 950 951 #endif 952 } 953 954 /* 955 * relock - called to update our lockfile when we are about to detach, 956 * thus changing our pid (we fork, the child carries on, and the parent dies). 957 * Note that this is called by the parent, with pid equal to the pid 958 * of the child. This avoids a potential race which would exist if 959 * we had the child rewrite the lockfile (the parent might die first, 960 * and another process could think the lock was stale if it checked 961 * between when the parent died and the child rewrote the lockfile). 962 */ 963 int 964 relock(pid) 965 int pid; 966 { 967 #ifdef LOCKLIB 968 /* XXX is there a way to do this? */ 969 return -1; 970 #else /* LOCKLIB */ 971 972 int fd; 973 char lock_buffer[12]; 974 975 if (lock_file[0] == 0) 976 return -1; 977 fd = open(lock_file, O_WRONLY, 0); 978 if (fd < 0) { 979 error("Couldn't reopen lock file %s: %m", lock_file); 980 lock_file[0] = 0; 981 return -1; 982 } 983 984 #ifndef LOCK_BINARY 985 slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid); 986 write (fd, lock_buffer, 11); 987 #else 988 write(fd, &pid, sizeof(pid)); 989 #endif /* LOCK_BINARY */ 990 close(fd); 991 return 0; 992 993 #endif /* LOCKLIB */ 994 } 995 996 /* 997 * unlock - remove our lockfile 998 */ 999 void 1000 unlock() 1001 { 1002 if (lock_file[0]) { 1003 #ifdef LOCKLIB 1004 (void) rmlock(lock_file, (void *) 0); 1005 #else 1006 unlink(lock_file); 1007 #endif 1008 lock_file[0] = 0; 1009 } 1010 } 1011 1012