main.c revision 66861
1219820Sjeff/* 2219820Sjeff * Copyright (c) 1980, 1986, 1993 3219820Sjeff * The Regents of the University of California. All rights reserved. 4219820Sjeff * 5219820Sjeff * Redistribution and use in source and binary forms, with or without 6219820Sjeff * modification, are permitted provided that the following conditions 7219820Sjeff * are met: 8219820Sjeff * 1. Redistributions of source code must retain the above copyright 9219820Sjeff * notice, this list of conditions and the following disclaimer. 10219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 11219820Sjeff * notice, this list of conditions and the following disclaimer in the 12219820Sjeff * documentation and/or other materials provided with the distribution. 13219820Sjeff * 3. All advertising materials mentioning features or use of this software 14219820Sjeff * must display the following acknowledgement: 15219820Sjeff * This product includes software developed by the University of 16219820Sjeff * California, Berkeley and its contributors. 17219820Sjeff * 4. Neither the name of the University nor the names of its contributors 18219820Sjeff * may be used to endorse or promote products derived from this software 19219820Sjeff * without specific prior written permission. 20219820Sjeff * 21219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22219820Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24219820Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25219820Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26219820Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27219820Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29219820Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31219820Sjeff * SUCH DAMAGE. 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#ifndef lint 35219820Sjeffstatic const char copyright[] = 36219820Sjeff"@(#) Copyright (c) 1980, 1986, 1993\n\ 37219820Sjeff The Regents of the University of California. All rights reserved.\n"; 38219820Sjeff#endif /* not lint */ 39219820Sjeff 40219820Sjeff#ifndef lint 41219820Sjeff#if 0 42219820Sjeffstatic char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/14/95"; 43219820Sjeff#endif 44219820Sjeffstatic const char rcsid[] = 45219820Sjeff "$FreeBSD: head/sbin/fsck_ffs/main.c 66861 2000-10-09 08:26:35Z adrian $"; 46219820Sjeff#endif /* not lint */ 47219820Sjeff 48219820Sjeff#include <sys/param.h> 49219820Sjeff#include <sys/stat.h> 50219820Sjeff#include <sys/time.h> 51219820Sjeff#include <sys/mount.h> 52219820Sjeff#include <sys/resource.h> 53219820Sjeff 54219820Sjeff#include <ufs/ufs/dinode.h> 55219820Sjeff#include <ufs/ufs/ufsmount.h> 56219820Sjeff#include <ufs/ffs/fs.h> 57219820Sjeff 58219820Sjeff#include <err.h> 59219820Sjeff#include <errno.h> 60219820Sjeff#include <fstab.h> 61219820Sjeff#include <paths.h> 62219820Sjeff 63219820Sjeff#include "fsck.h" 64219820Sjeff 65219820Sjeffint returntosingle; 66219820Sjeff 67219820Sjeffstatic void usage __P((void)); 68219820Sjeffstatic int argtoi __P((int flag, char *req, char *str, int base)); 69219820Sjeffstatic int docheck __P((struct fstab *fsp)); 70219820Sjeffstatic int checkfilesys __P((char *filesys, char *mntpt, long auxdata, 71219820Sjeff int child)); 72219820Sjeffstatic struct statfs *getmntpt __P((const char *)); 73219820Sjeffint main __P((int argc, char *argv[])); 74219820Sjeff 75219820Sjeffint 76219820Sjeffmain(argc, argv) 77219820Sjeff int argc; 78219820Sjeff char *argv[]; 79219820Sjeff{ 80219820Sjeff int ch; 81219820Sjeff struct rlimit rlimit; 82219820Sjeff int ret = 0; 83219820Sjeff 84219820Sjeff sync(); 85219820Sjeff skipclean = 1; 86219820Sjeff markclean = 1; 87219820Sjeff while ((ch = getopt(argc, argv, "b:c:dfm:npy")) != -1) { 88219820Sjeff switch (ch) { 89219820Sjeff case 'b': 90219820Sjeff skipclean = 0; 91219820Sjeff bflag = argtoi('b', "number", optarg, 10); 92219820Sjeff printf("Alternate super block location: %d\n", bflag); 93219820Sjeff break; 94219820Sjeff 95219820Sjeff case 'c': 96219820Sjeff skipclean = 0; 97219820Sjeff cvtlevel = argtoi('c', "conversion level", optarg, 10); 98219820Sjeff break; 99219820Sjeff 100219820Sjeff case 'd': 101219820Sjeff debug++; 102219820Sjeff break; 103219820Sjeff 104219820Sjeff case 'f': 105219820Sjeff skipclean = 0; 106219820Sjeff break; 107219820Sjeff 108219820Sjeff case 'm': 109219820Sjeff lfmode = argtoi('m', "mode", optarg, 8); 110219820Sjeff if (lfmode &~ 07777) 111219820Sjeff errx(EEXIT, "bad mode to -m: %o", lfmode); 112219820Sjeff printf("** lost+found creation mode %o\n", lfmode); 113219820Sjeff break; 114219820Sjeff 115219820Sjeff case 'n': 116219820Sjeff nflag++; 117219820Sjeff yflag = 0; 118219820Sjeff break; 119219820Sjeff 120219820Sjeff case 'p': 121219820Sjeff preen++; 122219820Sjeff break; 123219820Sjeff 124219820Sjeff case 'y': 125219820Sjeff yflag++; 126219820Sjeff nflag = 0; 127219820Sjeff break; 128219820Sjeff 129219820Sjeff default: 130219820Sjeff usage(); 131219820Sjeff } 132219820Sjeff } 133219820Sjeff argc -= optind; 134219820Sjeff argv += optind; 135219820Sjeff 136219820Sjeff if (!argc) 137219820Sjeff usage(); 138219820Sjeff 139219820Sjeff if (signal(SIGINT, SIG_IGN) != SIG_IGN) 140219820Sjeff (void)signal(SIGINT, catch); 141219820Sjeff if (preen) 142219820Sjeff (void)signal(SIGQUIT, catchquit); 143219820Sjeff /* 144219820Sjeff * Push up our allowed memory limit so we can cope 145219820Sjeff * with huge filesystems. 146219820Sjeff */ 147219820Sjeff if (getrlimit(RLIMIT_DATA, &rlimit) == 0) { 148219820Sjeff rlimit.rlim_cur = rlimit.rlim_max; 149219820Sjeff (void)setrlimit(RLIMIT_DATA, &rlimit); 150219820Sjeff } 151219820Sjeff while (argc-- > 0) 152219820Sjeff (void)checkfilesys(blockcheck(*argv++), 0, 0L, 0); 153219820Sjeff 154219820Sjeff if (returntosingle) 155219820Sjeff ret = 2; 156219820Sjeff exit(ret); 157219820Sjeff} 158219820Sjeff 159219820Sjeffstatic int 160219820Sjeffargtoi(flag, req, str, base) 161219820Sjeff int flag; 162219820Sjeff char *req, *str; 163219820Sjeff int base; 164219820Sjeff{ 165219820Sjeff char *cp; 166219820Sjeff int ret; 167219820Sjeff 168219820Sjeff ret = (int)strtol(str, &cp, base); 169219820Sjeff if (cp == str || *cp) 170219820Sjeff errx(EEXIT, "-%c flag requires a %s", flag, req); 171219820Sjeff return (ret); 172219820Sjeff} 173219820Sjeff 174219820Sjeff/* 175219820Sjeff * Check the specified filesystem. 176219820Sjeff */ 177219820Sjeff/* ARGSUSED */ 178219820Sjeffstatic int 179219820Sjeffcheckfilesys(filesys, mntpt, auxdata, child) 180219820Sjeff char *filesys, *mntpt; 181219820Sjeff long auxdata; 182219820Sjeff int child; 183219820Sjeff{ 184219820Sjeff ufs_daddr_t n_ffree, n_bfree; 185219820Sjeff struct dups *dp; 186219820Sjeff struct statfs *mntbuf; 187219820Sjeff struct zlncnt *zlnp; 188219820Sjeff int cylno; 189219820Sjeff 190219820Sjeff if (preen && child) 191219820Sjeff (void)signal(SIGQUIT, voidquit); 192219820Sjeff cdevname = filesys; 193219820Sjeff if (debug && preen) 194219820Sjeff pwarn("starting\n"); 195219820Sjeff switch (setup(filesys)) { 196219820Sjeff case 0: 197219820Sjeff if (preen) 198219820Sjeff pfatal("CAN'T CHECK FILE SYSTEM."); 199219820Sjeff return (0); 200219820Sjeff case -1: 201219820Sjeff pwarn("clean, %ld free ", sblock.fs_cstotal.cs_nffree + 202219820Sjeff sblock.fs_frag * sblock.fs_cstotal.cs_nbfree); 203219820Sjeff printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", 204219820Sjeff sblock.fs_cstotal.cs_nffree, sblock.fs_cstotal.cs_nbfree, 205219820Sjeff sblock.fs_cstotal.cs_nffree * 100.0 / sblock.fs_dsize); 206219820Sjeff return (0); 207219820Sjeff } 208219820Sjeff 209219820Sjeff /* 210219820Sjeff * Get the mount point information of the filesystem, if 211219820Sjeff * it is available. 212219820Sjeff */ 213219820Sjeff mntbuf = getmntpt(filesys); 214219820Sjeff 215219820Sjeff /* 216219820Sjeff * Cleared if any questions answered no. Used to decide if 217219820Sjeff * the superblock should be marked clean. 218219820Sjeff */ 219219820Sjeff resolved = 1; 220219820Sjeff /* 221219820Sjeff * 1: scan inodes tallying blocks used 222219820Sjeff */ 223219820Sjeff if (preen == 0) { 224219820Sjeff printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 225219820Sjeff if (mntbuf != NULL && mntbuf->f_flags & MNT_ROOTFS) 226219820Sjeff printf("** Root file system\n"); 227219820Sjeff printf("** Phase 1 - Check Blocks and Sizes\n"); 228219820Sjeff } 229219820Sjeff pass1(); 230219820Sjeff 231219820Sjeff /* 232219820Sjeff * 1b: locate first references to duplicates, if any 233219820Sjeff */ 234219820Sjeff if (duplist) { 235219820Sjeff if (preen || usedsoftdep) 236219820Sjeff pfatal("INTERNAL ERROR: dups with -p"); 237219820Sjeff printf("** Phase 1b - Rescan For More DUPS\n"); 238219820Sjeff pass1b(); 239219820Sjeff } 240219820Sjeff 241219820Sjeff /* 242219820Sjeff * 2: traverse directories from root to mark all connected directories 243219820Sjeff */ 244219820Sjeff if (preen == 0) 245219820Sjeff printf("** Phase 2 - Check Pathnames\n"); 246219820Sjeff pass2(); 247219820Sjeff 248219820Sjeff /* 249219820Sjeff * 3: scan inodes looking for disconnected directories 250219820Sjeff */ 251219820Sjeff if (preen == 0) 252219820Sjeff printf("** Phase 3 - Check Connectivity\n"); 253219820Sjeff pass3(); 254219820Sjeff 255219820Sjeff /* 256219820Sjeff * 4: scan inodes looking for disconnected files; check reference counts 257219820Sjeff */ 258219820Sjeff if (preen == 0) 259219820Sjeff printf("** Phase 4 - Check Reference Counts\n"); 260219820Sjeff pass4(); 261219820Sjeff 262219820Sjeff /* 263219820Sjeff * 5: check and repair resource counts in cylinder groups 264219820Sjeff */ 265219820Sjeff if (preen == 0) 266219820Sjeff printf("** Phase 5 - Check Cyl groups\n"); 267219820Sjeff pass5(); 268219820Sjeff 269219820Sjeff /* 270219820Sjeff * print out summary statistics 271219820Sjeff */ 272219820Sjeff n_ffree = sblock.fs_cstotal.cs_nffree; 273219820Sjeff n_bfree = sblock.fs_cstotal.cs_nbfree; 274219820Sjeff pwarn("%ld files, %ld used, %ld free ", 275219820Sjeff n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); 276219820Sjeff printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", 277219820Sjeff n_ffree, n_bfree, n_ffree * 100.0 / sblock.fs_dsize); 278219820Sjeff if (debug && 279219820Sjeff (n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree)) 280219820Sjeff printf("%d files missing\n", n_files); 281219820Sjeff if (debug) { 282219820Sjeff n_blks += sblock.fs_ncg * 283219820Sjeff (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 284219820Sjeff n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 285219820Sjeff n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 286219820Sjeff if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree)) 287219820Sjeff printf("%d blocks missing\n", n_blks); 288219820Sjeff if (duplist != NULL) { 289219820Sjeff printf("The following duplicate blocks remain:"); 290219820Sjeff for (dp = duplist; dp; dp = dp->next) 291219820Sjeff printf(" %d,", dp->dup); 292219820Sjeff printf("\n"); 293219820Sjeff } 294219820Sjeff if (zlnhead != NULL) { 295219820Sjeff printf("The following zero link count inodes remain:"); 296219820Sjeff for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) 297219820Sjeff printf(" %u,", zlnp->zlncnt); 298219820Sjeff printf("\n"); 299219820Sjeff } 300219820Sjeff } 301219820Sjeff zlnhead = (struct zlncnt *)0; 302219820Sjeff duplist = (struct dups *)0; 303219820Sjeff muldup = (struct dups *)0; 304219820Sjeff inocleanup(); 305219820Sjeff if (fsmodified) { 306219820Sjeff sblock.fs_time = time(NULL); 307219820Sjeff sbdirty(); 308219820Sjeff } 309219820Sjeff if (cvtlevel && sblk.b_dirty) { 310219820Sjeff /* 311219820Sjeff * Write out the duplicate super blocks 312219820Sjeff */ 313219820Sjeff for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 314219820Sjeff bwrite(fswritefd, (char *)&sblock, 315219820Sjeff fsbtodb(&sblock, cgsblock(&sblock, cylno)), SBSIZE); 316219820Sjeff } 317219820Sjeff if (rerun) 318219820Sjeff resolved = 0; 319219820Sjeff 320219820Sjeff /* 321219820Sjeff * Check to see if the filesystem is mounted read-write. 322219820Sjeff */ 323219820Sjeff if (mntbuf != NULL && (mntbuf->f_flags & MNT_RDONLY) == 0) 324219820Sjeff resolved = 0; 325219820Sjeff ckfini(resolved); 326219820Sjeff 327219820Sjeff for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 328219820Sjeff if (inostathead[cylno].il_stat != NULL) 329219820Sjeff free((char *)inostathead[cylno].il_stat); 330219820Sjeff free((char *)inostathead); 331219820Sjeff inostathead = NULL; 332219820Sjeff if (fsmodified && !preen) 333219820Sjeff printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 334219820Sjeff if (rerun) 335219820Sjeff printf("\n***** PLEASE RERUN FSCK *****\n"); 336219820Sjeff if (mntbuf != NULL) { 337219820Sjeff struct ufs_args args; 338219820Sjeff int ret; 339219820Sjeff /* 340219820Sjeff * We modified a mounted filesystem. Do a mount update on 341219820Sjeff * it unless it is read-write, so we can continue using it 342219820Sjeff * as safely as possible. 343219820Sjeff */ 344219820Sjeff if (mntbuf->f_flags & MNT_RDONLY) { 345219820Sjeff args.fspec = 0; 346219820Sjeff args.export.ex_flags = 0; 347219820Sjeff args.export.ex_root = 0; 348219820Sjeff ret = mount("ufs", mntbuf->f_mntonname, 349219820Sjeff mntbuf->f_flags | MNT_UPDATE | MNT_RELOAD, &args); 350219820Sjeff if (ret == 0) 351219820Sjeff return (0); 352219820Sjeff pwarn("mount reload of '%s' failed: %s\n\n", 353219820Sjeff mntbuf->f_mntonname, strerror(errno)); 354219820Sjeff } 355219820Sjeff if (!fsmodified) 356219820Sjeff return (0); 357219820Sjeff if (!preen) 358219820Sjeff printf("\n***** REBOOT NOW *****\n"); 359219820Sjeff sync(); 360219820Sjeff return (4); 361219820Sjeff } 362219820Sjeff return (0); 363219820Sjeff} 364219820Sjeff 365219820Sjeff/* 366219820Sjeff * Get the directory that the device is mounted on. 367219820Sjeff */ 368219820Sjeffstatic struct statfs * 369219820Sjeffgetmntpt(name) 370219820Sjeff const char *name; 371219820Sjeff{ 372219820Sjeff struct stat devstat, mntdevstat; 373219820Sjeff char device[sizeof(_PATH_DEV) - 1 + MNAMELEN]; 374219820Sjeff char *devname; 375219820Sjeff struct statfs *mntbuf; 376219820Sjeff int i, mntsize; 377219820Sjeff 378219820Sjeff if (stat(name, &devstat) != 0 || 379219820Sjeff !(S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode))) 380219820Sjeff return (NULL); 381219820Sjeff mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 382219820Sjeff for (i = 0; i < mntsize; i++) { 383219820Sjeff if (strcmp(mntbuf[i].f_fstypename, "ufs") != 0) 384219820Sjeff continue; 385219820Sjeff devname = mntbuf[i].f_mntfromname; 386219820Sjeff if (*devname != '/') { 387219820Sjeff strcpy(device, _PATH_DEV); 388219820Sjeff strcat(device, devname); 389219820Sjeff devname = device; 390219820Sjeff } 391219820Sjeff if (stat(devname, &mntdevstat) == 0 && 392219820Sjeff mntdevstat.st_rdev == devstat.st_rdev) 393219820Sjeff return (&mntbuf[i]); 394219820Sjeff } 395219820Sjeff return (NULL); 396219820Sjeff} 397219820Sjeff 398219820Sjeffstatic void 399219820Sjeffusage() 400219820Sjeff{ 401219820Sjeff extern char *__progname; 402219820Sjeff 403219820Sjeff (void) fprintf(stderr, 404219820Sjeff "Usage: %s [-dfnpy] [-B be|le] [-b block] [-c level] [-m mode] " 405219820Sjeff "filesystem ...\n", 406219820Sjeff __progname); 407219820Sjeff exit(1); 408219820Sjeff} 409219820Sjeff