11558Srgrimes/* 21558Srgrimes * Copyright (c) 1980, 1986, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 30114589Sobrien#if 0 311558Srgrimes#ifndef lint 327585Sbdestatic const char copyright[] = 331558Srgrimes"@(#) Copyright (c) 1980, 1986, 1993\n\ 341558Srgrimes The Regents of the University of California. All rights reserved.\n"; 351558Srgrimes#endif /* not lint */ 361558Srgrimes 371558Srgrimes#ifndef lint 3841477Sjulianstatic char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/14/95"; 39114589Sobrien#endif /* not lint */ 4041477Sjulian#endif 4193103Smarkm#include <sys/cdefs.h> 4293103Smarkm__FBSDID("$FreeBSD: stable/10/sbin/fsck_ffs/main.c 324675 2017-10-16 21:55:31Z mckusick $"); 4393103Smarkm 441558Srgrimes#include <sys/param.h> 4575557Smckusick#include <sys/file.h> 461558Srgrimes#include <sys/mount.h> 4740918Smjacob#include <sys/resource.h> 48217769Smckusick#include <sys/stat.h> 4986514Siedowse#include <sys/sysctl.h> 50172236Srodrigc#include <sys/uio.h> 5198542Smckusick#include <sys/disklabel.h> 5223675Speter 531558Srgrimes#include <ufs/ufs/dinode.h> 541558Srgrimes#include <ufs/ffs/fs.h> 5523675Speter 5623675Speter#include <err.h> 5755725Speter#include <errno.h> 581558Srgrimes#include <fstab.h> 59120901Smckusick#include <grp.h> 60307536Smckusick#include <inttypes.h> 61172236Srodrigc#include <mntopts.h> 6255725Speter#include <paths.h> 63101037Smux#include <stdint.h> 6486514Siedowse#include <string.h> 65217769Smckusick#include <time.h> 6623675Speter 671558Srgrimes#include "fsck.h" 681558Srgrimes 69260178Sscottlint restarts; 70260178Sscottl 7192839Simpstatic void usage(void) __dead2; 72307536Smckusickstatic intmax_t argtoimax(int flag, const char *req, const char *str, int base); 7392839Simpstatic int checkfilesys(char *filesys); 74171800Spjdstatic int chkdoreload(struct statfs *mntp); 7592839Simpstatic struct statfs *getmntpt(const char *); 7623675Speter 777585Sbdeint 7892839Simpmain(int argc, char *argv[]) 791558Srgrimes{ 801558Srgrimes int ch; 8141474Sjulian struct rlimit rlimit; 82126345Sscottl struct itimerval itimerval; 8366861Sadrian int ret = 0; 841558Srgrimes 851558Srgrimes sync(); 8666861Sadrian skipclean = 1; 87188110Smckusick inoopt = 0; 88260178Sscottl while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:npRrSyZ")) != -1) { 891558Srgrimes switch (ch) { 901558Srgrimes case 'b': 9166861Sadrian skipclean = 0; 92307536Smckusick bflag = argtoimax('b', "number", optarg, 10); 93307536Smckusick printf("Alternate super block location: %jd\n", bflag); 941558Srgrimes break; 951558Srgrimes 9674556Smckusick case 'B': 9774556Smckusick bkgrdflag = 1; 9874556Smckusick break; 9974556Smckusick 1001558Srgrimes case 'c': 10166861Sadrian skipclean = 0; 102307536Smckusick cvtlevel = argtoimax('c', "conversion level", optarg, 103307536Smckusick 10); 10498542Smckusick if (cvtlevel < 3) 10598542Smckusick errx(EEXIT, "cannot do level %d conversion", 10698542Smckusick cvtlevel); 1071558Srgrimes break; 1088871Srgrimes 1091558Srgrimes case 'd': 1101558Srgrimes debug++; 1111558Srgrimes break; 1121558Srgrimes 113221233Sdes case 'E': 114221233Sdes Eflag++; 115221233Sdes break; 116221233Sdes 1172153Sdg case 'f': 11866861Sadrian skipclean = 0; 1192153Sdg break; 1202153Sdg 12175927Smckusick case 'F': 12275927Smckusick bkgrdcheck = 1; 12375927Smckusick break; 12475927Smckusick 1251558Srgrimes case 'm': 126307536Smckusick lfmode = argtoimax('m', "mode", optarg, 8); 1271558Srgrimes if (lfmode &~ 07777) 12823675Speter errx(EEXIT, "bad mode to -m: %o", lfmode); 1291558Srgrimes printf("** lost+found creation mode %o\n", lfmode); 1301558Srgrimes break; 1311558Srgrimes 1321558Srgrimes case 'n': 1331558Srgrimes nflag++; 1341558Srgrimes yflag = 0; 1351558Srgrimes break; 1361558Srgrimes 13766861Sadrian case 'p': 13866861Sadrian preen++; 139187931Sobrien /*FALLTHROUGH*/ 140187931Sobrien 141187931Sobrien case 'C': 142187931Sobrien ckclean++; 14366861Sadrian break; 14466861Sadrian 145260178Sscottl case 'R': 146260178Sscottl wantrestart = 1; 147260178Sscottl break; 148188110Smckusick case 'r': 149188110Smckusick inoopt++; 150188110Smckusick break; 151188110Smckusick 152253822Sscottl case 'S': 153253822Sscottl surrender = 1; 154253822Sscottl break; 155253822Sscottl 1561558Srgrimes case 'y': 1571558Srgrimes yflag++; 1581558Srgrimes nflag = 0; 1591558Srgrimes break; 1601558Srgrimes 161250056Sdes case 'Z': 162250056Sdes Zflag++; 163250056Sdes break; 164250056Sdes 1651558Srgrimes default: 16666861Sadrian usage(); 1671558Srgrimes } 1681558Srgrimes } 1691558Srgrimes argc -= optind; 1701558Srgrimes argv += optind; 17166861Sadrian 17266861Sadrian if (!argc) 17366861Sadrian usage(); 17466861Sadrian 1751558Srgrimes if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1761558Srgrimes (void)signal(SIGINT, catch); 177187931Sobrien if (ckclean) 1781558Srgrimes (void)signal(SIGQUIT, catchquit); 17970050Siedowse signal(SIGINFO, infohandler); 180126345Sscottl if (bkgrdflag) { 181126345Sscottl signal(SIGALRM, alarmhandler); 182126345Sscottl itimerval.it_interval.tv_sec = 5; 183126345Sscottl itimerval.it_interval.tv_usec = 0; 184126345Sscottl itimerval.it_value.tv_sec = 5; 185126345Sscottl itimerval.it_value.tv_usec = 0; 186126345Sscottl setitimer(ITIMER_REAL, &itimerval, NULL); 187126345Sscottl } 18841474Sjulian /* 18941474Sjulian * Push up our allowed memory limit so we can cope 190102231Strhodes * with huge file systems. 19141474Sjulian */ 19241474Sjulian if (getrlimit(RLIMIT_DATA, &rlimit) == 0) { 19341474Sjulian rlimit.rlim_cur = rlimit.rlim_max; 19441474Sjulian (void)setrlimit(RLIMIT_DATA, &rlimit); 19541474Sjulian } 196260178Sscottl while (argc > 0) { 197260178Sscottl if (checkfilesys(*argv) == ERESTART) 198260178Sscottl continue; 199260178Sscottl argc--; 200260178Sscottl argv++; 201260178Sscottl } 20241474Sjulian 2031558Srgrimes if (returntosingle) 20466861Sadrian ret = 2; 2051558Srgrimes exit(ret); 2061558Srgrimes} 2071558Srgrimes 208307536Smckusickstatic intmax_t 209307536Smckusickargtoimax(int flag, const char *req, const char *str, int base) 2101558Srgrimes{ 2111558Srgrimes char *cp; 212307536Smckusick intmax_t ret; 2131558Srgrimes 214307536Smckusick ret = strtoimax(str, &cp, base); 2151558Srgrimes if (cp == str || *cp) 21623675Speter errx(EEXIT, "-%c flag requires a %s", flag, req); 2171558Srgrimes return (ret); 2181558Srgrimes} 2191558Srgrimes 2201558Srgrimes/* 221102231Strhodes * Check the specified file system. 2221558Srgrimes */ 2231558Srgrimes/* ARGSUSED */ 22423675Speterstatic int 22592839Simpcheckfilesys(char *filesys) 2261558Srgrimes{ 22798542Smckusick ufs2_daddr_t n_ffree, n_bfree; 2281558Srgrimes struct dups *dp; 22974556Smckusick struct statfs *mntp; 230120901Smckusick struct stat snapdir; 231120901Smckusick struct group *grp; 232172236Srodrigc struct iovec *iov; 233172236Srodrigc char errmsg[255]; 234324675Smckusick int ofsmodified; 235172236Srodrigc int iovlen; 236171800Spjd int cylno; 237241035Smdf intmax_t blks, files; 238101037Smux size_t size; 2391558Srgrimes 240172236Srodrigc iov = NULL; 241172236Srodrigc iovlen = 0; 242172236Srodrigc errmsg[0] = '\0'; 243260178Sscottl fsutilinit(); 244260178Sscottl fsckinit(); 245172236Srodrigc 2461558Srgrimes cdevname = filesys; 247187931Sobrien if (debug && ckclean) 2481558Srgrimes pwarn("starting\n"); 24975927Smckusick /* 25075927Smckusick * Make best effort to get the disk name. Check first to see 251102231Strhodes * if it is listed among the mounted file systems. Failing that 25275927Smckusick * check to see if it is listed in /etc/fstab. 25375927Smckusick */ 25475927Smckusick mntp = getmntpt(filesys); 25575927Smckusick if (mntp != NULL) 25675927Smckusick filesys = mntp->f_mntfromname; 25775927Smckusick else 25875927Smckusick filesys = blockcheck(filesys); 25975927Smckusick /* 26075927Smckusick * If -F flag specified, check to see whether a background check 26175927Smckusick * is possible and needed. If possible and needed, exit with 26275927Smckusick * status zero. Otherwise exit with status non-zero. A non-zero 26375927Smckusick * exit status will cause a foreground check to be run. 26475927Smckusick */ 26575557Smckusick sblock_init(); 26675927Smckusick if (bkgrdcheck) { 26775927Smckusick if ((fsreadfd = open(filesys, O_RDONLY)) < 0 || readsb(0) == 0) 26875927Smckusick exit(3); /* Cannot read superblock */ 26975927Smckusick close(fsreadfd); 270207141Sjeff /* Earlier background failed or journaled */ 271207141Sjeff if (sblock.fs_flags & (FS_NEEDSFSCK | FS_SUJ)) 272207141Sjeff exit(4); 27375927Smckusick if ((sblock.fs_flags & FS_DOSOFTDEP) == 0) 27475927Smckusick exit(5); /* Not running soft updates */ 27575927Smckusick size = MIBSIZE; 27675927Smckusick if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0) 27775927Smckusick exit(6); /* Lacks kernel support */ 27875927Smckusick if ((mntp == NULL && sblock.fs_clean == 1) || 27975927Smckusick (mntp != NULL && (sblock.fs_flags & FS_UNCLEAN) == 0)) 28075927Smckusick exit(7); /* Filesystem clean, report it now */ 28175927Smckusick exit(0); 28275927Smckusick } 283187931Sobrien if (ckclean && skipclean) { 284163845Spjd /* 285163845Spjd * If file system is gjournaled, check it here. 286163845Spjd */ 287163845Spjd if ((fsreadfd = open(filesys, O_RDONLY)) < 0 || readsb(0) == 0) 288163845Spjd exit(3); /* Cannot read superblock */ 289163845Spjd close(fsreadfd); 290163845Spjd if ((sblock.fs_flags & FS_GJOURNAL) != 0) { 291163845Spjd //printf("GJournaled file system detected on %s.\n", 292163845Spjd // filesys); 293163845Spjd if (sblock.fs_clean == 1) { 294163845Spjd pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); 295163845Spjd exit(0); 296163845Spjd } 297163845Spjd if ((sblock.fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) { 298163845Spjd gjournal_check(filesys); 299171800Spjd if (chkdoreload(mntp) == 0) 300171800Spjd exit(0); 301171800Spjd exit(4); 302163845Spjd } else { 303240405Sobrien pfatal( 304240405Sobrien "UNEXPECTED INCONSISTENCY, CANNOT RUN FAST FSCK\n"); 305163845Spjd } 306163845Spjd } 307163845Spjd } 30874556Smckusick /* 30974556Smckusick * If we are to do a background check: 310102231Strhodes * Get the mount point information of the file system 31174556Smckusick * create snapshot file 31274556Smckusick * return created snapshot file 31374556Smckusick * if not found, clear bkgrdflag and proceed with normal fsck 31474556Smckusick */ 31574556Smckusick if (bkgrdflag) { 31674556Smckusick if (mntp == NULL) { 31774556Smckusick bkgrdflag = 0; 31875557Smckusick pfatal("NOT MOUNTED, CANNOT RUN IN BACKGROUND\n"); 31974556Smckusick } else if ((mntp->f_flags & MNT_SOFTDEP) == 0) { 32074556Smckusick bkgrdflag = 0; 321240405Sobrien pfatal( 322240405Sobrien "NOT USING SOFT UPDATES, CANNOT RUN IN BACKGROUND\n"); 32374556Smckusick } else if ((mntp->f_flags & MNT_RDONLY) != 0) { 32474556Smckusick bkgrdflag = 0; 32575557Smckusick pfatal("MOUNTED READ-ONLY, CANNOT RUN IN BACKGROUND\n"); 32675557Smckusick } else if ((fsreadfd = open(filesys, O_RDONLY)) >= 0) { 32775557Smckusick if (readsb(0) != 0) { 328207141Sjeff if (sblock.fs_flags & (FS_NEEDSFSCK | FS_SUJ)) { 32975557Smckusick bkgrdflag = 0; 330240405Sobrien pfatal( 331240405Sobrien "UNEXPECTED INCONSISTENCY, CANNOT RUN IN BACKGROUND\n"); 33275557Smckusick } 33375557Smckusick if ((sblock.fs_flags & FS_UNCLEAN) == 0 && 334187931Sobrien skipclean && ckclean) { 33575557Smckusick /* 336102231Strhodes * file system is clean; 33775557Smckusick * skip snapshot and report it clean 33875557Smckusick */ 339240405Sobrien pwarn( 340240405Sobrien "FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); 34175557Smckusick goto clean; 34275557Smckusick } 34375557Smckusick } 34475557Smckusick close(fsreadfd); 34575557Smckusick } 34675557Smckusick if (bkgrdflag) { 347120901Smckusick snprintf(snapname, sizeof snapname, "%s/.snap", 34874556Smckusick mntp->f_mntonname); 349120901Smckusick if (stat(snapname, &snapdir) < 0) { 350120901Smckusick if (errno != ENOENT) { 351120901Smckusick bkgrdflag = 0; 352240405Sobrien pfatal( 353240405Sobrien "CANNOT FIND SNAPSHOT DIRECTORY %s: %s, CANNOT RUN IN BACKGROUND\n", 354240405Sobrien snapname, strerror(errno)); 355120901Smckusick } else if ((grp = getgrnam("operator")) == 0 || 356120901Smckusick mkdir(snapname, 0770) < 0 || 357120901Smckusick chown(snapname, -1, grp->gr_gid) < 0 || 358120901Smckusick chmod(snapname, 0770) < 0) { 359120901Smckusick bkgrdflag = 0; 360240405Sobrien pfatal( 361240405Sobrien "CANNOT CREATE SNAPSHOT DIRECTORY %s: %s, CANNOT RUN IN BACKGROUND\n", 362240405Sobrien snapname, strerror(errno)); 363120901Smckusick } 364120901Smckusick } else if (!S_ISDIR(snapdir.st_mode)) { 365120901Smckusick bkgrdflag = 0; 366240405Sobrien pfatal( 367240405Sobrien "%s IS NOT A DIRECTORY, CANNOT RUN IN BACKGROUND\n", 368240405Sobrien snapname); 369120901Smckusick } 370120901Smckusick } 371120901Smckusick if (bkgrdflag) { 372120901Smckusick snprintf(snapname, sizeof snapname, 373120901Smckusick "%s/.snap/fsck_snapshot", mntp->f_mntonname); 374172236Srodrigc build_iovec(&iov, &iovlen, "fstype", "ffs", 4); 375172236Srodrigc build_iovec(&iov, &iovlen, "from", snapname, 376172236Srodrigc (size_t)-1); 377172236Srodrigc build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, 378172236Srodrigc (size_t)-1); 379172236Srodrigc build_iovec(&iov, &iovlen, "errmsg", errmsg, 380172236Srodrigc sizeof(errmsg)); 381182027Srodrigc build_iovec(&iov, &iovlen, "update", NULL, 0); 382182027Srodrigc build_iovec(&iov, &iovlen, "snapshot", NULL, 0); 383172236Srodrigc 384186471Sobrien while (nmount(iov, iovlen, mntp->f_flags) < 0) { 38574556Smckusick if (errno == EEXIST && unlink(snapname) == 0) 38674556Smckusick continue; 38774556Smckusick bkgrdflag = 0; 388172236Srodrigc pfatal("CANNOT CREATE SNAPSHOT %s: %s %s\n", 389172236Srodrigc snapname, strerror(errno), errmsg); 39074556Smckusick break; 39174556Smckusick } 39274556Smckusick if (bkgrdflag != 0) 39374556Smckusick filesys = snapname; 39474556Smckusick } 39574556Smckusick } 39674556Smckusick 39723675Speter switch (setup(filesys)) { 39823675Speter case 0: 3991558Srgrimes if (preen) 4001558Srgrimes pfatal("CAN'T CHECK FILE SYSTEM."); 40141477Sjulian return (0); 40223675Speter case -1: 40375557Smckusick clean: 40486514Siedowse pwarn("clean, %ld free ", (long)(sblock.fs_cstotal.cs_nffree + 40586514Siedowse sblock.fs_frag * sblock.fs_cstotal.cs_nbfree)); 406241035Smdf printf("(%jd frags, %jd blocks, %.1f%% fragmentation)\n", 407241035Smdf (intmax_t)sblock.fs_cstotal.cs_nffree, 408241035Smdf (intmax_t)sblock.fs_cstotal.cs_nbfree, 40941477Sjulian sblock.fs_cstotal.cs_nffree * 100.0 / sblock.fs_dsize); 41031904Sbde return (0); 4112153Sdg } 412207141Sjeff /* 413207141Sjeff * Determine if we can and should do journal recovery. 414207141Sjeff */ 415209408Sdelphij if ((sblock.fs_flags & FS_SUJ) == FS_SUJ) { 416209408Sdelphij if ((sblock.fs_flags & FS_NEEDSFSCK) != FS_NEEDSFSCK && skipclean) { 417210793Sbz if (preen || reply("USE JOURNAL")) { 418209408Sdelphij if (suj_check(filesys) == 0) { 419209408Sdelphij printf("\n***** FILE SYSTEM MARKED CLEAN *****\n"); 420209408Sdelphij if (chkdoreload(mntp) == 0) 421209408Sdelphij exit(0); 422209408Sdelphij exit(4); 423209408Sdelphij } 424207141Sjeff } 425209408Sdelphij printf("** Skipping journal, falling through to full fsck\n\n"); 426207141Sjeff } 427207141Sjeff /* 428207141Sjeff * Write the superblock so we don't try to recover the 429324675Smckusick * journal on another pass. If this is the only change 430324675Smckusick * to the filesystem, we do not want it to be called 431324675Smckusick * out as modified. 432207141Sjeff */ 433207141Sjeff sblock.fs_mtime = time(NULL); 434207141Sjeff sbdirty(); 435324675Smckusick ofsmodified = fsmodified; 436324675Smckusick flush(fswritefd, &sblk); 437324675Smckusick fsmodified = ofsmodified; 438207141Sjeff } 439221110Sdes 44055275Speter /* 44134266Sjulian * Cleared if any questions answered no. Used to decide if 44234266Sjulian * the superblock should be marked clean. 44334266Sjulian */ 44434266Sjulian resolved = 1; 44534266Sjulian /* 4461558Srgrimes * 1: scan inodes tallying blocks used 4471558Srgrimes */ 4481558Srgrimes if (preen == 0) { 4491558Srgrimes printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 45074556Smckusick if (mntp != NULL && mntp->f_flags & MNT_ROOTFS) 451102231Strhodes printf("** Root file system\n"); 4521558Srgrimes printf("** Phase 1 - Check Blocks and Sizes\n"); 4531558Srgrimes } 454247212Smckusick clock_gettime(CLOCK_REALTIME_PRECISE, &startprog); 4551558Srgrimes pass1(); 456247212Smckusick IOstats("Pass1"); 4571558Srgrimes 4581558Srgrimes /* 4591558Srgrimes * 1b: locate first references to duplicates, if any 4601558Srgrimes */ 4611558Srgrimes if (duplist) { 46234266Sjulian if (preen || usedsoftdep) 463201708Smckusick pfatal("INTERNAL ERROR: dups with %s%s%s", 464201708Smckusick preen ? "-p" : "", 465201708Smckusick (preen && usedsoftdep) ? " and " : "", 466201708Smckusick usedsoftdep ? "softupdates" : ""); 4671558Srgrimes printf("** Phase 1b - Rescan For More DUPS\n"); 4681558Srgrimes pass1b(); 469247212Smckusick IOstats("Pass1b"); 4701558Srgrimes } 4711558Srgrimes 4721558Srgrimes /* 4731558Srgrimes * 2: traverse directories from root to mark all connected directories 4741558Srgrimes */ 4751558Srgrimes if (preen == 0) 4761558Srgrimes printf("** Phase 2 - Check Pathnames\n"); 4771558Srgrimes pass2(); 478247212Smckusick IOstats("Pass2"); 4791558Srgrimes 4801558Srgrimes /* 4811558Srgrimes * 3: scan inodes looking for disconnected directories 4821558Srgrimes */ 4831558Srgrimes if (preen == 0) 4841558Srgrimes printf("** Phase 3 - Check Connectivity\n"); 4851558Srgrimes pass3(); 486247212Smckusick IOstats("Pass3"); 4871558Srgrimes 4881558Srgrimes /* 4891558Srgrimes * 4: scan inodes looking for disconnected files; check reference counts 4901558Srgrimes */ 4911558Srgrimes if (preen == 0) 4921558Srgrimes printf("** Phase 4 - Check Reference Counts\n"); 4931558Srgrimes pass4(); 494247212Smckusick IOstats("Pass4"); 4951558Srgrimes 4961558Srgrimes /* 4971558Srgrimes * 5: check and repair resource counts in cylinder groups 4981558Srgrimes */ 4991558Srgrimes if (preen == 0) 5001558Srgrimes printf("** Phase 5 - Check Cyl groups\n"); 5011558Srgrimes pass5(); 502247212Smckusick IOstats("Pass5"); 5031558Srgrimes 5041558Srgrimes /* 5051558Srgrimes * print out summary statistics 5061558Srgrimes */ 5071558Srgrimes n_ffree = sblock.fs_cstotal.cs_nffree; 5081558Srgrimes n_bfree = sblock.fs_cstotal.cs_nbfree; 50974556Smckusick files = maxino - ROOTINO - sblock.fs_cstotal.cs_nifree - n_files; 51074556Smckusick blks = n_blks + 51174556Smckusick sblock.fs_ncg * (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 51274556Smckusick blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 51374556Smckusick blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 51474556Smckusick blks = maxfsblock - (n_ffree + sblock.fs_frag * n_bfree) - blks; 51574556Smckusick if (bkgrdflag && (files > 0 || blks > 0)) { 51674556Smckusick countdirs = sblock.fs_cstotal.cs_ndir - countdirs; 517241035Smdf pwarn("Reclaimed: %ld directories, %jd files, %jd fragments\n", 518241035Smdf countdirs, files - countdirs, blks); 51974556Smckusick } 520101037Smux pwarn("%ld files, %jd used, %ju free ", 521101037Smux (long)n_files, (intmax_t)n_blks, 522101037Smux (uintmax_t)n_ffree + sblock.fs_frag * n_bfree); 523101037Smux printf("(%ju frags, %ju blocks, %.1f%% fragmentation)\n", 524101037Smux (uintmax_t)n_ffree, (uintmax_t)n_bfree, 525101037Smux n_ffree * 100.0 / sblock.fs_dsize); 5261558Srgrimes if (debug) { 52774556Smckusick if (files < 0) 528241035Smdf printf("%jd inodes missing\n", -files); 52974556Smckusick if (blks < 0) 530241035Smdf printf("%jd blocks missing\n", -blks); 5311558Srgrimes if (duplist != NULL) { 5321558Srgrimes printf("The following duplicate blocks remain:"); 5331558Srgrimes for (dp = duplist; dp; dp = dp->next) 534241035Smdf printf(" %jd,", (intmax_t)dp->dup); 5351558Srgrimes printf("\n"); 5361558Srgrimes } 5371558Srgrimes } 5381558Srgrimes duplist = (struct dups *)0; 5391558Srgrimes muldup = (struct dups *)0; 5401558Srgrimes inocleanup(); 5412179Sdg if (fsmodified) { 54241474Sjulian sblock.fs_time = time(NULL); 5431558Srgrimes sbdirty(); 5441558Srgrimes } 5451558Srgrimes if (cvtlevel && sblk.b_dirty) { 5468871Srgrimes /* 5471558Srgrimes * Write out the duplicate super blocks 5481558Srgrimes */ 5491558Srgrimes for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 550163845Spjd blwrite(fswritefd, (char *)&sblock, 55198542Smckusick fsbtodb(&sblock, cgsblock(&sblock, cylno)), 55298542Smckusick SBLOCKSIZE); 5531558Srgrimes } 55434266Sjulian if (rerun) 55534266Sjulian resolved = 0; 556247212Smckusick finalIOstats(); 55755275Speter 55855725Speter /* 559102231Strhodes * Check to see if the file system is mounted read-write. 56055725Speter */ 56174556Smckusick if (bkgrdflag == 0 && mntp != NULL && (mntp->f_flags & MNT_RDONLY) == 0) 56255275Speter resolved = 0; 56334266Sjulian ckfini(resolved); 56441474Sjulian 56541474Sjulian for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 56641474Sjulian if (inostathead[cylno].il_stat != NULL) 56741474Sjulian free((char *)inostathead[cylno].il_stat); 56841474Sjulian free((char *)inostathead); 56941474Sjulian inostathead = NULL; 57041474Sjulian if (fsmodified && !preen) 5711558Srgrimes printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 572260178Sscottl if (rerun) { 573260178Sscottl if (wantrestart && (restarts++ < 10) && 574260178Sscottl (preen || reply("RESTART"))) 575260178Sscottl return (ERESTART); 57618808Sguido printf("\n***** PLEASE RERUN FSCK *****\n"); 577260178Sscottl } 578171800Spjd if (chkdoreload(mntp) != 0) { 57941474Sjulian if (!fsmodified) 58041474Sjulian return (0); 5811558Srgrimes if (!preen) 5821558Srgrimes printf("\n***** REBOOT NOW *****\n"); 5831558Srgrimes sync(); 5841558Srgrimes return (4); 5851558Srgrimes } 5861558Srgrimes return (0); 5871558Srgrimes} 58855275Speter 589171800Spjdstatic int 590171800Spjdchkdoreload(struct statfs *mntp) 591171800Spjd{ 592172236Srodrigc struct iovec *iov; 593172236Srodrigc int iovlen; 594172236Srodrigc char errmsg[255]; 595171800Spjd 596171800Spjd if (mntp == NULL) 597171800Spjd return (0); 598172236Srodrigc 599172236Srodrigc iov = NULL; 600172236Srodrigc iovlen = 0; 601172236Srodrigc errmsg[0] = '\0'; 602171800Spjd /* 603171800Spjd * We modified a mounted file system. Do a mount update on 604171800Spjd * it unless it is read-write, so we can continue using it 605171800Spjd * as safely as possible. 606171800Spjd */ 607171800Spjd if (mntp->f_flags & MNT_RDONLY) { 608172236Srodrigc build_iovec(&iov, &iovlen, "fstype", "ffs", 4); 609172236Srodrigc build_iovec(&iov, &iovlen, "from", mntp->f_mntfromname, 610172236Srodrigc (size_t)-1); 611172236Srodrigc build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, 612172236Srodrigc (size_t)-1); 613172236Srodrigc build_iovec(&iov, &iovlen, "errmsg", errmsg, 614172236Srodrigc sizeof(errmsg)); 615176822Srodrigc build_iovec(&iov, &iovlen, "update", NULL, 0); 616182027Srodrigc build_iovec(&iov, &iovlen, "reload", NULL, 0); 617177905Srodrigc /* 618177905Srodrigc * XX: We need the following line until we clean up 619177905Srodrigc * nmount parsing of root mounts and NFS root mounts. 620221110Sdes */ 621176822Srodrigc build_iovec(&iov, &iovlen, "ro", NULL, 0); 622186471Sobrien if (nmount(iov, iovlen, mntp->f_flags) == 0) { 623171800Spjd return (0); 624171800Spjd } 625172236Srodrigc pwarn("mount reload of '%s' failed: %s %s\n\n", 626172236Srodrigc mntp->f_mntonname, strerror(errno), errmsg); 627171800Spjd return (1); 628171800Spjd } 629171800Spjd return (0); 630171800Spjd} 631171800Spjd 63255275Speter/* 63375927Smckusick * Get the mount point information for name. 63455275Speter */ 63555275Speterstatic struct statfs * 63692839Simpgetmntpt(const char *name) 63755275Speter{ 63855725Speter struct stat devstat, mntdevstat; 63955725Speter char device[sizeof(_PATH_DEV) - 1 + MNAMELEN]; 640100935Sphk char *ddevname; 64175927Smckusick struct statfs *mntbuf, *statfsp; 64275927Smckusick int i, mntsize, isdev; 64355275Speter 64475927Smckusick if (stat(name, &devstat) != 0) 64555275Speter return (NULL); 64675927Smckusick if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode)) 64775927Smckusick isdev = 1; 64875927Smckusick else 64975927Smckusick isdev = 0; 65055275Speter mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 65155275Speter for (i = 0; i < mntsize; i++) { 65275927Smckusick statfsp = &mntbuf[i]; 653100935Sphk ddevname = statfsp->f_mntfromname; 654100935Sphk if (*ddevname != '/') { 655301782Sngie if (strlen(_PATH_DEV) + strlen(ddevname) + 1 > 656301782Sngie sizeof(statfsp->f_mntfromname)) 657301782Sngie continue; 65855725Speter strcpy(device, _PATH_DEV); 659100935Sphk strcat(device, ddevname); 66075927Smckusick strcpy(statfsp->f_mntfromname, device); 66155725Speter } 66275927Smckusick if (isdev == 0) { 66375927Smckusick if (strcmp(name, statfsp->f_mntonname)) 66475927Smckusick continue; 66575927Smckusick return (statfsp); 66675927Smckusick } 667100935Sphk if (stat(ddevname, &mntdevstat) == 0 && 66855725Speter mntdevstat.st_rdev == devstat.st_rdev) 66975927Smckusick return (statfsp); 67055275Speter } 67175927Smckusick statfsp = NULL; 67275927Smckusick return (statfsp); 67355275Speter} 67466861Sadrian 67566861Sadrianstatic void 67692839Simpusage(void) 67766861Sadrian{ 678221110Sdes (void) fprintf(stderr, 679240405Sobrien"usage: %s [-BEFfnpry] [-b block] [-c level] [-m mode] filesystem ...\n", 680221110Sdes getprogname()); 681221110Sdes exit(1); 68266861Sadrian} 683260178Sscottl 684260178Sscottlvoid 685260178Sscottlinfohandler(int sig __unused) 686260178Sscottl{ 687260178Sscottl got_siginfo = 1; 688260178Sscottl} 689260178Sscottl 690260178Sscottlvoid 691260178Sscottlalarmhandler(int sig __unused) 692260178Sscottl{ 693260178Sscottl got_sigalarm = 1; 694260178Sscottl} 695