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