1 /* 2 * Copyright (c) 1980, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#) Copyright (c) 1980, 1986, 1993 The Regents of the University of California. All rights reserved. 30 * @(#)main.c 8.6 (Berkeley) 5/14/95 31 * $FreeBSD: src/sbin/fsck/main.c,v 1.21.2.1 2001/01/23 23:11:07 iedowse Exp $ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/stat.h> 36 #include <sys/time.h> 37 #include <sys/mount.h> 38 #include <sys/resource.h> 39 40 #include <vfs/ufs/dinode.h> 41 #include <vfs/ufs/ufsmount.h> 42 #include <vfs/ufs/fs.h> 43 44 #include <err.h> 45 #include <errno.h> 46 #include <fstab.h> 47 #include <paths.h> 48 #include <string.h> 49 50 #include "fsck.h" 51 52 static int argtoi(int flag, char *req, char *str, int base); 53 static int docheck(struct fstab *fsp); 54 static int checkfilesys(char *filesys, char *mntpt, long auxdata, 55 int child); 56 static struct statfs *getmntpt(const char *); 57 58 int 59 main(int argc, char **argv) 60 { 61 int ch; 62 int ret, maxrun = 0; 63 struct rlimit rlimit; 64 65 sync(); 66 while ((ch = getopt(argc, argv, "dfLpnNyYb:c:l:m:")) != -1) { 67 switch (ch) { 68 case 'p': 69 preen++; 70 break; 71 72 case 'b': 73 bflag = argtoi('b', "number", optarg, 10); 74 printf("Alternate super block location: %d\n", bflag); 75 break; 76 77 case 'c': 78 cvtlevel = argtoi('c', "conversion level", optarg, 10); 79 break; 80 81 case 'd': 82 debug++; 83 break; 84 85 case 'f': 86 fflag++; 87 break; 88 89 case 'l': 90 maxrun = argtoi('l', "number", optarg, 10); 91 break; 92 93 case 'L': 94 lastmntonly++; 95 break; 96 97 case 'm': 98 lfmode = argtoi('m', "mode", optarg, 8); 99 if (lfmode &~ 07777) 100 errx(EEXIT, "bad mode to -m: %o", lfmode); 101 printf("** lost+found creation mode %o\n", lfmode); 102 break; 103 104 case 'n': 105 case 'N': 106 nflag++; 107 yflag = 0; 108 break; 109 110 case 'y': 111 case 'Y': 112 yflag++; 113 nflag = 0; 114 break; 115 116 default: 117 errx(EEXIT, "%c option?", ch); 118 } 119 } 120 argc -= optind; 121 argv += optind; 122 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 123 signal(SIGINT, catch); 124 if (preen) 125 signal(SIGQUIT, catchquit); 126 signal(SIGINFO, infohandler); 127 /* 128 * Push up our allowed memory limit so we can cope 129 * with huge filesystems. 130 */ 131 if (getrlimit(RLIMIT_DATA, &rlimit) == 0) { 132 rlimit.rlim_cur = rlimit.rlim_max; 133 setrlimit(RLIMIT_DATA, &rlimit); 134 } 135 if (argc) { 136 while (argc-- > 0) { 137 char *path = blockcheck(*argv); 138 139 if (path == NULL) 140 pfatal("Can't check %s\n", *argv); 141 else 142 checkfilesys(path, 0, 0L, 0); 143 ++argv; 144 } 145 exit(0); 146 } 147 ret = checkfstab(preen, maxrun, docheck, checkfilesys); 148 if (returntosingle) 149 exit(2); 150 exit(ret); 151 } 152 153 static int 154 argtoi(int flag, char *req, char *str, int base) 155 { 156 char *cp; 157 int ret; 158 159 ret = (int)strtol(str, &cp, base); 160 if (cp == str || *cp) 161 errx(EEXIT, "-%c flag requires a %s", flag, req); 162 return (ret); 163 } 164 165 /* 166 * Determine whether a filesystem should be checked. 167 */ 168 static int 169 docheck(struct fstab *fsp) 170 { 171 172 if (strcmp(fsp->fs_vfstype, "ufs") || 173 (strcmp(fsp->fs_type, FSTAB_RW) && 174 strcmp(fsp->fs_type, FSTAB_RO)) || 175 fsp->fs_passno == 0) 176 return (0); 177 return (1); 178 } 179 180 /* 181 * Check the specified filesystem. 182 */ 183 /* ARGSUSED */ 184 static int 185 checkfilesys(char *filesys, char *mntpt, long auxdata, int child) 186 { 187 ufs_daddr_t n_ffree, n_bfree; 188 struct dups *dp; 189 struct statfs *mntbuf; 190 struct zlncnt *zlnp; 191 int cylno; 192 193 if (preen && child) 194 signal(SIGQUIT, voidquit); 195 cdevname = filesys; 196 if (debug && preen) 197 pwarn("starting\n"); 198 switch (setup(filesys)) { 199 case 0: 200 if (preen) 201 pfatal("CAN'T CHECK FILE SYSTEM."); 202 return (0); 203 case -1: 204 pwarn("clean, %d free ", sblock.fs_cstotal.cs_nffree + 205 sblock.fs_frag * sblock.fs_cstotal.cs_nbfree); 206 printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", 207 sblock.fs_cstotal.cs_nffree, sblock.fs_cstotal.cs_nbfree, 208 sblock.fs_cstotal.cs_nffree * 100.0 / sblock.fs_dsize); 209 return (0); 210 } 211 got_siginfo = 0; 212 213 /* 214 * Get the mount point information of the filesystem, if 215 * it is available. 216 */ 217 mntbuf = getmntpt(filesys); 218 219 /* 220 * Cleared if any questions answered no. Used to decide if 221 * the superblock should be marked clean. 222 */ 223 resolved = 1; 224 /* 225 * 1: scan inodes tallying blocks used 226 */ 227 if (lastmntonly) { 228 printf("** %s Last Mounted on %s\n", filesys, sblock.fs_fsmnt); 229 return (0); 230 } 231 if (preen == 0) { 232 printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 233 if (mntbuf != NULL && mntbuf->f_flags & MNT_ROOTFS) 234 printf("** Root file system\n"); 235 printf("** Phase 1 - Check Blocks and Sizes\n"); 236 } 237 pass1(); 238 239 /* 240 * 1b: locate first references to duplicates, if any 241 */ 242 if (duplist) { 243 if (preen || usedsoftdep) 244 pfatal("INTERNAL ERROR: dups with -p"); 245 printf("** Phase 1b - Rescan For More DUPS\n"); 246 pass1b(); 247 } 248 249 /* 250 * 2: traverse directories from root to mark all connected directories 251 */ 252 if (preen == 0) 253 printf("** Phase 2 - Check Pathnames\n"); 254 pass2(); 255 256 /* 257 * 3: scan inodes looking for disconnected directories 258 */ 259 if (preen == 0) 260 printf("** Phase 3 - Check Connectivity\n"); 261 pass3(); 262 263 /* 264 * 4: scan inodes looking for disconnected files; check reference counts 265 */ 266 if (preen == 0) 267 printf("** Phase 4 - Check Reference Counts\n"); 268 pass4(); 269 270 /* 271 * 5: check and repair resource counts in cylinder groups 272 */ 273 if (preen == 0) 274 printf("** Phase 5 - Check Cyl groups\n"); 275 pass5(); 276 277 /* 278 * print out summary statistics 279 */ 280 n_ffree = sblock.fs_cstotal.cs_nffree; 281 n_bfree = sblock.fs_cstotal.cs_nbfree; 282 pwarn("%d files, %d used, %d free ", 283 n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); 284 printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", 285 n_ffree, n_bfree, n_ffree * 100.0 / sblock.fs_dsize); 286 if (debug && 287 (n_files -= maxino - UFS_ROOTINO - sblock.fs_cstotal.cs_nifree)) 288 printf("%d files missing\n", n_files); 289 if (debug) { 290 n_blks += sblock.fs_ncg * 291 (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 292 n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 293 n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 294 if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree)) 295 printf("%d blocks missing\n", n_blks); 296 if (duplist != NULL) { 297 printf("The following duplicate blocks remain:"); 298 for (dp = duplist; dp; dp = dp->next) 299 printf(" %d,", dp->dup); 300 printf("\n"); 301 } 302 if (zlnhead != NULL) { 303 printf("The following zero link count inodes remain:"); 304 for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) 305 printf(" %u,", zlnp->zlncnt); 306 printf("\n"); 307 } 308 } 309 zlnhead = NULL; 310 duplist = NULL; 311 muldup = NULL; 312 inocleanup(); 313 if (fsmodified) { 314 sblock.fs_time = time(NULL); 315 sbdirty(); 316 } 317 if (cvtlevel && sblk.b_dirty) { 318 /* 319 * Write out the duplicate super blocks 320 */ 321 for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 322 bwrite(fswritefd, (char *)&sblock, 323 fsbtodb(&sblock, cgsblock(&sblock, cylno)), SBSIZE); 324 } 325 if (rerun) 326 resolved = 0; 327 328 /* 329 * Check to see if the filesystem is mounted read-write. 330 */ 331 if (mntbuf != NULL && (mntbuf->f_flags & MNT_RDONLY) == 0) 332 resolved = 0; 333 ckfini(resolved); 334 335 for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 336 if (inostathead[cylno].il_stat != NULL) 337 free((char *)inostathead[cylno].il_stat); 338 free((char *)inostathead); 339 inostathead = NULL; 340 if (fsmodified && !preen) 341 printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 342 if (rerun) 343 printf("\n***** PLEASE RERUN FSCK *****\n"); 344 if (mntbuf != NULL) { 345 struct ufs_args args; 346 int ret; 347 /* 348 * We modified a mounted filesystem. Do a mount update on 349 * it unless it is read-write, so we can continue using it 350 * as safely as possible. 351 */ 352 if (mntbuf->f_flags & MNT_RDONLY) { 353 args.fspec = 0; 354 args.export.ex_flags = 0; 355 args.export.ex_root = 0; 356 ret = mount("ufs", mntbuf->f_mntonname, 357 mntbuf->f_flags | MNT_UPDATE | MNT_RELOAD, &args); 358 if (ret == 0) 359 return (0); 360 pwarn("mount reload of '%s' failed: %s\n\n", 361 mntbuf->f_mntonname, strerror(errno)); 362 } 363 if (!fsmodified) 364 return (0); 365 if (!preen) 366 printf("\n***** REBOOT NOW *****\n"); 367 sync(); 368 return (4); 369 } 370 return (0); 371 } 372 373 /* 374 * Get the directory that the device is mounted on. 375 */ 376 static struct statfs * 377 getmntpt(const char *name) 378 { 379 struct stat devstat, mntdevstat; 380 char device[sizeof(_PATH_DEV) - 1 + MNAMELEN]; 381 char *devname; 382 struct statfs *mntbuf; 383 int i, mntsize; 384 385 if (stat(name, &devstat) != 0 || 386 !(S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode))) 387 return (NULL); 388 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 389 for (i = 0; i < mntsize; i++) { 390 if (strcmp(mntbuf[i].f_fstypename, "ufs") != 0) 391 continue; 392 devname = mntbuf[i].f_mntfromname; 393 if (*devname != '/') { 394 strcpy(device, _PATH_DEV); 395 strcat(device, devname); 396 devname = device; 397 } 398 if (stat(devname, &mntdevstat) == 0 && 399 mntdevstat.st_rdev == devstat.st_rdev) 400 return (&mntbuf[i]); 401 } 402 return (NULL); 403 } 404