1 /* 2 * Copyright (c) 1980, 1989 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, 1989 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.11 (Berkeley) 03/19/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(), *malloc(); 28 int catch(), catchquit(), voidquit(); 29 int returntosingle; 30 int (*signal())(); 31 32 struct part { 33 char *name; /* device name */ 34 char *fsname; /* mounted filesystem name */ 35 struct part *next; /* forward link of partitions on disk */ 36 } *badlist, **badnext = &badlist; 37 38 struct disk { 39 char *name; /* disk base name */ 40 struct disk *next; /* forward link for list of disks */ 41 struct part *part; /* head of list of partitions on disk */ 42 int pid; /* If != 0, pid of proc working on */ 43 } *disks; 44 45 int nrun, ndisks, maxrun; 46 47 main(argc, argv) 48 int argc; 49 char *argv[]; 50 { 51 struct fstab *fsp; 52 int pid, passno, sumstatus; 53 char *name; 54 register struct disk *dk, *nextdisk; 55 register struct part *pt; 56 57 sync(); 58 while (--argc > 0 && **++argv == '-') { 59 switch (*++*argv) { 60 61 case 'p': 62 preen++; 63 break; 64 65 case 'b': 66 if (argv[0][1] != '\0') { 67 bflag = atoi(argv[0]+1); 68 } else { 69 bflag = atoi(*++argv); 70 argc--; 71 } 72 printf("Alternate super block location: %d\n", bflag); 73 break; 74 75 case 'c': 76 cvtflag++; 77 break; 78 79 case 'd': 80 debug++; 81 break; 82 83 case 'l': 84 if (!isdigit(argv[1][0])) 85 errexit("-l flag requires a number\n"); 86 maxrun = atoi(*++argv); 87 argc--; 88 break; 89 90 case 'm': 91 if (!isdigit(argv[1][0])) 92 errexit("-m flag requires a mode\n"); 93 sscanf(*++argv, "%o", &lfmode); 94 if (lfmode &~ 07777) 95 errexit("bad mode to -m: %o\n", lfmode); 96 argc--; 97 printf("** lost+found creation mode %o\n", lfmode); 98 break; 99 100 case 'n': /* default no answer flag */ 101 case 'N': 102 nflag++; 103 yflag = 0; 104 break; 105 106 case 'y': /* default yes answer flag */ 107 case 'Y': 108 yflag++; 109 nflag = 0; 110 break; 111 112 default: 113 errexit("%c option?\n", **argv); 114 } 115 } 116 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 117 (void)signal(SIGINT, catch); 118 if (preen) 119 (void)signal(SIGQUIT, catchquit); 120 if (argc) { 121 while (argc-- > 0) { 122 hotroot = 0; 123 checkfilesys(*argv++); 124 } 125 exit(0); 126 } 127 sumstatus = 0; 128 for (passno = 1; passno <= 2; passno++) { 129 if (setfsent() == 0) 130 errexit("Can't open checklist file: %s\n", FSTAB); 131 while ((fsp = getfsent()) != 0) { 132 if (strcmp(fsp->fs_type, FSTAB_RW) && 133 strcmp(fsp->fs_type, FSTAB_RO) && 134 strcmp(fsp->fs_type, FSTAB_RQ)) 135 continue; 136 if (preen == 0 || 137 passno == 1 && fsp->fs_passno == 1) { 138 name = blockcheck(fsp->fs_spec); 139 if (name != NULL) 140 checkfilesys(name); 141 else if (preen) 142 exit(8); 143 } else if (passno == 2 && fsp->fs_passno > 1) { 144 name = blockcheck(fsp->fs_spec); 145 if (name == NULL) { 146 pwarn("BAD DISK NAME %s\n", 147 fsp->fs_spec); 148 sumstatus |= 8; 149 continue; 150 } 151 addpart(name, fsp->fs_file); 152 } 153 } 154 } 155 if (preen) { 156 union wait status; 157 158 if (maxrun == 0) 159 maxrun = ndisks; 160 if (maxrun > ndisks) 161 maxrun = ndisks; 162 nextdisk = disks; 163 for (passno = 0; passno < maxrun; ++passno) { 164 startdisk(nextdisk); 165 nextdisk = nextdisk->next; 166 } 167 while ((pid = wait(&status)) != -1) { 168 if (status.w_termsig) 169 sumstatus |= 8; 170 else 171 sumstatus |= status.w_retcode; 172 for (dk = disks; dk; dk = dk->next) 173 if (dk->pid == pid) 174 break; 175 if (dk == 0) { 176 printf("Unknown pid %d\n", pid); 177 continue; 178 } 179 if (status.w_termsig) { 180 printf("%s (%s): EXITED WITH SIGNAL %d\n", 181 dk->part->name, dk->part->fsname, 182 status.w_termsig); 183 status.w_retcode = 8; 184 } 185 if (status.w_retcode != 0) { 186 *badnext = dk->part; 187 badnext = &dk->part->next; 188 dk->part = dk->part->next; 189 *badnext = NULL; 190 } else 191 dk->part = dk->part->next; 192 dk->pid = 0; 193 nrun--; 194 if (dk->part == NULL) 195 ndisks--; 196 197 if (nextdisk == NULL) { 198 if (dk->part) 199 startdisk(dk); 200 } else if (nrun < maxrun && nrun < ndisks) { 201 for ( ;; ) { 202 if ((nextdisk = nextdisk->next) == NULL) 203 nextdisk = disks; 204 if (nextdisk->part != NULL && 205 nextdisk->pid == 0) 206 break; 207 } 208 startdisk(nextdisk); 209 } 210 } 211 } 212 if (sumstatus) { 213 if (badlist == 0) 214 exit(8); 215 printf("THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 216 badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:"); 217 for (pt = badlist; pt; pt = pt->next) 218 printf("%s (%s)%s", pt->name, pt->fsname, 219 pt->next ? ", " : "\n"); 220 exit(8); 221 } 222 (void)endfsent(); 223 if (returntosingle) 224 exit(2); 225 exit(0); 226 } 227 228 struct disk * 229 finddisk(name) 230 char *name; 231 { 232 register struct disk *dk, **dkp; 233 register char *p; 234 int len; 235 236 for (p = name + strlen(name) - 1; p >= name; --p) 237 if (isdigit(*p)) { 238 len = p - name + 1; 239 break; 240 } 241 if (p < name) 242 len = strlen(name); 243 244 for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) { 245 if (strncmp(dk->name, name, len) == 0 && 246 dk->name[len] == 0) 247 return (dk); 248 } 249 if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) 250 errexit("out of memory"); 251 dk = *dkp; 252 if ((dk->name = malloc(len + 1)) == NULL) 253 errexit("out of memory"); 254 strncpy(dk->name, name, len); 255 dk->name[len] = '\0'; 256 dk->part = NULL; 257 dk->next = NULL; 258 dk->pid = 0; 259 ndisks++; 260 return (dk); 261 } 262 263 addpart(name, fsname) 264 char *name, *fsname; 265 { 266 struct disk *dk = finddisk(name); 267 register struct part *pt, **ppt = &dk->part; 268 269 for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next) 270 if (strcmp(pt->name, name) == 0) { 271 printf("%s in fstab more than once!\n", name); 272 return; 273 } 274 if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) 275 errexit("out of memory"); 276 pt = *ppt; 277 if ((pt->name = malloc(strlen(name) + 1)) == NULL) 278 errexit("out of memory"); 279 strcpy(pt->name, name); 280 if ((pt->fsname = malloc(strlen(fsname) + 1)) == NULL) 281 errexit("out of memory"); 282 strcpy(pt->fsname, fsname); 283 pt->next = NULL; 284 } 285 286 startdisk(dk) 287 register struct disk *dk; 288 { 289 290 nrun++; 291 dk->pid = fork(); 292 if (dk->pid < 0) { 293 perror("fork"); 294 exit(8); 295 } 296 if (dk->pid == 0) { 297 (void)signal(SIGQUIT, voidquit); 298 checkfilesys(dk->part->name); 299 exit(0); 300 } 301 } 302 303 checkfilesys(filesys) 304 char *filesys; 305 { 306 daddr_t n_ffree, n_bfree; 307 struct dups *dp; 308 struct zlncnt *zlnp; 309 310 devname = filesys; 311 if (debug && preen) 312 pwarn("starting\n"); 313 if (setup(filesys) == 0) { 314 if (preen) 315 pfatal("CAN'T CHECK FILE SYSTEM."); 316 return; 317 } 318 /* 319 * 1: scan inodes tallying blocks used 320 */ 321 if (preen == 0) { 322 printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 323 if (hotroot) 324 printf("** Root file system\n"); 325 printf("** Phase 1 - Check Blocks and Sizes\n"); 326 } 327 pass1(); 328 329 /* 330 * 1b: locate first references to duplicates, if any 331 */ 332 if (duplist) { 333 if (preen) 334 pfatal("INTERNAL ERROR: dups with -p"); 335 printf("** Phase 1b - Rescan For More DUPS\n"); 336 pass1b(); 337 } 338 339 /* 340 * 2: traverse directories from root to mark all connected directories 341 */ 342 if (preen == 0) 343 printf("** Phase 2 - Check Pathnames\n"); 344 pass2(); 345 346 /* 347 * 3: scan inodes looking for disconnected directories 348 */ 349 if (preen == 0) 350 printf("** Phase 3 - Check Connectivity\n"); 351 pass3(); 352 353 /* 354 * 4: scan inodes looking for disconnected files; check reference counts 355 */ 356 if (preen == 0) 357 printf("** Phase 4 - Check Reference Counts\n"); 358 pass4(); 359 360 /* 361 * 5: check and repair resource counts in cylinder groups 362 */ 363 if (preen == 0) 364 printf("** Phase 5 - Check Cyl groups\n"); 365 pass5(); 366 367 /* 368 * print out summary statistics 369 */ 370 n_ffree = sblock.fs_cstotal.cs_nffree; 371 n_bfree = sblock.fs_cstotal.cs_nbfree; 372 pwarn("%d files, %d used, %d free ", 373 n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); 374 printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", 375 n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize); 376 if (debug && (n_files -= imax - ROOTINO - sblock.fs_cstotal.cs_nifree)) 377 printf("%d files missing\n", n_files); 378 if (debug) { 379 n_blks += sblock.fs_ncg * 380 (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 381 n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 382 n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 383 if (n_blks -= fmax - (n_ffree + sblock.fs_frag * n_bfree)) 384 printf("%d blocks missing\n", n_blks); 385 if (duplist != NULL) { 386 printf("The following duplicate blocks remain:"); 387 for (dp = duplist; dp; dp = dp->next) 388 printf(" %d,", dp->dup); 389 printf("\n"); 390 } 391 if (zlnhead != NULL) { 392 printf("The following zero link count inodes remain:"); 393 for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) 394 printf(" %d,", zlnp->zlncnt); 395 printf("\n"); 396 } 397 } 398 zlnhead = (struct zlncnt *)0; 399 duplist = (struct dups *)0; 400 if (dfile.mod) { 401 (void)time(&sblock.fs_time); 402 sbdirty(); 403 } 404 ckfini(); 405 free(blockmap); 406 free(statemap); 407 free((char *)lncntp); 408 if (!dfile.mod) 409 return; 410 if (!preen) { 411 printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 412 if (hotroot) 413 printf("\n***** REBOOT UNIX *****\n"); 414 } 415 if (hotroot) { 416 sync(); 417 exit(4); 418 } 419 } 420 421 char * 422 blockcheck(name) 423 char *name; 424 { 425 struct stat stslash, stblock, stchar; 426 char *raw; 427 int looped = 0; 428 429 hotroot = 0; 430 if (stat("/", &stslash) < 0){ 431 perror("/"); 432 printf("Can't stat root\n"); 433 return (0); 434 } 435 retry: 436 if (stat(name, &stblock) < 0){ 437 perror(name); 438 printf("Can't stat %s\n", name); 439 return (0); 440 } 441 if ((stblock.st_mode & S_IFMT) == S_IFBLK) { 442 if (stslash.st_dev == stblock.st_rdev) { 443 hotroot++; 444 return (name); 445 } 446 raw = rawname(name); 447 if (stat(raw, &stchar) < 0){ 448 perror(raw); 449 printf("Can't stat %s\n", raw); 450 return (name); 451 } 452 if ((stchar.st_mode & S_IFMT) == S_IFCHR) 453 return (raw); 454 else { 455 printf("%s is not a character device\n", raw); 456 return (name); 457 } 458 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR) { 459 if (looped) { 460 printf("Can't make sense out of name %s\n", name); 461 return (0); 462 } 463 name = unrawname(name); 464 looped++; 465 goto retry; 466 } 467 printf("Can't make sense out of name %s\n", name); 468 return (0); 469 } 470 471 char * 472 unrawname(cp) 473 char *cp; 474 { 475 char *dp = rindex(cp, '/'); 476 struct stat stb; 477 478 if (dp == 0) 479 return (cp); 480 if (stat(cp, &stb) < 0) 481 return (cp); 482 if ((stb.st_mode&S_IFMT) != S_IFCHR) 483 return (cp); 484 if (*(dp+1) != 'r') 485 return (cp); 486 (void)strcpy(dp+1, dp+2); 487 return (cp); 488 } 489 490 char * 491 rawname(cp) 492 char *cp; 493 { 494 static char rawbuf[32]; 495 char *dp = rindex(cp, '/'); 496 497 if (dp == 0) 498 return (0); 499 *dp = 0; 500 (void)strcpy(rawbuf, cp); 501 *dp = '/'; 502 (void)strcat(rawbuf, "/r"); 503 (void)strcat(rawbuf, dp+1); 504 return (rawbuf); 505 } 506