122047Sdist /* 237216Skarels * Copyright (c) 1980, 1989 Regents of the University of California. 322047Sdist * All rights reserved. The Berkeley software License Agreement 422047Sdist * specifies the terms and conditions for redistribution. 522047Sdist */ 622047Sdist 712728Ssam #ifndef lint 822047Sdist char copyright[] = 937216Skarels "@(#) Copyright (c) 1980, 1989 Regents of the University of California.\n\ 1022047Sdist All rights reserved.\n"; 1122047Sdist #endif not lint 124428Smckusic 1322047Sdist #ifndef lint 14*39972Smckusick static char sccsid[] = "@(#)main.c 5.16 (Berkeley) 02/01/90"; 1522047Sdist #endif not lint 1622047Sdist 176489Smckusick #include <sys/param.h> 1839383Smckusick #include <ufs/dinode.h> 1938336Smckusick #include <ufs/fs.h> 2017930Smckusick #include <sys/stat.h> 2117930Smckusick #include <sys/wait.h> 2217930Smckusick #include <fstab.h> 2317930Smckusick #include <strings.h> 2436827Smckusick #include <ctype.h> 2516257Smckusick #include "fsck.h" 264236Smckusick 2737216Skarels char *rawname(), *unrawname(), *blockcheck(), *malloc(); 2839165Sbostic void catch(), catchquit(), voidquit(); 2924679Skarels int returntosingle; 3017930Smckusick 3137216Skarels struct part { 3237216Skarels char *name; /* device name */ 3337216Skarels char *fsname; /* mounted filesystem name */ 3437216Skarels struct part *next; /* forward link of partitions on disk */ 3537216Skarels } *badlist, **badnext = &badlist; 3637216Skarels 3737216Skarels struct disk { 3837216Skarels char *name; /* disk base name */ 3937216Skarels struct disk *next; /* forward link for list of disks */ 4037216Skarels struct part *part; /* head of list of partitions on disk */ 4137216Skarels int pid; /* If != 0, pid of proc working on */ 4237216Skarels } *disks; 4337216Skarels 4437216Skarels int nrun, ndisks, maxrun; 4537216Skarels 4617930Smckusick main(argc, argv) 4717930Smckusick int argc; 4817930Smckusick char *argv[]; 4917930Smckusick { 5017930Smckusick struct fstab *fsp; 5137216Skarels int pid, passno, sumstatus; 5217930Smckusick char *name; 5337216Skarels register struct disk *dk, *nextdisk; 5437216Skarels register struct part *pt; 5517930Smckusick 5617930Smckusick sync(); 5717930Smckusick while (--argc > 0 && **++argv == '-') { 5817930Smckusick switch (*++*argv) { 5917930Smckusick 6017930Smckusick case 'p': 6117930Smckusick preen++; 6217930Smckusick break; 6317930Smckusick 6417930Smckusick case 'b': 6517930Smckusick if (argv[0][1] != '\0') { 6617930Smckusick bflag = atoi(argv[0]+1); 6717930Smckusick } else { 6817930Smckusick bflag = atoi(*++argv); 6917930Smckusick argc--; 7017930Smckusick } 7117930Smckusick printf("Alternate super block location: %d\n", bflag); 7217930Smckusick break; 7317930Smckusick 7434139Smckusick case 'c': 7534139Smckusick cvtflag++; 7634139Smckusick break; 7734139Smckusick 7817930Smckusick case 'd': 7917930Smckusick debug++; 8017930Smckusick break; 8117930Smckusick 8237216Skarels case 'l': 8337216Skarels if (!isdigit(argv[1][0])) 8437216Skarels errexit("-l flag requires a number\n"); 8537216Skarels maxrun = atoi(*++argv); 8637216Skarels argc--; 8737216Skarels break; 8837216Skarels 8936827Smckusick case 'm': 9036827Smckusick if (!isdigit(argv[1][0])) 9136827Smckusick errexit("-m flag requires a mode\n"); 9236827Smckusick sscanf(*++argv, "%o", &lfmode); 9336827Smckusick if (lfmode &~ 07777) 9436827Smckusick errexit("bad mode to -m: %o\n", lfmode); 9536827Smckusick argc--; 9636827Smckusick printf("** lost+found creation mode %o\n", lfmode); 9736827Smckusick break; 9836827Smckusick 99*39972Smckusick case 'n': 10017930Smckusick case 'N': 10117930Smckusick nflag++; 10217930Smckusick yflag = 0; 10317930Smckusick break; 10417930Smckusick 105*39972Smckusick case 'y': 10617930Smckusick case 'Y': 10717930Smckusick yflag++; 10817930Smckusick nflag = 0; 10917930Smckusick break; 11017930Smckusick 11117930Smckusick default: 11217930Smckusick errexit("%c option?\n", **argv); 11317930Smckusick } 11417930Smckusick } 11517930Smckusick if (signal(SIGINT, SIG_IGN) != SIG_IGN) 11617930Smckusick (void)signal(SIGINT, catch); 11724679Skarels if (preen) 11824679Skarels (void)signal(SIGQUIT, catchquit); 11917930Smckusick if (argc) { 12017930Smckusick while (argc-- > 0) { 12117930Smckusick hotroot = 0; 12230565Skarels checkfilesys(*argv++); 12317930Smckusick } 12417930Smckusick exit(0); 12517930Smckusick } 12617930Smckusick sumstatus = 0; 12737216Skarels for (passno = 1; passno <= 2; passno++) { 12817930Smckusick if (setfsent() == 0) 12938336Smckusick errexit("Can't open checklist file: %s\n", _PATH_FSTAB); 13017930Smckusick while ((fsp = getfsent()) != 0) { 13117930Smckusick if (strcmp(fsp->fs_type, FSTAB_RW) && 13217930Smckusick strcmp(fsp->fs_type, FSTAB_RO) && 13317930Smckusick strcmp(fsp->fs_type, FSTAB_RQ)) 13417930Smckusick continue; 13517930Smckusick if (preen == 0 || 13637216Skarels passno == 1 && fsp->fs_passno == 1) { 13717930Smckusick name = blockcheck(fsp->fs_spec); 13817930Smckusick if (name != NULL) 13917930Smckusick checkfilesys(name); 14017930Smckusick else if (preen) 14117930Smckusick exit(8); 14237216Skarels } else if (passno == 2 && fsp->fs_passno > 1) { 14334159Smckusick name = blockcheck(fsp->fs_spec); 14434159Smckusick if (name == NULL) { 14534159Smckusick pwarn("BAD DISK NAME %s\n", 14634159Smckusick fsp->fs_spec); 14734159Smckusick sumstatus |= 8; 14834159Smckusick continue; 14934159Smckusick } 15037216Skarels addpart(name, fsp->fs_file); 15117930Smckusick } 15217930Smckusick } 15337216Skarels } 15437216Skarels if (preen) { 15537216Skarels union wait status; 15637216Skarels 15737216Skarels if (maxrun == 0) 15837216Skarels maxrun = ndisks; 15937216Skarels if (maxrun > ndisks) 16037216Skarels maxrun = ndisks; 16137216Skarels nextdisk = disks; 16237216Skarels for (passno = 0; passno < maxrun; ++passno) { 16337216Skarels startdisk(nextdisk); 16437216Skarels nextdisk = nextdisk->next; 16537216Skarels } 16637216Skarels while ((pid = wait(&status)) != -1) { 16737216Skarels for (dk = disks; dk; dk = dk->next) 16837216Skarels if (dk->pid == pid) 16937216Skarels break; 17037216Skarels if (dk == 0) { 17137216Skarels printf("Unknown pid %d\n", pid); 17237216Skarels continue; 17337216Skarels } 17437216Skarels if (status.w_termsig) { 17537216Skarels printf("%s (%s): EXITED WITH SIGNAL %d\n", 17637216Skarels dk->part->name, dk->part->fsname, 17737216Skarels status.w_termsig); 17837216Skarels status.w_retcode = 8; 17937216Skarels } 18037216Skarels if (status.w_retcode != 0) { 18138403Smckusick sumstatus |= status.w_retcode; 18237216Skarels *badnext = dk->part; 18337216Skarels badnext = &dk->part->next; 18437216Skarels dk->part = dk->part->next; 18537216Skarels *badnext = NULL; 18637216Skarels } else 18737216Skarels dk->part = dk->part->next; 18837216Skarels dk->pid = 0; 18937216Skarels nrun--; 19037216Skarels if (dk->part == NULL) 19137216Skarels ndisks--; 19237216Skarels 19337216Skarels if (nextdisk == NULL) { 19437216Skarels if (dk->part) 19537216Skarels startdisk(dk); 19637216Skarels } else if (nrun < maxrun && nrun < ndisks) { 19737216Skarels for ( ;; ) { 19837216Skarels if ((nextdisk = nextdisk->next) == NULL) 19937216Skarels nextdisk = disks; 20037216Skarels if (nextdisk->part != NULL && 20137216Skarels nextdisk->pid == 0) 20234159Smckusick break; 20334159Smckusick } 20437216Skarels startdisk(nextdisk); 20534159Smckusick } 20617930Smckusick } 20737216Skarels } 20834159Smckusick if (sumstatus) { 20934159Smckusick if (badlist == 0) 21034159Smckusick exit(8); 21134159Smckusick printf("THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t", 21234159Smckusick badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:"); 21337216Skarels for (pt = badlist; pt; pt = pt->next) 21437216Skarels printf("%s (%s)%s", pt->name, pt->fsname, 21537216Skarels pt->next ? ", " : "\n"); 21617930Smckusick exit(8); 21734159Smckusick } 21817930Smckusick (void)endfsent(); 21924679Skarels if (returntosingle) 22024679Skarels exit(2); 22117930Smckusick exit(0); 22217930Smckusick } 22317930Smckusick 22437216Skarels struct disk * 22537216Skarels finddisk(name) 22637216Skarels char *name; 22737216Skarels { 22837216Skarels register struct disk *dk, **dkp; 22937216Skarels register char *p; 23037216Skarels int len; 23137216Skarels 23237216Skarels for (p = name + strlen(name) - 1; p >= name; --p) 23337216Skarels if (isdigit(*p)) { 23437216Skarels len = p - name + 1; 23537216Skarels break; 23637216Skarels } 23737216Skarels if (p < name) 23837216Skarels len = strlen(name); 23937216Skarels 24037216Skarels for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) { 24137216Skarels if (strncmp(dk->name, name, len) == 0 && 24237216Skarels dk->name[len] == 0) 24337216Skarels return (dk); 24437216Skarels } 24537216Skarels if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) 24637216Skarels errexit("out of memory"); 24737216Skarels dk = *dkp; 248*39972Smckusick if ((dk->name = malloc((unsigned int)len + 1)) == NULL) 24937216Skarels errexit("out of memory"); 25037216Skarels strncpy(dk->name, name, len); 25137216Skarels dk->name[len] = '\0'; 25237216Skarels dk->part = NULL; 25337216Skarels dk->next = NULL; 25437216Skarels dk->pid = 0; 25537216Skarels ndisks++; 25637216Skarels return (dk); 25737216Skarels } 25837216Skarels 25937216Skarels addpart(name, fsname) 26037216Skarels char *name, *fsname; 26137216Skarels { 26237216Skarels struct disk *dk = finddisk(name); 26337216Skarels register struct part *pt, **ppt = &dk->part; 26437216Skarels 26537216Skarels for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next) 26637216Skarels if (strcmp(pt->name, name) == 0) { 26737216Skarels printf("%s in fstab more than once!\n", name); 26837216Skarels return; 26937216Skarels } 27037216Skarels if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) 27137216Skarels errexit("out of memory"); 27237216Skarels pt = *ppt; 273*39972Smckusick if ((pt->name = malloc((unsigned int)strlen(name) + 1)) == NULL) 27437216Skarels errexit("out of memory"); 27537216Skarels strcpy(pt->name, name); 276*39972Smckusick if ((pt->fsname = malloc((unsigned int)strlen(fsname) + 1)) == NULL) 27737216Skarels errexit("out of memory"); 27837216Skarels strcpy(pt->fsname, fsname); 27937216Skarels pt->next = NULL; 28037216Skarels } 28137216Skarels 28237216Skarels startdisk(dk) 28337216Skarels register struct disk *dk; 28437216Skarels { 28537216Skarels 28637216Skarels nrun++; 28737216Skarels dk->pid = fork(); 28837216Skarels if (dk->pid < 0) { 28937216Skarels perror("fork"); 29037216Skarels exit(8); 29137216Skarels } 29237216Skarels if (dk->pid == 0) { 29337216Skarels (void)signal(SIGQUIT, voidquit); 29437216Skarels checkfilesys(dk->part->name); 29537216Skarels exit(0); 29637216Skarels } 29737216Skarels } 29837216Skarels 2999255Smckusick checkfilesys(filesys) 3009255Smckusick char *filesys; 3014236Smckusick { 30217936Smckusick daddr_t n_ffree, n_bfree; 30321760Smckusick struct dups *dp; 30426479Smckusick struct zlncnt *zlnp; 3054236Smckusick 3069255Smckusick devname = filesys; 30737216Skarels if (debug && preen) 30837216Skarels pwarn("starting\n"); 3099255Smckusick if (setup(filesys) == 0) { 3104236Smckusick if (preen) 3119255Smckusick pfatal("CAN'T CHECK FILE SYSTEM."); 3124236Smckusick return; 3134236Smckusick } 31417936Smckusick /* 31517936Smckusick * 1: scan inodes tallying blocks used 31617936Smckusick */ 3176837Smckusick if (preen == 0) { 3186837Smckusick printf("** Last Mounted on %s\n", sblock.fs_fsmnt); 3194236Smckusick if (hotroot) 3204236Smckusick printf("** Root file system\n"); 3214236Smckusick printf("** Phase 1 - Check Blocks and Sizes\n"); 3224236Smckusick } 3239255Smckusick pass1(); 3249255Smckusick 32517936Smckusick /* 32617936Smckusick * 1b: locate first references to duplicates, if any 32717936Smckusick */ 32821743Smckusick if (duplist) { 3299255Smckusick if (preen) 3309255Smckusick pfatal("INTERNAL ERROR: dups with -p"); 3319255Smckusick printf("** Phase 1b - Rescan For More DUPS\n"); 3329255Smckusick pass1b(); 3339255Smckusick } 3349255Smckusick 33517936Smckusick /* 33617936Smckusick * 2: traverse directories from root to mark all connected directories 33717936Smckusick */ 3389255Smckusick if (preen == 0) 3399255Smckusick printf("** Phase 2 - Check Pathnames\n"); 3409255Smckusick pass2(); 3419255Smckusick 34217936Smckusick /* 34317936Smckusick * 3: scan inodes looking for disconnected directories 34417936Smckusick */ 3459255Smckusick if (preen == 0) 3469255Smckusick printf("** Phase 3 - Check Connectivity\n"); 3479255Smckusick pass3(); 3489255Smckusick 34917936Smckusick /* 35017936Smckusick * 4: scan inodes looking for disconnected files; check reference counts 35117936Smckusick */ 3529255Smckusick if (preen == 0) 3539255Smckusick printf("** Phase 4 - Check Reference Counts\n"); 3549255Smckusick pass4(); 3559255Smckusick 35617936Smckusick /* 35717936Smckusick * 5: check and repair resource counts in cylinder groups 35817936Smckusick */ 3599255Smckusick if (preen == 0) 3609255Smckusick printf("** Phase 5 - Check Cyl groups\n"); 3619255Smckusick pass5(); 3629255Smckusick 36317936Smckusick /* 36417936Smckusick * print out summary statistics 36517936Smckusick */ 36617936Smckusick n_ffree = sblock.fs_cstotal.cs_nffree; 36717936Smckusick n_bfree = sblock.fs_cstotal.cs_nbfree; 36825288Smckusick pwarn("%d files, %d used, %d free ", 36925288Smckusick n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree); 37025288Smckusick printf("(%d frags, %d blocks, %.1f%% fragmentation)\n", 37125288Smckusick n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize); 372*39972Smckusick if (debug && 373*39972Smckusick (n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree)) 37417936Smckusick printf("%d files missing\n", n_files); 37517936Smckusick if (debug) { 37617936Smckusick n_blks += sblock.fs_ncg * 37717936Smckusick (cgdmin(&sblock, 0) - cgsblock(&sblock, 0)); 37817936Smckusick n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0); 37917936Smckusick n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); 380*39972Smckusick if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree)) 38117936Smckusick printf("%d blocks missing\n", n_blks); 38221760Smckusick if (duplist != NULL) { 38321760Smckusick printf("The following duplicate blocks remain:"); 38421760Smckusick for (dp = duplist; dp; dp = dp->next) 38521760Smckusick printf(" %d,", dp->dup); 38621760Smckusick printf("\n"); 38721760Smckusick } 38826479Smckusick if (zlnhead != NULL) { 38926479Smckusick printf("The following zero link count inodes remain:"); 39026479Smckusick for (zlnp = zlnhead; zlnp; zlnp = zlnp->next) 39126479Smckusick printf(" %d,", zlnp->zlncnt); 39226479Smckusick printf("\n"); 39326479Smckusick } 3949255Smckusick } 39526479Smckusick zlnhead = (struct zlncnt *)0; 39626479Smckusick duplist = (struct dups *)0; 397*39972Smckusick if (fsmodified) { 39814952Smckusick (void)time(&sblock.fs_time); 3999255Smckusick sbdirty(); 4009255Smckusick } 4019255Smckusick ckfini(); 4029255Smckusick free(blockmap); 4039255Smckusick free(statemap); 40414952Smckusick free((char *)lncntp); 405*39972Smckusick if (!fsmodified) 40613729Sroot return; 40713729Sroot if (!preen) { 40813729Sroot printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); 40913729Sroot if (hotroot) 41013729Sroot printf("\n***** REBOOT UNIX *****\n"); 4119255Smckusick } 41213729Sroot if (hotroot) { 41313729Sroot sync(); 41413729Sroot exit(4); 41513729Sroot } 4169255Smckusick } 41717930Smckusick 41817930Smckusick char * 41917930Smckusick blockcheck(name) 42017930Smckusick char *name; 42117930Smckusick { 42217930Smckusick struct stat stslash, stblock, stchar; 42317930Smckusick char *raw; 424*39972Smckusick int retried = 0; 42517930Smckusick 42617930Smckusick hotroot = 0; 427*39972Smckusick if (stat("/", &stslash) < 0) { 42830565Skarels perror("/"); 42917930Smckusick printf("Can't stat root\n"); 43017930Smckusick return (0); 43117930Smckusick } 43217930Smckusick retry: 433*39972Smckusick if (stat(name, &stblock) < 0) { 43430565Skarels perror(name); 43517930Smckusick printf("Can't stat %s\n", name); 43617930Smckusick return (0); 43717930Smckusick } 43830156Smckusick if ((stblock.st_mode & S_IFMT) == S_IFBLK) { 43930565Skarels if (stslash.st_dev == stblock.st_rdev) { 44030565Skarels hotroot++; 44130565Skarels return (name); 44230565Skarels } 44317930Smckusick raw = rawname(name); 444*39972Smckusick if (stat(raw, &stchar) < 0) { 44530565Skarels perror(raw); 44617930Smckusick printf("Can't stat %s\n", raw); 44730565Skarels return (name); 44817930Smckusick } 449*39972Smckusick if ((stchar.st_mode & S_IFMT) == S_IFCHR) { 45017930Smckusick return (raw); 451*39972Smckusick } else { 45217930Smckusick printf("%s is not a character device\n", raw); 45330565Skarels return (name); 45417930Smckusick } 455*39972Smckusick } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) { 45617930Smckusick name = unrawname(name); 457*39972Smckusick retried++; 45817930Smckusick goto retry; 45917930Smckusick } 46017930Smckusick printf("Can't make sense out of name %s\n", name); 46117930Smckusick return (0); 46217930Smckusick } 46317930Smckusick 46417930Smckusick char * 465*39972Smckusick unrawname(name) 466*39972Smckusick char *name; 46717930Smckusick { 468*39972Smckusick char *dp; 46917930Smckusick struct stat stb; 47017930Smckusick 471*39972Smckusick if ((dp = rindex(name, '/')) == 0) 472*39972Smckusick return (name); 473*39972Smckusick if (stat(name, &stb) < 0) 474*39972Smckusick return (name); 475*39972Smckusick if ((stb.st_mode & S_IFMT) != S_IFCHR) 476*39972Smckusick return (name); 477*39972Smckusick if (*(dp + 1) != 'r') 478*39972Smckusick return (name); 479*39972Smckusick (void)strcpy(dp + 1, dp + 2); 480*39972Smckusick return (name); 48117930Smckusick } 48217930Smckusick 48317930Smckusick char * 484*39972Smckusick rawname(name) 485*39972Smckusick char *name; 48617930Smckusick { 48717930Smckusick static char rawbuf[32]; 488*39972Smckusick char *dp; 48917930Smckusick 490*39972Smckusick if ((dp = rindex(name, '/')) == 0) 49117930Smckusick return (0); 49217930Smckusick *dp = 0; 493*39972Smckusick (void)strcpy(rawbuf, name); 49417930Smckusick *dp = '/'; 49517930Smckusick (void)strcat(rawbuf, "/r"); 496*39972Smckusick (void)strcat(rawbuf, dp + 1); 49717930Smckusick return (rawbuf); 49817930Smckusick } 499