1 /* $NetBSD: fsck.c,v 1.46 2007/07/17 20:12:40 christos Exp $ */
4 * Copyright (c) 1996 Christos Zoulas. All rights reserved.
5 * Copyright (c) 1980, 1989, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * From: @(#)mount.c 8.19 (Berkeley) 4/19/94
33 * From: NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp
37 #include <sys/cdefs.h>
39 __RCSID("$NetBSD: fsck.c,v 1.46 2007/07/17 20:12:40 christos Exp $");
42 #include <sys/param.h>
43 #include <sys/mount.h>
44 #include <sys/queue.h>
49 #include <sys/disklabel.h>
50 #include <sys/ioctl.h>
64 #include "pathnames.h"
66 #include "exitvalues.h"
68 static enum { IN_LIST
, NOT_IN_LIST
} which
= NOT_IN_LIST
;
70 TAILQ_HEAD(fstypelist
, entry
) opthead
, selhead
;
75 TAILQ_ENTRY(entry
) entries
;
78 static int maxrun
= 0;
79 static char *options
= NULL
;
82 static int checkfs(const char *, const char *, const char *, void *, pid_t
*);
83 static int selected(const char *);
84 static void addoption(char *);
85 static const char *getoptions(const char *);
86 static void addentry(struct fstypelist
*, const char *, const char *);
87 static void maketypelist(char *);
88 static void catopt(char **, const char *);
89 static void mangle(char *, int *, const char ** volatile *, int *);
90 static const char *getfslab(const char *);
91 static void usage(void);
92 static void *isok(struct fstab
*);
95 main(int argc
, char *argv
[])
99 const char *vfstype
= NULL
;
101 int ret
= FSCK_EXIT_OK
;
106 TAILQ_INIT(&selhead
);
107 TAILQ_INIT(&opthead
);
109 while ((i
= getopt(argc
, argv
, "dfl:nPpqT:t:vy")) != -1) {
112 flags
|= CHECK_DEBUG
;
116 flags
|= CHECK_FORCE
;
120 flags
|= CHECK_NOFIX
;
124 flags
|= CHECK_PREEN
;
128 flags
|= CHECK_PROGRESS
;
135 maxrun
= atoi(optarg
);
144 if (TAILQ_FIRST(&selhead
) != NULL
)
145 errx(1, "only one -t option may be specified.");
147 maketypelist(optarg
);
152 flags
|= CHECK_VERBOSE
;
164 /* Pass option to fsck_xxxfs */
166 catopt(&options
, globopt
);
169 /* Don't do progress meters if we're debugging. */
170 if (flags
& CHECK_DEBUG
)
171 flags
&= ~CHECK_PROGRESS
;
174 * If progress meters are being used, force max parallel to 1
175 * so the progress meter outputs don't interfere with one another.
177 if (flags
& CHECK_PROGRESS
)
184 return checkfstab(flags
, maxrun
, isok
, checkfs
);
186 #define BADTYPE(type) \
187 (strcmp(type, FSTAB_RO) && \
188 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
191 for (; argc
--; argv
++) {
192 const char *spec
, *type
, *cp
;
193 char device
[MAXPATHLEN
];
196 cp
= strrchr(spec
, '/');
198 (void)snprintf(device
, sizeof(device
), "%s%s",
202 if ((fs
= getfsfile(spec
)) == NULL
&&
203 (fs
= getfsspec(spec
)) == NULL
) {
205 vfstype
= getfslab(spec
);
210 type
= fs
->fs_vfstype
;
211 if (BADTYPE(fs
->fs_type
))
212 errx(FSCK_EXIT_CHECK_FAILED
,
213 "%s has unknown file system type.",
217 rval
= checkfs(type
, blockcheck(spec
), *argv
, NULL
, NULL
);
227 isok(struct fstab
*fs
)
230 if (fs
->fs_passno
== 0)
233 if (BADTYPE(fs
->fs_type
))
236 if (!selected(fs
->fs_vfstype
))
244 checkfs(const char *vfst
, const char *spec
, const char *mntpt
, void *auxarg
,
247 /* List of directories containing fsck_xxx subcommands. */
248 static const char *edirs
[] = {
256 const char ** volatile argv
, **edir
;
257 const char * volatile vfstype
= vfst
;
259 int argc
, i
, status
, maxargc
;
261 char *volatile optbuf
;
262 char execname
[MAXPATHLEN
+ 1], execbase
[MAXPATHLEN
];
263 const char *extra
= getoptions(vfstype
);
265 if (!strcmp(vfstype
, "ufs"))
270 catopt(&optb
, options
);
272 catopt(&optb
, extra
);
276 argv
= emalloc(sizeof(char *) * maxargc
);
278 (void) snprintf(execbase
, sizeof(execbase
), "fsck_%s", vfstype
);
280 argv
[argc
++] = execbase
;
282 mangle(optbuf
, &argc
, &argv
, &maxargc
);
286 if (flags
& (CHECK_DEBUG
|CHECK_VERBOSE
)) {
287 (void)printf("start %s %swait", mntpt
,
289 for (i
= 0; i
< argc
; i
++)
290 (void)printf(" %s", argv
[i
]);
294 switch (pid
= vfork()) {
295 case -1: /* Error. */
300 return FSCK_EXIT_CHECK_FAILED
;
303 if ((flags
& CHECK_FORCE
) == 0) {
307 * if mntpt is a mountpoint of a mounted file
308 * system and it's mounted read-write, skip it
309 * unless -f is given.
311 if ((statvfs(mntpt
, &sfs
) == 0) &&
312 (strcmp(mntpt
, sfs
.f_mntonname
) == 0) &&
313 ((sfs
.f_flag
& MNT_RDONLY
) == 0)) {
315 "%s: file system is mounted read-write on %s; not checking\n",
317 if ((flags
& CHECK_PREEN
) && auxarg
!= NULL
)
318 _exit(FSCK_EXIT_OK
); /* fsck -p */
320 _exit(FSCK_EXIT_CHECK_FAILED
); /* fsck [[-p] ...] */
324 if (flags
& CHECK_DEBUG
)
327 /* Go find an executable. */
330 (void)snprintf(execname
,
331 sizeof(execname
), "%s/%s", *edir
, execbase
);
332 execv(execname
, (char * const *)__UNCONST(argv
));
333 if (errno
!= ENOENT
) {
335 warn("exec %s for %s", execname
, spec
);
337 warn("exec %s", execname
);
339 } while (*++edir
!= NULL
);
341 if (errno
== ENOENT
) {
343 warn("exec %s for %s", execname
, spec
);
345 warn("exec %s", execname
);
347 _exit(FSCK_EXIT_CHECK_FAILED
);
350 default: /* Parent. */
360 if (waitpid(pid
, &status
, 0) < 0) {
362 return FSCK_EXIT_CHECK_FAILED
;
365 if (WIFEXITED(status
)) {
366 if (WEXITSTATUS(status
) != 0)
367 return WEXITSTATUS(status
);
369 else if (WIFSIGNALED(status
)) {
370 warnx("%s: %s", spec
, strsignal(WTERMSIG(status
)));
371 return FSCK_EXIT_CHECK_FAILED
;
381 selected(const char *type
)
385 /* If no type specified, it's always selected. */
386 TAILQ_FOREACH(e
, &selhead
, entries
)
387 if (!strcmp(e
->type
, type
))
388 return which
== IN_LIST
? 1 : 0;
390 return which
== IN_LIST
? 0 : 1;
395 getoptions(const char *type
)
399 TAILQ_FOREACH(e
, &opthead
, entries
)
400 if (!strcmp(e
->type
, type
))
407 addoption(char *optstr
)
412 if ((newoptions
= strchr(optstr
, ':')) == NULL
)
413 errx(1, "Invalid option string");
415 *newoptions
++ = '\0';
417 TAILQ_FOREACH(e
, &opthead
, entries
)
418 if (!strcmp(e
->type
, optstr
)) {
419 catopt(&e
->options
, newoptions
);
422 addentry(&opthead
, optstr
, newoptions
);
427 addentry(struct fstypelist
*list
, const char *type
, const char *opts
)
431 e
= emalloc(sizeof(struct entry
));
432 e
->type
= estrdup(type
);
433 e
->options
= estrdup(opts
);
434 TAILQ_INSERT_TAIL(list
, e
, entries
);
439 maketypelist(char *fslist
)
443 if ((fslist
== NULL
) || (fslist
[0] == '\0'))
444 errx(1, "empty type list");
446 if (fslist
[0] == 'n' && fslist
[1] == 'o') {
453 while ((ptr
= strsep(&fslist
, ",")) != NULL
)
454 addentry(&selhead
, ptr
, "");
460 catopt(char **sp
, const char *o
)
468 j
= i
+ 1 + strlen(o
) + 1;
470 (void)snprintf(s
+ i
, j
, ",%s", o
);
478 mangle(char *opts
, int *argcp
, const char ** volatile *argvp
, int *maxargcp
)
488 for (s
= opts
; (p
= strsep(&s
, ",")) != NULL
;) {
489 /* Always leave space for one more argument and the NULL. */
490 if (argc
>= maxargc
- 3) {
492 argv
= erealloc(argv
, maxargc
* sizeof(char *));
515 getfslab(const char *str
)
517 static struct dkwedge_info dkw
;
524 /* deduce the file system type from the disk label */
525 if ((fd
= open(str
, O_RDONLY
)) == -1)
526 err(1, "cannot open `%s'", str
);
528 /* First check to see if it's a wedge. */
529 if (ioctl(fd
, DIOCGWEDGEINFO
, &dkw
) == 0) {
530 /* Yup, this is easy. */
532 return (dkw
.dkw_ptype
);
535 if (ioctl(fd
, DIOCGDINFO
, &dl
) == -1)
536 err(1, "cannot get disklabel for `%s'", str
);
540 p
= str
[strlen(str
) - 1];
542 if ((p
- 'a') >= dl
.d_npartitions
)
543 errx(1, "partition `%s' is not defined on disk", str
);
545 if ((t
= dl
.d_partitions
[p
- 'a'].p_fstype
) >= FSMAXTYPES
)
546 errx(1, "partition `%s' is not of a legal vfstype",
549 if ((vfstype
= fscknames
[t
]) == NULL
)
550 errx(1, "vfstype `%s' on partition `%s' is not supported",
551 fstypenames
[t
], str
);
560 static const char common
[] =
561 "[-dfnPpqvy] [-l maxparallel] [-T fstype:fsoptions]\n\t\t[-t fstype]";
563 (void)fprintf(stderr
, "usage: %s %s [special|node]...\n",
564 getprogname(), common
);
565 exit(FSCK_EXIT_USAGE
);