1 /* $NetBSD: fsck.c,v 1.49 2010/02/24 13:56:07 hannken 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.49 2010/02/24 13:56:07 hannken 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
, omhead
;
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 int omitted(const char *);
85 static void addoption(char *);
86 static const char *getoptions(const char *);
87 static void addentry(struct fstypelist
*, const char *, const char *);
88 static void maketypelist(char *);
89 static void catopt(char **, const char *);
90 static void mangle(char *, int *, const char ** volatile *, int *);
91 static const char *getfslab(const char *);
92 static void usage(void);
93 static void *isok(struct fstab
*);
96 main(int argc
, char *argv
[])
100 const char *vfstype
= NULL
;
102 int ret
= FSCK_EXIT_OK
;
107 TAILQ_INIT(&selhead
);
108 TAILQ_INIT(&opthead
);
111 while ((i
= getopt(argc
, argv
, "dfl:nPpqT:t:vx:y")) != -1) {
114 flags
|= CHECK_DEBUG
;
118 flags
|= CHECK_FORCE
;
122 flags
|= CHECK_NOFIX
;
126 flags
|= CHECK_PREEN
;
130 flags
|= CHECK_PROGRESS
;
137 maxrun
= atoi(optarg
);
146 if (TAILQ_FIRST(&selhead
) != NULL
)
147 errx(1, "only one -t option may be specified.");
149 maketypelist(optarg
);
154 flags
|= CHECK_VERBOSE
;
158 addentry(&omhead
, optarg
, "");
170 /* Pass option to fsck_xxxfs */
172 catopt(&options
, globopt
);
175 /* Don't do progress meters if we're debugging. */
176 if (flags
& CHECK_DEBUG
)
177 flags
&= ~CHECK_PROGRESS
;
180 * If progress meters are being used, force max parallel to 1
181 * so the progress meter outputs don't interfere with one another.
183 if (flags
& CHECK_PROGRESS
)
187 /* parallel checking heuristic doesn't work for minix currently */
195 return checkfstab(flags
, maxrun
, isok
, checkfs
);
197 #define BADTYPE(type) \
198 (strcmp(type, FSTAB_RO) && \
199 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
202 for (; argc
--; argv
++) {
203 const char *spec
, *type
, *cp
;
204 char device
[MAXPATHLEN
];
207 cp
= strrchr(spec
, '/');
209 (void)snprintf(device
, sizeof(device
), "%s%s",
213 if ((fs
= getfsfile(spec
)) == NULL
&&
214 (fs
= getfsspec(spec
)) == NULL
) {
216 vfstype
= getfslab(spec
);
221 type
= fs
->fs_vfstype
;
222 if (BADTYPE(fs
->fs_type
))
223 errx(FSCK_EXIT_CHECK_FAILED
,
224 "%s has unknown file system type.",
228 rval
= checkfs(type
, blockcheck(spec
), *argv
, NULL
, NULL
);
238 isok(struct fstab
*fs
)
241 if (fs
->fs_passno
== 0)
244 if (BADTYPE(fs
->fs_type
))
247 if (!selected(fs
->fs_vfstype
))
250 if (omitted(fs
->fs_file
))
258 checkfs(const char *vfst
, const char *spec
, const char *mntpt
, void *auxarg
,
261 /* List of directories containing fsck_xxx subcommands. */
262 static const char *edirs
[] = {
273 const char ** volatile argv
, **edir
;
274 const char * volatile vfstype
= vfst
;
276 int argc
, i
, status
, maxargc
;
278 char *volatile optbuf
;
279 char execname
[MAXPATHLEN
+ 1], execbase1
[MAXPATHLEN
], execbase2
[MAXPATHLEN
];
280 const char *extra
= getoptions(vfstype
);
282 if (!strcmp(vfstype
, "ufs"))
287 catopt(&optb
, options
);
289 catopt(&optb
, extra
);
293 argv
= emalloc(sizeof(char *) * maxargc
);
295 (void) snprintf(execbase1
, sizeof(execbase1
), "fsck_%s", vfstype
);
296 (void) snprintf(execbase2
, sizeof(execbase2
), "fsck.%s", vfstype
);
298 argv
[argc
++] = execbase1
;
300 mangle(optbuf
, &argc
, &argv
, &maxargc
);
304 if (flags
& (CHECK_DEBUG
|CHECK_VERBOSE
)) {
305 (void)printf("start %s %swait", mntpt
,
307 for (i
= 0; i
< argc
; i
++)
308 (void)printf(" %s", argv
[i
]);
312 switch (pid
= vfork()) {
313 case -1: /* Error. */
318 return FSCK_EXIT_CHECK_FAILED
;
322 if ((flags
& CHECK_FORCE
) == 0) {
326 * if mntpt is a mountpoint of a mounted file
327 * system and it's mounted read-write, skip it
328 * unless -f is given.
330 if ((statvfs(mntpt
, &sfs
) == 0) &&
331 (strcmp(mntpt
, sfs
.f_mntonname
) == 0) &&
332 ((sfs
.f_flag
& MNT_RDONLY
) == 0)) {
334 "%s: file system is mounted read-write on %s; not checking\n",
336 if ((flags
& CHECK_PREEN
) && auxarg
!= NULL
)
337 _exit(FSCK_EXIT_OK
); /* fsck -p */
339 _exit(FSCK_EXIT_CHECK_FAILED
); /* fsck [[-p] ...] */
344 if (flags
& CHECK_DEBUG
)
347 /* Go find an executable. */
350 (void)snprintf(execname
,
351 sizeof(execname
), "%s/%s", *edir
, execbase1
);
352 execv(execname
, (char * const *)__UNCONST(argv
));
353 if (errno
!= ENOENT
) {
355 warn("exec %s for %s", execname
, spec
);
357 warn("exec %s", execname
);
359 (void)snprintf(execname
,
360 sizeof(execname
), "%s/%s", *edir
, execbase2
);
361 execv(execname
, (char * const *)__UNCONST(argv
));
362 if (errno
!= ENOENT
) {
364 warn("exec %s for %s", execname
, spec
);
366 warn("exec %s", execname
);
368 } while (*++edir
!= NULL
);
370 if (errno
== ENOENT
) {
372 warn("exec %s for %s", execname
, spec
);
374 warn("exec %s", execname
);
376 _exit(FSCK_EXIT_CHECK_FAILED
);
379 default: /* Parent. */
389 if (waitpid(pid
, &status
, 0) < 0) {
391 return FSCK_EXIT_CHECK_FAILED
;
394 if (WIFEXITED(status
)) {
395 if (WEXITSTATUS(status
) != 0)
396 return WEXITSTATUS(status
);
398 else if (WIFSIGNALED(status
)) {
399 warnx("%s: %s", spec
, strsignal(WTERMSIG(status
)));
400 return FSCK_EXIT_CHECK_FAILED
;
410 selected(const char *type
)
414 /* If no type specified, it's always selected. */
415 TAILQ_FOREACH(e
, &selhead
, entries
)
416 if (!strcmp(e
->type
, type
))
417 return which
== IN_LIST
? 1 : 0;
419 return which
== IN_LIST
? 0 : 1;
424 omitted(const char *mountedon
)
428 /* If no type specified, it's always selected. */
429 TAILQ_FOREACH(e
, &omhead
, entries
)
430 if (!strcmp(e
->type
, mountedon
))
438 getoptions(const char *type
)
442 TAILQ_FOREACH(e
, &opthead
, entries
)
443 if (!strcmp(e
->type
, type
))
450 addoption(char *optstr
)
455 if ((newoptions
= strchr(optstr
, ':')) == NULL
)
456 errx(1, "Invalid option string");
458 *newoptions
++ = '\0';
460 TAILQ_FOREACH(e
, &opthead
, entries
)
461 if (!strcmp(e
->type
, optstr
)) {
462 catopt(&e
->options
, newoptions
);
465 addentry(&opthead
, optstr
, newoptions
);
470 addentry(struct fstypelist
*list
, const char *type
, const char *opts
)
474 e
= emalloc(sizeof(struct entry
));
475 e
->type
= estrdup(type
);
476 e
->options
= estrdup(opts
);
477 TAILQ_INSERT_TAIL(list
, e
, entries
);
482 maketypelist(char *fslist
)
486 if ((fslist
== NULL
) || (fslist
[0] == '\0'))
487 errx(1, "empty type list");
489 if (fslist
[0] == 'n' && fslist
[1] == 'o') {
496 while ((ptr
= strsep(&fslist
, ",")) != NULL
)
497 addentry(&selhead
, ptr
, "");
503 catopt(char **sp
, const char *o
)
511 j
= i
+ 1 + strlen(o
) + 1;
513 (void)snprintf(s
+ i
, j
, ",%s", o
);
521 mangle(char *opts
, int *argcp
, const char ** volatile *argvp
, int *maxargcp
)
531 for (s
= opts
; (p
= strsep(&s
, ",")) != NULL
;) {
532 /* Always leave space for one more argument and the NULL. */
533 if (argc
>= maxargc
- 3) {
535 argv
= erealloc(argv
, maxargc
* sizeof(char *));
558 getfslab(const char *str
)
561 errx(1, "cannot determine vfstype under minix");
563 static struct dkwedge_info dkw
;
570 /* deduce the file system type from the disk label */
571 if ((fd
= open(str
, O_RDONLY
)) == -1)
572 err(1, "cannot open `%s'", str
);
574 /* First check to see if it's a wedge. */
575 if (ioctl(fd
, DIOCGWEDGEINFO
, &dkw
) == 0) {
576 /* Yup, this is easy. */
578 return (dkw
.dkw_ptype
);
581 if (ioctl(fd
, DIOCGDINFO
, &dl
) == -1)
582 err(1, "cannot get disklabel for `%s'", str
);
586 p
= str
[strlen(str
) - 1];
588 if ((p
- 'a') >= dl
.d_npartitions
)
589 errx(1, "partition `%s' is not defined on disk", str
);
591 if ((t
= dl
.d_partitions
[p
- 'a'].p_fstype
) >= FSMAXTYPES
)
592 errx(1, "partition `%s' is not of a legal vfstype",
595 if ((vfstype
= fscknames
[t
]) == NULL
)
596 errx(1, "vfstype `%s' on partition `%s' is not supported",
597 fstypenames
[t
], str
);
607 static const char common
[] =
608 "[-dfnPpqvy] [-x excludemount] [-l maxparallel] [-T fstype:fsoptions]\n\t\t[-t fstype]";
610 (void)fprintf(stderr
, "usage: %s %s [special|node]...\n",
611 getprogname(), common
);
612 exit(FSCK_EXIT_USAGE
);