1/* 2 * misc.c - common miscellaneous functions for lsof 3 */ 4 5 6/* 7 * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana 8 * 47907. All rights reserved. 9 * 10 * Written by Victor A. Abell 11 * 12 * This software is not subject to any license of the American Telephone 13 * and Telegraph Company or the Regents of the University of California. 14 * 15 * Permission is granted to anyone to use this software for any purpose on 16 * any computer system, and to alter it and redistribute it freely, subject 17 * to the following restrictions: 18 * 19 * 1. Neither the authors nor Purdue University are responsible for any 20 * consequences of the use of this software. 21 * 22 * 2. The origin of this software must not be misrepresented, either by 23 * explicit claim or by omission. Credit to the authors and Purdue 24 * University must appear in documentation and sources. 25 * 26 * 3. Altered versions must be plainly marked as such, and must not be 27 * misrepresented as being the original software. 28 * 29 * 4. This notice may not be removed or altered. 30 */ 31 32#ifndef lint 33static char copyright[] = 34"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; 35static char *rcsid = "$Id: misc.c,v 1.26 2008/10/21 16:21:41 abe Exp $"; 36#endif 37 38 39#include "lsof.h" 40 41#if defined(HASWIDECHAR) && defined(WIDECHARINCL) 42#include WIDECHARINCL 43#endif /* defined(HASWIDECHAR) && defined(WIDECHARINCL) */ 44 45 46/* 47 * Local definitions 48 */ 49 50#if !defined(MAXSYMLINKS) 51#define MAXSYMLINKS 32 52#endif /* !defined(MAXSYMLINKS) */ 53 54 55/* 56 * Local function prototypes 57 */ 58 59_PROTOTYPE(static void closePipes,(void)); 60_PROTOTYPE(static int dolstat,(char *path, char *buf, int len)); 61_PROTOTYPE(static int dostat,(char *path, char *buf, int len)); 62_PROTOTYPE(static int doreadlink,(char *path, char *buf, int len)); 63_PROTOTYPE(static int doinchild,(int (*fn)(), char *fp, char *rbuf, int rbln)); 64 65#if defined(HASINTSIGNAL) 66_PROTOTYPE(static int handleint,(int sig)); 67#else /* !defined(HASINTSIGNAL) */ 68_PROTOTYPE(static void handleint,(int sig)); 69#endif /* defined(HASINTSIGNAL) */ 70 71_PROTOTYPE(static char *safepup,(unsigned int c, int *cl)); 72 73 74/* 75 * Local variables 76 */ 77 78static pid_t Cpid = 0; /* child PID */ 79static jmp_buf Jmp_buf; /* jump buffer */ 80static int Pipes[] = /* pipes for child process */ 81 { -1, -1, -1, -1 }; 82static int CtSigs[] = { 0, SIGINT, SIGKILL }; 83 /* child termination signals (in order 84 * of application) -- the first is a 85 * dummy to allow pipe closure to 86 * cause the child to exit */ 87#define NCTSIGS (sizeof(CtSigs) / sizeof(int)) 88 89 90#if defined(HASNLIST) 91/* 92 * build-Nl() - build kernel name list table 93 */ 94 95static struct drive_Nl *Build_Nl = (struct drive_Nl *)NULL; 96 /* the default Drive_Nl address */ 97 98void 99build_Nl(d) 100 struct drive_Nl *d; /* data to drive the construction */ 101{ 102 struct drive_Nl *dp; 103 int i, n; 104 105 for (dp = d, n = 0; dp->nn; dp++, n++) 106 ; 107 if (n < 1) { 108 (void) fprintf(stderr, 109 "%s: can't calculate kernel name list length\n", Pn); 110 Exit(1); 111 } 112 if (!(Nl = (struct NLIST_TYPE *)calloc((n + 1), 113 sizeof(struct NLIST_TYPE)))) 114 { 115 (void) fprintf(stderr, 116 "%s: can't allocate %d bytes to kernel name list structure\n", 117 Pn, (int)((n + 1) * sizeof(struct NLIST_TYPE))); 118 Exit(1); 119 } 120 for (dp = d, i = 0; i < n; dp++, i++) { 121 Nl[i].NL_NAME = dp->knm; 122 } 123 Nll = (int)((n + 1) * sizeof(struct NLIST_TYPE)); 124 Build_Nl = d; 125} 126#endif /* defined(HASNLIST) */ 127 128 129/* 130 * childx() - make child process exit (if possible) 131 */ 132 133void 134childx() 135{ 136 static int at, sx; 137 pid_t wpid; 138 139 if (Cpid > 1) { 140 141 /* 142 * First close the pipes to and from the child. That should cause the 143 * child to exit. Compute alarm time shares. 144 */ 145 (void) closePipes(); 146 if ((at = TmLimit / NCTSIGS) < TMLIMMIN) 147 at = TMLIMMIN; 148 /* 149 * Loop, waiting for the child to exit. After the first pass, help 150 * the child exit by sending it signals. 151 */ 152 for (sx = 0; sx < NCTSIGS; sx++) { 153 if (setjmp(Jmp_buf)) { 154 155 /* 156 * An alarm has rung. Disable further alarms. 157 * 158 * If there are more signals to send, continue the signal loop. 159 * 160 * If the last signal has been sent, issue a warning (unless 161 * warninge have been suppressed) and exit the signal loop. 162 */ 163 (void) alarm(0); 164 (void) signal(SIGALRM, SIG_DFL); 165 if (sx < (NCTSIGS - 1)) 166 continue; 167 if (!Fwarn) 168 (void) fprintf(stderr, 169 "%s: WARNING -- child process %d may be hung.\n", 170 Pn, (int)Cpid); 171 break; 172 } 173 /* 174 * Send the next signal to the child process, after the first pass 175 * through the loop. 176 * 177 * Wrap the wait() with an alarm. 178 */ 179 if (sx) 180 (void) kill(Cpid, CtSigs[sx]); 181 (void) signal(SIGALRM, handleint); 182 (void) alarm(at); 183 wpid = (pid_t) wait(NULL); 184 (void) alarm(0); 185 (void) signal(SIGALRM, SIG_DFL); 186 if (wpid == Cpid) 187 break; 188 } 189 Cpid = 0; 190 } 191} 192 193 194/* 195 * closePipes() - close open pipe file descriptors 196 */ 197 198static void 199closePipes() 200{ 201 int i; 202 203 for (i = 0; i < 4; i++) { 204 if (Pipes[i] >= 0) { 205 (void) close(Pipes[i]); 206 Pipes[i] = -1; 207 } 208 } 209} 210 211 212/* 213 * compdev() - compare Devtp[] entries 214 */ 215 216int 217compdev(a1, a2) 218 COMP_P *a1, *a2; 219{ 220 struct l_dev **p1 = (struct l_dev **)a1; 221 struct l_dev **p2 = (struct l_dev **)a2; 222 223 if ((dev_t)((*p1)->rdev) < (dev_t)((*p2)->rdev)) 224 return(-1); 225 if ((dev_t)((*p1)->rdev) > (dev_t)((*p2)->rdev)) 226 return(1); 227 if ((INODETYPE)((*p1)->inode) < (INODETYPE)((*p2)->inode)) 228 return(-1); 229 if ((INODETYPE)((*p1)->inode) > (INODETYPE)((*p2)->inode)) 230 return(1); 231 return(strcmp((*p1)->name, (*p2)->name)); 232} 233 234 235/* 236 * doinchild() -- do a function in a child process 237 */ 238 239static int 240doinchild(fn, fp, rbuf, rbln) 241 int (*fn)(); /* function to perform */ 242 char *fp; /* function parameter */ 243 char *rbuf; /* response buffer */ 244 int rbln; /* response buffer length */ 245{ 246 int en, rv; 247/* 248 * Check reply buffer size. 249 */ 250 if (!Fovhd && rbln > MAXPATHLEN) { 251 (void) fprintf(stderr, 252 "%s: doinchild error; response buffer too large: %d\n", 253 Pn, rbln); 254 Exit(1); 255 } 256/* 257 * Set up to handle an alarm signal; handle an alarm signal; build 258 * pipes for exchanging information with a child process; start the 259 * child process; and perform functions in the child process. 260 */ 261 if (!Fovhd) { 262 if (setjmp(Jmp_buf)) { 263 264 /* 265 * Process an alarm that has rung. 266 */ 267 (void) alarm(0); 268 (void) signal(SIGALRM, SIG_DFL); 269 (void) childx(); 270 errno = ETIMEDOUT; 271 return(1); 272 } else if (!Cpid) { 273 274 /* 275 * Create pipes to exchange function information with a child 276 * process. 277 */ 278 if (pipe(Pipes) < 0 || pipe(&Pipes[2]) < 0) { 279 (void) fprintf(stderr, "%s: can't open pipes: %s\n", 280 Pn, strerror(errno)); 281 Exit(1); 282 } 283 /* 284 * Fork a child to execute functions. 285 */ 286 if ((Cpid = fork()) == 0) { 287 288 /* 289 * Begin the child process. 290 */ 291 292 int fd, nd, r_al, r_rbln; 293 char r_arg[MAXPATHLEN+1], r_rbuf[MAXPATHLEN+1]; 294 int (*r_fn)(); 295 /* 296 * Close all open file descriptors except Pipes[0] and 297 * Pipes[3]. 298 */ 299 for (fd = 0, nd = GET_MAX_FD(); fd < nd; fd++) { 300 if (fd == Pipes[0] || fd == Pipes[3]) 301 continue; 302 (void) close(fd); 303 if (fd == Pipes[1]) 304 Pipes[1] = -1; 305 else if (fd == Pipes[2]) 306 Pipes[2] = -1; 307 } 308 if (Pipes[1] >= 0) { 309 (void) close(Pipes[1]); 310 Pipes[1] = -1; 311 } 312 if (Pipes[2] >= 0) { 313 (void) close(Pipes[2]); 314 Pipes[2] = -1; 315 } 316 /* 317 * Read function requests, process them, and return replies. 318 */ 319 for (;;) { 320 if (read(Pipes[0], (char *)&r_fn, sizeof(r_fn)) 321 != (int)sizeof(r_fn) 322 || read(Pipes[0], (char *)&r_al, sizeof(int)) 323 != (int)sizeof(int) 324 || r_al < 1 325 || r_al > (int)sizeof(r_arg) 326 || read(Pipes[0], r_arg, r_al) != r_al 327 || read(Pipes[0], (char *)&r_rbln, sizeof(r_rbln)) 328 != (int)sizeof(r_rbln) 329 || r_rbln < 1 || r_rbln > (int)sizeof(r_rbuf)) 330 break; 331 rv = r_fn(r_arg, r_rbuf, r_rbln); 332 en = errno; 333 if (write(Pipes[3], (char *)&rv, sizeof(rv)) 334 != sizeof(rv) 335 || write(Pipes[3], (char *)&en, sizeof(en)) 336 != sizeof(en) 337 || write(Pipes[3], r_rbuf, r_rbln) != r_rbln) 338 break; 339 } 340 (void) _exit(0); 341 } 342 /* 343 * Continue in the parent process to finish the setup. 344 */ 345 if (Cpid < 0) { 346 (void) fprintf(stderr, "%s: can't fork: %s\n", 347 Pn, strerror(errno)); 348 Exit(1); 349 } 350 (void) close(Pipes[0]); 351 (void) close(Pipes[3]); 352 Pipes[0] = Pipes[3] = -1; 353 } 354 } 355 if (!Fovhd) { 356 int len; 357 358 /* 359 * Send a function to the child and wait for the response. 360 */ 361 len = strlen(fp) + 1; 362 (void) signal(SIGALRM, handleint); 363 (void) alarm(TmLimit); 364 if (write(Pipes[1], (char *)&fn, sizeof(fn)) != sizeof(fn) 365 || write(Pipes[1], (char *)&len, sizeof(len)) != sizeof(len) 366 || write(Pipes[1], fp, len) != len 367 || write(Pipes[1], (char *)&rbln, sizeof(rbln)) != sizeof(rbln) 368 || read(Pipes[2], (char *)&rv, sizeof(rv)) != sizeof(rv) 369 || read(Pipes[2], (char *)&en, sizeof(en)) != sizeof(en) 370 || read(Pipes[2], rbuf, rbln) != rbln) { 371 (void) alarm(0); 372 (void) signal(SIGALRM, SIG_DFL); 373 (void) childx(); 374 errno = ECHILD; 375 return(-1); 376 } 377 } else { 378 379 /* 380 * Do the operation directly -- not in a child. 381 */ 382 (void) signal(SIGALRM, handleint); 383 (void) alarm(TmLimit); 384 rv = fn(fp, rbuf, rbln); 385 en = errno; 386 } 387/* 388 * Function completed, response collected -- complete the operation. 389 */ 390 (void) alarm(0); 391 (void) signal(SIGALRM, SIG_DFL); 392 errno = en; 393 return(rv); 394} 395 396 397/* 398 * dolstat() - do an lstat() function 399 */ 400 401static int 402dolstat(path, rbuf, rbln) 403 char *path; /* path */ 404 char *rbuf; /* response buffer */ 405 int rbln; /* response buffer length */ 406 407/* ARGSUSED */ 408 409{ 410 return(lstat(path, (struct stat *)rbuf)); 411} 412 413 414/* 415 * doreadlink() -- do a readlink() function 416 */ 417 418static int 419doreadlink(path, rbuf, rbln) 420 char *path; /* path */ 421 char *rbuf; /* response buffer */ 422 int rbln; /* response buffer length */ 423{ 424 return(readlink(path, rbuf, rbln)); 425} 426 427 428/* 429 * dostat() - do a stat() function 430 */ 431 432static int 433dostat(path, rbuf, rbln) 434 char *path; /* path */ 435 char *rbuf; /* response buffer */ 436 int rbln; /* response buffer length */ 437 438/* ARGSUSED */ 439 440{ 441 return(stat(path, (struct stat *)rbuf)); 442} 443 444 445#if defined(WILLDROPGID) 446/* 447 * dropgid() - drop setgid permission 448 */ 449 450void 451dropgid() 452{ 453 if (!Setuidroot && Setgid) { 454 if (setgid(Mygid) < 0) { 455 (void) fprintf(stderr, "%s: can't setgid(%d): %s\n", 456 Pn, (int)Mygid, strerror(errno)); 457 Exit(1); 458 } 459 Setgid = 0; 460 } 461} 462#endif /* defined(WILLDROPGID) */ 463 464 465/* 466 * enter_dev_ch() - enter device characters in file structure 467 */ 468 469void 470enter_dev_ch(m) 471 char *m; 472{ 473 char *mp; 474 475 if (!m || *m == '\0') 476 return; 477 if (!(mp = mkstrcpy(m, (MALLOC_S *)NULL))) { 478 (void) fprintf(stderr, "%s: no more dev_ch space at PID %d: \n", 479 Pn, Lp->pid); 480 safestrprt(m, stderr, 1); 481 Exit(1); 482 } 483 if (Lf->dev_ch) 484 (void) free((FREE_P *)Lf->dev_ch); 485 Lf->dev_ch = mp; 486} 487 488 489/* 490 * enter_IPstate() -- enter a TCP or UDP state 491 */ 492 493void 494enter_IPstate(ty, nm, nr) 495 char *ty; /* type -- TCP or UDP */ 496 char *nm; /* state name (may be NULL) */ 497 int nr; /* state number */ 498{ 499 500#if defined(USE_LIB_PRINT_TCPTPI) 501 TcpNstates = nr; 502#else /* !defined(USE_LIB_PRINT_TCPTPI) */ 503 504 int al, i, j, oc, nn, ns, off, tx; 505 char *cp; 506 MALLOC_S len; 507/* 508 * Check the type name and set the type index. 509 */ 510 if (!ty) { 511 (void) fprintf(stderr, 512 "%s: no type specified to enter_IPstate()\n", Pn); 513 Exit(1); 514 } 515 if (!strcmp(ty, "TCP")) 516 tx = 0; 517 else if (!strcmp(ty, "UDP")) 518 tx = 1; 519 else { 520 (void) fprintf(stderr, "%s: unknown type for enter_IPstate: %s\n", 521 Pn, ty); 522 Exit(1); 523 } 524/* 525 * If the name argument is NULL, reduce the allocated table to its minimum 526 * size. 527 */ 528 if (!nm) { 529 if (tx) { 530 if (UdpSt) { 531 if (!UdpNstates) { 532 (void) free((MALLOC_P *)UdpSt); 533 UdpSt = (char **)NULL; 534 } 535 if (UdpNstates < UdpStAlloc) { 536 len = (MALLOC_S)(UdpNstates * sizeof(char *)); 537 if (!(UdpSt = (char **)realloc((MALLOC_P *)UdpSt, len))) 538 { 539 (void) fprintf(stderr, 540 "%s: can't reduce UdpSt[]\n", Pn); 541 Exit(1); 542 } 543 } 544 UdpStAlloc = UdpNstates; 545 } 546 } else { 547 if (TcpSt) { 548 if (!TcpNstates) { 549 (void) free((MALLOC_P *)TcpSt); 550 TcpSt = (char **)NULL; 551 } 552 if (TcpNstates < TcpStAlloc) { 553 len = (MALLOC_S)(TcpNstates * sizeof(char *)); 554 if (!(TcpSt = (char **)realloc((MALLOC_P *)TcpSt, len))) 555 { 556 (void) fprintf(stderr, 557 "%s: can't reduce TcpSt[]\n", Pn); 558 Exit(1); 559 } 560 } 561 TcpStAlloc = TcpNstates; 562 } 563 } 564 return; 565 } 566/* 567 * Check the name and number. 568 */ 569 if ((len = (size_t)strlen(nm)) < 1) { 570 (void) fprintf(stderr, 571 "%s: bad %s name (\"%s\"), number=%d\n", Pn, ty, nm, nr); 572 Exit(1); 573 } 574/* 575 * Make a copy of the name. 576 */ 577 if (!(cp = mkstrcpy(nm, (MALLOC_S *)NULL))) { 578 (void) fprintf(stderr, 579 "%s: enter_IPstate(): no %s space for %s\n", 580 Pn, ty, nm); 581 Exit(1); 582 } 583/* 584 * Set the necessary offset for using nr as an index. If it is 585 * a new offset, adjust previous entries. 586 */ 587 if ((nr < 0) && ((off = -nr) > (tx ? UdpStOff : TcpStOff))) { 588 if (tx ? UdpSt : TcpSt) { 589 590 /* 591 * A new, larger offset (smaller negative state number) could mean 592 * a previously allocated state table must be enlarged and its 593 * previous entries moved. 594 */ 595 oc = off - (tx ? UdpStOff : TcpStOff); 596 al = tx ? UdpStAlloc : TcpStAlloc; 597 ns = tx ? UdpNstates : TcpNstates; 598 if ((nn = ns + oc) >= al) { 599 while ((nn + 5) > al) { 600 al += TCPUDPALLOC; 601 } 602 len = (MALLOC_S)(al * sizeof(char *)); 603 if (tx) { 604 if (!(UdpSt = (char **)realloc((MALLOC_P *)UdpSt, len))) 605 goto no_IP_space; 606 UdpStAlloc = al; 607 } else { 608 if (!(TcpSt = (char **)realloc((MALLOC_P *)TcpSt, len))) 609 goto no_IP_space; 610 TcpStAlloc = al; 611 } 612 for (i = 0, j = oc; i < oc; i++, j++) { 613 if (tx) { 614 if (i < UdpNstates) 615 UdpSt[j] = UdpSt[i]; 616 UdpSt[i] = (char *)NULL; 617 } else { 618 if (i < TcpNstates) 619 TcpSt[j] = TcpSt[i]; 620 TcpSt[i] = (char *)NULL; 621 } 622 } 623 if (tx) 624 UdpNstates += oc; 625 else 626 TcpNstates += oc; 627 } 628 } 629 if (tx) 630 UdpStOff = off; 631 else 632 TcpStOff = off; 633 } 634/* 635 * Enter name as {Tc|Ud}pSt[nr + {Tc|Ud}pStOff]. 636 * 637 * Allocate space, as required. 638 */ 639 al = tx ? UdpStAlloc : TcpStAlloc; 640 off = tx ? UdpStOff : TcpStOff; 641 nn = nr + off + 1; 642 if (nn > al) { 643 i = tx ? UdpNstates : TcpNstates; 644 while ((nn + 5) > al) { 645 al += TCPUDPALLOC; 646 } 647 len = (MALLOC_S)(al * sizeof(char *)); 648 if (tx) { 649 if (UdpSt) 650 UdpSt = (char **)realloc((MALLOC_P *)UdpSt, len); 651 else 652 UdpSt = (char **)malloc(len); 653 if (!UdpSt) { 654 655no_IP_space: 656 657 (void) fprintf(stderr, "%s: no %s state space\n", Pn, ty); 658 Exit(1); 659 } 660 UdpNstates = nn; 661 UdpStAlloc = al; 662 } else { 663 if (TcpSt) 664 TcpSt = (char **)realloc((MALLOC_P *)TcpSt, len); 665 else 666 TcpSt = (char **)malloc(len); 667 if (!TcpSt) 668 goto no_IP_space; 669 TcpNstates = nn; 670 TcpStAlloc = al; 671 } 672 while (i < al) { 673 if (tx) 674 UdpSt[i] = (char *)NULL; 675 else 676 TcpSt[i] = (char *)NULL; 677 i++; 678 } 679 } else { 680 if (tx) { 681 if (nn > UdpNstates) 682 UdpNstates = nn; 683 } else { 684 if (nn > TcpNstates) 685 TcpNstates = nn; 686 } 687 } 688 if (tx) { 689 if (UdpSt[nr + UdpStOff]) { 690 691dup_IP_state: 692 693 (void) fprintf(stderr, 694 "%s: duplicate %s state %d (already %s): %s\n", 695 Pn, ty, nr, 696 tx ? UdpSt[nr + UdpStOff] : TcpSt[nr + TcpStOff], 697 nm); 698 Exit(1); 699 } 700 UdpSt[nr + UdpStOff] = cp; 701 } else { 702 if (TcpSt[nr + TcpStOff]) 703 goto dup_IP_state; 704 TcpSt[nr + TcpStOff] = cp; 705 } 706#endif /* defined(USE_LIB_PRINT_TCPTPI) */ 707 708} 709 710 711/* 712 * enter_nm() - enter name in local file structure 713 */ 714 715void 716enter_nm(m) 717 char *m; 718{ 719 char *mp; 720 721 if (!m || *m == '\0') 722 return; 723 if (!(mp = mkstrcpy(m, (MALLOC_S *)NULL))) { 724 (void) fprintf(stderr, "%s: no more nm space at PID %d for: ", 725 Pn, Lp->pid); 726 safestrprt(m, stderr, 1); 727 Exit(1); 728 } 729 if (Lf->nm) 730 (void) free((FREE_P *)Lf->nm); 731 Lf->nm = mp; 732} 733 734 735/* 736 * Exit() - do a clean exit() 737 */ 738 739void 740Exit(xv) 741 int xv; /* exit() value */ 742{ 743 (void) childx(); 744 745#if defined(HASDCACHE) 746 if (DCrebuilt && !Fwarn) 747 (void) fprintf(stderr, "%s: WARNING: %s was updated.\n", 748 Pn, DCpath[DCpathX]); 749#endif /* defined(HASDCACHE) */ 750 751 exit(xv); 752} 753 754 755#if defined(HASNLIST) 756/* 757 * get_Nl_value() - get Nl value for nickname 758 */ 759 760int 761get_Nl_value(nn, d, v) 762 char *nn; /* nickname of requested entry */ 763 struct drive_Nl *d; /* drive_Nl table that built Nl 764 * (if NULL, use Build_Nl) */ 765 KA_T *v; /* returned value (if NULL, 766 * return nothing) */ 767{ 768 int i; 769 770 if (!Nl || !Nll) 771 return(-1); 772 if (!d) 773 d = Build_Nl; 774 for (i = 0; d->nn; d++, i++) { 775 if (strcmp(d->nn, nn) == 0) { 776 if (v) 777 *v = (KA_T)Nl[i].n_value; 778 return(i); 779 } 780 } 781 return(-1); 782} 783#endif /* defined(HASNLIST) */ 784 785 786/* 787 * handleint() - handle an interrupt 788 */ 789 790#if defined(HASINTSIGNAL) 791static int 792#else 793static void 794#endif 795 796/* ARGSUSED */ 797 798handleint(sig) 799 int sig; 800{ 801 longjmp(Jmp_buf, 1); 802} 803 804 805/* 806 * hashbyname() - hash by name 807 */ 808 809int 810hashbyname(nm, mod) 811 char *nm; /* pointer to NUL-terminated name */ 812 int mod; /* hash modulus */ 813{ 814 int i, j; 815 816 for (i = j = 0; *nm; nm++) { 817 i ^= (int)*nm << j; 818 if (++j > 7) 819 j = 0; 820 } 821 return(((int)(i * 31415)) & (mod - 1)); 822} 823 824 825/* 826 * is_nw_addr() - is this network address selected? 827 */ 828 829int 830is_nw_addr(ia, p, af) 831 unsigned char *ia; /* Internet address */ 832 int p; /* port */ 833 int af; /* address family -- e.g., AF_INET, 834 * AF_INET6 */ 835{ 836 struct nwad *n; 837 838 if (!(n = Nwad)) 839 return(0); 840 for (; n; n = n->next) { 841 if (n->proto) { 842 if (strcasecmp(n->proto, Lf->iproto) != 0) 843 continue; 844 } 845 if (af && n->af && af != n->af) 846 continue; 847 848#if defined(HASIPv6) 849 if (af == AF_INET6) { 850 if (n->a[15] || n->a[14] || n->a[13] || n->a[12] 851 || n->a[11] || n->a[10] || n->a[9] || n->a[8] 852 || n->a[7] || n->a[6] || n->a[5] || n->a[4] 853 || n->a[3] || n->a[2] || n->a[1] || n->a[0]) { 854 if (ia[15] != n->a[15] || ia[14] != n->a[14] 855 || ia[13] != n->a[13] || ia[12] != n->a[12] 856 || ia[11] != n->a[11] || ia[10] != n->a[10] 857 || ia[9] != n->a[9] || ia[8] != n->a[8] 858 || ia[7] != n->a[7] || ia[6] != n->a[6] 859 || ia[5] != n->a[5] || ia[4] != n->a[4] 860 || ia[3] != n->a[3] || ia[2] != n->a[2] 861 || ia[1] != n->a[1] || ia[0] != n->a[0]) 862 continue; 863 } 864 } else if (af == AF_INET) 865#endif /* defined(HASIPv6) */ 866 867 { 868 if (n->a[3] || n->a[2] || n->a[1] || n->a[0]) { 869 if (ia[3] != n->a[3] || ia[2] != n->a[2] 870 || ia[1] != n->a[1] || ia[0] != n->a[0]) 871 continue; 872 } 873 } 874 875#if defined(HASIPv6) 876 else 877 continue; 878#endif /* defined(HASIPv6) */ 879 880 if (n->sport == -1 || (p >= n->sport && p <= n->eport)) { 881 n->f = 1; 882 return(1); 883 } 884 } 885 return(0); 886} 887 888 889/* 890 * mkstrcpy() - make a string copy in malloc()'d space 891 * 892 * return: copy pointer 893 * copy length (optional) 894 */ 895 896char * 897mkstrcpy(src, rlp) 898 char *src; /* source */ 899 MALLOC_S *rlp; /* returned length pointer (optional) 900 * The returned length is an strlen() 901 * equivalent */ 902{ 903 MALLOC_S len; 904 char *ns; 905 906 len = (MALLOC_S)(src ? strlen(src) : 0); 907 ns = (char *)malloc(len + 1); 908 if (ns) { 909 if (src) 910 (void) snpf(ns, len + 1, "%s", src); 911 else 912 *ns = '\0'; 913 } 914 if (rlp) 915 *rlp = len; 916 return(ns); 917} 918 919 920/* 921 * mkstrcat() - make a catenated copy of up to three strings under optional 922 * string-by-string count control 923 * 924 * return: copy pointer 925 * copy string length (optional) 926 */ 927 928char * 929mkstrcat(s1, l1, s2, l2, s3, l3, clp) 930 char *s1; /* source string 1 */ 931 int l1; /* length of string 1 (-1 if none) */ 932 char *s2; /* source string 2 */ 933 int l2; /* length of string 2 (-1 if none) */ 934 char *s3; /* source string 3 (optional) */ 935 int l3 ; /* length of string 3 (-1 if none) */ 936 MALLOC_S *clp; /* pointer to return of copy length 937 * (optional) */ 938{ 939 MALLOC_S cl, len1, len2, len3; 940 char *cp; 941 942 if (s1) 943 len1 = (MALLOC_S)((l1 >= 0) ? l1 : strlen(s1)); 944 else 945 len1 = (MALLOC_S)0; 946 if (s2) 947 len2 = (MALLOC_S)((l2 >= 0) ? l2 : strlen(s2)); 948 else 949 len2 = (MALLOC_S)0; 950 if (s3) 951 len3 = (MALLOC_S)((l3 >= 0) ? l3 : strlen(s3)); 952 else 953 len3 = (MALLOC_S)0; 954 cl = len1 + len2 + len3; 955 if ((cp = (char *)malloc(cl + 1))) { 956 char *tp = cp; 957 958 if (s1 && len1) { 959 (void) strncpy(tp, s1, len1); 960 tp += len1; 961 } 962 if (s2 && len2) { 963 (void) strncpy(tp, s2, len2); 964 tp += len2; 965 } 966 if (s3 && len3) { 967 (void) strncpy(tp, s3, len3); 968 tp += len3; 969 } 970 *tp = '\0'; 971 } 972 if (clp) 973 *clp = cl; 974 return(cp); 975} 976 977 978/* 979 * is_readable() -- is file readable 980 */ 981 982int 983is_readable(path, msg) 984 char *path; /* file path */ 985 int msg; /* issue warning message if 1 */ 986{ 987 if (access(path, R_OK) < 0) { 988 if (!Fwarn && msg == 1) 989 (void) fprintf(stderr, ACCESSERRFMT, Pn, path, strerror(errno)); 990 return(0); 991 } 992 return(1); 993} 994 995 996/* 997 * lstatsafely() - lstat path safely (i. e., with timeout) 998 */ 999 1000int 1001lstatsafely(path, buf) 1002 char *path; /* file path */ 1003 struct stat *buf; /* stat buffer address */ 1004{ 1005 if (Fblock) { 1006 if (!Fwarn) 1007 (void) fprintf(stderr, 1008 "%s: avoiding stat(%s): -b was specified.\n", 1009 Pn, path); 1010 errno = EWOULDBLOCK; 1011 return(1); 1012 } 1013 return(doinchild(dolstat, path, (char *)buf, sizeof(struct stat))); 1014} 1015 1016 1017/* 1018 * Readlink() - read and interpret file system symbolic links 1019 */ 1020 1021char * 1022Readlink(arg) 1023 char *arg; /* argument to be interpreted */ 1024{ 1025 char abuf[MAXPATHLEN+1]; 1026 int alen; 1027 char *ap; 1028 char *argp1, *argp2; 1029 int i, len, llen, slen; 1030 char lbuf[MAXPATHLEN+1]; 1031 static char *op = (char *)NULL; 1032 static int ss = 0; 1033 char *s1; 1034 static char **stk = (char **)NULL; 1035 static int sx = 0; 1036 char tbuf[MAXPATHLEN+1]; 1037/* 1038 * See if avoiding kernel blocks. 1039 */ 1040 if (Fblock) { 1041 if (!Fwarn) { 1042 (void) fprintf(stderr, "%s: avoiding readlink(", Pn); 1043 safestrprt(arg, stderr, 0); 1044 (void) fprintf(stderr, "): -b was specified.\n"); 1045 } 1046 op = (char *)NULL; 1047 return(arg); 1048 } 1049/* 1050 * Save the original path. 1051 */ 1052 if (!op) 1053 op = arg; 1054/* 1055 * Evaluate each component of the argument for a symbolic link. 1056 */ 1057 for (alen = 0, ap = abuf, argp1 = argp2 = arg; *argp2; argp1 = argp2 ) { 1058 for (argp2 = argp1 + 1; *argp2 && *argp2 != '/'; argp2++) 1059 ; 1060 if ((len = argp2 - arg) >= (int)sizeof(tbuf)) { 1061 1062path_too_long: 1063 if (!Fwarn) { 1064 (void) fprintf(stderr, 1065 "%s: readlink() path too long: ", Pn); 1066 safestrprt(op ? op : arg, stderr, 1); 1067 } 1068 op = (char *)NULL; 1069 return((char *)NULL); 1070 } 1071 (void) strncpy(tbuf, arg, len); 1072 tbuf[len] = '\0'; 1073 /* 1074 * Dereference a symbolic link. 1075 */ 1076 if ((llen=doinchild(doreadlink,tbuf,lbuf,sizeof(lbuf) - 1)) >= 0) { 1077 1078 /* 1079 * If the link is a new absolute path, replace 1080 * the previous assembly with it. 1081 */ 1082 if (lbuf[0] == '/') { 1083 (void) strncpy(abuf, lbuf, llen); 1084 ap = &abuf[llen]; 1085 *ap = '\0'; 1086 alen = llen; 1087 continue; 1088 } 1089 lbuf[llen] = '\0'; 1090 s1 = lbuf; 1091 } else { 1092 llen = argp2 - argp1; 1093 s1 = argp1; 1094 } 1095 /* 1096 * Make sure two components are separated by a `/'. 1097 * 1098 * If the first component is not a link, don't force 1099 * a leading '/'. 1100 * 1101 * If the first component is a link and the source of 1102 * the link has a leading '/', force a leading '/'. 1103 */ 1104 if (*s1 == '/') 1105 slen = 1; 1106 else { 1107 if (alen > 0) { 1108 1109 /* 1110 * This is not the first component. 1111 */ 1112 if (abuf[alen - 1] == '/') 1113 slen = 1; 1114 else 1115 slen = 2; 1116 } else { 1117 1118 /* 1119 * This is the first component. 1120 */ 1121 if (s1 == lbuf && tbuf[0] == '/') 1122 slen = 2; 1123 else 1124 slen = 1; 1125 } 1126 } 1127 /* 1128 * Add to the path assembly. 1129 */ 1130 if ((alen + llen + slen) >= (int)sizeof(abuf)) 1131 goto path_too_long; 1132 if (slen == 2) 1133 *ap++ = '/'; 1134 (void) strncpy(ap, s1, llen); 1135 ap += llen; 1136 *ap = '\0'; 1137 alen += (llen + slen - 1); 1138 } 1139/* 1140 * If the assembled path and argument are the same, free all but the 1141 * last string in the stack, and return the argument. 1142 */ 1143 if (strcmp(arg, abuf) == 0) { 1144 for (i = 0; i < sx; i++) { 1145 if (i < (sx - 1)) 1146 (void) free((FREE_P *)stk[i]); 1147 stk[i] = (char *)NULL; 1148 } 1149 sx = 0; 1150 op = (char *)NULL; 1151 return(arg); 1152 } 1153/* 1154 * If the assembled path and argument are different, add it to the 1155 * string stack, then Readlink() it. 1156 */ 1157 if (!(s1 = mkstrcpy(abuf, (MALLOC_S *)NULL))) { 1158 1159no_readlink_space: 1160 1161 (void) fprintf(stderr, "%s: no Readlink string space for ", Pn); 1162 safestrprt(abuf, stderr, 1); 1163 Exit(1); 1164 } 1165 if (sx >= MAXSYMLINKS) { 1166 1167 /* 1168 * If there are too many symbolic links, report an error, clear 1169 * the stack, and return no path. 1170 */ 1171 if (!Fwarn) { 1172 (void) fprintf(stderr, 1173 "%s: too many (> %d) symbolic links in readlink() path: ", 1174 Pn, MAXSYMLINKS); 1175 safestrprt(op ? op : arg, stderr, 1); 1176 } 1177 for (i = 0; i < sx; i++) { 1178 (void) free((FREE_P *)stk[i]); 1179 stk[i] = (char *)NULL; 1180 } 1181 (void) free((FREE_P *)stk); 1182 stk = (char **)NULL; 1183 ss = sx = 0; 1184 op = (char *)NULL; 1185 return((char *)NULL); 1186 } 1187 if (++sx > ss) { 1188 if (!stk) 1189 stk = (char **)malloc((MALLOC_S)(sizeof(char *) * sx)); 1190 else 1191 stk = (char **)realloc((MALLOC_P *)stk, 1192 (MALLOC_S)(sizeof(char *) * sx)); 1193 if (!stk) 1194 goto no_readlink_space; 1195 ss = sx; 1196 } 1197 stk[sx - 1] = s1; 1198 return(Readlink(s1)); 1199} 1200 1201 1202#if defined(HASSTREAMS) 1203/* 1204 * readstdata() - read stream's stdata structure 1205 */ 1206 1207int 1208readstdata(addr, buf) 1209 KA_T addr; /* stdata address in kernel*/ 1210 struct stdata *buf; /* buffer addess */ 1211{ 1212 if (!addr 1213 || kread(addr, (char *)buf, sizeof(struct stdata))) { 1214 (void) snpf(Namech, Namechl, "no stream data in %s", 1215 print_kptr(addr, (char *)NULL, 0)); 1216 return(1); 1217 } 1218 return(0); 1219} 1220 1221 1222/* 1223 * readsthead() - read stream head 1224 */ 1225 1226int 1227readsthead(addr, buf) 1228 KA_T addr; /* starting queue pointer in kernel */ 1229 struct queue *buf; /* buffer for queue head */ 1230{ 1231 KA_T qp; 1232 1233 if (!addr) { 1234 (void) snpf(Namech, Namechl, "no stream queue head"); 1235 return(1); 1236 } 1237 for (qp = addr; qp; qp = (KA_T)buf->q_next) { 1238 if (kread(qp, (char *)buf, sizeof(struct queue))) { 1239 (void) snpf(Namech, Namechl, "bad stream queue link at %s", 1240 print_kptr(qp, (char *)NULL, 0)); 1241 return(1); 1242 } 1243 } 1244 return(0); 1245} 1246 1247 1248/* 1249 * readstidnm() - read stream module ID name 1250 */ 1251 1252int 1253readstidnm(addr, buf, len) 1254 KA_T addr; /* module ID name address in kernel */ 1255 char *buf; /* receiving buffer address */ 1256 READLEN_T len; /* buffer length */ 1257{ 1258 if (!addr || kread(addr, buf, len)) { 1259 (void) snpf(Namech, Namechl, "can't read module ID name from %s", 1260 print_kptr(addr, (char *)NULL, 0)); 1261 return(1); 1262 } 1263 return(0); 1264} 1265 1266 1267/* 1268 * readstmin() - read stream's module info 1269 */ 1270 1271int 1272readstmin(addr, buf) 1273 KA_T addr; /* module info address in kernel */ 1274 struct module_info *buf; /* receiving buffer address */ 1275{ 1276 if (!addr || kread(addr, (char *)buf, sizeof(struct module_info))) { 1277 (void) snpf(Namech, Namechl, "can't read module info from %s", 1278 print_kptr(addr, (char *)NULL, 0)); 1279 return(1); 1280 } 1281 return(0); 1282} 1283 1284 1285/* 1286 * readstqinit() - read stream's queue information structure 1287 */ 1288 1289int 1290readstqinit(addr, buf) 1291 KA_T addr; /* queue info address in kernel */ 1292 struct qinit *buf; /* receiving buffer address */ 1293{ 1294 if (!addr || kread(addr, (char *)buf, sizeof(struct qinit))) { 1295 (void) snpf(Namech, Namechl, "can't read queue info from %s", 1296 print_kptr(addr, (char *)NULL, 0)); 1297 return(1); 1298 } 1299 return(0); 1300} 1301#endif /* HASSTREAMS */ 1302 1303 1304/* 1305 * safepup() - safely print an unprintable character -- i.e., print it in a 1306 * printable form 1307 * 1308 * return: char * to printable equivalent 1309 * cl = strlen(printable equivalent) 1310 */ 1311 1312static char * 1313safepup(c, cl) 1314 unsigned int c; /* unprintable (i.e., !isprint()) 1315 * character */ 1316 int *cl; /* returned printable strlen -- NULL if 1317 * no return needed */ 1318{ 1319 int len; 1320 char *rp; 1321 static char up[8]; 1322 1323 if (c < 0x20) { 1324 switch (c) { 1325 case '\b': 1326 rp = "\\b"; 1327 break; 1328 case '\f': 1329 rp = "\\f"; 1330 break; 1331 case '\n': 1332 rp = "\\n"; 1333 break; 1334 case '\r': 1335 rp = "\\r"; 1336 break; 1337 case '\t': 1338 rp = "\\t"; 1339 break; 1340 default: 1341 (void) snpf(up, sizeof(up), "^%c", c + 0x40); 1342 rp = up; 1343 } 1344 len = 2; 1345 } else if (c == 0xff) { 1346 rp = "^?"; 1347 len = 2; 1348 } else { 1349 (void) snpf(up, sizeof(up), "\\x%02x", (int)(c & 0xff)); 1350 rp = up; 1351 len = 4; 1352 } 1353 if (cl) 1354 *cl = len; 1355 return(rp); 1356} 1357 1358 1359/* 1360 * safestrlen() - calculate a "safe" string length -- i.e., compute space for 1361 * non-printable characters when printed in a printable form 1362 */ 1363 1364int 1365safestrlen(sp, flags) 1366 char *sp; /* string pointer */ 1367 int flags; /* flags: 1368 * bit 0: 0 (0) = no NL 1369 * 1 (1) = add trailing NL 1370 * 1: 0 (0) = ' ' printable 1371 * 1 (2) = ' ' not printable 1372 */ 1373{ 1374 char c; 1375 int len = 0; 1376 1377 c = (flags & 2) ? ' ' : '\0'; 1378 if (sp) { 1379 for (; *sp; sp++) { 1380 if (!isprint((unsigned char)*sp) || *sp == c) { 1381 if (*sp < 0x20 || (unsigned char)*sp == 0xff) 1382 len += 2; /* length of \. or ^. form */ 1383 else 1384 len += 4; /* length of "\x%02x" printf */ 1385 } else 1386 len++; 1387 } 1388 } 1389 return(len); 1390} 1391 1392 1393/* 1394 * safestrprt() - print a string "safely" to the indicated stream -- i.e., 1395 * print unprintable characters in a printable form 1396 */ 1397 1398void 1399safestrprt(sp, fs, flags) 1400 char *sp; /* string to print pointer pointer */ 1401 FILE *fs; /* destination stream -- e.g., stderr 1402 * or stdout */ 1403 int flags; /* flags: 1404 * bit 0: 0 (0) = no NL 1405 * 1 (1) = add trailing NL 1406 * 1: 0 (0) = ' ' printable 1407 * 1 (2) = ' ' not printable 1408 * 2: 0 (0) = print string as is 1409 * 1 (4) = surround string 1410 * with '"' 1411 * 4: 0 (0) = print ending '\n' 1412 * 1 (8) = don't print ending 1413 * '\n' 1414 */ 1415{ 1416 char c; 1417 int lnc, lnt, sl; 1418 1419#if defined(HASWIDECHAR) 1420 wchar_t w; 1421 int wcmx = MB_CUR_MAX; 1422#else /* !defined(HASWIDECHAR) */ 1423 static int wcmx = 1; 1424#endif /* defined(HASWIDECHAR) */ 1425 1426 c = (flags & 2) ? ' ' : '\0'; 1427 if (flags & 4) 1428 putc('"', fs); 1429 if (sp) { 1430 for (sl = strlen(sp); *sp; sl -= lnc, sp += lnc) { 1431 1432#if defined(HASWIDECHAR) 1433 if (wcmx > 1) { 1434 lnc = mblen(sp, sl); 1435 if (lnc > 1) { 1436 if ((mbtowc(&w, sp, sl) == lnc) && iswprint(w)) { 1437 for (lnt = 0; lnt < lnc; lnt++) { 1438 putc((int)*(sp + lnt), fs); 1439 } 1440 } else { 1441 for (lnt = 0; lnt < lnc; lnt++) { 1442 fputs(safepup((unsigned int)*(sp + lnt), 1443 (int *)NULL), fs); 1444 } 1445 } 1446 continue; 1447 } else 1448 lnc = 1; 1449 } else 1450 lnc = 1; 1451#else /* !defined(HASWIDECHAR) */ 1452 lnc = 1; 1453#endif /* defined(HASWIDECHAR) */ 1454 1455 if (isprint((unsigned char)*sp) && *sp != c) 1456 putc((int)(*sp & 0xff), fs); 1457 else { 1458 if ((flags & 8) && (*sp == '\n') && !*(sp + 1)) 1459 break; 1460 fputs(safepup((unsigned int)*sp, (int *)NULL), fs); 1461 } 1462 } 1463 } 1464 if (flags & 4) 1465 putc('"', fs); 1466 if (flags & 1) 1467 putc('\n', fs); 1468} 1469 1470 1471/* 1472 * safestrprtn() - print a specified number of characters from a string 1473 * "safely" to the indicated stream 1474 */ 1475 1476void 1477safestrprtn(sp, len, fs, flags) 1478 char *sp; /* string to print pointer pointer */ 1479 int len; /* safe number of characters to 1480 * print */ 1481 FILE *fs; /* destination stream -- e.g., stderr 1482 * or stdout */ 1483 int flags; /* flags: 1484 * bit 0: 0 (0) = no NL 1485 * 1 (1) = add trailing NL 1486 * 1: 0 (0) = ' ' printable 1487 * 1 (2) = ' ' not printable 1488 * 2: 0 (0) = print string as is 1489 * 1 (4) = surround string 1490 * with '"' 1491 * 4: 0 (0) = print ending '\n' 1492 * 1 (8) = don't print ending 1493 * '\n' 1494 */ 1495{ 1496 char c, *up; 1497 int cl, i; 1498 1499 if (flags & 4) 1500 putc('"', fs); 1501 if (sp) { 1502 c = (flags & 2) ? ' ' : '\0'; 1503 for (i = 0; i < len && *sp; sp++) { 1504 if (isprint((unsigned char)*sp) && *sp != c) { 1505 putc((int)(*sp & 0xff), fs); 1506 i++; 1507 } else { 1508 if ((flags & 8) && (*sp == '\n') && !*(sp + 1)) 1509 break; 1510 up = safepup((unsigned int)*sp, &cl); 1511 if ((i + cl) > len) 1512 break; 1513 fputs(up, fs); 1514 i += cl; 1515 } 1516 } 1517 } else 1518 i = 0; 1519 for (; i < len; i++) 1520 putc(' ', fs); 1521 if (flags & 4) 1522 putc('"', fs); 1523 if (flags & 1) 1524 putc('\n', fs); 1525} 1526 1527 1528/* 1529 * statsafely() - stat path safely (i. e., with timeout) 1530 */ 1531 1532int 1533statsafely(path, buf) 1534 char *path; /* file path */ 1535 struct stat *buf; /* stat buffer address */ 1536{ 1537 if (Fblock) { 1538 if (!Fwarn) 1539 (void) fprintf(stderr, 1540 "%s: avoiding stat(%s): -b was specified.\n", 1541 Pn, path); 1542 errno = EWOULDBLOCK; 1543 return(1); 1544 } 1545 return(doinchild(dostat, path, (char *)buf, sizeof(struct stat))); 1546} 1547 1548 1549/* 1550 * stkdir() - stack directory name 1551 */ 1552 1553void 1554stkdir(p) 1555 char *p; /* directory path */ 1556{ 1557 MALLOC_S len; 1558/* 1559 * Provide adequate space for directory stack pointers. 1560 */ 1561 if (Dstkx >= Dstkn) { 1562 Dstkn += 128; 1563 len = (MALLOC_S)(Dstkn * sizeof(char *)); 1564 if (!Dstk) 1565 Dstk = (char **)malloc(len); 1566 else 1567 Dstk = (char **)realloc((MALLOC_P *)Dstk, len); 1568 if (!Dstk) { 1569 (void) fprintf(stderr, 1570 "%s: no space for directory stack at: ", Pn); 1571 safestrprt(p, stderr, 1); 1572 Exit(1); 1573 } 1574 } 1575/* 1576 * Allocate space for the name, copy it there and put its pointer on the stack. 1577 */ 1578 if (!(Dstk[Dstkx] = mkstrcpy(p, (MALLOC_S *)NULL))) { 1579 (void) fprintf(stderr, "%s: no space for: ", Pn); 1580 safestrprt(p, stderr, 1); 1581 Exit(1); 1582 } 1583 Dstkx++; 1584} 1585 1586 1587/* 1588 * x2dev() - convert hexadecimal ASCII string to device number 1589 */ 1590 1591char * 1592x2dev(s, d) 1593 char *s; /* ASCII string */ 1594 dev_t *d; /* device receptacle */ 1595{ 1596 char *cp, *cp1; 1597 int n; 1598 dev_t r; 1599 1600/* 1601 * Skip an optional leading 0x. Count the number of hex digits up to the end 1602 * of the string, or to a space, or to a comma. Return an error if an unknown 1603 * character is encountered. If the count is larger than (2 * sizeof(dev_t)) 1604 * -- e.g., because of sign extension -- ignore excess leading hex 0xf digits, 1605 * but return an error if an excess leading digit isn't 0xf. 1606 */ 1607 if (strncasecmp(s, "0x", 2) == 0) 1608 s += 2; 1609 for (cp = s, n = 0; *cp; cp++, n++) { 1610 if (isdigit((unsigned char)*cp)) 1611 continue; 1612 if ((unsigned char)*cp >= 'a' && (unsigned char)*cp <= 'f') 1613 continue; 1614 if ((unsigned char)*cp >= 'A' && (unsigned char)*cp <= 'F') 1615 continue; 1616 if (*cp == ' ' || *cp == ',') 1617 break; 1618 return((char *)NULL); 1619 } 1620 if (!n) 1621 return((char *)NULL); 1622 if (n > (2 * (int)sizeof(dev_t))) { 1623 cp1 = s; 1624 s += (n - (2 * sizeof(dev_t))); 1625 while (cp1 < s) { 1626 if (*cp1 != 'f' && *cp1 != 'F') 1627 return((char *)NULL); 1628 cp1++; 1629 } 1630 } 1631/* 1632 * Assemble the validated hex digits of the device number, starting at a point 1633 * in the string relevant to sizeof(dev_t). 1634 */ 1635 for (r = 0; s < cp; s++) { 1636 r = r << 4; 1637 if (isdigit((unsigned char)*s)) 1638 r |= (unsigned char)(*s - '0') & 0xf; 1639 else { 1640 if (isupper((unsigned char)*s)) 1641 r |= ((unsigned char)(*s - 'A') + 10) & 0xf; 1642 else 1643 r |= ((unsigned char)(*s - 'a') + 10) & 0xf; 1644 } 1645 } 1646 *d = r; 1647 return(s); 1648} 1649