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