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