1 /* $NetBSD: fsck.c,v 1.51 2012/04/07 04:52:20 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.51 2012/04/07 04:52:20 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
, 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 __dead
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
;
103 char buf
[MAXPATHLEN
];
108 TAILQ_INIT(&selhead
);
109 TAILQ_INIT(&opthead
);
112 while ((i
= getopt(argc
, argv
, "dfl:nPpqT:t:vx:y")) != -1) {
115 flags
|= CHECK_DEBUG
;
119 flags
|= CHECK_FORCE
;
123 flags
|= CHECK_NOFIX
;
127 flags
|= CHECK_PREEN
;
131 flags
|= CHECK_PROGRESS
;
138 maxrun
= atoi(optarg
);
147 if (TAILQ_FIRST(&selhead
) != NULL
)
148 errx(1, "only one -t option may be specified.");
150 maketypelist(optarg
);
155 flags
|= CHECK_VERBOSE
;
159 addentry(&omhead
, optarg
, "");
171 /* Pass option to fsck_xxxfs */
173 catopt(&options
, globopt
);
176 /* Don't do progress meters if we're debugging. */
177 if (flags
& CHECK_DEBUG
)
178 flags
&= ~CHECK_PROGRESS
;
181 * If progress meters are being used, force max parallel to 1
182 * so the progress meter outputs don't interfere with one another.
184 if (flags
& CHECK_PROGRESS
)
188 /* parallel checking heuristic doesn't work for minix currently */
190 #endif /* !defined(__minix) */
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
);
220 spec
= getfsspecname(buf
, sizeof(buf
), fs
->fs_spec
);
222 err(FSCK_EXIT_CHECK_FAILED
, "%s", buf
);
223 type
= fs
->fs_vfstype
;
224 if (BADTYPE(fs
->fs_type
))
225 errx(FSCK_EXIT_CHECK_FAILED
,
226 "%s has unknown file system type.",
230 rval
= checkfs(type
, blockcheck(spec
), *argv
, NULL
, NULL
);
240 isok(struct fstab
*fs
)
243 if (fs
->fs_passno
== 0)
246 if (BADTYPE(fs
->fs_type
))
249 if (!selected(fs
->fs_vfstype
))
252 if (omitted(fs
->fs_file
))
260 checkfs(const char *vfst
, const char *spec
, const char *mntpt
, void *auxarg
,
263 /* List of directories containing fsck_xxx subcommands. */
264 static const char *edirs
[] = {
272 #endif /* defined(__minix) */
275 const char ** volatile argv
, **edir
;
276 const char * volatile vfstype
= vfst
;
278 int argc
, i
, status
, maxargc
;
280 char *volatile optbuf
;
281 char execname
[MAXPATHLEN
+ 1], execbase
[MAXPATHLEN
];
282 const char *extra
= getoptions(vfstype
);
284 if (!strcmp(vfstype
, "ufs"))
289 catopt(&optb
, options
);
291 catopt(&optb
, extra
);
295 argv
= emalloc(sizeof(char *) * maxargc
);
297 (void) snprintf(execbase
, sizeof(execbase
), "fsck_%s", vfstype
);
299 argv
[argc
++] = execbase
;
301 mangle(optbuf
, &argc
, &argv
, &maxargc
);
305 if (flags
& (CHECK_DEBUG
|CHECK_VERBOSE
)) {
306 (void)printf("start %s %swait", mntpt
,
308 for (i
= 0; i
< argc
; i
++)
309 (void)printf(" %s", argv
[i
]);
313 switch (pid
= vfork()) {
314 case -1: /* Error. */
319 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] ...] */
343 if (flags
& CHECK_DEBUG
)
346 /* Go find an executable. */
349 (void)snprintf(execname
,
350 sizeof(execname
), "%s/%s", *edir
, execbase
);
351 execv(execname
, (char * const *)__UNCONST(argv
));
352 if (errno
!= ENOENT
) {
354 warn("exec %s for %s", execname
, spec
);
356 warn("exec %s", execname
);
358 } while (*++edir
!= NULL
);
360 if (errno
== ENOENT
) {
362 warn("exec %s for %s", execname
, spec
);
364 warn("exec %s", execname
);
366 _exit(FSCK_EXIT_CHECK_FAILED
);
369 default: /* Parent. */
379 if (waitpid(pid
, &status
, 0) < 0) {
381 return FSCK_EXIT_CHECK_FAILED
;
384 if (WIFEXITED(status
)) {
385 if (WEXITSTATUS(status
) != 0)
386 return WEXITSTATUS(status
);
388 else if (WIFSIGNALED(status
)) {
389 warnx("%s: %s", spec
, strsignal(WTERMSIG(status
)));
390 return FSCK_EXIT_CHECK_FAILED
;
400 selected(const char *type
)
404 /* If no type specified, it's always selected. */
405 TAILQ_FOREACH(e
, &selhead
, entries
)
406 if (!strcmp(e
->type
, type
))
407 return which
== IN_LIST
? 1 : 0;
409 return which
== IN_LIST
? 0 : 1;
414 omitted(const char *mountedon
)
418 /* If no type specified, it's always selected. */
419 TAILQ_FOREACH(e
, &omhead
, entries
)
420 if (!strcmp(e
->type
, mountedon
))
428 getoptions(const char *type
)
432 TAILQ_FOREACH(e
, &opthead
, entries
)
433 if (!strcmp(e
->type
, type
))
440 addoption(char *optstr
)
445 if ((newoptions
= strchr(optstr
, ':')) == NULL
)
446 errx(1, "Invalid option string");
448 *newoptions
++ = '\0';
450 TAILQ_FOREACH(e
, &opthead
, entries
)
451 if (!strcmp(e
->type
, optstr
)) {
452 catopt(&e
->options
, newoptions
);
455 addentry(&opthead
, optstr
, newoptions
);
460 addentry(struct fstypelist
*list
, const char *type
, const char *opts
)
464 e
= emalloc(sizeof(struct entry
));
465 e
->type
= estrdup(type
);
466 e
->options
= estrdup(opts
);
467 TAILQ_INSERT_TAIL(list
, e
, entries
);
472 maketypelist(char *fslist
)
476 if ((fslist
== NULL
) || (fslist
[0] == '\0'))
477 errx(1, "empty type list");
479 if (fslist
[0] == 'n' && fslist
[1] == 'o') {
486 while ((ptr
= strsep(&fslist
, ",")) != NULL
)
487 addentry(&selhead
, ptr
, "");
493 catopt(char **sp
, const char *o
)
501 j
= i
+ 1 + strlen(o
) + 1;
503 (void)snprintf(s
+ i
, j
, ",%s", o
);
511 mangle(char *opts
, int *argcp
, const char ** volatile *argvp
, int *maxargcp
)
521 for (s
= opts
; (p
= strsep(&s
, ",")) != NULL
;) {
522 /* Always leave space for one more argument and the NULL. */
523 if (argc
>= maxargc
- 3) {
525 argv
= erealloc(argv
, maxargc
* sizeof(char *));
548 getfslab(const char *str
)
551 errx(1, "cannot determine vfstype under minix");
553 static struct dkwedge_info dkw
;
560 /* deduce the file system type from the disk label */
561 if ((fd
= open(str
, O_RDONLY
)) == -1)
562 err(1, "cannot open `%s'", str
);
564 /* First check to see if it's a wedge. */
565 if (ioctl(fd
, DIOCGWEDGEINFO
, &dkw
) == 0) {
566 /* Yup, this is easy. */
568 return (dkw
.dkw_ptype
);
571 if (ioctl(fd
, DIOCGDINFO
, &dl
) == -1)
572 err(1, "cannot get disklabel for `%s'", str
);
576 p
= str
[strlen(str
) - 1];
578 if ((p
- 'a') >= dl
.d_npartitions
)
579 errx(1, "partition `%s' is not defined on disk", str
);
581 if ((t
= dl
.d_partitions
[p
- 'a'].p_fstype
) >= FSMAXTYPES
)
582 errx(1, "partition `%s' is not of a legal vfstype",
585 if ((vfstype
= fscknames
[t
]) == NULL
)
586 errx(1, "vfstype `%s' on partition `%s' is not supported",
587 fstypenames
[t
], str
);
590 #endif /* defined(__minix) */
597 static const char common
[] =
598 "[-dfnPpqvy] [-x excludemount] [-l maxparallel] [-T fstype:fsoptions]\n\t\t[-t fstype]";
600 (void)fprintf(stderr
, "usage: %s %s [special|node]...\n",
601 getprogname(), common
);
602 exit(FSCK_EXIT_USAGE
);