xref: /csrg-svn/sbin/fsck/main.c (revision 39972)
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