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