1 /* $NetBSD: fsck.c,v 1.52 2014/10/25 22:00:19 mlelstv 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.52 2014/10/25 22:00:19 mlelstv 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
, *spec2
, *mntpt
, *type
, *cp
;
204 char device
[MAXPATHLEN
];
206 spec
= mntpt
= *argv
;
207 spec2
= getfsspecname(buf
, sizeof(buf
), spec
);
211 cp
= strrchr(spec2
, '/');
213 (void)snprintf(device
, sizeof(device
), "%s%s",
218 fs
= getfsfile(spec
);
220 fs
= getfsspec(spec
);
221 if (fs
== NULL
&& spec
!= spec2
) {
222 fs
= getfsspec(spec2
);
227 spec
= getfsspecname(buf
, sizeof(buf
), fs
->fs_spec
);
229 err(FSCK_EXIT_CHECK_FAILED
, "%s", buf
);
230 type
= fs
->fs_vfstype
;
231 if (BADTYPE(fs
->fs_type
))
232 errx(FSCK_EXIT_CHECK_FAILED
,
233 "%s has unknown file system type.",
237 vfstype
= getfslab(spec
);
241 rval
= checkfs(type
, blockcheck(spec
), *argv
, NULL
, NULL
);
251 isok(struct fstab
*fs
)
254 if (fs
->fs_passno
== 0)
257 if (BADTYPE(fs
->fs_type
))
260 if (!selected(fs
->fs_vfstype
))
263 if (omitted(fs
->fs_file
))
271 checkfs(const char *vfst
, const char *spec
, const char *mntpt
, void *auxarg
,
274 /* List of directories containing fsck_xxx subcommands. */
275 static const char *edirs
[] = {
283 #endif /* defined(__minix) */
286 const char ** volatile argv
, **edir
;
287 const char * volatile vfstype
= vfst
;
289 int argc
, i
, status
, maxargc
;
291 char *volatile optbuf
;
292 char execname
[MAXPATHLEN
+ 1], execbase
[MAXPATHLEN
];
293 const char *extra
= getoptions(vfstype
);
295 if (!strcmp(vfstype
, "ufs"))
300 catopt(&optb
, options
);
302 catopt(&optb
, extra
);
306 argv
= emalloc(sizeof(char *) * maxargc
);
308 (void) snprintf(execbase
, sizeof(execbase
), "fsck_%s", vfstype
);
310 argv
[argc
++] = execbase
;
312 mangle(optbuf
, &argc
, &argv
, &maxargc
);
316 if (flags
& (CHECK_DEBUG
|CHECK_VERBOSE
)) {
317 (void)printf("start %s %swait", mntpt
,
319 for (i
= 0; i
< argc
; i
++)
320 (void)printf(" %s", argv
[i
]);
324 switch (pid
= vfork()) {
325 case -1: /* Error. */
330 return FSCK_EXIT_CHECK_FAILED
;
333 if ((flags
& CHECK_FORCE
) == 0) {
337 * if mntpt is a mountpoint of a mounted file
338 * system and it's mounted read-write, skip it
339 * unless -f is given.
341 if ((statvfs(mntpt
, &sfs
) == 0) &&
342 (strcmp(mntpt
, sfs
.f_mntonname
) == 0) &&
343 ((sfs
.f_flag
& MNT_RDONLY
) == 0)) {
345 "%s: file system is mounted read-write on %s; not checking\n",
347 if ((flags
& CHECK_PREEN
) && auxarg
!= NULL
)
348 _exit(FSCK_EXIT_OK
); /* fsck -p */
350 _exit(FSCK_EXIT_CHECK_FAILED
); /* fsck [[-p] ...] */
354 if (flags
& CHECK_DEBUG
)
357 /* Go find an executable. */
360 (void)snprintf(execname
,
361 sizeof(execname
), "%s/%s", *edir
, execbase
);
362 execv(execname
, (char * const *)__UNCONST(argv
));
363 if (errno
!= ENOENT
) {
365 warn("exec %s for %s", execname
, spec
);
367 warn("exec %s", execname
);
369 } while (*++edir
!= NULL
);
371 if (errno
== ENOENT
) {
373 warn("exec %s for %s", execname
, spec
);
375 warn("exec %s", execname
);
377 _exit(FSCK_EXIT_CHECK_FAILED
);
380 default: /* Parent. */
390 if (waitpid(pid
, &status
, 0) < 0) {
392 return FSCK_EXIT_CHECK_FAILED
;
395 if (WIFEXITED(status
)) {
396 if (WEXITSTATUS(status
) != 0)
397 return WEXITSTATUS(status
);
399 else if (WIFSIGNALED(status
)) {
400 warnx("%s: %s", spec
, strsignal(WTERMSIG(status
)));
401 return FSCK_EXIT_CHECK_FAILED
;
411 selected(const char *type
)
415 /* If no type specified, it's always selected. */
416 TAILQ_FOREACH(e
, &selhead
, entries
)
417 if (!strcmp(e
->type
, type
))
418 return which
== IN_LIST
? 1 : 0;
420 return which
== IN_LIST
? 0 : 1;
425 omitted(const char *mountedon
)
429 /* If no type specified, it's always selected. */
430 TAILQ_FOREACH(e
, &omhead
, entries
)
431 if (!strcmp(e
->type
, mountedon
))
439 getoptions(const char *type
)
443 TAILQ_FOREACH(e
, &opthead
, entries
)
444 if (!strcmp(e
->type
, type
))
451 addoption(char *optstr
)
456 if ((newoptions
= strchr(optstr
, ':')) == NULL
)
457 errx(1, "Invalid option string");
459 *newoptions
++ = '\0';
461 TAILQ_FOREACH(e
, &opthead
, entries
)
462 if (!strcmp(e
->type
, optstr
)) {
463 catopt(&e
->options
, newoptions
);
466 addentry(&opthead
, optstr
, newoptions
);
471 addentry(struct fstypelist
*list
, const char *type
, const char *opts
)
475 e
= emalloc(sizeof(struct entry
));
476 e
->type
= estrdup(type
);
477 e
->options
= estrdup(opts
);
478 TAILQ_INSERT_TAIL(list
, e
, entries
);
483 maketypelist(char *fslist
)
487 if ((fslist
== NULL
) || (fslist
[0] == '\0'))
488 errx(1, "empty type list");
490 if (fslist
[0] == 'n' && fslist
[1] == 'o') {
497 while ((ptr
= strsep(&fslist
, ",")) != NULL
)
498 addentry(&selhead
, ptr
, "");
504 catopt(char **sp
, const char *o
)
512 j
= i
+ 1 + strlen(o
) + 1;
514 (void)snprintf(s
+ i
, j
, ",%s", o
);
522 mangle(char *opts
, int *argcp
, const char ** volatile *argvp
, int *maxargcp
)
532 for (s
= opts
; (p
= strsep(&s
, ",")) != NULL
;) {
533 /* Always leave space for one more argument and the NULL. */
534 if (argc
>= maxargc
- 3) {
536 argv
= erealloc(argv
, maxargc
* sizeof(char *));
559 getfslab(const char *str
)
562 errx(1, "cannot determine vfstype under minix");
564 static struct dkwedge_info dkw
;
571 /* deduce the file system type from the disk label */
572 if ((fd
= open(str
, O_RDONLY
)) == -1)
573 err(1, "cannot open `%s'", str
);
575 /* First check to see if it's a wedge. */
576 if (ioctl(fd
, DIOCGWEDGEINFO
, &dkw
) == 0) {
577 /* Yup, this is easy. */
579 return (dkw
.dkw_ptype
);
582 if (ioctl(fd
, DIOCGDINFO
, &dl
) == -1)
583 err(1, "cannot get disklabel for `%s'", str
);
587 p
= str
[strlen(str
) - 1];
589 if ((p
- 'a') >= dl
.d_npartitions
)
590 errx(1, "partition `%s' is not defined on disk", str
);
592 if ((t
= dl
.d_partitions
[p
- 'a'].p_fstype
) >= FSMAXTYPES
)
593 errx(1, "partition `%s' is not of a legal vfstype",
596 if ((vfstype
= fscknames
[t
]) == NULL
)
597 errx(1, "vfstype `%s' on partition `%s' is not supported",
598 fstypenames
[t
], str
);
601 #endif /* defined(__minix) */
608 static const char common
[] =
609 "[-dfnPpqvy] [-x excludemount] [-l maxparallel] [-T fstype:fsoptions]\n\t\t[-t fstype]";
611 (void)fprintf(stderr
, "usage: %s %s [special|node]...\n",
612 getprogname(), common
);
613 exit(FSCK_EXIT_USAGE
);