/* $NetBSD: main.c,v 1.28 2008/03/16 23:17:55 lukem Exp $ */ /* * Copyright (c) 1980, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 1997 Manuel Bouyer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Manuel Bouyer. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #ifndef lint __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1993\n\ The Regents of the University of California. All rights reserved.\n"); #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/23/94"; #else __RCSID("$NetBSD: main.c,v 1.28 2008/03/16 23:17:55 lukem Exp $"); #endif #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fsck.h" #include "extern.h" #include "fsutil.h" #include "exitvalues.h" int returntosingle = 0; static int argtoi(int, const char *, const char *, int); static int checkfilesys(const char *, char *, long, int); static void usage(void) __dead; int main(int argc, char *argv[]) { int ch; int ret = FSCK_EXIT_OK; sync(); skipclean = 1; while ((ch = getopt(argc, argv, "b:dfm:npqy")) != -1) { switch (ch) { case 'b': skipclean = 0; bflag = argtoi('b', "number", optarg, 10); printf("Alternate super block location: %d\n", bflag); break; case 'd': debug++; break; case 'f': skipclean = 0; break; case 'm': lfmode = argtoi('m', "mode", optarg, 8); if (lfmode &~ 07777) errexit("bad mode to -m: %o", lfmode); printf("** lost+found creation mode %o\n", lfmode); break; case 'n': nflag++; yflag = 0; break; case 'p': preen++; break; case 'P': /* Progress meter not implemented. */ break; case 'q': /* Quiet not implemented */ break; case 'y': yflag++; nflag = 0; break; default: usage(); } } argc -= optind; argv += optind; if (!argc) usage(); if (signal(SIGINT, SIG_IGN) != SIG_IGN) (void)signal(SIGINT, catch); if (preen) (void)signal(SIGQUIT, catchquit); while (argc-- > 0) { int nret = checkfilesys(blockcheck(*argv++), 0, 0L, 0); if (ret < nret) ret = nret; } return returntosingle ? FSCK_EXIT_UNRESOLVED : ret; } static int argtoi(int flag, const char *req, const char *str, int base) { char *cp; int ret; ret = (int)strtol(str, &cp, base); if (cp == str || *cp) errexit("-%c flag requires a %s", flag, req); return (ret); } /* * Check the specified filesystem. */ /* ARGSUSED */ static int checkfilesys(const char *filesys, char *mntpt, long auxdata, int child) { daddr_t n_bfree; struct dups *dp; struct zlncnt *zlnp; int i; if (preen && child) (void)signal(SIGQUIT, voidquit); setcdevname(filesys, preen); if (debug && preen) pwarn("starting\n"); switch (setup(filesys)) { case 0: if (preen) pfatal("CAN'T CHECK FILE SYSTEM."); case -1: return FSCK_EXIT_OK; } /* * 1: scan inodes tallying blocks used */ if (preen == 0) { if (sblock.e2fs.e2fs_rev > E2FS_REV0) { printf("** Last Mounted on %s\n", sblock.e2fs.e2fs_fsmnt); } if (hotroot()) printf("** Root file system\n"); printf("** Phase 1 - Check Blocks and Sizes\n"); } pass1(); /* * 1b: locate first references to duplicates, if any */ if (duplist) { if (preen) pfatal("INTERNAL ERROR: dups with -p"); printf("** Phase 1b - Rescan For More DUPS\n"); pass1b(); } /* * 2: traverse directories from root to mark all connected directories */ if (preen == 0) printf("** Phase 2 - Check Pathnames\n"); pass2(); /* * 3: scan inodes looking for disconnected directories */ if (preen == 0) printf("** Phase 3 - Check Connectivity\n"); pass3(); /* * 4: scan inodes looking for disconnected files; check reference counts */ if (preen == 0) printf("** Phase 4 - Check Reference Counts\n"); pass4(); /* * 5: check and repair resource counts in cylinder groups */ if (preen == 0) printf("** Phase 5 - Check Cyl groups\n"); pass5(); /* * print out summary statistics */ n_bfree = sblock.e2fs.e2fs_fbcount; pwarn("%lld files, %lld used, %lld free\n", (long long)n_files, (long long)n_blks, (long long)n_bfree); if (debug && /* 9 reserved and unused inodes in FS */ (n_files -= maxino - 9 - sblock.e2fs.e2fs_ficount)) printf("%lld files missing\n", (long long)n_files); if (debug) { for (i = 0; i < sblock.e2fs_ncg; i++) n_blks += cgoverhead(i); n_blks += sblock.e2fs.e2fs_first_dblock; if (n_blks -= maxfsblock - n_bfree) printf("%lld blocks missing\n", (long long)n_blks); if (duplist != NULL) { printf("The following duplicate blocks remain:"); for (dp = duplist; dp; dp = dp->next) printf(" %lld,", (long long)dp->dup); printf("\n"); } if (zlnhead != NULL) { printf("The following zero link count inodes remain:"); for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) printf(" %llu,", (unsigned long long)zlnp->zlncnt); printf("\n"); } } zlnhead = (struct zlncnt *)0; duplist = (struct dups *)0; muldup = (struct dups *)0; inocleanup(); if (fsmodified) { time_t t; (void)time(&t); sblock.e2fs.e2fs_wtime = t; sblock.e2fs.e2fs_lastfsck = t; sbdirty(); } ckfini(1); free(blockmap); free(statemap); free((char *)lncntp); if (!fsmodified) return FSCK_EXIT_OK; if (!preen) printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); if (rerun) printf("\n***** PLEASE RERUN FSCK *****\n"); if (hotroot()) { struct statvfs stfs_buf; /* * We modified the root. Do a mount update on * it, unless it is read-write, so we can continue. */ if (statvfs("/", &stfs_buf) == 0) { long flags = stfs_buf.f_flag; struct ufs_args args; if (flags & MNT_RDONLY) { args.fspec = 0; flags |= MNT_UPDATE | MNT_RELOAD; if (mount(MOUNT_EXT2FS, "/", flags, &args, sizeof args) == 0) return FSCK_EXIT_OK; } } if (!preen) printf("\n***** REBOOT NOW *****\n"); sync(); return FSCK_EXIT_ROOT_CHANGED; } return FSCK_EXIT_OK; } static void usage(void) { (void) fprintf(stderr, "Usage: %s [-dfnpy] [-b block] [-c level] [-m mode] filesystem ...\n", getprogname()); exit(FSCK_EXIT_USAGE); }