xref: /illumos-gate/usr/src/cmd/fs.d/fsck.c (revision 24da5b34)
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