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