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: releng/10.2/sbin/fsck_ffs/main.c 260178 2014-01-02 01:44:14Z scottl $"); 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> 60172236Srodrigc#include <mntopts.h> 6155725Speter#include <paths.h> 62101037Smux#include <stdint.h> 6386514Siedowse#include <string.h> 64217769Smckusick#include <time.h> 6523675Speter 661558Srgrimes#include "fsck.h" 671558Srgrimes 68260178Sscottlint restarts; 69260178Sscottl 7092839Simpstatic void usage(void) __dead2; 71100935Sphkstatic int argtoi(int flag, const char *req, const char *str, int base); 7292839Simpstatic int checkfilesys(char *filesys); 73171800Spjdstatic int chkdoreload(struct statfs *mntp); 7492839Simpstatic struct statfs *getmntpt(const char *); 7523675Speter 767585Sbdeint 7792839Simpmain(int argc, char *argv[]) 781558Srgrimes{ 791558Srgrimes int ch; 8041474Sjulian struct rlimit rlimit; 81126345Sscottl struct itimerval itimerval; 8266861Sadrian int ret = 0; 831558Srgrimes 841558Srgrimes sync(); 8566861Sadrian skipclean = 1; 86188110Smckusick inoopt = 0; 87260178Sscottl while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:npRrSyZ")) != -1) { 881558Srgrimes switch (ch) { 891558Srgrimes case 'b': 9066861Sadrian skipclean = 0; 911558Srgrimes bflag = argtoi('b', "number", optarg, 10); 921558Srgrimes printf("Alternate super block location: %d\n", bflag); 931558Srgrimes break; 941558Srgrimes 9574556Smckusick case 'B': 9674556Smckusick bkgrdflag = 1; 9774556Smckusick break; 9874556Smckusick 991558Srgrimes case 'c': 10066861Sadrian skipclean = 0; 1011558Srgrimes cvtlevel = argtoi('c', "conversion level", optarg, 10); 10298542Smckusick if (cvtlevel < 3) 10398542Smckusick errx(EEXIT, "cannot do level %d conversion", 10498542Smckusick cvtlevel); 1051558Srgrimes break; 1068871Srgrimes 1071558Srgrimes case 'd': 1081558Srgrimes debug++; 1091558Srgrimes break; 1101558Srgrimes 111221233Sdes case 'E': 112221233Sdes Eflag++; 113221233Sdes break; 114221233Sdes 1152153Sdg case 'f': 11666861Sadrian skipclean = 0; 1172153Sdg break; 1182153Sdg 11975927Smckusick case 'F': 12075927Smckusick bkgrdcheck = 1; 12175927Smckusick break; 12275927Smckusick 1231558Srgrimes case 'm': 1241558Srgrimes lfmode = argtoi('m', "mode", optarg, 8); 1251558Srgrimes if (lfmode &~ 07777) 12623675Speter errx(EEXIT, "bad mode to -m: %o", lfmode); 1271558Srgrimes printf("** lost+found creation mode %o\n", lfmode); 1281558Srgrimes break; 1291558Srgrimes 1301558Srgrimes case 'n': 1311558Srgrimes nflag++; 1321558Srgrimes yflag = 0; 1331558Srgrimes break; 1341558Srgrimes 13566861Sadrian case 'p': 13666861Sadrian preen++; 137187931Sobrien /*FALLTHROUGH*/ 138187931Sobrien 139187931Sobrien case 'C': 140187931Sobrien ckclean++; 14166861Sadrian break; 14266861Sadrian 143260178Sscottl case 'R': 144260178Sscottl wantrestart = 1; 145260178Sscottl break; 146188110Smckusick case 'r': 147188110Smckusick inoopt++; 148188110Smckusick break; 149188110Smckusick 150253822Sscottl case 'S': 151253822Sscottl surrender = 1; 152253822Sscottl break; 153253822Sscottl 1541558Srgrimes case 'y': 1551558Srgrimes yflag++; 1561558Srgrimes nflag = 0; 1571558Srgrimes break; 1581558Srgrimes 159250056Sdes case 'Z': 160250056Sdes Zflag++; 161250056Sdes break; 162250056Sdes 1631558Srgrimes default: 16466861Sadrian usage(); 1651558Srgrimes } 1661558Srgrimes } 1671558Srgrimes argc -= optind; 1681558Srgrimes argv += optind; 16966861Sadrian 17066861Sadrian if (!argc) 17166861Sadrian usage(); 17266861Sadrian 1731558Srgrimes if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1741558Srgrimes (void)signal(SIGINT, catch); 175187931Sobrien if (ckclean) 1761558Srgrimes (void)signal(SIGQUIT, catchquit); 17770050Siedowse signal(SIGINFO, infohandler); 178126345Sscottl if (bkgrdflag) { 179126345Sscottl signal(SIGALRM, alarmhandler); 180126345Sscottl itimerval.it_interval.tv_sec = 5; 181126345Sscottl itimerval.it_interval.tv_usec = 0; 182126345Sscottl itimerval.it_value.tv_sec = 5; 183126345Sscottl itimerval.it_value.tv_usec = 0; 184126345Sscottl setitimer(ITIMER_REAL, &itimerval, NULL); 185126345Sscottl } 18641474Sjulian /* 18741474Sjulian * Push up our allowed memory limit so we can cope 188102231Strhodes * with huge file systems. 18941474Sjulian */ 19041474Sjulian if (getrlimit(RLIMIT_DATA, &rlimit) == 0) { 19141474Sjulian rlimit.rlim_cur = rlimit.rlim_max; 19241474Sjulian (void)setrlimit(RLIMIT_DATA, &rlimit); 19341474Sjulian } 194260178Sscottl while (argc > 0) { 195260178Sscottl if (checkfilesys(*argv) == ERESTART) 196260178Sscottl continue; 197260178Sscottl argc--; 198260178Sscottl argv++; 199260178Sscottl } 20041474Sjulian 2011558Srgrimes if (returntosingle) 20266861Sadrian ret = 2; 2031558Srgrimes exit(ret); 2041558Srgrimes} 2051558Srgrimes 20623675Speterstatic int 207100935Sphkargtoi(int flag, const char *req, const char *str, int base) 2081558Srgrimes{ 2091558Srgrimes char *cp; 2101558Srgrimes int ret; 2111558Srgrimes 2121558Srgrimes ret = (int)strtol(str, &cp, base); 2131558Srgrimes if (cp == str || *cp) 21423675Speter errx(EEXIT, "-%c flag requires a %s", flag, req); 2151558Srgrimes return (ret); 2161558Srgrimes} 2171558Srgrimes 2181558Srgrimes/* 219102231Strhodes * Check the specified file system. 2201558Srgrimes */ 2211558Srgrimes/* ARGSUSED */ 22223675Speterstatic int 22392839Simpcheckfilesys(char *filesys) 2241558Srgrimes{ 22598542Smckusick ufs2_daddr_t n_ffree, n_bfree; 2261558Srgrimes struct dups *dp; 22774556Smckusick struct statfs *mntp; 228120901Smckusick struct stat snapdir; 229120901Smckusick struct group *grp; 230172236Srodrigc struct iovec *iov; 231172236Srodrigc char errmsg[255]; 232172236Srodrigc int iovlen; 233171800Spjd int cylno; 234241035Smdf intmax_t blks, files; 235101037Smux size_t size; 2361558Srgrimes 237172236Srodrigc iov = NULL; 238172236Srodrigc iovlen = 0; 239172236Srodrigc errmsg[0] = '\0'; 240260178Sscottl fsutilinit(); 241260178Sscottl fsckinit(); 242172236Srodrigc 2431558Srgrimes cdevname = filesys; 244187931Sobrien if (debug && ckclean) 2451558Srgrimes pwarn("starting\n"); 24675927Smckusick /* 24775927Smckusick * Make best effort to get the disk name. Check first to see 248102231Strhodes * if it is listed among the mounted file systems. Failing that 24975927Smckusick * check to see if it is listed in /etc/fstab. 25075927Smckusick */ 25175927Smckusick mntp = getmntpt(filesys); 25275927Smckusick if (mntp != NULL) 25375927Smckusick filesys = mntp->f_mntfromname; 25475927Smckusick else 25575927Smckusick filesys = blockcheck(filesys); 25675927Smckusick /* 25775927Smckusick * If -F flag specified, check to see whether a background check 25875927Smckusick * is possible and needed. If possible and needed, exit with 25975927Smckusick * status zero. Otherwise exit with status non-zero. A non-zero 26075927Smckusick * exit status will cause a foreground check to be run. 26175927Smckusick */ 26275557Smckusick sblock_init(); 26375927Smckusick if (bkgrdcheck) { 26475927Smckusick if ((fsreadfd = open(filesys, O_RDONLY)) < 0 || readsb(0) == 0) 26575927Smckusick exit(3); /* Cannot read superblock */ 26675927Smckusick close(fsreadfd); 267207141Sjeff /* Earlier background failed or journaled */ 268207141Sjeff if (sblock.fs_flags & (FS_NEEDSFSCK | FS_SUJ)) 269207141Sjeff exit(4); 27075927Smckusick if ((sblock.fs_flags & FS_DOSOFTDEP) == 0) 27175927Smckusick exit(5); /* Not running soft updates */ 27275927Smckusick size = MIBSIZE; 27375927Smckusick if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0) 27475927Smckusick exit(6); /* Lacks kernel support */ 27575927Smckusick if ((mntp == NULL && sblock.fs_clean == 1) || 27675927Smckusick (mntp != NULL && (sblock.fs_flags & FS_UNCLEAN) == 0)) 27775927Smckusick exit(7); /* Filesystem clean, report it now */ 27875927Smckusick exit(0); 27975927Smckusick } 280187931Sobrien if (ckclean && skipclean) { 281163845Spjd /* 282163845Spjd * If file system is gjournaled, check it here. 283163845Spjd */ 284163845Spjd if ((fsreadfd = open(filesys, O_RDONLY)) < 0 || readsb(0) == 0) 285163845Spjd exit(3); /* Cannot read superblock */ 286163845Spjd close(fsreadfd); 287163845Spjd if ((sblock.fs_flags & FS_GJOURNAL) != 0) { 288163845Spjd //printf("GJournaled file system detected on %s.\n", 289163845Spjd // filesys); 290163845Spjd if (sblock.fs_clean == 1) { 291163845Spjd pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); 292163845Spjd exit(0); 293163845Spjd } 294163845Spjd if ((sblock.fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) { 295163845Spjd gjournal_check(filesys); 296171800Spjd if (chkdoreload(mntp) == 0) 297171800Spjd exit(0); 298171800Spjd exit(4); 299163845Spjd } else { 300240405Sobrien pfatal( 301240405Sobrien "UNEXPECTED INCONSISTENCY, CANNOT RUN FAST FSCK\n"); 302163845Spjd } 303163845Spjd } 304163845Spjd } 30574556Smckusick /* 30674556Smckusick * If we are to do a background check: 307102231Strhodes * Get the mount point information of the file system 30874556Smckusick * create snapshot file 30974556Smckusick * return created snapshot file 31074556Smckusick * if not found, clear bkgrdflag and proceed with normal fsck 31174556Smckusick */ 31274556Smckusick if (bkgrdflag) { 31374556Smckusick if (mntp == NULL) { 31474556Smckusick bkgrdflag = 0; 31575557Smckusick pfatal("NOT MOUNTED, CANNOT RUN IN BACKGROUND\n"); 31674556Smckusick } else if ((mntp->f_flags & MNT_SOFTDEP) == 0) { 31774556Smckusick bkgrdflag = 0; 318240405Sobrien pfatal( 319240405Sobrien "NOT USING SOFT UPDATES, CANNOT RUN IN BACKGROUND\n"); 32074556Smckusick } else if ((mntp->f_flags & MNT_RDONLY) != 0) { 32174556Smckusick bkgrdflag = 0; 32275557Smckusick pfatal("MOUNTED READ-ONLY, CANNOT RUN IN BACKGROUND\n"); 32375557Smckusick } else if ((fsreadfd = open(filesys, O_RDONLY)) >= 0) { 32475557Smckusick if (readsb(0) != 0) { 325207141Sjeff if (sblock.fs_flags & (FS_NEEDSFSCK | FS_SUJ)) { 32675557Smckusick bkgrdflag = 0; 327240405Sobrien pfatal( 328240405Sobrien "UNEXPECTED INCONSISTENCY, CANNOT RUN IN BACKGROUND\n"); 32975557Smckusick } 33075557Smckusick if ((sblock.fs_flags & FS_UNCLEAN) == 0 && 331187931Sobrien skipclean && ckclean) { 33275557Smckusick /* 333102231Strhodes * file system is clean; 33475557Smckusick * skip snapshot and report it clean 33575557Smckusick */ 336240405Sobrien pwarn( 337240405Sobrien "FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); 33875557Smckusick goto clean; 33975557Smckusick } 34075557Smckusick } 34175557Smckusick close(fsreadfd); 34275557Smckusick } 34375557Smckusick if (bkgrdflag) { 344120901Smckusick snprintf(snapname, sizeof snapname, "%s/.snap", 34574556Smckusick mntp->f_mntonname); 346120901Smckusick if (stat(snapname, &snapdir) < 0) { 347120901Smckusick if (errno != ENOENT) { 348120901Smckusick bkgrdflag = 0; 349240405Sobrien pfatal( 350240405Sobrien "CANNOT FIND SNAPSHOT DIRECTORY %s: %s, CANNOT RUN IN BACKGROUND\n", 351240405Sobrien snapname, strerror(errno)); 352120901Smckusick } else if ((grp = getgrnam("operator")) == 0 || 353120901Smckusick mkdir(snapname, 0770) < 0 || 354120901Smckusick chown(snapname, -1, grp->gr_gid) < 0 || 355120901Smckusick chmod(snapname, 0770) < 0) { 356120901Smckusick bkgrdflag = 0; 357240405Sobrien pfatal( 358240405Sobrien "CANNOT CREATE SNAPSHOT DIRECTORY %s: %s, CANNOT RUN IN BACKGROUND\n", 359240405Sobrien snapname, strerror(errno)); 360120901Smckusick } 361120901Smckusick } else if (!S_ISDIR(snapdir.st_mode)) { 362120901Smckusick bkgrdflag = 0; 363240405Sobrien pfatal( 364240405Sobrien "%s IS NOT A DIRECTORY, CANNOT RUN IN BACKGROUND\n", 365240405Sobrien snapname); 366120901Smckusick } 367120901Smckusick } 368120901Smckusick if (bkgrdflag) { 369120901Smckusick snprintf(snapname, sizeof snapname, 370120901Smckusick "%s/.snap/fsck_snapshot", mntp->f_mntonname); 371172236Srodrigc build_iovec(&iov, &iovlen, "fstype", "ffs", 4); 372172236Srodrigc build_iovec(&iov, &iovlen, "from", snapname, 373172236Srodrigc (size_t)-1); 374172236Srodrigc build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, 375172236Srodrigc (size_t)-1); 376172236Srodrigc build_iovec(&iov, &iovlen, "errmsg", errmsg, 377172236Srodrigc sizeof(errmsg)); 378182027Srodrigc build_iovec(&iov, &iovlen, "update", NULL, 0); 379182027Srodrigc build_iovec(&iov, &iovlen, "snapshot", NULL, 0); 380172236Srodrigc 381186471Sobrien while (nmount(iov, iovlen, mntp->f_flags) < 0) { 38274556Smckusick if (errno == EEXIST && unlink(snapname) == 0) 38374556Smckusick continue; 38474556Smckusick bkgrdflag = 0; 385172236Srodrigc pfatal("CANNOT CREATE SNAPSHOT %s: %s %s\n", 386172236Srodrigc snapname, strerror(errno), errmsg); 38774556Smckusick break; 38874556Smckusick } 38974556Smckusick if (bkgrdflag != 0) 39074556Smckusick filesys = snapname; 39174556Smckusick } 39274556Smckusick } 39374556Smckusick 39423675Speter switch (setup(filesys)) { 39523675Speter case 0: 3961558Srgrimes if (preen) 3971558Srgrimes pfatal("CAN'T CHECK FILE SYSTEM."); 39841477Sjulian return (0); 39923675Speter case -1: 40075557Smckusick clean: 40186514Siedowse pwarn("clean, %ld free ", (long)(sblock.fs_cstotal.cs_nffree + 40286514Siedowse sblock.fs_frag * sblock.fs_cstotal.cs_nbfree)); 403241035Smdf printf("(%jd frags, %jd blocks, %.1f%% fragmentation)\n", 404241035Smdf (intmax_t)sblock.fs_cstotal.cs_nffree, 405241035Smdf (intmax_t)sblock.fs_cstotal.cs_nbfree, 40641477Sjulian sblock.fs_cstotal.cs_nffree * 100.0 / sblock.fs_dsize); 40731904Sbde return (0); 4082153Sdg } 409207141Sjeff /* 410207141Sjeff * Determine if we can and should do journal recovery. 411207141Sjeff */ 412209408Sdelphij if ((sblock.fs_flags & FS_SUJ) == FS_SUJ) { 413209408Sdelphij if ((sblock.fs_flags & FS_NEEDSFSCK) != FS_NEEDSFSCK && skipclean) { 414210793Sbz if (preen || reply("USE JOURNAL")) { 415209408Sdelphij if (suj_check(filesys) == 0) { 416209408Sdelphij printf("\n***** FILE SYSTEM MARKED CLEAN *****\n"); 417209408Sdelphij if (chkdoreload(mntp) == 0) 418209408Sdelphij exit(0); 419209408Sdelphij exit(4); 420209408Sdelphij } 421207141Sjeff } 422209408Sdelphij printf("** Skipping journal, falling through to full fsck\n\n"); 423207141Sjeff } 424207141Sjeff /* 425207141Sjeff * Write the superblock so we don't try to recover the 426207141Sjeff * journal on another pass. 427207141Sjeff */ 428207141Sjeff sblock.fs_mtime = time(NULL); 429207141Sjeff sbdirty(); 430207141Sjeff } 431221110Sdes 43255275Speter /* 43334266Sjulian * Cleared if any questions answered no. Used to decide if 43434266Sjulian * the superblock should be marked clean. 43534266Sjulian */ 43634266Sjulian resolved = 1; 43734266Sjulian /* 4381558Srgrimes * 1: scan inodes tallying blocks used 4391558Srgrimes */ 4401558Srgrimes if (preen == 0) { 4411558Srgrimes printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 44274556Smckusick if (mntp != NULL && mntp->f_flags & MNT_ROOTFS) 443102231Strhodes printf("** Root file system\n"); 4441558Srgrimes printf("** Phase 1 - Check Blocks and Sizes\n"); 4451558Srgrimes } 446247212Smckusick clock_gettime(CLOCK_REALTIME_PRECISE, &startprog); 4471558Srgrimes pass1(); 448247212Smckusick IOstats("Pass1"); 4491558Srgrimes 4501558Srgrimes /* 4511558Srgrimes * 1b: locate first references to duplicates, if any 4521558Srgrimes */ 4531558Srgrimes if (duplist) { 45434266Sjulian if (preen || usedsoftdep) 455201708Smckusick pfatal("INTERNAL ERROR: dups with %s%s%s", 456201708Smckusick preen ? "-p" : "", 457201708Smckusick (preen && usedsoftdep) ? " and " : "", 458201708Smckusick usedsoftdep ? "softupdates" : ""); 4591558Srgrimes printf("** Phase 1b - Rescan For More DUPS\n"); 4601558Srgrimes pass1b(); 461247212Smckusick IOstats("Pass1b"); 4621558Srgrimes } 4631558Srgrimes 4641558Srgrimes /* 4651558Srgrimes * 2: traverse directories from root to mark all connected directories 4661558Srgrimes */ 4671558Srgrimes if (preen == 0) 4681558Srgrimes printf("** Phase 2 - Check Pathnames\n"); 4691558Srgrimes pass2(); 470247212Smckusick IOstats("Pass2"); 4711558Srgrimes 4721558Srgrimes /* 4731558Srgrimes * 3: scan inodes looking for disconnected directories 4741558Srgrimes */ 4751558Srgrimes if (preen == 0) 4761558Srgrimes printf("** Phase 3 - Check Connectivity\n"); 4771558Srgrimes pass3(); 478247212Smckusick IOstats("Pass3"); 4791558Srgrimes 4801558Srgrimes /* 4811558Srgrimes * 4: scan inodes looking for disconnected files; check reference counts 4821558Srgrimes */ 4831558Srgrimes if (preen == 0) 4841558Srgrimes printf("** Phase 4 - Check Reference Counts\n"); 4851558Srgrimes pass4(); 486247212Smckusick IOstats("Pass4"); 4871558Srgrimes 4881558Srgrimes /* 4891558Srgrimes * 5: check and repair resource counts in cylinder groups 4901558Srgrimes */ 4911558Srgrimes if (preen == 0) 4921558Srgrimes printf("** Phase 5 - Check Cyl groups\n"); 4931558Srgrimes pass5(); 494247212Smckusick IOstats("Pass5"); 4951558Srgrimes 4961558Srgrimes /* 4971558Srgrimes * print out summary statistics 4981558Srgrimes */ 4991558Srgrimes n_ffree = sblock.fs_cstotal.cs_nffree; 5001558Srgrimes n_bfree = sblock.fs_cstotal.cs_nbfree; 50174556Smckusick files = maxino - ROOTINO - sblock.fs_cstotal.cs_nifree - n_files; 50274556Smckusick blks = n_blks + 50374556Smckusick sblock.fs_ncg * (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 50474556Smckusick blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 50574556Smckusick blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 50674556Smckusick blks = maxfsblock - (n_ffree + sblock.fs_frag * n_bfree) - blks; 50774556Smckusick if (bkgrdflag && (files > 0 || blks > 0)) { 50874556Smckusick countdirs = sblock.fs_cstotal.cs_ndir - countdirs; 509241035Smdf pwarn("Reclaimed: %ld directories, %jd files, %jd fragments\n", 510241035Smdf countdirs, files - countdirs, blks); 51174556Smckusick } 512101037Smux pwarn("%ld files, %jd used, %ju free ", 513101037Smux (long)n_files, (intmax_t)n_blks, 514101037Smux (uintmax_t)n_ffree + sblock.fs_frag * n_bfree); 515101037Smux printf("(%ju frags, %ju blocks, %.1f%% fragmentation)\n", 516101037Smux (uintmax_t)n_ffree, (uintmax_t)n_bfree, 517101037Smux n_ffree * 100.0 / sblock.fs_dsize); 5181558Srgrimes if (debug) { 51974556Smckusick if (files < 0) 520241035Smdf printf("%jd inodes missing\n", -files); 52174556Smckusick if (blks < 0) 522241035Smdf printf("%jd blocks missing\n", -blks); 5231558Srgrimes if (duplist != NULL) { 5241558Srgrimes printf("The following duplicate blocks remain:"); 5251558Srgrimes for (dp = duplist; dp; dp = dp->next) 526241035Smdf printf(" %jd,", (intmax_t)dp->dup); 5271558Srgrimes printf("\n"); 5281558Srgrimes } 5291558Srgrimes } 5301558Srgrimes duplist = (struct dups *)0; 5311558Srgrimes muldup = (struct dups *)0; 5321558Srgrimes inocleanup(); 5332179Sdg if (fsmodified) { 53441474Sjulian sblock.fs_time = time(NULL); 5351558Srgrimes sbdirty(); 5361558Srgrimes } 5371558Srgrimes if (cvtlevel && sblk.b_dirty) { 5388871Srgrimes /* 5391558Srgrimes * Write out the duplicate super blocks 5401558Srgrimes */ 5411558Srgrimes for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 542163845Spjd blwrite(fswritefd, (char *)&sblock, 54398542Smckusick fsbtodb(&sblock, cgsblock(&sblock, cylno)), 54498542Smckusick SBLOCKSIZE); 5451558Srgrimes } 54634266Sjulian if (rerun) 54734266Sjulian resolved = 0; 548247212Smckusick finalIOstats(); 54955275Speter 55055725Speter /* 551102231Strhodes * Check to see if the file system is mounted read-write. 55255725Speter */ 55374556Smckusick if (bkgrdflag == 0 && mntp != NULL && (mntp->f_flags & MNT_RDONLY) == 0) 55455275Speter resolved = 0; 55534266Sjulian ckfini(resolved); 55641474Sjulian 55741474Sjulian for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 55841474Sjulian if (inostathead[cylno].il_stat != NULL) 55941474Sjulian free((char *)inostathead[cylno].il_stat); 56041474Sjulian free((char *)inostathead); 56141474Sjulian inostathead = NULL; 56241474Sjulian if (fsmodified && !preen) 5631558Srgrimes printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 564260178Sscottl if (rerun) { 565260178Sscottl if (wantrestart && (restarts++ < 10) && 566260178Sscottl (preen || reply("RESTART"))) 567260178Sscottl return (ERESTART); 56818808Sguido printf("\n***** PLEASE RERUN FSCK *****\n"); 569260178Sscottl } 570171800Spjd if (chkdoreload(mntp) != 0) { 57141474Sjulian if (!fsmodified) 57241474Sjulian return (0); 5731558Srgrimes if (!preen) 5741558Srgrimes printf("\n***** REBOOT NOW *****\n"); 5751558Srgrimes sync(); 5761558Srgrimes return (4); 5771558Srgrimes } 5781558Srgrimes return (0); 5791558Srgrimes} 58055275Speter 581171800Spjdstatic int 582171800Spjdchkdoreload(struct statfs *mntp) 583171800Spjd{ 584172236Srodrigc struct iovec *iov; 585172236Srodrigc int iovlen; 586172236Srodrigc char errmsg[255]; 587171800Spjd 588171800Spjd if (mntp == NULL) 589171800Spjd return (0); 590172236Srodrigc 591172236Srodrigc iov = NULL; 592172236Srodrigc iovlen = 0; 593172236Srodrigc errmsg[0] = '\0'; 594171800Spjd /* 595171800Spjd * We modified a mounted file system. Do a mount update on 596171800Spjd * it unless it is read-write, so we can continue using it 597171800Spjd * as safely as possible. 598171800Spjd */ 599171800Spjd if (mntp->f_flags & MNT_RDONLY) { 600172236Srodrigc build_iovec(&iov, &iovlen, "fstype", "ffs", 4); 601172236Srodrigc build_iovec(&iov, &iovlen, "from", mntp->f_mntfromname, 602172236Srodrigc (size_t)-1); 603172236Srodrigc build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, 604172236Srodrigc (size_t)-1); 605172236Srodrigc build_iovec(&iov, &iovlen, "errmsg", errmsg, 606172236Srodrigc sizeof(errmsg)); 607176822Srodrigc build_iovec(&iov, &iovlen, "update", NULL, 0); 608182027Srodrigc build_iovec(&iov, &iovlen, "reload", NULL, 0); 609177905Srodrigc /* 610177905Srodrigc * XX: We need the following line until we clean up 611177905Srodrigc * nmount parsing of root mounts and NFS root mounts. 612221110Sdes */ 613176822Srodrigc build_iovec(&iov, &iovlen, "ro", NULL, 0); 614186471Sobrien if (nmount(iov, iovlen, mntp->f_flags) == 0) { 615171800Spjd return (0); 616171800Spjd } 617172236Srodrigc pwarn("mount reload of '%s' failed: %s %s\n\n", 618172236Srodrigc mntp->f_mntonname, strerror(errno), errmsg); 619171800Spjd return (1); 620171800Spjd } 621171800Spjd return (0); 622171800Spjd} 623171800Spjd 62455275Speter/* 62575927Smckusick * Get the mount point information for name. 62655275Speter */ 62755275Speterstatic struct statfs * 62892839Simpgetmntpt(const char *name) 62955275Speter{ 63055725Speter struct stat devstat, mntdevstat; 63155725Speter char device[sizeof(_PATH_DEV) - 1 + MNAMELEN]; 632100935Sphk char *ddevname; 63375927Smckusick struct statfs *mntbuf, *statfsp; 63475927Smckusick int i, mntsize, isdev; 63555275Speter 63675927Smckusick if (stat(name, &devstat) != 0) 63755275Speter return (NULL); 63875927Smckusick if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode)) 63975927Smckusick isdev = 1; 64075927Smckusick else 64175927Smckusick isdev = 0; 64255275Speter mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 64355275Speter for (i = 0; i < mntsize; i++) { 64475927Smckusick statfsp = &mntbuf[i]; 645100935Sphk ddevname = statfsp->f_mntfromname; 646100935Sphk if (*ddevname != '/') { 64755725Speter strcpy(device, _PATH_DEV); 648100935Sphk strcat(device, ddevname); 64975927Smckusick strcpy(statfsp->f_mntfromname, device); 65055725Speter } 65175927Smckusick if (isdev == 0) { 65275927Smckusick if (strcmp(name, statfsp->f_mntonname)) 65375927Smckusick continue; 65475927Smckusick return (statfsp); 65575927Smckusick } 656100935Sphk if (stat(ddevname, &mntdevstat) == 0 && 65755725Speter mntdevstat.st_rdev == devstat.st_rdev) 65875927Smckusick return (statfsp); 65955275Speter } 66075927Smckusick statfsp = NULL; 66175927Smckusick return (statfsp); 66255275Speter} 66366861Sadrian 66466861Sadrianstatic void 66592839Simpusage(void) 66666861Sadrian{ 667221110Sdes (void) fprintf(stderr, 668240405Sobrien"usage: %s [-BEFfnpry] [-b block] [-c level] [-m mode] filesystem ...\n", 669221110Sdes getprogname()); 670221110Sdes exit(1); 67166861Sadrian} 672260178Sscottl 673260178Sscottlvoid 674260178Sscottlinfohandler(int sig __unused) 675260178Sscottl{ 676260178Sscottl got_siginfo = 1; 677260178Sscottl} 678260178Sscottl 679260178Sscottlvoid 680260178Sscottlalarmhandler(int sig __unused) 681260178Sscottl{ 682260178Sscottl got_sigalarm = 1; 683260178Sscottl} 684