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