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