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