1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)main.c 5.9 (Berkeley) 02/17/89"; 15 #endif not lint 16 17 #include <sys/param.h> 18 #include <sys/inode.h> 19 #include <sys/fs.h> 20 #include <sys/stat.h> 21 #include <sys/wait.h> 22 #include <fstab.h> 23 #include <strings.h> 24 #include <ctype.h> 25 #include "fsck.h" 26 27 char *rawname(), *unrawname(), *blockcheck(); 28 int catch(), catchquit(), voidquit(); 29 int returntosingle; 30 int (*signal())(); 31 32 main(argc, argv) 33 int argc; 34 char *argv[]; 35 { 36 struct fstab *fsp; 37 int pid, passno, anygtr, sumstatus; 38 char *name; 39 struct worklist { 40 int pid; /* pid of child doing the check */ 41 struct worklist *next; /* next in list */ 42 char name[MAXMNTLEN];/* name of file system */ 43 } *listhead = 0, *freelist = 0, *badlist = 0; 44 register struct worklist *wp, *pwp; 45 46 sync(); 47 while (--argc > 0 && **++argv == '-') { 48 switch (*++*argv) { 49 50 case 'p': 51 preen++; 52 break; 53 54 case 'b': 55 if (argv[0][1] != '\0') { 56 bflag = atoi(argv[0]+1); 57 } else { 58 bflag = atoi(*++argv); 59 argc--; 60 } 61 printf("Alternate super block location: %d\n", bflag); 62 break; 63 64 case 'c': 65 cvtflag++; 66 break; 67 68 case 'd': 69 debug++; 70 break; 71 72 case 'm': 73 if (!isdigit(argv[1][0])) 74 errexit("-m flag requires a mode\n"); 75 sscanf(*++argv, "%o", &lfmode); 76 if (lfmode &~ 07777) 77 errexit("bad mode to -m: %o\n", lfmode); 78 argc--; 79 printf("** lost+found creation mode %o\n", lfmode); 80 break; 81 82 case 'n': /* default no answer flag */ 83 case 'N': 84 nflag++; 85 yflag = 0; 86 break; 87 88 case 'y': /* default yes answer flag */ 89 case 'Y': 90 yflag++; 91 nflag = 0; 92 break; 93 94 default: 95 errexit("%c option?\n", **argv); 96 } 97 } 98 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 99 (void)signal(SIGINT, catch); 100 if (preen) 101 (void)signal(SIGQUIT, catchquit); 102 if (argc) { 103 while (argc-- > 0) { 104 hotroot = 0; 105 checkfilesys(*argv++); 106 } 107 exit(0); 108 } 109 sumstatus = 0; 110 passno = 1; 111 do { 112 anygtr = 0; 113 if (setfsent() == 0) 114 errexit("Can't open checklist file: %s\n", FSTAB); 115 while ((fsp = getfsent()) != 0) { 116 if (strcmp(fsp->fs_type, FSTAB_RW) && 117 strcmp(fsp->fs_type, FSTAB_RO) && 118 strcmp(fsp->fs_type, FSTAB_RQ)) 119 continue; 120 if (preen == 0 || 121 passno == 1 && fsp->fs_passno == passno) { 122 name = blockcheck(fsp->fs_spec); 123 if (name != NULL) 124 checkfilesys(name); 125 else if (preen) 126 exit(8); 127 } else if (fsp->fs_passno > passno) { 128 anygtr = 1; 129 } else if (fsp->fs_passno == passno) { 130 name = blockcheck(fsp->fs_spec); 131 if (name == NULL) { 132 pwarn("BAD DISK NAME %s\n", 133 fsp->fs_spec); 134 sumstatus |= 8; 135 continue; 136 } 137 pid = fork(); 138 if (pid < 0) { 139 perror("fork"); 140 exit(8); 141 } 142 if (pid == 0) { 143 (void)signal(SIGQUIT, voidquit); 144 checkfilesys(name); 145 exit(0); 146 } else { 147 if (freelist == 0) { 148 wp = (struct worklist *) malloc 149 (sizeof(struct worklist)); 150 } else { 151 wp = freelist; 152 freelist = wp->next; 153 } 154 wp->next = listhead; 155 listhead = wp; 156 wp->pid = pid; 157 sprintf(wp->name, "%s (%s)", name, 158 fsp->fs_file); 159 } 160 } 161 } 162 if (preen) { 163 union wait status; 164 while ((pid = wait(&status)) != -1) { 165 sumstatus |= status.w_retcode; 166 pwp = 0; 167 for (wp = listhead; wp; pwp = wp, wp = wp->next) 168 if (wp->pid == pid) 169 break; 170 if (wp == 0) { 171 printf("Unknown pid %d\n", pid); 172 continue; 173 } 174 if (pwp == 0) 175 listhead = wp->next; 176 else 177 pwp->next = wp->next; 178 if (status.w_retcode != 0) { 179 wp->next = badlist; 180 badlist = wp; 181 } else { 182 wp->next = freelist; 183 freelist = wp; 184 } 185 } 186 } 187 passno++; 188 } while (anygtr); 189 if (sumstatus) { 190 if (badlist == 0) 191 exit(8); 192 printf("THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 193 badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:"); 194 for (wp = badlist; wp; wp = wp->next) 195 printf("%s%s", wp->name, wp->next ? ", " : "\n"); 196 exit(8); 197 } 198 (void)endfsent(); 199 if (returntosingle) 200 exit(2); 201 exit(0); 202 } 203 204 checkfilesys(filesys) 205 char *filesys; 206 { 207 daddr_t n_ffree, n_bfree; 208 struct dups *dp; 209 struct zlncnt *zlnp; 210 211 devname = filesys; 212 if (setup(filesys) == 0) { 213 if (preen) 214 pfatal("CAN'T CHECK FILE SYSTEM."); 215 return; 216 } 217 /* 218 * 1: scan inodes tallying blocks used 219 */ 220 if (preen == 0) { 221 printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 222 if (hotroot) 223 printf("** Root file system\n"); 224 printf("** Phase 1 - Check Blocks and Sizes\n"); 225 } 226 pass1(); 227 228 /* 229 * 1b: locate first references to duplicates, if any 230 */ 231 if (duplist) { 232 if (preen) 233 pfatal("INTERNAL ERROR: dups with -p"); 234 printf("** Phase 1b - Rescan For More DUPS\n"); 235 pass1b(); 236 } 237 238 /* 239 * 2: traverse directories from root to mark all connected directories 240 */ 241 if (preen == 0) 242 printf("** Phase 2 - Check Pathnames\n"); 243 pass2(); 244 245 /* 246 * 3: scan inodes looking for disconnected directories 247 */ 248 if (preen == 0) 249 printf("** Phase 3 - Check Connectivity\n"); 250 pass3(); 251 252 /* 253 * 4: scan inodes looking for disconnected files; check reference counts 254 */ 255 if (preen == 0) 256 printf("** Phase 4 - Check Reference Counts\n"); 257 pass4(); 258 259 /* 260 * 5: check and repair resource counts in cylinder groups 261 */ 262 if (preen == 0) 263 printf("** Phase 5 - Check Cyl groups\n"); 264 pass5(); 265 266 /* 267 * print out summary statistics 268 */ 269 n_ffree = sblock.fs_cstotal.cs_nffree; 270 n_bfree = sblock.fs_cstotal.cs_nbfree; 271 pwarn("%d files, %d used, %d free ", 272 n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); 273 printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", 274 n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize); 275 if (debug && (n_files -= imax - ROOTINO - sblock.fs_cstotal.cs_nifree)) 276 printf("%d files missing\n", n_files); 277 if (debug) { 278 n_blks += sblock.fs_ncg * 279 (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 280 n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 281 n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 282 if (n_blks -= fmax - (n_ffree + sblock.fs_frag * n_bfree)) 283 printf("%d blocks missing\n", n_blks); 284 if (duplist != NULL) { 285 printf("The following duplicate blocks remain:"); 286 for (dp = duplist; dp; dp = dp->next) 287 printf(" %d,", dp->dup); 288 printf("\n"); 289 } 290 if (zlnhead != NULL) { 291 printf("The following zero link count inodes remain:"); 292 for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) 293 printf(" %d,", zlnp->zlncnt); 294 printf("\n"); 295 } 296 } 297 zlnhead = (struct zlncnt *)0; 298 duplist = (struct dups *)0; 299 if (dfile.mod) { 300 (void)time(&sblock.fs_time); 301 sbdirty(); 302 } 303 ckfini(); 304 free(blockmap); 305 free(statemap); 306 free((char *)lncntp); 307 if (!dfile.mod) 308 return; 309 if (!preen) { 310 printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 311 if (hotroot) 312 printf("\n***** REBOOT UNIX *****\n"); 313 } 314 if (hotroot) { 315 sync(); 316 exit(4); 317 } 318 } 319 320 char * 321 blockcheck(name) 322 char *name; 323 { 324 struct stat stslash, stblock, stchar; 325 char *raw; 326 int looped = 0; 327 328 hotroot = 0; 329 if (stat("/", &stslash) < 0){ 330 perror("/"); 331 printf("Can't stat root\n"); 332 return (0); 333 } 334 retry: 335 if (stat(name, &stblock) < 0){ 336 perror(name); 337 printf("Can't stat %s\n", name); 338 return (0); 339 } 340 if ((stblock.st_mode & S_IFMT) == S_IFBLK) { 341 if (stslash.st_dev == stblock.st_rdev) { 342 hotroot++; 343 return (name); 344 } 345 raw = rawname(name); 346 if (stat(raw, &stchar) < 0){ 347 perror(raw); 348 printf("Can't stat %s\n", raw); 349 return (name); 350 } 351 if ((stchar.st_mode & S_IFMT) == S_IFCHR) 352 return (raw); 353 else { 354 printf("%s is not a character device\n", raw); 355 return (name); 356 } 357 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR) { 358 if (looped) { 359 printf("Can't make sense out of name %s\n", name); 360 return (0); 361 } 362 name = unrawname(name); 363 looped++; 364 goto retry; 365 } 366 printf("Can't make sense out of name %s\n", name); 367 return (0); 368 } 369 370 char * 371 unrawname(cp) 372 char *cp; 373 { 374 char *dp = rindex(cp, '/'); 375 struct stat stb; 376 377 if (dp == 0) 378 return (cp); 379 if (stat(cp, &stb) < 0) 380 return (cp); 381 if ((stb.st_mode&S_IFMT) != S_IFCHR) 382 return (cp); 383 if (*(dp+1) != 'r') 384 return (cp); 385 (void)strcpy(dp+1, dp+2); 386 return (cp); 387 } 388 389 char * 390 rawname(cp) 391 char *cp; 392 { 393 static char rawbuf[32]; 394 char *dp = rindex(cp, '/'); 395 396 if (dp == 0) 397 return (0); 398 *dp = 0; 399 (void)strcpy(rawbuf, cp); 400 *dp = '/'; 401 (void)strcat(rawbuf, "/r"); 402 (void)strcat(rawbuf, dp+1); 403 return (rawbuf); 404 } 405