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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
34 #include <sys/types.h>
37 #include <sys/vfstab.h>
38 #include <sys/mntent.h>
39 #include <sys/sysmacros.h>
47 #define VFS_PATH "/usr/lib/fs"
48 #define VFS_PATH2 "/etc/fs"
50 #define CHECK(xx, yy)\
52 fprintf(stderr, gettext("%s: too many arguments\n"), myname); \
57 nargv[nargc++] = flag; \
58 CHECK(nargc, ARGV_MAX); \
61 nargv[nargc++] = flag; \
62 CHECK(nargc, ARGV_MAX); \
64 nargv[nargc++] = optarg; \
65 CHECK(nargc, ARGV_MAX); \
71 int maxrun
= 8; /* should be based on the machine resources */
73 extern char *default_fstype();
80 char *nargv
[ARGV_MAX
];
81 char *myname
, *fstype
;
83 char vfstab
[] = VFSTAB
;
84 char pflg
= 0, Vflg
= 0;
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.
92 enum dev_arg_t
{ UNKNOWN
, SPECIAL
, FSCKDEV
, MOUNTPT
};
93 enum dev_arg_t arg_hint
= UNKNOWN
;
95 static struct devlist
{
100 } *newdev(), *getdev();
103 * private copy vfstab functions
105 static struct vfstab vfsave
= {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
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
);
117 vfdup(struct vfstab
*vp
)
119 if (vfsave
.vfs_special
!= NULL
) {
120 free(vfsave
.vfs_special
);
121 vfsave
.vfs_special
= NULL
;
123 if ((vp
->vfs_special
!= NULL
) &&
124 ((vfsave
.vfs_special
= strdup(vp
->vfs_special
)) == NULL
)) {
126 return (4); /* XXX */
129 if (vfsave
.vfs_fsckdev
!= NULL
) {
130 free(vfsave
.vfs_fsckdev
);
131 vfsave
.vfs_fsckdev
= NULL
;
133 if ((vp
->vfs_fsckdev
!= NULL
) &&
134 ((vfsave
.vfs_fsckdev
= strdup(vp
->vfs_fsckdev
)) == NULL
)) {
136 return (4); /* XXX */
139 if (vfsave
.vfs_mountp
!= NULL
) {
140 free(vfsave
.vfs_mountp
);
141 vfsave
.vfs_mountp
= NULL
;
143 if ((vp
->vfs_mountp
!= NULL
) &&
144 ((vfsave
.vfs_mountp
= strdup(vp
->vfs_mountp
)) == NULL
)) {
146 return (4); /* XXX */
149 if (vfsave
.vfs_fstype
!= NULL
) {
150 free(vfsave
.vfs_fstype
);
151 vfsave
.vfs_fstype
= NULL
;
153 if ((vp
->vfs_fstype
!= NULL
) &&
154 ((vfsave
.vfs_fstype
= strdup(vp
->vfs_fstype
)) == NULL
)) {
156 return (4); /* XXX */
159 if (vfsave
.vfs_fsckpass
!= NULL
) {
160 free(vfsave
.vfs_fsckpass
);
161 vfsave
.vfs_fsckpass
= NULL
;
163 if ((vp
->vfs_fsckpass
!= NULL
) &&
164 ((vfsave
.vfs_fsckpass
= strdup(vp
->vfs_fsckpass
)) == NULL
)) {
166 return (4); /* XXX */
169 if (vfsave
.vfs_automnt
!= NULL
) {
170 free(vfsave
.vfs_automnt
);
171 vfsave
.vfs_automnt
= NULL
;
173 if ((vp
->vfs_automnt
!= NULL
) &&
174 ((vfsave
.vfs_automnt
= strdup(vp
->vfs_automnt
)) == NULL
)) {
176 return (4); /* XXX */
179 if (vfsave
.vfs_mntopts
!= NULL
) {
180 free(vfsave
.vfs_mntopts
);
181 vfsave
.vfs_mntopts
= NULL
;
183 if ((vp
->vfs_mntopts
!= NULL
) &&
184 ((vfsave
.vfs_mntopts
= strdup(vp
->vfs_mntopts
)) == NULL
)) {
186 return (4); /* XXX */
194 mygetvfsent(FILE *fp
, struct vfstab
*vp
)
198 if ((error
= getvfsent(fp
, vp
)) != 0)
204 mygetvfsany(FILE *fp
, struct vfstab
*vp
, struct vfstab
*vrefp
)
208 if ((error
= getvfsany(fp
, vp
, vrefp
)) != 0)
214 main(int argc
, char *argv
[])
216 int cc
, ret
, other_than_ufs
= 0;
217 int questflg
= 0, Fflg
= 0, Vflg
= 0, sanity
= 0;
221 struct vfstab vget
, vref
;
222 struct dk_minfo dkminfo
;
224 struct devlist
*dp
, *devs
= NULL
;
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 */
232 (void) textdomain(TEXT_DOMAIN
);
234 myname
= strrchr(argv
[0], '/');
240 while ((cc
= getopt(argc
, argv
, "?F:mnNo:vVyY")) != -1) {
246 nargv
[nargc
++] = "-?";
247 CHECK(nargc
, ARGV_MAX
);
251 /* check for more that one -F */
254 gettext("%s: more than one fstype specified\n"),
259 if (strlen(fstype
) > (size_t)FSTYPE_MAX
) {
261 gettext("%s: Fstype %s exceeds %d characters\n"),
262 myname
, fstype
, FSTYPE_MAX
);
275 while (*subopt
!= '\0') {
276 if (*subopt
== 'p') {
298 /* copy '--' to specific */
299 if (strcmp(argv
[optind
-1], "--") == 0) {
300 nargv
[nargc
++] = argv
[optind
-1];
301 CHECK(nargc
, ARGV_MAX
);
307 nargv
[nargc
++] = "-?";
309 do_exec(fstype
, nargv
);
314 if ((sanity
) && (options
> 1)) {
318 if (optind
== argc
) { /* no device name is specified */
319 if (fstype
== NULL
) {
320 if ((argc
> 2) && (sanity
)) {
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.
329 if (fstype
== NULL
|| strcmp(fstype
, MNTTYPE_UFS
) == 0) {
330 if ((fd
= fopen(vfstab
, "r")) == NULL
) {
332 gettext("%s: cannot open vfstab\n"),
336 while ((ret
= mygetvfsent(fd
, &vget
)) == 0) {
337 if (strcmp(vget
.vfs_fstype
, MNTTYPE_UFS
) &&
338 numbers(vget
.vfs_fsckpass
)) {
342 if (numbers(vget
.vfs_fsckpass
))
343 mnt_passno
= atoi(vget
.vfs_fsckpass
);
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
)
354 } else if (preen_addev(vget
.vfs_fsckdev
) == 0) {
361 * preening setup failed, so
362 * execute serially here...
365 gettext("%s: preen_addev error\n"),
367 status
= execute(vget
.vfs_fsckdev
,
368 MNTTYPE_UFS
, Vflg
, fd
);
369 /* return the highest exit code */
370 if (status
> exitstat
)
377 if (pflg
&& exitstat
== 0) {
378 fsck_dopreen(&devs
, preencnt
);
384 if (other_than_ufs
) {
385 if ((fd
= fopen(vfstab
, "r")) == NULL
) {
387 gettext("%s: cannot open vfstab\n"),
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
&&
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
)
408 } else { /* device name is specified */
409 if (fstype
== NULL
&& (fd
= fopen(vfstab
, "r")) == NULL
) {
410 fprintf(stderr
, gettext("%s: cannot open vfstab\n"),
415 while (optind
< argc
) {
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.
423 if (fstype
== NULL
) {
424 if ((argc
> 3) && (sanity
)) {
427 /* must check for both special && raw devices */
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.
446 vref
.vfs_mountp
= argv
[optind
];
447 if ((ret
= mygetvfsany(fd
, &vget
,
449 vget
.vfs_fstype
== NULL
) {
451 vref
.vfs_mountp
= NULL
;
454 if (arg_hint
== MOUNTPT
) {
461 if (vget
.vfs_fsckdev
!= NULL
) {
470 vref
.vfs_fsckdev
= argv
[optind
];
473 * Check the media sector size
475 if (((devfd
= open(vref
.vfs_fsckdev
,
476 O_RDWR
)) >= 0) && (ioctl(devfd
,
477 DKIOCGMEDIAINFO
, &dkminfo
) !=
479 lbs
= dkminfo
.dki_lbsize
;
480 if (lbs
!= 0 && ISP2(lbs
/
497 if ((ret
= mygetvfsany(fd
, &vget
,
499 vget
.vfs_fstype
== NULL
) {
501 vref
.vfs_fsckdev
= NULL
;
504 if (arg_hint
== FSCKDEV
) {
516 vref
.vfs_special
= argv
[optind
];
517 if ((ret
= mygetvfsany(fd
, &vget
,
519 vget
.vfs_fstype
== NULL
) {
521 vref
.vfs_special
= NULL
;
524 if (arg_hint
== SPECIAL
) {
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)) {
545 status
= execute(argv
[optind
],
546 vget
.vfs_fstype
, Vflg
, fd
);
547 if (status
> exitstat
)
550 } else if (ret
== -1 ||
551 vget
.vfs_fstype
== NULL
) {
553 default_fstype(argv
[optind
]);
554 status
= execute(argv
[optind
], fstype
,
556 /* return the highest exit code */
557 if (status
> exitstat
)
562 status
= execute(argv
[optind
], fstype
,
564 /* return the highest exit code */
565 if (status
> exitstat
)
572 if ((pflg
) && (exitstat
== 0)) {
573 fsck_dopreen(&devs
, preencnt
);
580 fsck_dopreen(struct devlist
**devp
, int ndevs
)
585 struct devlist
*bl
, *bdp
;
586 struct devlist
*badlist
;
591 waiter(&bl
, &badlist
);
592 rc
= preen_getdev(name
);
597 bdp
= getdev(name
, devp
);
600 gettext("%s: unknown dev: `%s'\n"),
610 waiter(&bl
, &badlist
);
614 gettext("%s: bad return `%d' from preen_getdev\n"),
620 waiter(&bl
, &badlist
);
624 print_badlist(badlist
);
628 startdisk(struct devlist
*dp
)
633 if ((pid
= fork()) == -1) {
636 } else if (pid
== 0) {
637 exitstat
= execute(dp
->name
, MNTTYPE_UFS
, Vflg
, NULL
);
645 waiter(struct devlist
**blp
, struct devlist
**badlist
)
649 struct devlist
*bdp
, *pbdp
;
651 curpid
= wait(&status
);
657 for (pbdp
= NULL
, bdp
= *blp
; bdp
!= NULL
; pbdp
= bdp
, bdp
= bdp
->nxt
) {
658 if (bdp
->pid
== curpid
) {
667 pbdp
->nxt
= bdp
->nxt
;
670 preen_releasedev(bdp
->name
);
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;
677 if (WHIBYTE(status
) != 0) {
678 if (WHIBYTE(status
) > exitstat
)
679 exitstat
= WHIBYTE(status
);
680 while (*badlist
!= NULL
)
681 badlist
= &(*badlist
)->nxt
;
688 print_badlist(struct devlist
*lp
)
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;
703 printf("%s (%s)%s", lp
->name
, lp
->fsname
,
704 lp
->nxt
? "," : "\n");
709 * allocate and initialize a `devlist' structure
713 newdev(struct vfstab
*vfsp
)
716 extern char *strdup();
718 dp
= (struct devlist
*)malloc(sizeof (struct devlist
));
720 fprintf(stderr
, gettext("%s: out of memory\n"), myname
);
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
);
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.
739 getdev(char *name
, struct devlist
**list
)
741 struct devlist
*p
, *lp
;
743 for (lp
= NULL
, p
= *list
; p
!= NULL
; lp
= p
, p
= p
->nxt
) {
744 if (strcmp(p
->name
, name
) == 0)
757 /* see if all numbers */
763 while ('0' <= *yp
&& *yp
<= '9')
771 execute(char *fsckdev
, char *fstype
, int Vflg
, FILE *fd
)
775 char full_path
[PATH_MAX
];
776 char *vfs_path
= VFS_PATH
;
779 nargv
[nargc
] = fsckdev
;
782 prnt_cmd(stdout
, fstype
);
787 fcntl(fileno(fd
), F_SETFD
, 1); /* close on exec */
789 if ((fk
= fork()) == (pid_t
)-1) {
791 gettext("%s: cannot fork. Try again later\n"),
798 /* Try to exec the fstype dependent portion of the fsck. */
799 do_exec(fstype
, nargv
);
801 /* parent waits for child */
802 if (wait(&st
) == (pid_t
)-1) {
803 fprintf(stderr
, gettext("%s: bad wait\n"), myname
);
808 if ((st
& 0xff) == 0x7f) {
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) {
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);
824 gettext("%s: warning: the following command"
825 " (process %d) was terminated by signal %d\n"),
826 myname
, fk
, st
& 0x7f);
828 prnt_cmd(stderr
, fstype
);
829 status
= ((st
& 0xff) | 0x80);
830 } else if (st
& 0xff00)
831 status
= (st
>> 8) & 0xff;
838 do_exec(char *fstype
, char *nargv
[])
840 char full_path
[PATH_MAX
];
841 char *vfs_path
= VFS_PATH
;
843 if (strlen(fstype
) > (size_t)FSTYPE_MAX
) {
845 gettext("%s: Fstype %s exceeds %d characters\n"),
846 myname
, fstype
, FSTYPE_MAX
);
849 /* build the full pathname of the fstype dependent command. */
850 sprintf(full_path
, "%s/%s/%s", vfs_path
, fstype
, myname
);
852 /* set the new argv[0] to the filename */
854 /* Try to exec the fstype dependent portion of the fsck. */
855 execv(full_path
, &nargv
[1]);
856 if (errno
== EACCES
) {
858 gettext("%s: cannot execute %s - permission denied\n"),
861 if (errno
== ENOEXEC
) {
863 nargv
[1] = full_path
;
864 execv("/sbin/sh", &nargv
[0]);
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
);
871 /* set the new argv[0] to the filename */
873 /* Try to exec the second fstype dependent portion of the fsck. */
874 execv(full_path
, &nargv
[1]);
875 if (errno
== EACCES
) {
877 gettext("%s: cannot execute %s - permission denied\n"),
881 if (errno
== ENOEXEC
) {
883 nargv
[1] = full_path
;
884 execv("/sbin/sh", &nargv
[0]);
887 gettext("%s: operation not applicable to FSType %s\n"),
893 prnt_cmd(FILE *fd
, char *fstype
)
897 fprintf(fd
, "%s -F %s", myname
, fstype
);
898 for (argp
= &nargv
[2]; *argp
; argp
++)
899 fprintf(fd
, " %s", *argp
);
909 gettext("%s: line in vfstab exceeds %d characters\n"),
910 myname
, VFS_LINE_MAX
-2);
914 gettext("%s: line in vfstab has too few entries\n"),
919 gettext("%s: line in vfstab has too many entries\n"),
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"),