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 2009 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 #include	<stdio.h>
     30 #include	<errno.h>
     31 #include	<limits.h>
     32 #include	<fcntl.h>
     33 #include	<string.h>
     34 #include	<sys/types.h>
     35 #include	<sys/stat.h>
     36 #include	<sys/wait.h>
     37 #include	<sys/vfstab.h>
     38 #include	<sys/mntent.h>
     39 #include	<sys/sysmacros.h>
     40 #include	<locale.h>
     41 #include	<libintl.h>
     42 #include	<sys/dkio.h>
     43 
     44 #define	DEV_BSIZE	512
     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 	int	devfd;
    221 	struct vfstab	vget, vref;
    222 	struct dk_minfo dkminfo;
    223 	int preencnt = 0;
    224 	struct devlist *dp, *devs = NULL;
    225 	int status;
    226 	uint_t lbs;
    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 
    415 		while (optind < argc) {
    416 			/*
    417 			 * If "-F FStype" is specified, use that fs type.
    418 			 * Otherwise, determine the fs type from /etc/vfstab
    419 			 * if the entry exists.  Otherwise, determine the
    420 			 * local or remote fs type from /etc/default/df
    421 			 * or /etc/dfs/fstypes respectively.
    422 			 */
    423 			if (fstype == NULL) {
    424 				if ((argc > 3) && (sanity)) {
    425 					usage();
    426 				}
    427 				/* must check for both special && raw devices */
    428 				vfsnull(&vref);
    429 
    430 				/*
    431 				 * Find the vfstab entry for this device.
    432 				 * arg_hint tells us what to try to match,
    433 				 * based on the type of the last arg. If
    434 				 * arg_hint equals UNKNOWN, then we're not
    435 				 * sure of the type and need to fallthrough
    436 				 * all 3 possibilities for vfstab lookup.
    437 				 * Try it as a mountpt first, since that's
    438 				 * what mountall gives us.
    439 				 */
    440 try_again:
    441 				switch (arg_hint) {
    442 				case UNKNOWN:
    443 					/* FALLTHROUGH */
    444 
    445 				case MOUNTPT:
    446 					vref.vfs_mountp = argv[optind];
    447 					if ((ret = mygetvfsany(fd, &vget,
    448 						&vref)) == -1 ||
    449 						vget.vfs_fstype == NULL) {
    450 
    451 						vref.vfs_mountp = NULL;
    452 						rewind(fd);
    453 
    454 						if (arg_hint == MOUNTPT) {
    455 							arg_hint = UNKNOWN;
    456 							goto try_again;
    457 						}
    458 						/* FALLTHROUGH */
    459 					} else {
    460 						/* Found it */
    461 						if (vget.vfs_fsckdev != NULL) {
    462 							argv[optind] =
    463 							vget.vfs_fsckdev;
    464 						}
    465 						arg_hint = MOUNTPT;
    466 						break;
    467 					}
    468 
    469 				case FSCKDEV:
    470 					vref.vfs_fsckdev = argv[optind];
    471 
    472 					/*
    473 					 * Check the media sector size
    474 					 */
    475 					if (((devfd = open(vref.vfs_fsckdev,
    476 					    O_RDWR)) >= 0) && (ioctl(devfd,
    477 					    DKIOCGMEDIAINFO, &dkminfo) !=
    478 					    -1)) {
    479 						lbs =  dkminfo.dki_lbsize;
    480 						if (lbs != 0 && ISP2(lbs /
    481 						    DEV_BSIZE) &&
    482 						    lbs != DEV_BSIZE) {
    483 							fprintf(stderr,
    484 							    gettext("The device"
    485 							    " sector size is"
    486 							    " not supported by"
    487 							    " fsck\n"));
    488 							(void) close(devfd);
    489 							exit(1);
    490 						}
    491 					}
    492 
    493 					if (devfd >= 0) {
    494 						(void) close(devfd);
    495 					}
    496 
    497 					if ((ret = mygetvfsany(fd, &vget,
    498 						&vref)) == -1 ||
    499 						vget.vfs_fstype == NULL) {
    500 
    501 						vref.vfs_fsckdev = NULL;
    502 						rewind(fd);
    503 
    504 						if (arg_hint == FSCKDEV) {
    505 							arg_hint = UNKNOWN;
    506 							goto try_again;
    507 						}
    508 						/* FALLTHROUGH */
    509 					} else {
    510 						/* Found it */
    511 						arg_hint = FSCKDEV;
    512 						break;
    513 					}
    514 
    515 				case SPECIAL:
    516 					vref.vfs_special = argv[optind];
    517 					if ((ret = mygetvfsany(fd, &vget,
    518 						&vref)) == -1 ||
    519 						vget.vfs_fstype == NULL) {
    520 
    521 						vref.vfs_special = NULL;
    522 						rewind(fd);
    523 
    524 						if (arg_hint == SPECIAL) {
    525 							arg_hint = UNKNOWN;
    526 							goto try_again;
    527 						}
    528 						/* FALLTHROUGH */
    529 					} else {
    530 						/* Found it */
    531 						arg_hint = SPECIAL;
    532 						break;
    533 					}
    534 				}
    535 
    536 				if (ret == 0 && vget.vfs_fstype) {
    537 					if ((pflg) && (strcmp(vget.vfs_fstype,
    538 					    MNTTYPE_UFS) == 0) && (preen_addev(
    539 					    vget.vfs_fsckdev) == 0)) {
    540 						preencnt++;
    541 						dp = newdev(&vget);
    542 						dp->nxt = devs;
    543 						devs = dp;
    544 					} else {
    545 						status = execute(argv[optind],
    546 						    vget.vfs_fstype, Vflg, fd);
    547 						if (status > exitstat)
    548 							exitstat = status;
    549 					}
    550 				} else if (ret == -1 ||
    551 				    vget.vfs_fstype == NULL) {
    552 					fstype =
    553 					    default_fstype(argv[optind]);
    554 					status = execute(argv[optind], fstype,
    555 					    Vflg, fd);
    556 					/* return the highest exit code */
    557 					if (status > exitstat)
    558 						exitstat = status;
    559 				} else
    560 					vfserror(ret);
    561 			} else {
    562 				status = execute(argv[optind], fstype,
    563 				    Vflg, NULL);
    564 				/* return the highest exit code */
    565 				if (status > exitstat)
    566 					exitstat = status;
    567 			}
    568 			optind++;
    569 		}
    570 		if (fd != NULL)
    571 			fclose(fd);
    572 		if ((pflg) && (exitstat == 0)) {
    573 			fsck_dopreen(&devs, preencnt);
    574 		}
    575 	}
    576 	return (exitstat);
    577 }
    578 
    579 static void
    580 fsck_dopreen(struct devlist **devp, int ndevs)
    581 {
    582 	char name[1024];
    583 	int rc;
    584 	int i;
    585 	struct devlist *bl, *bdp;
    586 	struct devlist *badlist;
    587 
    588 	bl = badlist = NULL;
    589 	while (ndevs > 0) {
    590 		if (nrun > maxrun)
    591 			waiter(&bl, &badlist);
    592 		rc = preen_getdev(name);
    593 		switch (rc) {
    594 		case 0:
    595 			break;
    596 		case 1:
    597 			bdp = getdev(name, devp);
    598 			if (bdp == NULL) {
    599 				fprintf(stderr,
    600 					gettext("%s: unknown dev: `%s'\n"),
    601 					myname, name);
    602 				exit(1);
    603 			}
    604 			bdp->nxt = bl;
    605 			bl = bdp;
    606 			startdisk(bdp);
    607 			ndevs--;
    608 			break;
    609 		case 2:
    610 			waiter(&bl, &badlist);
    611 			break;
    612 		default:
    613 			fprintf(stderr,
    614 			gettext("%s: bad return `%d' from preen_getdev\n"),
    615 				myname, rc);
    616 			break;
    617 		}
    618 	}
    619 	while (bl != NULL) {
    620 		waiter(&bl, &badlist);
    621 	}
    622 
    623 	if (badlist != NULL)
    624 		print_badlist(badlist);
    625 }
    626 
    627 static void
    628 startdisk(struct devlist *dp)
    629 {
    630 	pid_t pid;
    631 
    632 	nrun++;
    633 	if ((pid = fork()) == -1) {
    634 		perror("fork");
    635 		exit(1);
    636 	} else if (pid == 0) {
    637 		exitstat = execute(dp->name, MNTTYPE_UFS, Vflg, NULL);
    638 		exit(exitstat);
    639 	} else {
    640 		dp->pid = pid;
    641 	}
    642 }
    643 
    644 static void
    645 waiter(struct devlist **blp, struct devlist **badlist)
    646 {
    647 	pid_t curpid;
    648 	int status;
    649 	struct devlist *bdp, *pbdp;
    650 
    651 	curpid = wait(&status);
    652 	if (curpid == -1) {
    653 		perror("wait");
    654 		exit(1);
    655 	}
    656 
    657 	for (pbdp = NULL, bdp = *blp; bdp != NULL; pbdp = bdp, bdp = bdp->nxt) {
    658 		if (bdp->pid == curpid) {
    659 			break;
    660 		}
    661 	}
    662 	if (bdp == NULL)
    663 		return;
    664 	nrun--;
    665 
    666 	if (pbdp)
    667 		pbdp->nxt = bdp->nxt;
    668 	else
    669 		*blp = bdp->nxt;
    670 	preen_releasedev(bdp->name);
    671 
    672 	if (WTERMSIG(status)) {
    673 		printf(gettext("%s (%s): EXITED WITH SIGNAL %d\n"),
    674 			bdp->name, bdp->fsname, WTERMSIG(status));
    675 		status = status&0377 | 8<<8;
    676 	}
    677 	if (WHIBYTE(status) != 0) {
    678 		if (WHIBYTE(status) > exitstat)
    679 			exitstat = WHIBYTE(status);
    680 		while (*badlist != NULL)
    681 			badlist = &(*badlist)->nxt;
    682 		*badlist = bdp;
    683 		bdp->nxt = NULL;
    684 	}
    685 }
    686 
    687 static void
    688 print_badlist(struct devlist *lp)
    689 {
    690 	int x, len;
    691 
    692 	printf(
    693 gettext("\nTHE FOLLOWING FILE SYSTEM(S) HAD AN UNEXPECTED INCONSISTENCY:"));
    694 	for (x = 3; lp != NULL; lp = lp->nxt) {
    695 		len = strlen(lp->name) + strlen(lp->fsname) + 5;
    696 		x += len;
    697 		if (x >= 80) {
    698 			printf("\n   ");
    699 			x = len + 3;
    700 		} else {
    701 			printf(" ");
    702 		}
    703 		printf("%s (%s)%s", lp->name, lp->fsname,
    704 		    lp->nxt ? "," : "\n");
    705 	}
    706 }
    707 
    708 /*
    709  * allocate and initialize a `devlist' structure
    710  */
    711 static
    712 struct devlist *
    713 newdev(struct vfstab *vfsp)
    714 {
    715 	struct devlist *dp;
    716 	extern char *strdup();
    717 
    718 	dp = (struct devlist *)malloc(sizeof (struct devlist));
    719 	if (dp == NULL) {
    720 		fprintf(stderr, gettext("%s: out of memory\n"), myname);
    721 		exit(1);
    722 	}
    723 	dp->name = strdup(vfsp->vfs_fsckdev);
    724 	dp->fsname = strdup(vfsp->vfs_mountp);
    725 	if (dp->name == NULL || dp->fsname == NULL) {
    726 		fprintf(stderr, gettext("%s: out of memory\n"), myname);
    727 		exit(1);
    728 	}
    729 	return (dp);
    730 }
    731 
    732 /*
    733  * locate the devlist structure in the given list that matches `name'.
    734  * If found, the structure is removed from the list, and a pointer to
    735  * it is returned.  If not, NULL is returned.
    736  */
    737 static
    738 struct devlist *
    739 getdev(char *name, struct devlist **list)
    740 {
    741 	struct devlist *p, *lp;
    742 
    743 	for (lp = NULL, p = *list; p != NULL; lp = p, p = p->nxt) {
    744 		if (strcmp(p->name, name) == 0)
    745 			break;
    746 	}
    747 
    748 	if (p != NULL) {
    749 		if (lp != NULL)
    750 			lp->nxt = p->nxt;
    751 		else
    752 			*list = p->nxt;
    753 	}
    754 	return (p);
    755 }
    756 
    757 /* see if all numbers */
    758 int
    759 numbers(char *yp)
    760 {
    761 	if (yp == NULL)
    762 		return (0);
    763 	while ('0' <= *yp && *yp <= '9')
    764 		yp++;
    765 	if (*yp)
    766 		return (0);
    767 	return (1);
    768 }
    769 
    770 int
    771 execute(char *fsckdev, char *fstype, int Vflg, FILE *fd)
    772 {
    773 	int	st;
    774 	pid_t	fk;
    775 	char	full_path[PATH_MAX];
    776 	char	*vfs_path = VFS_PATH;
    777 	int	status = 0;
    778 
    779 	nargv[nargc] = fsckdev;
    780 
    781 	if (Vflg) {
    782 		prnt_cmd(stdout, fstype);
    783 		return (0);
    784 	}
    785 
    786 	if (fd)
    787 		fcntl(fileno(fd), F_SETFD, 1);	/* close on exec */
    788 
    789 	if ((fk = fork()) == (pid_t)-1) {
    790 		fprintf(stderr,
    791 			gettext("%s: cannot fork.  Try again later\n"),
    792 			myname);
    793 		perror(myname);
    794 		exit(1);
    795 	}
    796 
    797 	if (fk == 0) {
    798 		/* Try to exec the fstype dependent portion of the fsck. */
    799 		do_exec(fstype, nargv);
    800 	} else {
    801 		/* parent waits for child */
    802 		if (wait(&st) == (pid_t)-1) {
    803 			fprintf(stderr, gettext("%s: bad wait\n"), myname);
    804 			perror(myname);
    805 			exit(1);
    806 		}
    807 
    808 		if ((st & 0xff) == 0x7f) {
    809 			fprintf(stderr,
    810 				gettext("%s: warning: the following command"
    811 				" (process %d) was stopped by signal %d\n"),
    812 				myname, fk, (st >> 8) & 0xff);
    813 			prnt_cmd(stderr, fstype);
    814 			status = ((st >> 8) & 0xff) | 0x80;
    815 		} else if (st & 0xff) {
    816 			if (st & 0x80)
    817 				fprintf(stderr,
    818 				gettext("%s: warning: the following command"
    819 				" (process %d) was terminated by signal %d"
    820 				" and dumped core\n"),
    821 				myname, fk, st & 0x7f);
    822 			else
    823 				fprintf(stderr,
    824 				gettext("%s: warning: the following command"
    825 				" (process %d) was terminated by signal %d\n"),
    826 				myname, fk, st & 0x7f);
    827 
    828 			prnt_cmd(stderr, fstype);
    829 			status = ((st & 0xff) | 0x80);
    830 		} else if (st & 0xff00)
    831 			status = (st >> 8) & 0xff;
    832 	}
    833 
    834 	return (status);
    835 }
    836 
    837 static void
    838 do_exec(char *fstype, char *nargv[])
    839 {
    840 	char	full_path[PATH_MAX];
    841 	char	*vfs_path = VFS_PATH;
    842 
    843 	if (strlen(fstype) > (size_t)FSTYPE_MAX) {
    844 		fprintf(stderr,
    845 			gettext("%s: Fstype %s exceeds %d characters\n"),
    846 			myname, fstype, FSTYPE_MAX);
    847 		exit(1);
    848 	}
    849 	/* build the full pathname of the fstype dependent command. */
    850 	sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname);
    851 
    852 	/* set the new argv[0] to the filename */
    853 	nargv[1] = myname;
    854 	/* Try to exec the fstype dependent portion of the fsck. */
    855 	execv(full_path, &nargv[1]);
    856 	if (errno == EACCES) {
    857 		fprintf(stderr,
    858 			gettext("%s: cannot execute %s - permission denied\n"),
    859 			myname, full_path);
    860 	}
    861 	if (errno == ENOEXEC) {
    862 		nargv[0] = "sh";
    863 		nargv[1] = full_path;
    864 		execv("/sbin/sh", &nargv[0]);
    865 	}
    866 	/* second path to try */
    867 	vfs_path = VFS_PATH2;
    868 	/* build the full pathname of the fstype dependent command. */
    869 	sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname);
    870 
    871 	/* set the new argv[0] to the filename */
    872 	nargv[1] = myname;
    873 	/* Try to exec the second fstype dependent portion of the fsck. */
    874 	execv(full_path, &nargv[1]);
    875 	if (errno == EACCES) {
    876 		fprintf(stderr,
    877 			gettext("%s: cannot execute %s - permission denied\n"),
    878 			myname, full_path);
    879 		exit(1);
    880 	}
    881 	if (errno == ENOEXEC) {
    882 		nargv[0] = "sh";
    883 		nargv[1] = full_path;
    884 		execv("/sbin/sh", &nargv[0]);
    885 	}
    886 	fprintf(stderr,
    887 		gettext("%s: operation not applicable to FSType %s\n"),
    888 		myname, fstype);
    889 	exit(1);
    890 }
    891 
    892 static void
    893 prnt_cmd(FILE *fd, char *fstype)
    894 {
    895 	char	**argp;
    896 
    897 	fprintf(fd, "%s -F %s", myname, fstype);
    898 	for (argp = &nargv[2]; *argp; argp++)
    899 		fprintf(fd, " %s", *argp);
    900 	fprintf(fd, "\n");
    901 }
    902 
    903 static void
    904 vfserror(int flag)
    905 {
    906 	switch (flag) {
    907 	case VFS_TOOLONG:
    908 		fprintf(stderr,
    909 			gettext("%s: line in vfstab exceeds %d characters\n"),
    910 			myname, VFS_LINE_MAX-2);
    911 		break;
    912 	case VFS_TOOFEW:
    913 		fprintf(stderr,
    914 			gettext("%s: line in vfstab has too few entries\n"),
    915 			myname);
    916 		break;
    917 	case VFS_TOOMANY:
    918 		fprintf(stderr,
    919 			gettext("%s: line in vfstab has too many entries\n"),
    920 			myname);
    921 		break;
    922 	}
    923 	exit(1);
    924 }
    925 
    926 static void
    927 usage(void)
    928 {
    929 	fprintf(stderr,
    930 		gettext("Usage:\n%s [-F FSType] [-V] [-m] [special ...]\n"
    931 			"%s [-F FSType] [-V] [-y|Y|n|N]"
    932 			" [-o specific_options] [special ...]\n"),
    933 			myname, myname);
    934 
    935 	exit(1);
    936 }
    937