Home | History | Annotate | Line # | Download | only in fsck_lfs
      1 /* $NetBSD: main.c,v 1.58 2025/09/14 21:29:31 wiz Exp $	 */
      2 
      3 /*
      4  * Copyright (c) 1980, 1986, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/param.h>
     33 #include <sys/time.h>
     34 #include <sys/mount.h>
     35 
     36 #include <ufs/lfs/lfs.h>
     37 #include <ufs/lfs/lfs_accessors.h>
     38 
     39 #include <fstab.h>
     40 #include <stdbool.h>
     41 #include <stdarg.h>
     42 #include <stdlib.h>
     43 #include <string.h>
     44 #include <ctype.h>
     45 #include <stdio.h>
     46 #include <unistd.h>
     47 #include <err.h>
     48 #include <util.h>
     49 #include <signal.h>
     50 
     51 #include "fsck.h"
     52 #include "extern.h"
     53 #include "fsutil.h"
     54 #include "exitvalues.h"
     55 
     56 int	Uflag;
     57 extern int asked_question;
     58 
     59 static int argtoi(int, const char *, const char *, int);
     60 static int checkfilesys(const char *, char *, long, int);
     61 static void usage(void);
     62 static void efun(int, const char *, ...);
     63 
     64 static void
     65 efun(int eval, const char *fmt, ...)
     66 {
     67 	va_list ap;
     68 	va_start(ap, fmt);
     69 	verr(EEXIT, fmt, ap);
     70 	va_end(ap);
     71 }
     72 
     73 int
     74 main(int argc, char **argv)
     75 {
     76 	int ch;
     77 	int ret = FSCK_EXIT_OK;
     78 	const char *optstring = "ab:dfi:m:npPqUy";
     79 	bool reallypreen;
     80 
     81 	reallypreen = false;
     82 	ckfinish = ckfini;
     83 	skipclean = 1;
     84 	exitonfail = 0;
     85 	idaddr = 0x0;
     86 	panic_func = vmsg;
     87 	esetfunc(efun);
     88 	while ((ch = getopt(argc, argv, optstring)) != -1) {
     89 		switch (ch) {
     90 		case 'a':
     91 			aflag++;
     92 			break;
     93 		case 'b':
     94 			skipclean = 0;
     95 			bflag = argtoi('b', "number", optarg, 0);
     96 			printf("Alternate super block location: %d\n", bflag);
     97 			break;
     98 		case 'd':
     99 			debug++;
    100 			break;
    101 		case 'e':
    102 			exitonfail++;
    103 			break;
    104 		case 'f':
    105 			skipclean = 0;
    106 			reallypreen = true;
    107 			break;
    108 		case 'i':
    109 			idaddr = strtol(optarg, NULL, 0);
    110 			break;
    111 		case 'm':
    112 			lfmode = argtoi('m', "mode", optarg, 8);
    113 			if (lfmode & ~07777)
    114 				err(1, "bad mode to -m: %o", lfmode);
    115 			printf("** lost+found creation mode %o\n", lfmode);
    116 			break;
    117 
    118 		case 'n':
    119 			nflag++;
    120 			yflag = 0;
    121 			break;
    122 
    123 		case 'p':
    124 			preen++;
    125 			break;
    126 
    127 		case 'P':		/* Progress meter not implemented. */
    128 			break;
    129 
    130 		case 'q':
    131 			quiet++;
    132 			break;
    133 #ifndef SMALL
    134 		case 'U':
    135 			Uflag++;
    136 			break;
    137 #endif
    138 		case 'y':
    139 			yflag++;
    140 			nflag = 0;
    141 			break;
    142 
    143 		default:
    144 			usage();
    145 		}
    146 	}
    147 
    148 	argc -= optind;
    149 	argv += optind;
    150 
    151 	if (!argc)
    152 		usage();
    153 
    154 	/*
    155 	 * Don't do anything in preen mode. This is a replacement for
    156 	 * version 1.111 of src/distrib/utils/sysinst/disks.c, which
    157 	 * disabled fsck on installer-generated lfs partitions. That
    158 	 * isn't the right way to do it; better to run fsck but have
    159 	 * it not do anything, so that when the issues in fsck get
    160 	 * resolved it can be turned back on.
    161 	 *
    162 	 * If you really want to run fsck in preen mode you can do:
    163 	 *    fsck_lfs -p -f image
    164 	 *
    165 	 * This was prompted by
    166 	 * http://mail-index.netbsd.org/tech-kern/2010/02/09/msg007306.html.
    167 	 *
    168 	 * It would be nice if someone prepared a more detailed report
    169 	 * of the problems.
    170 	 *
    171 	 * XXX.
    172 	 */
    173 	if (preen && !reallypreen) {
    174 		return ret;
    175 	}
    176 
    177 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
    178 		(void) signal(SIGINT, catch);
    179 	if (preen)
    180 		(void) signal(SIGQUIT, catchquit);
    181 
    182 	while (argc-- > 0) {
    183 		int nret = checkfilesys(blockcheck(*argv++), 0, 0L, 0);
    184 		if (ret < nret)
    185 			ret = nret;
    186 	}
    187 
    188 	return returntosingle ? FSCK_EXIT_UNRESOLVED : ret;
    189 }
    190 
    191 static int
    192 argtoi(int flag, const char *req, const char *str, int base)
    193 {
    194 	char *cp;
    195 	int ret;
    196 
    197 	ret = (int) strtol(str, &cp, base);
    198 	if (cp == str || *cp)
    199 		err(FSCK_EXIT_USAGE, "-%c flag requires a %s", flag, req);
    200 	return (ret);
    201 }
    202 
    203 /*
    204  * Check the specified filesystem.
    205  */
    206 
    207 /* ARGSUSED */
    208 static int
    209 checkfilesys(const char *filesys, char *mntpt, long auxdata, int child)
    210 {
    211 	struct dups *dp;
    212 	struct zlncnt *zlnp;
    213 
    214 	if (preen && child)
    215 		(void) signal(SIGQUIT, voidquit);
    216 	setcdevname(filesys, preen);
    217 	if (debug && preen)
    218 		pwarn("starting\n");
    219 	switch (setup(filesys)) {
    220 	case 0:
    221 		if (preen)
    222 			pfatal("CAN'T CHECK FILE SYSTEM.");
    223 		/* FALLTHROUGH */
    224 	case -1:
    225 		return FSCK_EXIT_OK;
    226 	}
    227 
    228 	/*
    229 	 * For LFS, "preen" means "roll forward".  We don't check anything
    230 	 * else.
    231 	 */
    232 	if (preen == 0) {
    233 		printf("** Last Mounted on %s\n", lfs_sb_getfsmnt(fs));
    234 		if (hotroot())
    235 			printf("** Root file system\n");
    236 		/*
    237 		 * 0: check segment checksums, inode ranges
    238 		 */
    239 		printf("** Phase 0 - Check Inode Free List\n");
    240 	}
    241 
    242 	/*
    243 	 * Check inode free list - we do this even if idaddr is set,
    244 	 * since if we're writing we don't want to write a bad list.
    245 	 */
    246 	pass0();
    247 
    248 	if (preen == 0) {
    249 		/*
    250 		 * 1: scan inodes tallying blocks used
    251 		 */
    252 		printf("** Phase 1 - Check Blocks and Sizes\n");
    253 		pass1();
    254 
    255 		/*
    256 		 * 2: traverse directories from root to mark all connected directories
    257 		 */
    258 		printf("** Phase 2 - Check Pathnames\n");
    259 		pass2();
    260 
    261 		/*
    262 		 * 3: scan inodes looking for disconnected directories
    263 		 */
    264 		printf("** Phase 3 - Check Connectivity\n");
    265 		pass3();
    266 
    267 		/*
    268 		 * 4: scan inodes looking for disconnected files; check reference counts
    269 		 */
    270 		printf("** Phase 4 - Check Reference Counts\n");
    271 		pass4();
    272 	}
    273 
    274 	/*
    275 	 * 5: check segment byte totals and dirty flags, and cleanerinfo
    276 	 */
    277 	if (!preen)
    278 		printf("** Phase 5 - Check Segment Block Accounting\n");
    279 	pass5();
    280 
    281 	if (debug && !preen) {
    282 		if (duplist != NULL) {
    283 			printf("The following duplicate blocks remain:");
    284 			for (dp = duplist; dp; dp = dp->next)
    285 				printf(" %lld,", (long long) dp->dup);
    286 			printf("\n");
    287 		}
    288 		if (zlnhead != NULL) {
    289 			printf("The following zero link count inodes remain:");
    290 			for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
    291 				printf(" %llu,",
    292 				    (unsigned long long)zlnp->zlncnt);
    293 			printf("\n");
    294 		}
    295 	}
    296 
    297 	if (!nflag && !rerun) {
    298 		if (!preen) {
    299 			if (reply("ROLL FILESYSTEM FORWARD") == 1) {
    300 				printf("** Phase 6 - Roll Forward\n");
    301 				pass6();
    302 			}
    303 		}
    304 		else {
    305 			pass6();
    306 		}
    307 	}
    308 	zlnhead = (struct zlncnt *) 0;
    309 	orphead = (struct zlncnt *) 0;
    310 	duplist = (struct dups *) 0;
    311 	muldup = (struct dups *) 0;
    312 	inocleanup();
    313 
    314 	/*
    315 	 * print out summary statistics
    316 	 */
    317 	pwarn("%ju files, %jd used, %jd free\n",
    318 	    (uintmax_t) n_files, (intmax_t) n_blks,
    319 	    (intmax_t) lfs_sb_getbfree(fs));
    320 
    321 	ckfini(1);
    322 
    323 	free(blockmap);
    324 	free(statemap);
    325 	free((char *)lncntp);
    326 	if (!fsmodified) {
    327 		return (nflag && asked_question ?
    328 			FSCK_EXIT_UNRESOLVED : FSCK_EXIT_OK);
    329 	}
    330 	if (!preen)
    331 		printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
    332 	if (rerun)
    333 		printf("\n***** PLEASE RERUN FSCK *****\n");
    334 	if (hotroot()) {
    335 		struct statvfs stfs_buf;
    336 		/*
    337 		 * We modified the root.  Do a mount update on
    338 		 * it, unless it is read-write, so we can continue.
    339 		 */
    340 		if (statvfs("/", &stfs_buf) == 0) {
    341 			long flags = stfs_buf.f_flag;
    342 			struct ulfs_args args;
    343 
    344 			if (flags & MNT_RDONLY) {
    345 				args.fspec = 0;
    346 				flags |= MNT_UPDATE | MNT_RELOAD;
    347 				if (mount(MOUNT_LFS, "/", flags,
    348 				    &args, sizeof args) == 0)
    349 					return FSCK_EXIT_OK;
    350 			}
    351 		}
    352 		if (!preen)
    353 			printf("\n***** REBOOT NOW *****\n");
    354 		sync();
    355 		return FSCK_EXIT_ROOT_CHANGED;
    356 	}
    357 	return FSCK_EXIT_OK;
    358 }
    359 
    360 static void
    361 usage(void)
    362 {
    363 
    364 	(void) fprintf(stderr,
    365 	    "Usage: %s [-adfpqU] [-b block] [-i idaddr] [-m mode] [-y | -n] filesystem ...\n",
    366 	    getprogname());
    367 	exit(FSCK_EXIT_USAGE);
    368 }
    369