1*6ce4f404Sjoerg /* $NetBSD: main.c,v 1.41 2020/04/05 15:25:39 joerg Exp $ */
2bf07c871Sagc
3bf07c871Sagc /*
4bf07c871Sagc * Copyright (c) 1980, 1986, 1993
5bf07c871Sagc * The Regents of the University of California. All rights reserved.
6bf07c871Sagc *
7bf07c871Sagc * Redistribution and use in source and binary forms, with or without
8bf07c871Sagc * modification, are permitted provided that the following conditions
9bf07c871Sagc * are met:
10bf07c871Sagc * 1. Redistributions of source code must retain the above copyright
11bf07c871Sagc * notice, this list of conditions and the following disclaimer.
12bf07c871Sagc * 2. Redistributions in binary form must reproduce the above copyright
13bf07c871Sagc * notice, this list of conditions and the following disclaimer in the
14bf07c871Sagc * documentation and/or other materials provided with the distribution.
15bf07c871Sagc * 3. Neither the name of the University nor the names of its contributors
16bf07c871Sagc * may be used to endorse or promote products derived from this software
17bf07c871Sagc * without specific prior written permission.
18bf07c871Sagc *
19bf07c871Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20bf07c871Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21bf07c871Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22bf07c871Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23bf07c871Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24bf07c871Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25bf07c871Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26bf07c871Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27bf07c871Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28bf07c871Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29bf07c871Sagc * SUCH DAMAGE.
30bf07c871Sagc */
318f7c2b37Sbouyer
328f7c2b37Sbouyer /*
338f7c2b37Sbouyer * Copyright (c) 1997 Manuel Bouyer.
348f7c2b37Sbouyer *
358f7c2b37Sbouyer * Redistribution and use in source and binary forms, with or without
368f7c2b37Sbouyer * modification, are permitted provided that the following conditions
378f7c2b37Sbouyer * are met:
388f7c2b37Sbouyer * 1. Redistributions of source code must retain the above copyright
398f7c2b37Sbouyer * notice, this list of conditions and the following disclaimer.
408f7c2b37Sbouyer * 2. Redistributions in binary form must reproduce the above copyright
418f7c2b37Sbouyer * notice, this list of conditions and the following disclaimer in the
428f7c2b37Sbouyer * documentation and/or other materials provided with the distribution.
438f7c2b37Sbouyer *
442f853da9Sbouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
452f853da9Sbouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
462f853da9Sbouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
472f853da9Sbouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
482f853da9Sbouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
492f853da9Sbouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
502f853da9Sbouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
512f853da9Sbouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
522f853da9Sbouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
532f853da9Sbouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
548f7c2b37Sbouyer */
558f7c2b37Sbouyer
564b836889Slukem #include <sys/cdefs.h>
578f7c2b37Sbouyer #ifndef lint
586543a91fSlukem __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1993\
596543a91fSlukem The Regents of the University of California. All rights reserved.");
608f7c2b37Sbouyer #endif /* not lint */
618f7c2b37Sbouyer
628f7c2b37Sbouyer #ifndef lint
638f7c2b37Sbouyer #if 0
648f7c2b37Sbouyer static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/23/94";
658f7c2b37Sbouyer #else
66*6ce4f404Sjoerg __RCSID("$NetBSD: main.c,v 1.41 2020/04/05 15:25:39 joerg Exp $");
678f7c2b37Sbouyer #endif
688f7c2b37Sbouyer #endif /* not lint */
698f7c2b37Sbouyer
708f7c2b37Sbouyer #include <sys/param.h>
718f7c2b37Sbouyer #include <sys/time.h>
728f7c2b37Sbouyer #include <sys/mount.h>
73e5bc90f4Sfvdl #include <ufs/ufs/ufsmount.h>
748f7c2b37Sbouyer #include <ufs/ext2fs/ext2fs_dinode.h>
758f7c2b37Sbouyer #include <ufs/ext2fs/ext2fs.h>
768f7c2b37Sbouyer #include <fstab.h>
778f7c2b37Sbouyer #include <stdlib.h>
788f7c2b37Sbouyer #include <string.h>
798f7c2b37Sbouyer #include <ctype.h>
808f7c2b37Sbouyer #include <stdio.h>
810369f1ecSkleink #include <time.h>
828f7c2b37Sbouyer #include <unistd.h>
83628f1591Sdrochner #include <signal.h>
848f7c2b37Sbouyer
858f7c2b37Sbouyer #include "fsck.h"
868f7c2b37Sbouyer #include "extern.h"
878f7c2b37Sbouyer #include "fsutil.h"
88742b48d5Schristos #include "exitvalues.h"
898f7c2b37Sbouyer
90*6ce4f404Sjoerg struct bufarea bufhead;
91*6ce4f404Sjoerg struct bufarea sblk;
92*6ce4f404Sjoerg struct bufarea asblk;
93*6ce4f404Sjoerg struct bufarea *pdirbp;
94*6ce4f404Sjoerg struct bufarea *pbp;
95*6ce4f404Sjoerg struct bufarea *getdatablk(daddr_t, long);
96*6ce4f404Sjoerg struct m_ext2fs sblock;
97*6ce4f404Sjoerg struct dups *duplist;
98*6ce4f404Sjoerg struct dups *muldup;
99*6ce4f404Sjoerg struct zlncnt *zlnhead;
100*6ce4f404Sjoerg struct inoinfo **inphead, **inpsort;
101*6ce4f404Sjoerg long numdirs, listmax, inplast;
102*6ce4f404Sjoerg long dev_bsize;
103*6ce4f404Sjoerg long secsize;
104*6ce4f404Sjoerg char nflag;
105*6ce4f404Sjoerg char yflag;
106*6ce4f404Sjoerg int bflag;
107*6ce4f404Sjoerg int Uflag;
108*6ce4f404Sjoerg int debug;
109*6ce4f404Sjoerg int preen;
110*6ce4f404Sjoerg char havesb;
111*6ce4f404Sjoerg char skipclean;
112*6ce4f404Sjoerg int fsmodified;
113*6ce4f404Sjoerg int fsreadfd;
114*6ce4f404Sjoerg int fswritefd;
115*6ce4f404Sjoerg int rerun;
116*6ce4f404Sjoerg daddr_t maxfsblock;
117*6ce4f404Sjoerg char *blockmap;
118*6ce4f404Sjoerg ino_t maxino;
119*6ce4f404Sjoerg ino_t lastino;
120*6ce4f404Sjoerg char *statemap;
121*6ce4f404Sjoerg u_char *typemap;
122*6ce4f404Sjoerg int16_t *lncntp;
123*6ce4f404Sjoerg ino_t lfdir;
124*6ce4f404Sjoerg daddr_t n_blks;
125*6ce4f404Sjoerg daddr_t n_files;
126*6ce4f404Sjoerg struct ext2fs_dinode zino;
1278f7c2b37Sbouyer
12897880e96Schristos static int argtoi(int, const char *, const char *, int);
129ccde05f0Sxtraeme static int checkfilesys(const char *, char *, long, int);
130742b48d5Schristos static void usage(void) __dead;
1318f7c2b37Sbouyer
1328f7c2b37Sbouyer int
main(int argc,char * argv[])133ccde05f0Sxtraeme main(int argc, char *argv[])
1348f7c2b37Sbouyer {
1358f7c2b37Sbouyer int ch;
136742b48d5Schristos int ret = FSCK_EXIT_OK;
1378f7c2b37Sbouyer
13823ffdf5bSchristos ckfinish = ckfini;
1398f7c2b37Sbouyer sync();
1408f7c2b37Sbouyer skipclean = 1;
141e67b5654Stron while ((ch = getopt(argc, argv, "b:dfm:npPqUy")) != -1) {
1428f7c2b37Sbouyer switch (ch) {
1438f7c2b37Sbouyer case 'b':
1448f7c2b37Sbouyer skipclean = 0;
1458f7c2b37Sbouyer bflag = argtoi('b', "number", optarg, 10);
1468f7c2b37Sbouyer printf("Alternate super block location: %d\n", bflag);
1478f7c2b37Sbouyer break;
1488f7c2b37Sbouyer
1498f7c2b37Sbouyer case 'd':
1508f7c2b37Sbouyer debug++;
1518f7c2b37Sbouyer break;
1528f7c2b37Sbouyer
1538f7c2b37Sbouyer case 'f':
1548f7c2b37Sbouyer skipclean = 0;
1558f7c2b37Sbouyer break;
1568f7c2b37Sbouyer
1578f7c2b37Sbouyer case 'm':
1588f7c2b37Sbouyer lfmode = argtoi('m', "mode", optarg, 8);
1598f7c2b37Sbouyer if (lfmode &~ 07777)
160481ad7b0Slukem errexit("bad mode to -m: %o", lfmode);
1618f7c2b37Sbouyer printf("** lost+found creation mode %o\n", lfmode);
1628f7c2b37Sbouyer break;
1638f7c2b37Sbouyer
1648f7c2b37Sbouyer case 'n':
1658f7c2b37Sbouyer nflag++;
1668f7c2b37Sbouyer yflag = 0;
1678f7c2b37Sbouyer break;
1688f7c2b37Sbouyer
1698f7c2b37Sbouyer case 'p':
1708f7c2b37Sbouyer preen++;
1718f7c2b37Sbouyer break;
1728f7c2b37Sbouyer
173a73c2bd5Schristos case 'P':
174a73c2bd5Schristos /* Progress meter not implemented. */
175a73c2bd5Schristos break;
176a73c2bd5Schristos
177e69ce3e4Sdsl case 'q': /* Quiet not implemented */
178e69ce3e4Sdsl break;
179e69ce3e4Sdsl
18059334248Schristos #ifndef SMALL
18159334248Schristos case 'U':
18259334248Schristos Uflag++;
18359334248Schristos break;
18459334248Schristos #endif
18559334248Schristos
1868f7c2b37Sbouyer case 'y':
1878f7c2b37Sbouyer yflag++;
1888f7c2b37Sbouyer nflag = 0;
1898f7c2b37Sbouyer break;
1908f7c2b37Sbouyer
1918f7c2b37Sbouyer default:
1928f7c2b37Sbouyer usage();
1938f7c2b37Sbouyer }
1948f7c2b37Sbouyer }
1958f7c2b37Sbouyer
1968f7c2b37Sbouyer argc -= optind;
1978f7c2b37Sbouyer argv += optind;
1988f7c2b37Sbouyer
1998f7c2b37Sbouyer if (!argc)
2008f7c2b37Sbouyer usage();
2018f7c2b37Sbouyer
2028f7c2b37Sbouyer if (signal(SIGINT, SIG_IGN) != SIG_IGN)
2038f7c2b37Sbouyer (void)signal(SIGINT, catch);
2048f7c2b37Sbouyer if (preen)
2058f7c2b37Sbouyer (void)signal(SIGQUIT, catchquit);
2068f7c2b37Sbouyer
207742b48d5Schristos while (argc-- > 0) {
208742b48d5Schristos int nret = checkfilesys(blockcheck(*argv++), 0, 0L, 0);
209742b48d5Schristos if (ret < nret)
210742b48d5Schristos ret = nret;
211742b48d5Schristos }
2128f7c2b37Sbouyer
213742b48d5Schristos return returntosingle ? FSCK_EXIT_UNRESOLVED : ret;
2148f7c2b37Sbouyer }
2158f7c2b37Sbouyer
2168f7c2b37Sbouyer static int
argtoi(int flag,const char * req,const char * str,int base)21797880e96Schristos argtoi(int flag, const char *req, const char *str, int base)
2188f7c2b37Sbouyer {
2198f7c2b37Sbouyer char *cp;
2208f7c2b37Sbouyer int ret;
2218f7c2b37Sbouyer
2228f7c2b37Sbouyer ret = (int)strtol(str, &cp, base);
2238f7c2b37Sbouyer if (cp == str || *cp)
224481ad7b0Slukem errexit("-%c flag requires a %s", flag, req);
2258f7c2b37Sbouyer return (ret);
2268f7c2b37Sbouyer }
2278f7c2b37Sbouyer
2288f7c2b37Sbouyer /*
2298f7c2b37Sbouyer * Check the specified filesystem.
2308f7c2b37Sbouyer */
2318f7c2b37Sbouyer /* ARGSUSED */
2328f7c2b37Sbouyer static int
checkfilesys(const char * filesys,char * mntpt,long auxdata,int child)233ccde05f0Sxtraeme checkfilesys(const char *filesys, char *mntpt, long auxdata, int child)
2348f7c2b37Sbouyer {
2358f7c2b37Sbouyer daddr_t n_bfree;
2368f7c2b37Sbouyer struct dups *dp;
2378f7c2b37Sbouyer struct zlncnt *zlnp;
23809d4663fSbouyer int i;
2398f7c2b37Sbouyer
2408f7c2b37Sbouyer if (preen && child)
2418f7c2b37Sbouyer (void)signal(SIGQUIT, voidquit);
2428f7c2b37Sbouyer setcdevname(filesys, preen);
2438f7c2b37Sbouyer if (debug && preen)
2448f7c2b37Sbouyer pwarn("starting\n");
2458f7c2b37Sbouyer switch (setup(filesys)) {
2468f7c2b37Sbouyer case 0:
2478f7c2b37Sbouyer if (preen)
2488f7c2b37Sbouyer pfatal("CAN'T CHECK FILE SYSTEM.");
249fbffadb9Smrg /* FALLTHROUGH */
2508f7c2b37Sbouyer case -1:
251742b48d5Schristos return FSCK_EXIT_OK;
2528f7c2b37Sbouyer }
2538f7c2b37Sbouyer /*
2548f7c2b37Sbouyer * 1: scan inodes tallying blocks used
2558f7c2b37Sbouyer */
2568f7c2b37Sbouyer if (preen == 0) {
2575fb6bc4eSbouyer if (sblock.e2fs.e2fs_rev > E2FS_REV0) {
2585fb6bc4eSbouyer printf("** Last Mounted on %s\n",
2595fb6bc4eSbouyer sblock.e2fs.e2fs_fsmnt);
2605fb6bc4eSbouyer }
2618f7c2b37Sbouyer if (hotroot())
2628f7c2b37Sbouyer printf("** Root file system\n");
2638f7c2b37Sbouyer printf("** Phase 1 - Check Blocks and Sizes\n");
2648f7c2b37Sbouyer }
2658f7c2b37Sbouyer pass1();
2668f7c2b37Sbouyer
2678f7c2b37Sbouyer /*
2688f7c2b37Sbouyer * 1b: locate first references to duplicates, if any
2698f7c2b37Sbouyer */
2708f7c2b37Sbouyer if (duplist) {
2718f7c2b37Sbouyer if (preen)
2728f7c2b37Sbouyer pfatal("INTERNAL ERROR: dups with -p");
2738f7c2b37Sbouyer printf("** Phase 1b - Rescan For More DUPS\n");
2748f7c2b37Sbouyer pass1b();
2758f7c2b37Sbouyer }
2768f7c2b37Sbouyer
2778f7c2b37Sbouyer /*
2788f7c2b37Sbouyer * 2: traverse directories from root to mark all connected directories
2798f7c2b37Sbouyer */
2808f7c2b37Sbouyer if (preen == 0)
2818f7c2b37Sbouyer printf("** Phase 2 - Check Pathnames\n");
2828f7c2b37Sbouyer pass2();
2838f7c2b37Sbouyer
2848f7c2b37Sbouyer /*
2858f7c2b37Sbouyer * 3: scan inodes looking for disconnected directories
2868f7c2b37Sbouyer */
2878f7c2b37Sbouyer if (preen == 0)
2888f7c2b37Sbouyer printf("** Phase 3 - Check Connectivity\n");
2898f7c2b37Sbouyer pass3();
2908f7c2b37Sbouyer
2918f7c2b37Sbouyer /*
2928f7c2b37Sbouyer * 4: scan inodes looking for disconnected files; check reference counts
2938f7c2b37Sbouyer */
2948f7c2b37Sbouyer if (preen == 0)
2958f7c2b37Sbouyer printf("** Phase 4 - Check Reference Counts\n");
2968f7c2b37Sbouyer pass4();
2978f7c2b37Sbouyer
2988f7c2b37Sbouyer /*
2998f7c2b37Sbouyer * 5: check and repair resource counts in cylinder groups
3008f7c2b37Sbouyer */
3018f7c2b37Sbouyer if (preen == 0)
3028f7c2b37Sbouyer printf("** Phase 5 - Check Cyl groups\n");
3038f7c2b37Sbouyer pass5();
3048f7c2b37Sbouyer
3058f7c2b37Sbouyer /*
3068f7c2b37Sbouyer * print out summary statistics
3078f7c2b37Sbouyer */
3088f7c2b37Sbouyer n_bfree = sblock.e2fs.e2fs_fbcount;
3098f7c2b37Sbouyer
310a3ff3a30Sfvdl pwarn("%lld files, %lld used, %lld free\n",
311a3ff3a30Sfvdl (long long)n_files, (long long)n_blks, (long long)n_bfree);
3128f7c2b37Sbouyer if (debug &&
3138f7c2b37Sbouyer /* 9 reserved and unused inodes in FS */
3148f7c2b37Sbouyer (n_files -= maxino - 9 - sblock.e2fs.e2fs_ficount))
315a3ff3a30Sfvdl printf("%lld files missing\n", (long long)n_files);
3168f7c2b37Sbouyer if (debug) {
31709d4663fSbouyer for (i = 0; i < sblock.e2fs_ncg; i++)
31809d4663fSbouyer n_blks += cgoverhead(i);
3198f7c2b37Sbouyer n_blks += sblock.e2fs.e2fs_first_dblock;
3208f7c2b37Sbouyer if (n_blks -= maxfsblock - n_bfree)
321a3ff3a30Sfvdl printf("%lld blocks missing\n", (long long)n_blks);
3228f7c2b37Sbouyer if (duplist != NULL) {
3238f7c2b37Sbouyer printf("The following duplicate blocks remain:");
3248f7c2b37Sbouyer for (dp = duplist; dp; dp = dp->next)
325a3ff3a30Sfvdl printf(" %lld,", (long long)dp->dup);
3268f7c2b37Sbouyer printf("\n");
3278f7c2b37Sbouyer }
3288f7c2b37Sbouyer if (zlnhead != NULL) {
3298f7c2b37Sbouyer printf("The following zero link count inodes remain:");
3308f7c2b37Sbouyer for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
331c4ee9f6dSchristos printf(" %llu,",
332c4ee9f6dSchristos (unsigned long long)zlnp->zlncnt);
3338f7c2b37Sbouyer printf("\n");
3348f7c2b37Sbouyer }
3358f7c2b37Sbouyer }
3368f7c2b37Sbouyer zlnhead = (struct zlncnt *)0;
3378f7c2b37Sbouyer duplist = (struct dups *)0;
3388f7c2b37Sbouyer muldup = (struct dups *)0;
3398f7c2b37Sbouyer inocleanup();
3408f7c2b37Sbouyer if (fsmodified) {
3418f7c2b37Sbouyer time_t t;
3428f7c2b37Sbouyer (void)time(&t);
3438f7c2b37Sbouyer sblock.e2fs.e2fs_wtime = t;
3448f7c2b37Sbouyer sblock.e2fs.e2fs_lastfsck = t;
3458f7c2b37Sbouyer sbdirty();
3468f7c2b37Sbouyer }
3478f7c2b37Sbouyer ckfini(1);
3488f7c2b37Sbouyer free(blockmap);
3498f7c2b37Sbouyer free(statemap);
3508f7c2b37Sbouyer free((char *)lncntp);
3518f7c2b37Sbouyer if (!fsmodified)
352742b48d5Schristos return FSCK_EXIT_OK;
3538f7c2b37Sbouyer if (!preen)
3548f7c2b37Sbouyer printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
3558f7c2b37Sbouyer if (rerun)
3568f7c2b37Sbouyer printf("\n***** PLEASE RERUN FSCK *****\n");
3578f7c2b37Sbouyer if (hotroot()) {
3586bd1d6d4Schristos struct statvfs stfs_buf;
3598f7c2b37Sbouyer /*
3608f7c2b37Sbouyer * We modified the root. Do a mount update on
3618f7c2b37Sbouyer * it, unless it is read-write, so we can continue.
3628f7c2b37Sbouyer */
3636bd1d6d4Schristos if (statvfs("/", &stfs_buf) == 0) {
3646bd1d6d4Schristos long flags = stfs_buf.f_flag;
3658f7c2b37Sbouyer struct ufs_args args;
3668f7c2b37Sbouyer
3678f7c2b37Sbouyer if (flags & MNT_RDONLY) {
3688f7c2b37Sbouyer args.fspec = 0;
3698f7c2b37Sbouyer flags |= MNT_UPDATE | MNT_RELOAD;
370742b48d5Schristos if (mount(MOUNT_EXT2FS, "/", flags,
371742b48d5Schristos &args, sizeof args) == 0)
372742b48d5Schristos return FSCK_EXIT_OK;
3738f7c2b37Sbouyer }
3748f7c2b37Sbouyer }
3758f7c2b37Sbouyer if (!preen)
3768f7c2b37Sbouyer printf("\n***** REBOOT NOW *****\n");
3778f7c2b37Sbouyer sync();
378742b48d5Schristos return FSCK_EXIT_ROOT_CHANGED;
3798f7c2b37Sbouyer }
380742b48d5Schristos return FSCK_EXIT_OK;
3818f7c2b37Sbouyer }
3828f7c2b37Sbouyer
3838f7c2b37Sbouyer static void
usage(void)384ccde05f0Sxtraeme usage(void)
3858f7c2b37Sbouyer {
3868a986b2eScgd
3878f7c2b37Sbouyer (void) fprintf(stderr,
388697ce855Ssevan "usage: %s [-dfnpUy] [-b block] [-m mode] filesystem ...\n",
3898a986b2eScgd getprogname());
390742b48d5Schristos exit(FSCK_EXIT_USAGE);
3918f7c2b37Sbouyer }
392