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