xref: /csrg-svn/sbin/fsck/setup.c (revision 30399)
122054Sdist /*
222054Sdist  * Copyright (c) 1980 Regents of the University of California.
322054Sdist  * All rights reserved.  The Berkeley software License Agreement
422054Sdist  * specifies the terms and conditions for redistribution.
522054Sdist  */
622054Sdist 
716268Smckusick #ifndef lint
8*30399Smckusick static char sccsid[] = "@(#)setup.c	5.4 (Berkeley) 01/15/87";
922054Sdist #endif not lint
1016268Smckusick 
11*30399Smckusick #define DKTYPENAMES
1216268Smckusick #include <sys/param.h>
1316268Smckusick #include <sys/inode.h>
1416268Smckusick #include <sys/fs.h>
1516268Smckusick #include <sys/stat.h>
16*30399Smckusick #include <sys/ioctl.h>
17*30399Smckusick #include <sys/disklabel.h>
18*30399Smckusick #include <sys/file.h>
19*30399Smckusick #include <ctype.h>
2016268Smckusick #include "fsck.h"
2116268Smckusick 
22*30399Smckusick #define POWEROF2(num)	(((num) & ((num) - 1)) == 0)
23*30399Smckusick 
2416268Smckusick char	*calloc();
25*30399Smckusick char	*index();
2616268Smckusick 
2716268Smckusick setup(dev)
2816268Smckusick 	char *dev;
2916268Smckusick {
3016268Smckusick 	dev_t rootdev;
31*30399Smckusick 	long cg, ncg, size, i, j;
3216268Smckusick 	struct stat statb;
33*30399Smckusick 	struct fs proto;
3416268Smckusick 
3516268Smckusick 	if (stat("/", &statb) < 0)
3616268Smckusick 		errexit("Can't stat root\n");
3716268Smckusick 	rootdev = statb.st_dev;
3816268Smckusick 	if (stat(dev, &statb) < 0) {
3917931Smckusick 		printf("Can't stat %s\n", dev);
4016268Smckusick 		return (0);
4116268Smckusick 	}
4216268Smckusick 	rawflg = 0;
4316268Smckusick 	if ((statb.st_mode & S_IFMT) == S_IFBLK)
4416268Smckusick 		;
4516268Smckusick 	else if ((statb.st_mode & S_IFMT) == S_IFCHR)
4616268Smckusick 		rawflg++;
4716268Smckusick 	else {
4816268Smckusick 		if (reply("file is not a block or character device; OK") == 0)
4916268Smckusick 			return (0);
5016268Smckusick 	}
5116268Smckusick 	if (rootdev == statb.st_rdev)
5216268Smckusick 		hotroot++;
53*30399Smckusick 	if ((dfile.rfdes = open(dev, O_RDONLY)) < 0) {
5417931Smckusick 		printf("Can't open %s\n", dev);
5516268Smckusick 		return (0);
5616268Smckusick 	}
5716268Smckusick 	if (preen == 0)
5816268Smckusick 		printf("** %s", dev);
59*30399Smckusick 	if (nflag || (dfile.wfdes = open(dev, O_WRONLY)) < 0) {
6016268Smckusick 		dfile.wfdes = -1;
6116268Smckusick 		if (preen)
6216268Smckusick 			pfatal("NO WRITE ACCESS");
6316268Smckusick 		printf(" (NO WRITE)");
6416268Smckusick 	}
6516268Smckusick 	if (preen == 0)
6616268Smckusick 		printf("\n");
6716268Smckusick 	dfile.mod = 0;
6816268Smckusick 	lfdir = 0;
6916268Smckusick 	initbarea(&sblk);
7016268Smckusick 	initbarea(&fileblk);
7116268Smckusick 	initbarea(&inoblk);
7216268Smckusick 	initbarea(&cgblk);
7316268Smckusick 	/*
74*30399Smckusick 	 * Read in the superblock, looking for alternates if necessary
7516268Smckusick 	 */
76*30399Smckusick 	if (readsb(1) == 0) {
77*30399Smckusick 		if (bflag || calcsb(dev, dfile.rfdes, &proto) == 0 || preen)
78*30399Smckusick 			return(0);
79*30399Smckusick 		if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
80*30399Smckusick 			return (0);
81*30399Smckusick 		for (cg = 0; cg < proto.fs_ncg; cg++) {
82*30399Smckusick 			bflag = fsbtodb(&proto, cgsblock(&proto, cg));
83*30399Smckusick 			if (readsb(0) != 0)
84*30399Smckusick 				break;
85*30399Smckusick 		}
86*30399Smckusick 		if (cg >= proto.fs_ncg) {
87*30399Smckusick 			printf("%s %s\n%s %s\n%s %s\n",
88*30399Smckusick 				"SEARCH FOR ALTERNATE SUPER-BLOCK",
89*30399Smckusick 				"FAILED. YOU MUST USE THE",
90*30399Smckusick 				"-b OPTION TO FSCK TO SPECIFY THE",
91*30399Smckusick 				"LOCATION OF AN ALTERNATE",
92*30399Smckusick 				"SUPER-BLOCK TO SUPPLY NEEDED",
93*30399Smckusick 				"INFORMATION; SEE fsck(8).");
94*30399Smckusick 			return(0);
95*30399Smckusick 		}
96*30399Smckusick 		pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
97*30399Smckusick 	}
98*30399Smckusick 	fmax = sblock.fs_size;
99*30399Smckusick 	imax = sblock.fs_ncg * sblock.fs_ipg;
10016268Smckusick 	/*
10128213Smckusick 	 * Check and potentially fix certain fields in the super block.
10228213Smckusick 	 */
10328213Smckusick 	if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
10428213Smckusick 		pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
10528213Smckusick 		if (reply("SET TO DEFAULT") == 1) {
10628213Smckusick 			sblock.fs_optim = FS_OPTTIME;
10728213Smckusick 			sbdirty();
10828213Smckusick 		}
10928213Smckusick 	}
11028213Smckusick 	if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
11128213Smckusick 		pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
11228213Smckusick 			sblock.fs_minfree);
11328213Smckusick 		if (reply("SET TO DEFAULT") == 1) {
11428213Smckusick 			sblock.fs_minfree = 10;
11528213Smckusick 			sbdirty();
11628213Smckusick 		}
11728213Smckusick 	}
11828213Smckusick 	/*
11916268Smckusick 	 * read in the summary info.
12016268Smckusick 	 */
12116268Smckusick 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
12216268Smckusick 		size = sblock.fs_cssize - i < sblock.fs_bsize ?
12316268Smckusick 		    sblock.fs_cssize - i : sblock.fs_bsize;
12416268Smckusick 		sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size);
12516268Smckusick 		if (bread(&dfile, (char *)sblock.fs_csp[j],
12616268Smckusick 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
12721540Smckusick 		    size) != 0)
12816268Smckusick 			return (0);
12916268Smckusick 	}
13016268Smckusick 	/*
13116268Smckusick 	 * allocate and initialize the necessary maps
13216268Smckusick 	 */
13316268Smckusick 	bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
13416268Smckusick 	blockmap = calloc((unsigned)bmapsz, sizeof (char));
13516268Smckusick 	if (blockmap == NULL) {
13616268Smckusick 		printf("cannot alloc %d bytes for blockmap\n", bmapsz);
13716268Smckusick 		goto badsb;
13816268Smckusick 	}
13916268Smckusick 	statemap = calloc((unsigned)(imax + 1), sizeof(char));
14016268Smckusick 	if (statemap == NULL) {
14116268Smckusick 		printf("cannot alloc %d bytes for statemap\n", imax + 1);
14216268Smckusick 		goto badsb;
14316268Smckusick 	}
14416268Smckusick 	lncntp = (short *)calloc((unsigned)(imax + 1), sizeof(short));
14516268Smckusick 	if (lncntp == NULL) {
14616268Smckusick 		printf("cannot alloc %d bytes for lncntp\n",
14716268Smckusick 		    (imax + 1) * sizeof(short));
14816268Smckusick 		goto badsb;
14916268Smckusick 	}
15016268Smckusick 
15116268Smckusick 	return (1);
15216268Smckusick 
15316268Smckusick badsb:
15416268Smckusick 	ckfini();
15516268Smckusick 	return (0);
156*30399Smckusick }
157*30399Smckusick 
158*30399Smckusick /*
159*30399Smckusick  * Read in the super block and its summary info.
160*30399Smckusick  */
161*30399Smckusick readsb(listerr)
162*30399Smckusick 	int listerr;
163*30399Smckusick {
164*30399Smckusick 	BUFAREA asblk;
165*30399Smckusick #	define altsblock asblk.b_un.b_fs
166*30399Smckusick 	daddr_t super = bflag ? bflag : SBLOCK;
167*30399Smckusick 
168*30399Smckusick 	initbarea(&asblk);
169*30399Smckusick 	if (bread(&dfile, (char *)&sblock, super, (long)SBSIZE) != 0)
170*30399Smckusick 		return (0);
171*30399Smckusick 	sblk.b_bno = super;
172*30399Smckusick 	sblk.b_size = SBSIZE;
173*30399Smckusick 	/*
174*30399Smckusick 	 * run a few consistency checks of the super block
175*30399Smckusick 	 */
176*30399Smckusick 	if (sblock.fs_magic != FS_MAGIC)
177*30399Smckusick 		{ badsb(listerr, "MAGIC NUMBER WRONG"); return (0); }
178*30399Smckusick 	if (sblock.fs_ncg < 1)
179*30399Smckusick 		{ badsb(listerr, "NCG OUT OF RANGE"); return (0); }
180*30399Smckusick 	if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
181*30399Smckusick 		{ badsb(listerr, "CPG OUT OF RANGE"); return (0); }
182*30399Smckusick 	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
183*30399Smckusick 	    (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
184*30399Smckusick 		{ badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); }
185*30399Smckusick 	if (sblock.fs_sbsize > SBSIZE)
186*30399Smckusick 		{ badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
187*30399Smckusick 	/*
188*30399Smckusick 	 * Set all possible fields that could differ, then do check
189*30399Smckusick 	 * of whole super block against an alternate super block.
190*30399Smckusick 	 * When an alternate super-block is specified this check is skipped.
191*30399Smckusick 	 */
192*30399Smckusick 	if (bflag)
193*30399Smckusick 		return (1);
194*30399Smckusick 	getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
195*30399Smckusick 	if (asblk.b_errs != NULL)
196*30399Smckusick 		return (0);
197*30399Smckusick 	altsblock.fs_link = sblock.fs_link;
198*30399Smckusick 	altsblock.fs_rlink = sblock.fs_rlink;
199*30399Smckusick 	altsblock.fs_time = sblock.fs_time;
200*30399Smckusick 	altsblock.fs_cstotal = sblock.fs_cstotal;
201*30399Smckusick 	altsblock.fs_cgrotor = sblock.fs_cgrotor;
202*30399Smckusick 	altsblock.fs_fmod = sblock.fs_fmod;
203*30399Smckusick 	altsblock.fs_clean = sblock.fs_clean;
204*30399Smckusick 	altsblock.fs_ronly = sblock.fs_ronly;
205*30399Smckusick 	altsblock.fs_flags = sblock.fs_flags;
206*30399Smckusick 	altsblock.fs_maxcontig = sblock.fs_maxcontig;
207*30399Smckusick 	altsblock.fs_minfree = sblock.fs_minfree;
208*30399Smckusick 	altsblock.fs_optim = sblock.fs_optim;
209*30399Smckusick 	altsblock.fs_rotdelay = sblock.fs_rotdelay;
210*30399Smckusick 	altsblock.fs_maxbpg = sblock.fs_maxbpg;
211*30399Smckusick 	bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp,
212*30399Smckusick 		sizeof sblock.fs_csp);
213*30399Smckusick 	bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt,
214*30399Smckusick 		sizeof sblock.fs_fsmnt);
215*30399Smckusick 	if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize))
216*30399Smckusick 		{ badsb(listerr, "TRASHED VALUES IN SUPER BLOCK"); return (0); }
217*30399Smckusick 	return (1);
21816268Smckusick #	undef altsblock
21916268Smckusick }
22016268Smckusick 
221*30399Smckusick badsb(listerr, s)
222*30399Smckusick 	int listerr;
22316268Smckusick 	char *s;
22416268Smckusick {
22516268Smckusick 
226*30399Smckusick 	if (!listerr)
227*30399Smckusick 		return;
22816268Smckusick 	if (preen)
22916268Smckusick 		printf("%s: ", devname);
230*30399Smckusick 	pfatal("BAD SUPER BLOCK: %s\n", s);
23116268Smckusick }
232*30399Smckusick 
233*30399Smckusick /*
234*30399Smckusick  * Calculate a prototype superblock based on information in the disk label.
235*30399Smckusick  * When done the cgsblock macro can be calculated and the fs_ncg field
236*30399Smckusick  * can be used. Do NOT attempt to use other macros without verifying that
237*30399Smckusick  * their needed information is available!
238*30399Smckusick  */
239*30399Smckusick calcsb(dev, devfd, fs)
240*30399Smckusick 	char *dev;
241*30399Smckusick 	int devfd;
242*30399Smckusick 	register struct fs *fs;
243*30399Smckusick {
244*30399Smckusick 	register struct disklabel *lp;
245*30399Smckusick 	register struct partition *pp;
246*30399Smckusick 	register char *cp;
247*30399Smckusick 	struct disklabel *getdisklabel();
248*30399Smckusick 	int i;
249*30399Smckusick 
250*30399Smckusick 	cp = index(dev, '\0') - 1;
251*30399Smckusick 	if (cp == (char *)-1 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) {
252*30399Smckusick 		pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
253*30399Smckusick 		return (0);
254*30399Smckusick 	}
255*30399Smckusick 	lp = getdisklabel(dev, devfd);
256*30399Smckusick 	if (isdigit(*cp))
257*30399Smckusick 		pp = &lp->d_partitions[0];
258*30399Smckusick 	else
259*30399Smckusick 		pp = &lp->d_partitions[*cp - 'a'];
260*30399Smckusick 	if (pp->p_fstype != FS_BSDFFS) {
261*30399Smckusick 		pfatal("%s: NOT FORMATTED AS A BSD FILE SYSTEM (%s)\n",
262*30399Smckusick 			dev, pp->p_fstype < FSMAXTYPES ?
263*30399Smckusick 			fstypenames[pp->p_fstype] : "unknown");
264*30399Smckusick 		return (0);
265*30399Smckusick 	}
266*30399Smckusick 	bzero(fs, sizeof(struct fs));
267*30399Smckusick 	fs->fs_fsize = pp->p_fsize;
268*30399Smckusick 	fs->fs_frag = pp->p_frag;
269*30399Smckusick 	fs->fs_cpg = pp->p_cpg;
270*30399Smckusick 	fs->fs_size = pp->p_size;
271*30399Smckusick 	fs->fs_ntrak = lp->d_ntracks;
272*30399Smckusick 	fs->fs_nsect = lp->d_nsectors;
273*30399Smckusick 	fs->fs_spc = lp->d_secpercyl;
274*30399Smckusick 	fs->fs_nspf = fs->fs_fsize / lp->d_secsize;
275*30399Smckusick 	fs->fs_sblkno = roundup(
276*30399Smckusick 		howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize),
277*30399Smckusick 		fs->fs_frag);
278*30399Smckusick 	fs->fs_cgmask = 0xffffffff;
279*30399Smckusick 	for (i = fs->fs_ntrak; i > 1; i >>= 1)
280*30399Smckusick 		fs->fs_cgmask <<= 1;
281*30399Smckusick 	if (!POWEROF2(fs->fs_ntrak))
282*30399Smckusick 		fs->fs_cgmask <<= 1;
283*30399Smckusick 	fs->fs_cgoffset = roundup(
284*30399Smckusick 		howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag);
285*30399Smckusick 	fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs);
286*30399Smckusick 	fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg);
287*30399Smckusick 	for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1)
288*30399Smckusick 		fs->fs_fsbtodb++;
289*30399Smckusick 	return (1);
290*30399Smckusick }
291*30399Smckusick 
292*30399Smckusick #ifdef byioctl
293*30399Smckusick struct disklabel *
294*30399Smckusick getdisklabel(s, fd)
295*30399Smckusick 	char *s;
296*30399Smckusick 	int	fd;
297*30399Smckusick {
298*30399Smckusick 	static struct disklabel lab;
299*30399Smckusick 
300*30399Smckusick 	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
301*30399Smckusick 		perror("ioctl (GDINFO)");
302*30399Smckusick 		fatal("%s: can't read disk label", s);
303*30399Smckusick 	}
304*30399Smckusick 	return (&lab);
305*30399Smckusick }
306*30399Smckusick #else byioctl
307*30399Smckusick char specname[64];
308*30399Smckusick char boot[BBSIZE];
309*30399Smckusick 
310*30399Smckusick struct disklabel *
311*30399Smckusick getdisklabel(s, fd)
312*30399Smckusick 	char *s;
313*30399Smckusick 	int	fd;
314*30399Smckusick {
315*30399Smckusick 	char *cp;
316*30399Smckusick 	u_long magic = htonl(DISKMAGIC);
317*30399Smckusick 	register struct disklabel *lp;
318*30399Smckusick 	int cfd;
319*30399Smckusick 
320*30399Smckusick 	/*
321*30399Smckusick 	 * Make name for 'c' partition.
322*30399Smckusick 	 */
323*30399Smckusick 	strcpy(specname, s);
324*30399Smckusick 	cp = specname + strlen(specname) - 1;
325*30399Smckusick 	if (!isdigit(*cp))
326*30399Smckusick 		*cp = 'c';
327*30399Smckusick 	cfd = open(specname, O_RDONLY);
328*30399Smckusick 	if (cfd < 0) {
329*30399Smckusick 		perror(specname);
330*30399Smckusick 		exit(2);
331*30399Smckusick 	}
332*30399Smckusick 
333*30399Smckusick 	if (read(cfd, boot, BBSIZE) < BBSIZE) {
334*30399Smckusick 		perror(specname);
335*30399Smckusick 		exit(2);
336*30399Smckusick 	}
337*30399Smckusick 	close(cfd);
338*30399Smckusick 	for (lp = (struct disklabel *)(boot + LABELOFFSET);
339*30399Smckusick 	    lp <= (struct disklabel *)(boot + BBSIZE -
340*30399Smckusick 	    sizeof(struct disklabel));
341*30399Smckusick 	    lp = (struct disklabel *)((char *)lp + 128))
342*30399Smckusick 		if (lp->d_magic == magic && lp->d_magic2 == magic)
343*30399Smckusick 			break;
344*30399Smckusick 	if (lp > (struct disklabel *)(boot + BBSIZE -
345*30399Smckusick 	    sizeof(struct disklabel)) ||
346*30399Smckusick 	    lp->d_magic != magic || lp->d_magic2 != magic ||
347*30399Smckusick 	    dkcksum(lp) != 0) {
348*30399Smckusick 		printf("Bad pack magic number %s\n",
349*30399Smckusick 			"(label is damaged, or pack is unlabeled)");
350*30399Smckusick 		exit(1);
351*30399Smckusick 	}
352*30399Smckusick #if ENDIAN != BIG
353*30399Smckusick 	swablabel(lp);
354*30399Smckusick #endif
355*30399Smckusick 	return (lp);
356*30399Smckusick }
357*30399Smckusick #endif byioctl
358