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