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