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