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.4 (Berkeley) 3/5/86"; 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 "fsck.h" 25: 26: char *rawname(), *unrawname(), *blockcheck(); 27: int catch(), catchquit(), voidquit(); 28: int returntosingle; 29: int (*signal())(); 30: 31: main(argc, argv) 32: int argc; 33: char *argv[]; 34: { 35: struct fstab *fsp; 36: int pid, passno, anygtr, sumstatus; 37: char *name; 38: 39: sync(); 40: while (--argc > 0 && **++argv == '-') { 41: switch (*++*argv) { 42: 43: case 'p': 44: preen++; 45: break; 46: 47: case 'b': 48: if (argv[0][1] != '\0') { 49: bflag = atoi(argv[0]+1); 50: } else { 51: bflag = atoi(*++argv); 52: argc--; 53: } 54: printf("Alternate super block location: %d\n", bflag); 55: break; 56: 57: case 'd': 58: debug++; 59: break; 60: 61: case 'n': /* default no answer flag */ 62: case 'N': 63: nflag++; 64: yflag = 0; 65: break; 66: 67: case 'y': /* default yes answer flag */ 68: case 'Y': 69: yflag++; 70: nflag = 0; 71: break; 72: 73: default: 74: errexit("%c option?\n", **argv); 75: } 76: } 77: if (signal(SIGINT, SIG_IGN) != SIG_IGN) 78: (void)signal(SIGINT, catch); 79: if (preen) 80: (void)signal(SIGQUIT, catchquit); 81: if (argc) { 82: while (argc-- > 0) { 83: hotroot = 0; 84: checkfilesys(*argv++); 85: } 86: exit(0); 87: } 88: sumstatus = 0; 89: passno = 1; 90: do { 91: anygtr = 0; 92: if (setfsent() == 0) 93: errexit("Can't open checklist file: %s\n", FSTAB); 94: while ((fsp = getfsent()) != 0) { 95: if (strcmp(fsp->fs_type, FSTAB_RW) && 96: strcmp(fsp->fs_type, FSTAB_RO) && 97: strcmp(fsp->fs_type, FSTAB_RQ)) 98: continue; 99: if (preen == 0 || 100: passno == 1 && fsp->fs_passno == passno) { 101: name = blockcheck(fsp->fs_spec); 102: if (name != NULL) 103: checkfilesys(name); 104: else if (preen) 105: exit(8); 106: } else if (fsp->fs_passno > passno) { 107: anygtr = 1; 108: } else if (fsp->fs_passno == passno) { 109: pid = fork(); 110: if (pid < 0) { 111: perror("fork"); 112: exit(8); 113: } 114: if (pid == 0) { 115: (void)signal(SIGQUIT, voidquit); 116: name = blockcheck(fsp->fs_spec); 117: if (name == NULL) 118: exit(8); 119: checkfilesys(name); 120: exit(0); 121: } 122: } 123: } 124: if (preen) { 125: union wait status; 126: while (wait(&status) != -1) 127: sumstatus |= status.w_retcode; 128: } 129: passno++; 130: } while (anygtr); 131: if (sumstatus) 132: exit(8); 133: (void)endfsent(); 134: if (returntosingle) 135: exit(2); 136: exit(0); 137: } 138: 139: checkfilesys(filesys) 140: char *filesys; 141: { 142: daddr_t n_ffree, n_bfree; 143: struct dups *dp; 144: struct zlncnt *zlnp; 145: 146: devname = filesys; 147: if (setup(filesys) == 0) { 148: if (preen) 149: pfatal("CAN'T CHECK FILE SYSTEM."); 150: return; 151: } 152: /* 153: * 1: scan inodes tallying blocks used 154: */ 155: if (preen == 0) { 156: printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 157: if (hotroot) 158: printf("** Root file system\n"); 159: printf("** Phase 1 - Check Blocks and Sizes\n"); 160: } 161: pass1(); 162: 163: /* 164: * 1b: locate first references to duplicates, if any 165: */ 166: if (duplist) { 167: if (preen) 168: pfatal("INTERNAL ERROR: dups with -p"); 169: printf("** Phase 1b - Rescan For More DUPS\n"); 170: pass1b(); 171: } 172: 173: /* 174: * 2: traverse directories from root to mark all connected directories 175: */ 176: if (preen == 0) 177: printf("** Phase 2 - Check Pathnames\n"); 178: pass2(); 179: 180: /* 181: * 3: scan inodes looking for disconnected directories 182: */ 183: if (preen == 0) 184: printf("** Phase 3 - Check Connectivity\n"); 185: pass3(); 186: 187: /* 188: * 4: scan inodes looking for disconnected files; check reference counts 189: */ 190: if (preen == 0) 191: printf("** Phase 4 - Check Reference Counts\n"); 192: pass4(); 193: 194: /* 195: * 5: check and repair resource counts in cylinder groups 196: */ 197: if (preen == 0) 198: printf("** Phase 5 - Check Cyl groups\n"); 199: pass5(); 200: 201: /* 202: * print out summary statistics 203: */ 204: n_ffree = sblock.fs_cstotal.cs_nffree; 205: n_bfree = sblock.fs_cstotal.cs_nbfree; 206: pwarn("%d files, %d used, %d free ", 207: n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); 208: printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", 209: n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize); 210: if (debug && (n_files -= imax - ROOTINO - sblock.fs_cstotal.cs_nifree)) 211: printf("%d files missing\n", n_files); 212: if (debug) { 213: n_blks += sblock.fs_ncg * 214: (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 215: n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 216: n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 217: if (n_blks -= fmax - (n_ffree + sblock.fs_frag * n_bfree)) 218: printf("%d blocks missing\n", n_blks); 219: if (duplist != NULL) { 220: printf("The following duplicate blocks remain:"); 221: for (dp = duplist; dp; dp = dp->next) 222: printf(" %d,", dp->dup); 223: printf("\n"); 224: } 225: if (zlnhead != NULL) { 226: printf("The following zero link count inodes remain:"); 227: for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) 228: printf(" %d,", zlnp->zlncnt); 229: printf("\n"); 230: } 231: } 232: zlnhead = (struct zlncnt *)0; 233: duplist = (struct dups *)0; 234: if (dfile.mod) { 235: (void)time(&sblock.fs_time); 236: sbdirty(); 237: } 238: ckfini(); 239: free(blockmap); 240: free(statemap); 241: free((char *)lncntp); 242: if (!dfile.mod) 243: return; 244: if (!preen) { 245: printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 246: if (hotroot) 247: printf("\n***** REBOOT UNIX *****\n"); 248: } 249: if (hotroot) { 250: sync(); 251: exit(4); 252: } 253: } 254: 255: char * 256: blockcheck(name) 257: char *name; 258: { 259: struct stat stslash, stblock, stchar; 260: char *raw; 261: int looped = 0; 262: 263: hotroot = 0; 264: if (stat("/", &stslash) < 0){ 265: printf("Can't stat root\n"); 266: return (0); 267: } 268: retry: 269: if (stat(name, &stblock) < 0){ 270: printf("Can't stat %s\n", name); 271: return (0); 272: } 273: if (stblock.st_mode & S_IFBLK) { 274: raw = rawname(name); 275: if (stat(raw, &stchar) < 0){ 276: printf("Can't stat %s\n", raw); 277: return (0); 278: } 279: if (stchar.st_mode & S_IFCHR) { 280: if (stslash.st_dev == stblock.st_rdev) { 281: hotroot++; 282: raw = unrawname(name); 283: } 284: return (raw); 285: } else { 286: printf("%s is not a character device\n", raw); 287: return (0); 288: } 289: } else if (stblock.st_mode & S_IFCHR) { 290: if (looped) { 291: printf("Can't make sense out of name %s\n", name); 292: return (0); 293: } 294: name = unrawname(name); 295: looped++; 296: goto retry; 297: } 298: printf("Can't make sense out of name %s\n", name); 299: return (0); 300: } 301: 302: char * 303: unrawname(cp) 304: char *cp; 305: { 306: char *dp = rindex(cp, '/'); 307: struct stat stb; 308: 309: if (dp == 0) 310: return (cp); 311: if (stat(cp, &stb) < 0) 312: return (cp); 313: if ((stb.st_mode&S_IFMT) != S_IFCHR) 314: return (cp); 315: if (*(dp+1) != 'r') 316: return (cp); 317: (void)strcpy(dp+1, dp+2); 318: return (cp); 319: } 320: 321: char * 322: rawname(cp) 323: char *cp; 324: { 325: static char rawbuf[32]; 326: char *dp = rindex(cp, '/'); 327: 328: if (dp == 0) 329: return (0); 330: *dp = 0; 331: (void)strcpy(rawbuf, cp); 332: *dp = '/'; 333: (void)strcat(rawbuf, "/r"); 334: (void)strcat(rawbuf, dp+1); 335: return (rawbuf); 336: }