1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <stdio.h> 34 #include <errno.h> 35 #include <limits.h> 36 #include <fcntl.h> 37 #include <string.h> 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <sys/wait.h> 41 #include <sys/vfstab.h> 42 #include <sys/mntent.h> 43 #include <locale.h> 44 #include <libintl.h> 45 46 #define ARGV_MAX 16 47 #define FSTYPE_MAX 8 48 #define VFS_PATH "/usr/lib/fs" 49 #define VFS_PATH2 "/etc/fs" 50 51 #define CHECK(xx, yy)\ 52 if (xx == (yy)-1) {\ 53 fprintf(stderr, gettext("%s: too many arguments\n"), myname); \ 54 usage(); \ 55 } 56 #define OPTION(flag)\ 57 options++; \ 58 nargv[nargc++] = flag; \ 59 CHECK(nargc, ARGV_MAX); \ 60 break 61 #define OPTARG(flag)\ 62 nargv[nargc++] = flag; \ 63 CHECK(nargc, ARGV_MAX); \ 64 if (optarg) {\ 65 nargv[nargc++] = optarg; \ 66 CHECK(nargc, ARGV_MAX); \ 67 }\ 68 break 69 70 71 int nrun, ndisks; 72 int maxrun = 8; /* should be based on the machine resources */ 73 74 extern char *optarg; 75 extern int optind; 76 extern char *default_fstype(); 77 78 int nargc = 2; 79 int options = 0; 80 int mnt_passno = 0; 81 int exitstat = 0; 82 int verbose = 0; 83 char *nargv[ARGV_MAX]; 84 char *myname, *fstype; 85 char *malloc(); 86 char vfstab[] = VFSTAB; 87 char pflg = 0, Vflg = 0; 88 89 /* 90 * Keep an idea of the last device arg type as a hint to the 91 * type of the next arg. In the case of mountall, it's very likely 92 * to be the same type and the next entry in the file. This should 93 * help speed vfstab lookups. 94 */ 95 enum dev_arg_t { UNKNOWN, SPECIAL, FSCKDEV, MOUNTPT }; 96 enum dev_arg_t arg_hint = UNKNOWN; 97 98 static struct devlist { 99 char *name; 100 char *fsname; 101 pid_t pid; 102 struct devlist *nxt; 103 } *newdev(), *getdev(); 104 105 /* 106 * private copy vfstab functions 107 */ 108 static struct vfstab vfsave = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; 109 110 static void usage(void); 111 static void fsck_dopreen(struct devlist **devp, int ndevs); 112 static void waiter(struct devlist **blp, struct devlist **badlist); 113 static void print_badlist(struct devlist *lp); 114 static void startdisk(struct devlist *dp); 115 static void do_exec(char *fstype, char *nargv[]); 116 static void prnt_cmd(FILE *fd, char *fstype); 117 static void vfserror(int flag); 118 119 static int 120 vfdup(struct vfstab *vp) 121 { 122 if (vfsave.vfs_special != NULL) { 123 free(vfsave.vfs_special); 124 vfsave.vfs_special = NULL; 125 } 126 if ((vp->vfs_special != NULL) && 127 ((vfsave.vfs_special = strdup(vp->vfs_special)) == NULL)) { 128 perror(myname); 129 return (4); /* XXX */ 130 } 131 132 if (vfsave.vfs_fsckdev != NULL) { 133 free(vfsave.vfs_fsckdev); 134 vfsave.vfs_fsckdev = NULL; 135 } 136 if ((vp->vfs_fsckdev != NULL) && 137 ((vfsave.vfs_fsckdev = strdup(vp->vfs_fsckdev)) == NULL)) { 138 perror(myname); 139 return (4); /* XXX */ 140 } 141 142 if (vfsave.vfs_mountp != NULL) { 143 free(vfsave.vfs_mountp); 144 vfsave.vfs_mountp = NULL; 145 } 146 if ((vp->vfs_mountp != NULL) && 147 ((vfsave.vfs_mountp = strdup(vp->vfs_mountp)) == NULL)) { 148 perror(myname); 149 return (4); /* XXX */ 150 } 151 152 if (vfsave.vfs_fstype != NULL) { 153 free(vfsave.vfs_fstype); 154 vfsave.vfs_fstype = NULL; 155 } 156 if ((vp->vfs_fstype != NULL) && 157 ((vfsave.vfs_fstype = strdup(vp->vfs_fstype)) == NULL)) { 158 perror(myname); 159 return (4); /* XXX */ 160 } 161 162 if (vfsave.vfs_fsckpass != NULL) { 163 free(vfsave.vfs_fsckpass); 164 vfsave.vfs_fsckpass = NULL; 165 } 166 if ((vp->vfs_fsckpass != NULL) && 167 ((vfsave.vfs_fsckpass = strdup(vp->vfs_fsckpass)) == NULL)) { 168 perror(myname); 169 return (4); /* XXX */ 170 } 171 172 if (vfsave.vfs_automnt != NULL) { 173 free(vfsave.vfs_automnt); 174 vfsave.vfs_automnt = NULL; 175 } 176 if ((vp->vfs_automnt != NULL) && 177 ((vfsave.vfs_automnt = strdup(vp->vfs_automnt)) == NULL)) { 178 perror(myname); 179 return (4); /* XXX */ 180 } 181 182 if (vfsave.vfs_mntopts != NULL) { 183 free(vfsave.vfs_mntopts); 184 vfsave.vfs_mntopts = NULL; 185 } 186 if ((vp->vfs_mntopts != NULL) && 187 ((vfsave.vfs_mntopts = strdup(vp->vfs_mntopts)) == NULL)) { 188 perror(myname); 189 return (4); /* XXX */ 190 } 191 192 *vp = vfsave; 193 return (0); 194 } 195 196 static int 197 mygetvfsent(FILE *fp, struct vfstab *vp) 198 { 199 int error; 200 201 if ((error = getvfsent(fp, vp)) != 0) 202 return (error); 203 return (vfdup(vp)); 204 } 205 206 static int 207 mygetvfsany(FILE *fp, struct vfstab *vp, struct vfstab *vrefp) 208 { 209 int error; 210 211 if ((error = getvfsany(fp, vp, vrefp)) != 0) 212 return (error); 213 return (vfdup(vp)); 214 } 215 216 int 217 main(int argc, char *argv[]) 218 { 219 int cc, ret, other_than_ufs = 0; 220 int questflg = 0, Fflg = 0, Vflg = 0, sanity = 0; 221 char *subopt; 222 FILE *fd = NULL; 223 struct vfstab vget, vref; 224 int preencnt = 0; 225 struct devlist *dp, *devs = NULL; 226 int status; 227 228 (void) setlocale(LC_ALL, ""); 229 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 230 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 231 #endif 232 (void) textdomain(TEXT_DOMAIN); 233 234 myname = strrchr(argv[0], '/'); 235 if (myname) 236 myname++; 237 else 238 myname = argv[0]; 239 240 while ((cc = getopt(argc, argv, "?F:mnNo:vVyY")) != -1) { 241 switch (cc) { 242 case '?': 243 questflg++; 244 if (questflg > 1) 245 usage(); 246 nargv[nargc++] = "-?"; 247 CHECK(nargc, ARGV_MAX); 248 break; 249 case 'F': 250 Fflg++; 251 /* check for more that one -F */ 252 if (Fflg > 1) { 253 fprintf(stderr, 254 gettext("%s: more than one fstype specified\n"), 255 myname); 256 usage(); 257 } 258 fstype = optarg; 259 if (strlen(fstype) > (size_t)FSTYPE_MAX) { 260 fprintf(stderr, 261 gettext("%s: Fstype %s exceeds %d characters\n"), 262 myname, fstype, FSTYPE_MAX); 263 exit(1); 264 } 265 break; 266 case 'm': 267 sanity++; 268 OPTION("-m"); 269 case 'n': 270 OPTION("-n"); 271 case 'N': 272 OPTION("-N"); 273 case 'o': 274 subopt = optarg; 275 while (*subopt != '\0') { 276 if (*subopt == 'p') { 277 pflg++; 278 break; 279 } 280 subopt++; 281 } 282 OPTARG("-o"); 283 case 'v': 284 OPTION("-v"); 285 case 'V': 286 Vflg++; 287 if (Vflg > 1) 288 usage(); 289 break; 290 case 'y': 291 OPTION("-y"); 292 case 'Y': 293 OPTION("-Y"); 294 } 295 optarg = NULL; 296 } 297 298 /* copy '--' to specific */ 299 if (strcmp(argv[optind-1], "--") == 0) { 300 nargv[nargc++] = argv[optind-1]; 301 CHECK(nargc, ARGV_MAX); 302 } 303 304 if (questflg) { 305 if (Fflg) { 306 nargc = 2; 307 nargv[nargc++] = "-?"; 308 nargv[nargc] = NULL; 309 do_exec(fstype, nargv); 310 } 311 usage(); 312 } 313 314 if ((sanity) && (options > 1)) { 315 usage(); 316 } 317 318 if (optind == argc) { /* no device name is specified */ 319 if (fstype == NULL) { 320 if ((argc > 2) && (sanity)) { 321 usage(); 322 } 323 } 324 /* 325 * Try to check UFS filesystems first, then check other 326 * filesystems if they exist. 327 * Note: Parallel checking is only available in UFS for now. 328 */ 329 if (fstype == NULL || strcmp(fstype, MNTTYPE_UFS) == 0) { 330 if ((fd = fopen(vfstab, "r")) == NULL) { 331 fprintf(stderr, 332 gettext("%s: cannot open vfstab\n"), 333 myname); 334 exit(1); 335 } 336 while ((ret = mygetvfsent(fd, &vget)) == 0) { 337 if (strcmp(vget.vfs_fstype, MNTTYPE_UFS) && 338 numbers(vget.vfs_fsckpass)) { 339 other_than_ufs ++; 340 continue; 341 } 342 if (numbers(vget.vfs_fsckpass)) 343 mnt_passno = atoi(vget.vfs_fsckpass); 344 else 345 continue; 346 if (mnt_passno < 1) 347 continue; 348 if (pflg == 0 || mnt_passno == 1) { 349 status = execute(vget.vfs_fsckdev, 350 MNTTYPE_UFS, Vflg, fd); 351 /* return the highest exit code */ 352 if (status > exitstat) 353 exitstat = status; 354 } else if (preen_addev(vget.vfs_fsckdev) == 0) { 355 preencnt++; 356 dp = newdev(&vget); 357 dp->nxt = devs; 358 devs = dp; 359 } else { 360 /* 361 * preening setup failed, so 362 * execute serially here... 363 */ 364 fprintf(stderr, 365 gettext("%s: preen_addev error\n"), 366 myname); 367 status = execute(vget.vfs_fsckdev, 368 MNTTYPE_UFS, Vflg, fd); 369 /* return the highest exit code */ 370 if (status > exitstat) 371 exitstat = status; 372 } 373 } 374 fclose(fd); 375 if (ret > 0) 376 vfserror(ret); 377 if (pflg && exitstat == 0) { 378 fsck_dopreen(&devs, preencnt); 379 } 380 } 381 else 382 other_than_ufs = 1; 383 384 if (other_than_ufs) { 385 if ((fd = fopen(vfstab, "r")) == NULL) { 386 fprintf(stderr, 387 gettext("%s: cannot open vfstab\n"), 388 myname); 389 exit(1); 390 } 391 while ((ret = mygetvfsent(fd, &vget)) == 0) 392 if (strcmp(vget.vfs_fstype, MNTTYPE_UFS) && 393 numbers(vget.vfs_fsckpass) && 394 vget.vfs_fsckdev != NULL && 395 (fstype == NULL || 396 strcmp(fstype, vget.vfs_fstype) == 0)) { 397 status = execute(vget.vfs_fsckdev, 398 vget.vfs_fstype, Vflg, fd); 399 /* return the highest exit code */ 400 if (status > exitstat) 401 exitstat = status; 402 } 403 fclose(fd); 404 if (ret > 0) 405 vfserror(ret); 406 } 407 408 } else { /* device name is specified */ 409 if (fstype == NULL && (fd = fopen(vfstab, "r")) == NULL) { 410 fprintf(stderr, gettext("%s: cannot open vfstab\n"), 411 myname); 412 exit(1); 413 } 414 while (optind < argc) { 415 /* 416 * If "-F FStype" is specified, use that fs type. 417 * Otherwise, determine the fs type from /etc/vfstab 418 * if the entry exists. Otherwise, determine the 419 * local or remote fs type from /etc/default/df 420 * or /etc/dfs/fstypes respectively. 421 */ 422 if (fstype == NULL) { 423 if ((argc > 3) && (sanity)) { 424 usage(); 425 } 426 /* must check for both special && raw devices */ 427 vfsnull(&vref); 428 429 /* 430 * Find the vfstab entry for this device. 431 * arg_hint tells us what to try to match, 432 * based on the type of the last arg. If 433 * arg_hint equals UNKNOWN, then we're not 434 * sure of the type and need to fallthrough 435 * all 3 possibilities for vfstab lookup. 436 * Try it as a mountpt first, since that's 437 * what mountall gives us. 438 */ 439 try_again: 440 switch (arg_hint) { 441 case UNKNOWN: 442 /* FALLTHROUGH */ 443 444 case MOUNTPT: 445 vref.vfs_mountp = argv[optind]; 446 if ((ret = mygetvfsany(fd, &vget, 447 &vref)) == -1 || 448 vget.vfs_fstype == NULL) { 449 450 vref.vfs_mountp = NULL; 451 rewind(fd); 452 453 if (arg_hint == MOUNTPT) { 454 arg_hint = UNKNOWN; 455 goto try_again; 456 } 457 /* FALLTHROUGH */ 458 } else { 459 /* Found it */ 460 if (vget.vfs_fsckdev != NULL) { 461 argv[optind] = 462 vget.vfs_fsckdev; 463 } 464 arg_hint = MOUNTPT; 465 break; 466 } 467 468 case FSCKDEV: 469 vref.vfs_fsckdev = argv[optind]; 470 if ((ret = mygetvfsany(fd, &vget, 471 &vref)) == -1 || 472 vget.vfs_fstype == NULL) { 473 474 vref.vfs_fsckdev = NULL; 475 rewind(fd); 476 477 if (arg_hint == FSCKDEV) { 478 arg_hint = UNKNOWN; 479 goto try_again; 480 } 481 /* FALLTHROUGH */ 482 } else { 483 /* Found it */ 484 arg_hint = FSCKDEV; 485 break; 486 } 487 488 case SPECIAL: 489 vref.vfs_special = argv[optind]; 490 if ((ret = mygetvfsany(fd, &vget, 491 &vref)) == -1 || 492 vget.vfs_fstype == NULL) { 493 494 vref.vfs_special = NULL; 495 rewind(fd); 496 497 if (arg_hint == SPECIAL) { 498 arg_hint = UNKNOWN; 499 goto try_again; 500 } 501 /* FALLTHROUGH */ 502 } else { 503 /* Found it */ 504 arg_hint = SPECIAL; 505 break; 506 } 507 } 508 509 if (ret == 0 && vget.vfs_fstype) { 510 if ((pflg) && (strcmp(vget.vfs_fstype, 511 MNTTYPE_UFS) == 0) && (preen_addev( 512 vget.vfs_fsckdev) == 0)) { 513 preencnt++; 514 dp = newdev(&vget); 515 dp->nxt = devs; 516 devs = dp; 517 } else { 518 status = execute(argv[optind], 519 vget.vfs_fstype, Vflg, fd); 520 if (status > exitstat) 521 exitstat = status; 522 } 523 } else if (ret == -1 || 524 vget.vfs_fstype == NULL) { 525 fstype = 526 default_fstype(argv[optind]); 527 status = execute(argv[optind], fstype, 528 Vflg, fd); 529 /* return the highest exit code */ 530 if (status > exitstat) 531 exitstat = status; 532 } else 533 vfserror(ret); 534 } else { 535 status = execute(argv[optind], fstype, 536 Vflg, NULL); 537 /* return the highest exit code */ 538 if (status > exitstat) 539 exitstat = status; 540 } 541 optind++; 542 } 543 if (fd != NULL) 544 fclose(fd); 545 if ((pflg) && (exitstat == 0)) { 546 fsck_dopreen(&devs, preencnt); 547 } 548 } 549 return (exitstat); 550 } 551 552 static void 553 fsck_dopreen(struct devlist **devp, int ndevs) 554 { 555 char name[1024]; 556 int rc; 557 int i; 558 struct devlist *bl, *bdp; 559 struct devlist *badlist; 560 561 bl = badlist = NULL; 562 while (ndevs > 0) { 563 if (nrun > maxrun) 564 waiter(&bl, &badlist); 565 rc = preen_getdev(name); 566 switch (rc) { 567 case 0: 568 break; 569 case 1: 570 bdp = getdev(name, devp); 571 if (bdp == NULL) { 572 fprintf(stderr, 573 gettext("%s: unknown dev: `%s'\n"), 574 myname, name); 575 exit(1); 576 } 577 bdp->nxt = bl; 578 bl = bdp; 579 startdisk(bdp); 580 ndevs--; 581 break; 582 case 2: 583 waiter(&bl, &badlist); 584 break; 585 default: 586 fprintf(stderr, 587 gettext("%s: bad return `%d' from preen_getdev\n"), 588 myname, rc); 589 break; 590 } 591 } 592 while (bl != NULL) { 593 waiter(&bl, &badlist); 594 } 595 596 if (badlist != NULL) 597 print_badlist(badlist); 598 } 599 600 static void 601 startdisk(struct devlist *dp) 602 { 603 pid_t pid; 604 605 nrun++; 606 if ((pid = fork()) == -1) { 607 perror("fork"); 608 exit(1); 609 } else if (pid == 0) { 610 exitstat = execute(dp->name, MNTTYPE_UFS, Vflg, NULL); 611 exit(exitstat); 612 } else { 613 dp->pid = pid; 614 } 615 } 616 617 static void 618 waiter(struct devlist **blp, struct devlist **badlist) 619 { 620 pid_t curpid; 621 int status; 622 struct devlist *bdp, *pbdp; 623 624 curpid = wait(&status); 625 if (curpid == -1) { 626 perror("wait"); 627 exit(1); 628 } 629 630 for (pbdp = NULL, bdp = *blp; bdp != NULL; pbdp = bdp, bdp = bdp->nxt) { 631 if (bdp->pid == curpid) { 632 break; 633 } 634 } 635 if (bdp == NULL) 636 return; 637 nrun--; 638 639 if (pbdp) 640 pbdp->nxt = bdp->nxt; 641 else 642 *blp = bdp->nxt; 643 preen_releasedev(bdp->name); 644 645 if (WTERMSIG(status)) { 646 printf(gettext("%s (%s): EXITED WITH SIGNAL %d\n"), 647 bdp->name, bdp->fsname, WTERMSIG(status)); 648 status = status&0377 | 8<<8; 649 } 650 if (WHIBYTE(status) != 0) { 651 if (WHIBYTE(status) > exitstat) 652 exitstat = WHIBYTE(status); 653 while (*badlist != NULL) 654 badlist = &(*badlist)->nxt; 655 *badlist = bdp; 656 bdp->nxt = NULL; 657 } 658 } 659 660 static void 661 print_badlist(struct devlist *lp) 662 { 663 int x, len; 664 665 printf( 666 gettext("\nTHE FOLLOWING FILE SYSTEM(S) HAD AN UNEXPECTED INCONSISTENCY:")); 667 for (x = 3; lp != NULL; lp = lp->nxt) { 668 len = strlen(lp->name) + strlen(lp->fsname) + 5; 669 x += len; 670 if (x >= 80) { 671 printf("\n "); 672 x = len + 3; 673 } else { 674 printf(" "); 675 } 676 printf("%s (%s)%s", lp->name, lp->fsname, 677 lp->nxt ? "," : "\n"); 678 } 679 } 680 681 /* 682 * allocate and initialize a `devlist' structure 683 */ 684 static 685 struct devlist * 686 newdev(struct vfstab *vfsp) 687 { 688 struct devlist *dp; 689 extern char *strdup(); 690 691 dp = (struct devlist *)malloc(sizeof (struct devlist)); 692 if (dp == NULL) { 693 fprintf(stderr, gettext("%s: out of memory\n"), myname); 694 exit(1); 695 } 696 dp->name = strdup(vfsp->vfs_fsckdev); 697 dp->fsname = strdup(vfsp->vfs_mountp); 698 if (dp->name == NULL || dp->fsname == NULL) { 699 fprintf(stderr, gettext("%s: out of memory\n"), myname); 700 exit(1); 701 } 702 return (dp); 703 } 704 705 /* 706 * locate the devlist structure in the given list that matches `name'. 707 * If found, the structure is removed from the list, and a pointer to 708 * it is returned. If not, NULL is returned. 709 */ 710 static 711 struct devlist * 712 getdev(char *name, struct devlist **list) 713 { 714 struct devlist *p, *lp; 715 716 for (lp = NULL, p = *list; p != NULL; lp = p, p = p->nxt) { 717 if (strcmp(p->name, name) == 0) 718 break; 719 } 720 721 if (p != NULL) { 722 if (lp != NULL) 723 lp->nxt = p->nxt; 724 else 725 *list = p->nxt; 726 } 727 return (p); 728 } 729 730 /* see if all numbers */ 731 int 732 numbers(char *yp) 733 { 734 if (yp == NULL) 735 return (0); 736 while ('0' <= *yp && *yp <= '9') 737 yp++; 738 if (*yp) 739 return (0); 740 return (1); 741 } 742 743 int 744 execute(char *fsckdev, char *fstype, int Vflg, FILE *fd) 745 { 746 int st; 747 pid_t fk; 748 char full_path[PATH_MAX]; 749 char *vfs_path = VFS_PATH; 750 int status = 0; 751 752 nargv[nargc] = fsckdev; 753 754 if (Vflg) { 755 prnt_cmd(stdout, fstype); 756 return (0); 757 } 758 759 if (fd) 760 fcntl(fileno(fd), F_SETFD, 1); /* close on exec */ 761 762 if ((fk = fork()) == (pid_t)-1) { 763 fprintf(stderr, 764 gettext("%s: cannot fork. Try again later\n"), 765 myname); 766 perror(myname); 767 exit(1); 768 } 769 770 if (fk == 0) { 771 /* Try to exec the fstype dependent portion of the fsck. */ 772 do_exec(fstype, nargv); 773 } else { 774 /* parent waits for child */ 775 if (wait(&st) == (pid_t)-1) { 776 fprintf(stderr, gettext("%s: bad wait\n"), myname); 777 perror(myname); 778 exit(1); 779 } 780 781 if ((st & 0xff) == 0x7f) { 782 fprintf(stderr, 783 gettext("%s: warning: the following command" 784 " (process %d) was stopped by signal %d\n"), 785 myname, fk, (st >> 8) & 0xff); 786 prnt_cmd(stderr, fstype); 787 status = ((st >> 8) & 0xff) | 0x80; 788 } else if (st & 0xff) { 789 if (st & 0x80) 790 fprintf(stderr, 791 gettext("%s: warning: the following command" 792 " (process %d) was terminated by signal %d" 793 " and dumped core\n"), 794 myname, fk, st & 0x7f); 795 else 796 fprintf(stderr, 797 gettext("%s: warning: the following command" 798 " (process %d) was terminated by signal %d\n"), 799 myname, fk, st & 0x7f); 800 801 prnt_cmd(stderr, fstype); 802 status = ((st & 0xff) | 0x80); 803 } else if (st & 0xff00) 804 status = (st >> 8) & 0xff; 805 } 806 807 return (status); 808 } 809 810 static void 811 do_exec(char *fstype, char *nargv[]) 812 { 813 char full_path[PATH_MAX]; 814 char *vfs_path = VFS_PATH; 815 816 if (strlen(fstype) > (size_t)FSTYPE_MAX) { 817 fprintf(stderr, 818 gettext("%s: Fstype %s exceeds %d characters\n"), 819 myname, fstype, FSTYPE_MAX); 820 exit(1); 821 } 822 /* build the full pathname of the fstype dependent command. */ 823 sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname); 824 825 /* set the new argv[0] to the filename */ 826 nargv[1] = myname; 827 /* Try to exec the fstype dependent portion of the fsck. */ 828 execv(full_path, &nargv[1]); 829 if (errno == EACCES) { 830 fprintf(stderr, 831 gettext("%s: cannot execute %s - permission denied\n"), 832 myname, full_path); 833 } 834 if (errno == ENOEXEC) { 835 nargv[0] = "sh"; 836 nargv[1] = full_path; 837 execv("/sbin/sh", &nargv[0]); 838 } 839 /* second path to try */ 840 vfs_path = VFS_PATH2; 841 /* build the full pathname of the fstype dependent command. */ 842 sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname); 843 844 /* set the new argv[0] to the filename */ 845 nargv[1] = myname; 846 /* Try to exec the second fstype dependent portion of the fsck. */ 847 execv(full_path, &nargv[1]); 848 if (errno == EACCES) { 849 fprintf(stderr, 850 gettext("%s: cannot execute %s - permission denied\n"), 851 myname, full_path); 852 exit(1); 853 } 854 if (errno == ENOEXEC) { 855 nargv[0] = "sh"; 856 nargv[1] = full_path; 857 execv("/sbin/sh", &nargv[0]); 858 } 859 fprintf(stderr, 860 gettext("%s: operation not applicable to FSType %s\n"), 861 myname, fstype); 862 exit(1); 863 } 864 865 static void 866 prnt_cmd(FILE *fd, char *fstype) 867 { 868 char **argp; 869 870 fprintf(fd, "%s -F %s", myname, fstype); 871 for (argp = &nargv[2]; *argp; argp++) 872 fprintf(fd, " %s", *argp); 873 fprintf(fd, "\n"); 874 } 875 876 static void 877 vfserror(int flag) 878 { 879 switch (flag) { 880 case VFS_TOOLONG: 881 fprintf(stderr, 882 gettext("%s: line in vfstab exceeds %d characters\n"), 883 myname, VFS_LINE_MAX-2); 884 break; 885 case VFS_TOOFEW: 886 fprintf(stderr, 887 gettext("%s: line in vfstab has too few entries\n"), 888 myname); 889 break; 890 case VFS_TOOMANY: 891 fprintf(stderr, 892 gettext("%s: line in vfstab has too many entries\n"), 893 myname); 894 break; 895 } 896 exit(1); 897 } 898 899 int opterr = 1, optind = 1, optopt = 0; 900 char *optarg = 0; 901 902 int 903 getopt(int argc, char * const *argv, const char *opts) 904 { 905 static int sp = 1; 906 int c; 907 char *cp; 908 909 if (sp == 1) 910 if (optind >= argc || 911 argv[optind][0] != '-' || argv[optind][1] == '\0') 912 return (-1); 913 else if (strcmp(argv[optind], "--") == 0) { 914 optind++; 915 return (-1); 916 } 917 optopt = c = argv[optind][sp]; 918 if (c == ':' || (cp = strchr(opts, c)) == 0) { 919 if (opterr) 920 fprintf(stderr, 921 gettext("%s: illegal option -- %c\n"), 922 *argv, c); 923 if (argv[optind][++sp] == '\0') { 924 optind++; 925 sp = 1; 926 } 927 return ('?'); 928 } 929 if (*++cp == ':') { 930 if (argv[optind][sp+1] != '\0') 931 optarg = &argv[optind++][sp+1]; 932 else if (++optind >= argc) { 933 if (opterr) 934 fprintf(stderr, 935 gettext("%s: option requires an argument -- %c\n"), *argv, c); 936 sp = 1; 937 return ('?'); 938 } else 939 optarg = argv[optind++]; 940 sp = 1; 941 } else if (*cp == ';') { 942 if (argv[optind][++sp] != '\0') 943 if (isoptarg(c, &argv[optind][sp])) { 944 optarg = &argv[optind++][sp]; 945 sp = 1; 946 } else 947 optarg = NULL; 948 else { 949 sp = 1; 950 if (++optind >= argc || !isoptarg(c, &argv[optind][0])) 951 optarg = NULL; 952 else 953 optarg = argv[optind++]; 954 } 955 } else { 956 if (argv[optind][++sp] == '\0') { 957 sp = 1; 958 optind++; 959 } 960 optarg = NULL; 961 } 962 return (c); 963 } 964 965 int 966 isoptarg(int cc, char *arg) 967 { 968 if (cc == 's' || cc == 'S') { 969 while (*arg >= '0' && *arg <= '9') 970 arg++; 971 if (*arg++ != ':') 972 return (0); 973 while (*arg >= '0' && *arg <= '9') 974 arg++; 975 if (*arg) 976 return (0); 977 return (1); 978 } 979 return (0); 980 } 981 982 static void 983 usage(void) 984 { 985 fprintf(stderr, 986 gettext("Usage:\n%s [-F FSType] [-V] [-m] [special ...]\n" 987 "%s [-F FSType] [-V] [-y|Y|n|N]" 988 " [-o specific_options] [special ...]\n"), 989 myname, myname); 990 991 exit(1); 992 } 993