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