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