xref: /csrg-svn/sbin/fsck/utilities.c (revision 30859)
122055Sdist /*
222055Sdist  * Copyright (c) 1980 Regents of the University of California.
322055Sdist  * All rights reserved.  The Berkeley software License Agreement
422055Sdist  * specifies the terms and conditions for redistribution.
522055Sdist  */
622055Sdist 
716269Smckusick #ifndef lint
8*30859Skarels static char sccsid[] = "@(#)utilities.c	5.10 (Berkeley) 04/07/87";
922055Sdist #endif not lint
1016269Smckusick 
1116269Smckusick #include <stdio.h>
1216269Smckusick #include <ctype.h>
1316269Smckusick #include <sys/param.h>
1416269Smckusick #include <sys/inode.h>
1516269Smckusick #include <sys/fs.h>
1617991Smckusick #include <sys/dir.h>
1716269Smckusick #include "fsck.h"
1816269Smckusick 
1916269Smckusick long	lseek();
2016269Smckusick 
2116269Smckusick ftypeok(dp)
2216269Smckusick 	DINODE *dp;
2316269Smckusick {
2416269Smckusick 	switch (dp->di_mode & IFMT) {
2516269Smckusick 
2616269Smckusick 	case IFDIR:
2716269Smckusick 	case IFREG:
2816269Smckusick 	case IFBLK:
2916269Smckusick 	case IFCHR:
3016269Smckusick 	case IFLNK:
3116269Smckusick 	case IFSOCK:
3216269Smckusick 		return (1);
3316269Smckusick 
3416269Smckusick 	default:
3516269Smckusick 		if (debug)
3616269Smckusick 			printf("bad file type 0%o\n", dp->di_mode);
3716269Smckusick 		return (0);
3816269Smckusick 	}
3916269Smckusick }
4016269Smckusick 
4116269Smckusick reply(s)
4216269Smckusick 	char *s;
4316269Smckusick {
4416269Smckusick 	char line[80];
4530609Skarels 	int cont = (strcmp(s, "CONTINUE") == 0);
4616269Smckusick 
4716269Smckusick 	if (preen)
4816269Smckusick 		pfatal("INTERNAL ERROR: GOT TO reply()");
4916269Smckusick 	printf("\n%s? ", s);
5030609Skarels 	if (!cont && (nflag || dfile.wfdes < 0)) {
5116269Smckusick 		printf(" no\n\n");
5216269Smckusick 		return (0);
5316269Smckusick 	}
5430609Skarels 	if (yflag || (cont && nflag)) {
5516269Smckusick 		printf(" yes\n\n");
5616269Smckusick 		return (1);
5716269Smckusick 	}
5816269Smckusick 	if (getline(stdin, line, sizeof(line)) == EOF)
5916269Smckusick 		errexit("\n");
6016269Smckusick 	printf("\n");
6116269Smckusick 	if (line[0] == 'y' || line[0] == 'Y')
6216269Smckusick 		return (1);
6316269Smckusick 	else
6416269Smckusick 		return (0);
6516269Smckusick }
6616269Smckusick 
6716269Smckusick getline(fp, loc, maxlen)
6816269Smckusick 	FILE *fp;
6916269Smckusick 	char *loc;
7016269Smckusick {
7116269Smckusick 	register n;
7216269Smckusick 	register char *p, *lastloc;
7316269Smckusick 
7416269Smckusick 	p = loc;
7516269Smckusick 	lastloc = &p[maxlen-1];
7616269Smckusick 	while ((n = getc(fp)) != '\n') {
7716269Smckusick 		if (n == EOF)
7816269Smckusick 			return (EOF);
7916269Smckusick 		if (!isspace(n) && p < lastloc)
8016269Smckusick 			*p++ = n;
8116269Smckusick 	}
8216269Smckusick 	*p = 0;
8316269Smckusick 	return (p - loc);
8416269Smckusick }
8516269Smckusick 
8616269Smckusick BUFAREA *
8716269Smckusick getblk(bp, blk, size)
8816269Smckusick 	register BUFAREA *bp;
8916269Smckusick 	daddr_t blk;
9016269Smckusick 	long size;
9116269Smckusick {
9216269Smckusick 	register struct filecntl *fcp;
9316269Smckusick 	daddr_t dblk;
9416269Smckusick 
9516269Smckusick 	fcp = &dfile;
9616269Smckusick 	dblk = fsbtodb(&sblock, blk);
9716269Smckusick 	if (bp->b_bno == dblk)
9816269Smckusick 		return (bp);
9916269Smckusick 	flush(fcp, bp);
10021540Smckusick 	bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size);
10121540Smckusick 	bp->b_bno = dblk;
10221540Smckusick 	bp->b_size = size;
10321540Smckusick 	return (bp);
10416269Smckusick }
10516269Smckusick 
10616269Smckusick flush(fcp, bp)
10716269Smckusick 	struct filecntl *fcp;
10816269Smckusick 	register BUFAREA *bp;
10916269Smckusick {
11017931Smckusick 	register int i, j;
11116269Smckusick 
11217931Smckusick 	if (!bp->b_dirty)
11317931Smckusick 		return;
11421540Smckusick 	if (bp->b_errs != 0)
11530609Skarels 		pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
11630609Skarels 		    (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
11730609Skarels 		    bp->b_bno);
11816269Smckusick 	bp->b_dirty = 0;
11921540Smckusick 	bp->b_errs = 0;
12021758Smckusick 	bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
12117931Smckusick 	if (bp != &sblk)
12217931Smckusick 		return;
12317931Smckusick 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
12421758Smckusick 		bwrite(&dfile, (char *)sblock.fs_csp[j],
12517931Smckusick 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
12617931Smckusick 		    sblock.fs_cssize - i < sblock.fs_bsize ?
12717931Smckusick 		    sblock.fs_cssize - i : sblock.fs_bsize);
12817931Smckusick 	}
12916269Smckusick }
13016269Smckusick 
13116269Smckusick rwerr(s, blk)
13216269Smckusick 	char *s;
13316269Smckusick 	daddr_t blk;
13416269Smckusick {
13516269Smckusick 
13616269Smckusick 	if (preen == 0)
13716269Smckusick 		printf("\n");
13816269Smckusick 	pfatal("CANNOT %s: BLK %ld", s, blk);
13916269Smckusick 	if (reply("CONTINUE") == 0)
14016269Smckusick 		errexit("Program terminated\n");
14116269Smckusick }
14216269Smckusick 
14316269Smckusick ckfini()
14416269Smckusick {
14516269Smckusick 
14616269Smckusick 	flush(&dfile, &fileblk);
14716269Smckusick 	flush(&dfile, &sblk);
148*30859Skarels 	if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
14930518Smckusick 	    !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
15030556Smckusick 		sblk.b_bno = SBOFF / dev_bsize;
15116269Smckusick 		sbdirty();
15216269Smckusick 		flush(&dfile, &sblk);
15316269Smckusick 	}
15416269Smckusick 	flush(&dfile, &inoblk);
15518002Smckusick 	flush(&dfile, &cgblk);
15616269Smckusick 	(void)close(dfile.rfdes);
15716269Smckusick 	(void)close(dfile.wfdes);
15816269Smckusick }
15916269Smckusick 
16016269Smckusick bread(fcp, buf, blk, size)
16116269Smckusick 	register struct filecntl *fcp;
16216269Smckusick 	char *buf;
16316269Smckusick 	daddr_t blk;
16416269Smckusick 	long size;
16516269Smckusick {
16621540Smckusick 	char *cp;
16721540Smckusick 	int i, errs;
16821540Smckusick 
16930557Smckusick 	if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0)
17016269Smckusick 		rwerr("SEEK", blk);
17116269Smckusick 	else if (read(fcp->rfdes, buf, (int)size) == size)
17221540Smckusick 		return (0);
17316269Smckusick 	rwerr("READ", blk);
17430557Smckusick 	if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0)
17521540Smckusick 		rwerr("SEEK", blk);
17621540Smckusick 	errs = 0;
17730463Smckusick 	bzero(buf, size);
17830609Skarels 	printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
17930609Skarels 	for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
18030609Skarels 		if (read(fcp->rfdes, cp, secsize) < 0) {
18130609Skarels 			lseek(fcp->rfdes, blk * dev_bsize + i + secsize, 0);
182*30859Skarels 			if (secsize != dev_bsize && dev_bsize != 1)
18330609Skarels 				printf(" %d (%d),",
18430609Skarels 				    (blk * dev_bsize + i) / secsize,
18530609Skarels 				    blk + i / dev_bsize);
18630609Skarels 			else
18730609Skarels 				printf(" %d,", blk + i / dev_bsize);
18821540Smckusick 			errs++;
18921540Smckusick 		}
19021540Smckusick 	}
19121758Smckusick 	printf("\n");
19221540Smckusick 	return (errs);
19316269Smckusick }
19416269Smckusick 
19516269Smckusick bwrite(fcp, buf, blk, size)
19616269Smckusick 	register struct filecntl *fcp;
19716269Smckusick 	char *buf;
19816269Smckusick 	daddr_t blk;
19916269Smckusick 	long size;
20016269Smckusick {
20121758Smckusick 	int i;
20221758Smckusick 	char *cp;
20316269Smckusick 
20416269Smckusick 	if (fcp->wfdes < 0)
20521758Smckusick 		return;
20630557Smckusick 	if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0)
20716269Smckusick 		rwerr("SEEK", blk);
20816269Smckusick 	else if (write(fcp->wfdes, buf, (int)size) == size) {
20916269Smckusick 		fcp->mod = 1;
21021758Smckusick 		return;
21116269Smckusick 	}
21216269Smckusick 	rwerr("WRITE", blk);
21330557Smckusick 	if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0)
21421758Smckusick 		rwerr("SEEK", blk);
21530609Skarels 	printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
21630518Smckusick 	for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
21730518Smckusick 		if (write(fcp->wfdes, cp, dev_bsize) < 0) {
21830557Smckusick 			lseek(fcp->rfdes, blk * dev_bsize + i + dev_bsize, 0);
21930518Smckusick 			printf(" %d,", blk + i / dev_bsize);
22030395Smckusick 		}
22121758Smckusick 	printf("\n");
22221758Smckusick 	return;
22316269Smckusick }
22416269Smckusick 
22517944Smckusick /*
22617944Smckusick  * allocate a data block with the specified number of fragments
22717944Smckusick  */
22817944Smckusick allocblk(frags)
22917944Smckusick 	int frags;
23017944Smckusick {
23117944Smckusick 	register int i, j, k;
23217944Smckusick 
23317944Smckusick 	if (frags <= 0 || frags > sblock.fs_frag)
23417944Smckusick 		return (0);
23517944Smckusick 	for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) {
23617944Smckusick 		for (j = 0; j <= sblock.fs_frag - frags; j++) {
23717944Smckusick 			if (getbmap(i + j))
23817944Smckusick 				continue;
23917944Smckusick 			for (k = 1; k < frags; k++)
24017944Smckusick 				if (getbmap(i + j + k))
24117944Smckusick 					break;
24217944Smckusick 			if (k < frags) {
24317944Smckusick 				j += k;
24417944Smckusick 				continue;
24517944Smckusick 			}
24617944Smckusick 			for (k = 0; k < frags; k++)
24717944Smckusick 				setbmap(i + j + k);
24817944Smckusick 			n_blks += frags;
24917944Smckusick 			return (i + j);
25017944Smckusick 		}
25117944Smckusick 	}
25217944Smckusick 	return (0);
25317944Smckusick }
25417944Smckusick 
25517944Smckusick /*
25617944Smckusick  * Free a previously allocated block
25717944Smckusick  */
25817944Smckusick freeblk(blkno, frags)
25917944Smckusick 	daddr_t blkno;
26017944Smckusick 	int frags;
26117944Smckusick {
26217944Smckusick 	struct inodesc idesc;
26317944Smckusick 
26417944Smckusick 	idesc.id_blkno = blkno;
26517944Smckusick 	idesc.id_numfrags = frags;
26617944Smckusick 	pass4check(&idesc);
26717944Smckusick }
26817944Smckusick 
26917991Smckusick /*
27017991Smckusick  * Find a pathname
27117991Smckusick  */
27217991Smckusick getpathname(namebuf, curdir, ino)
27317991Smckusick 	char *namebuf;
27417991Smckusick 	ino_t curdir, ino;
27517991Smckusick {
27617991Smckusick 	int len;
27717991Smckusick 	register char *cp;
27817991Smckusick 	struct inodesc idesc;
27917991Smckusick 	extern int findname();
28017991Smckusick 
28117991Smckusick 	if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) {
28217991Smckusick 		strcpy(namebuf, "?");
28317991Smckusick 		return;
28417991Smckusick 	}
28517991Smckusick 	bzero(&idesc, sizeof(struct inodesc));
28617991Smckusick 	idesc.id_type = DATA;
28717991Smckusick 	cp = &namebuf[BUFSIZ - 1];
28830354Smckusick 	*cp = '\0';
28917991Smckusick 	if (curdir != ino) {
29017991Smckusick 		idesc.id_parent = curdir;
29117991Smckusick 		goto namelookup;
29217991Smckusick 	}
29317991Smckusick 	while (ino != ROOTINO) {
29417991Smckusick 		idesc.id_number = ino;
29517991Smckusick 		idesc.id_func = findino;
29617991Smckusick 		idesc.id_name = "..";
29730354Smckusick 		if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
29817991Smckusick 			break;
29917991Smckusick 	namelookup:
30017991Smckusick 		idesc.id_number = idesc.id_parent;
30117991Smckusick 		idesc.id_parent = ino;
30217991Smckusick 		idesc.id_func = findname;
30317991Smckusick 		idesc.id_name = namebuf;
30430354Smckusick 		if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0)
30517991Smckusick 			break;
30617991Smckusick 		len = strlen(namebuf);
30717991Smckusick 		cp -= len;
30817991Smckusick 		if (cp < &namebuf[MAXNAMLEN])
30917991Smckusick 			break;
31017991Smckusick 		bcopy(namebuf, cp, len);
31117991Smckusick 		*--cp = '/';
31217991Smckusick 		ino = idesc.id_number;
31317991Smckusick 	}
31417991Smckusick 	if (ino != ROOTINO) {
31517991Smckusick 		strcpy(namebuf, "?");
31617991Smckusick 		return;
31717991Smckusick 	}
31817991Smckusick 	bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp);
31917991Smckusick }
32017991Smckusick 
32116269Smckusick catch()
32216269Smckusick {
32316269Smckusick 
32416269Smckusick 	ckfini();
32516269Smckusick 	exit(12);
32616269Smckusick }
32716269Smckusick 
32816269Smckusick /*
32924680Skarels  * When preening, allow a single quit to signal
33024680Skarels  * a special exit after filesystem checks complete
33124680Skarels  * so that reboot sequence may be interrupted.
33224680Skarels  */
33324680Skarels catchquit()
33424680Skarels {
33524680Skarels 	extern returntosingle;
33624680Skarels 
33724680Skarels 	printf("returning to single-user after filesystem check\n");
33824680Skarels 	returntosingle = 1;
33924680Skarels 	(void)signal(SIGQUIT, SIG_DFL);
34024680Skarels }
34124680Skarels 
34224680Skarels /*
34324680Skarels  * Ignore a single quit signal; wait and flush just in case.
34424680Skarels  * Used by child processes in preen.
34524680Skarels  */
34624680Skarels voidquit()
34724680Skarels {
34824680Skarels 
34924680Skarels 	sleep(1);
35024680Skarels 	(void)signal(SIGQUIT, SIG_IGN);
35124680Skarels 	(void)signal(SIGQUIT, SIG_DFL);
35224680Skarels }
35324680Skarels 
35424680Skarels /*
35516269Smckusick  * determine whether an inode should be fixed.
35616269Smckusick  */
35717931Smckusick dofix(idesc, msg)
35816269Smckusick 	register struct inodesc *idesc;
35917931Smckusick 	char *msg;
36016269Smckusick {
36116269Smckusick 
36216269Smckusick 	switch (idesc->id_fix) {
36316269Smckusick 
36416269Smckusick 	case DONTKNOW:
36517931Smckusick 		if (idesc->id_type == DATA)
36617931Smckusick 			direrr(idesc->id_number, msg);
36717931Smckusick 		else
36817931Smckusick 			pwarn(msg);
36917931Smckusick 		if (preen) {
37017931Smckusick 			printf(" (SALVAGED)\n");
37117931Smckusick 			idesc->id_fix = FIX;
37217931Smckusick 			return (ALTERED);
37317931Smckusick 		}
37416269Smckusick 		if (reply("SALVAGE") == 0) {
37516269Smckusick 			idesc->id_fix = NOFIX;
37616269Smckusick 			return (0);
37716269Smckusick 		}
37816269Smckusick 		idesc->id_fix = FIX;
37916269Smckusick 		return (ALTERED);
38016269Smckusick 
38116269Smckusick 	case FIX:
38216269Smckusick 		return (ALTERED);
38316269Smckusick 
38416269Smckusick 	case NOFIX:
38516269Smckusick 		return (0);
38616269Smckusick 
38716269Smckusick 	default:
38816269Smckusick 		errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
38916269Smckusick 	}
39016269Smckusick 	/* NOTREACHED */
39116269Smckusick }
39216269Smckusick 
39316269Smckusick /* VARARGS1 */
39417931Smckusick errexit(s1, s2, s3, s4)
39516269Smckusick 	char *s1;
39616269Smckusick {
39716269Smckusick 	printf(s1, s2, s3, s4);
39816269Smckusick 	exit(8);
39916269Smckusick }
40016269Smckusick 
40116269Smckusick /*
40216269Smckusick  * An inconsistency occured which shouldn't during normal operations.
40316269Smckusick  * Die if preening, otherwise just printf.
40416269Smckusick  */
40516269Smckusick /* VARARGS1 */
40616269Smckusick pfatal(s, a1, a2, a3)
40716269Smckusick 	char *s;
40816269Smckusick {
40916269Smckusick 
41016269Smckusick 	if (preen) {
41116269Smckusick 		printf("%s: ", devname);
41216269Smckusick 		printf(s, a1, a2, a3);
41316269Smckusick 		printf("\n");
41417931Smckusick 		printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
41517931Smckusick 			devname);
41617931Smckusick 		exit(8);
41716269Smckusick 	}
41816269Smckusick 	printf(s, a1, a2, a3);
41916269Smckusick }
42016269Smckusick 
42116269Smckusick /*
42216269Smckusick  * Pwarn is like printf when not preening,
42316269Smckusick  * or a warning (preceded by filename) when preening.
42416269Smckusick  */
42516269Smckusick /* VARARGS1 */
42616269Smckusick pwarn(s, a1, a2, a3, a4, a5, a6)
42716269Smckusick 	char *s;
42816269Smckusick {
42916269Smckusick 
43016269Smckusick 	if (preen)
43116269Smckusick 		printf("%s: ", devname);
43216269Smckusick 	printf(s, a1, a2, a3, a4, a5, a6);
43316269Smckusick }
43416269Smckusick 
43516269Smckusick #ifndef lint
43616269Smckusick /*
43716269Smckusick  * Stub for routines from kernel.
43816269Smckusick  */
43916269Smckusick panic(s)
44016269Smckusick 	char *s;
44116269Smckusick {
44216269Smckusick 
44317931Smckusick 	pfatal("INTERNAL INCONSISTENCY:");
44417931Smckusick 	errexit(s);
44516269Smckusick }
44616269Smckusick #endif
447