xref: /netbsd-src/sbin/fsck_lfs/setup.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /* $NetBSD: setup.c,v 1.33 2007/10/08 21:39:50 ad Exp $ */
2 
3 /*-
4  * Copyright (c) 2003 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Konrad E. Schroder <perseant@hhhh.org>.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 /*
39  * Copyright (c) 1980, 1986, 1993
40  *	The Regents of the University of California.  All rights reserved.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  * 3. Neither the name of the University nor the names of its contributors
51  *    may be used to endorse or promote products derived from this software
52  *    without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64  * SUCH DAMAGE.
65  */
66 
67 /* #define DKTYPENAMES */
68 #define FSTYPENAMES
69 #include <sys/types.h>
70 #include <sys/param.h>
71 #include <sys/time.h>
72 #include <sys/buf.h>
73 #include <sys/mount.h>
74 #include <sys/queue.h>
75 #include <sys/stat.h>
76 #include <sys/ioctl.h>
77 #include <sys/disklabel.h>
78 #include <sys/file.h>
79 
80 #include <ufs/ufs/inode.h>
81 #include <ufs/ufs/ufsmount.h>
82 #define vnode uvnode
83 #include <ufs/lfs/lfs.h>
84 #undef vnode
85 
86 #include <ctype.h>
87 #include <err.h>
88 #include <errno.h>
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <string.h>
92 #include <time.h>
93 #include <util.h>
94 
95 #include "bufcache.h"
96 #include "vnode.h"
97 #include "lfs_user.h"
98 
99 #include "fsck.h"
100 #include "extern.h"
101 #include "fsutil.h"
102 
103 extern u_int32_t cksum(void *, size_t);
104 static struct disklabel *getdisklabel(const char *, int);
105 static uint64_t calcmaxfilesize(int);
106 
107 ufs_daddr_t *din_table;
108 SEGUSE *seg_table;
109 
110 #ifdef DKTYPENAMES
111 int useless(void);
112 
113 int
114 useless(void)
115 {
116 	char **foo = (char **) dktypenames;
117 	char **bar = (char **) fscknames;
118 
119 	return foo - bar;
120 }
121 #endif
122 
123 /*
124  * calculate the maximum file size allowed with the specified block shift.
125  */
126 static uint64_t
127 calcmaxfilesize(int bshift)
128 {
129 	uint64_t nptr; /* number of block pointers per block */
130 	uint64_t maxblock;
131 
132 	nptr = (1 << bshift) / sizeof(uint32_t);
133 	maxblock = NDADDR + nptr + nptr * nptr + nptr * nptr * nptr;
134 
135 	return maxblock << bshift;
136 }
137 
138 void
139 reset_maxino(ino_t len)
140 {
141 	if (debug)
142 		pwarn("maxino reset from %lld to %lld\n", (long long)maxino,
143 			(long long)len);
144 
145 	din_table = erealloc(din_table, len * sizeof(*din_table));
146 	statemap = erealloc(statemap, len * sizeof(char));
147 	typemap = erealloc(typemap, len * sizeof(char));
148 	lncntp = erealloc(lncntp, len * sizeof(int16_t));
149 
150 	memset(din_table + maxino, 0, (len - maxino) * sizeof(*din_table));
151 	memset(statemap + maxino, USTATE, (len - maxino) * sizeof(char));
152 	memset(typemap + maxino, 0, (len - maxino) * sizeof(char));
153 	memset(lncntp + maxino, 0, (len - maxino) * sizeof(int16_t));
154 
155 	maxino = len;
156 
157 	/*
158 	 * We can't roll forward after allocating new inodes in previous
159 	 * phases, or thy would conflict (lost+found, for example, might
160 	 * disappear to be replaced by a file found in roll-forward).
161 	 */
162 	no_roll_forward = 1;
163 
164 	return;
165 }
166 
167 extern time_t write_time;
168 
169 int
170 setup(const char *dev)
171 {
172 	long bmapsize;
173 	struct disklabel *lp;
174 	struct stat statb;
175 	int doskipclean;
176 	u_int64_t maxfilesize;
177 	int open_flags;
178 	struct uvnode *ivp;
179 	struct ubuf *bp;
180 	int i, isdirty;
181 	long sn, curseg;
182 	SEGUSE *sup;
183 
184 	havesb = 0;
185 	doskipclean = skipclean;
186 	if (stat(dev, &statb) < 0) {
187 		pfatal("Can't stat %s: %s\n", dev, strerror(errno));
188 		return (0);
189 	}
190 	if (!S_ISCHR(statb.st_mode) && skipclean) {
191 		pfatal("%s is not a character device", dev);
192 		if (reply("CONTINUE") == 0)
193 			return (0);
194 	}
195 	if (nflag)
196 		open_flags = O_RDONLY;
197 	else
198 		open_flags = O_RDWR;
199 
200 	if ((fsreadfd = open(dev, open_flags)) < 0) {
201 		pfatal("Can't open %s: %s\n", dev, strerror(errno));
202 		return (0);
203 	}
204 	if (nflag) {
205 		if (preen)
206 			pfatal("NO WRITE ACCESS");
207 		printf("** %s (NO WRITE)\n", dev);
208 		quiet = 0;
209 	} else if (!preen && !quiet)
210 		printf("** %s\n", dev);
211 
212 	fsmodified = 0;
213 	lfdir = 0;
214 
215 	/* Initialize time in case we have to write */
216 	time(&write_time);
217 
218 	bufinit(0); /* XXX we could make a better guess */
219 	fs = lfs_init(fsreadfd, bflag, idaddr, 0, debug);
220 	if (fs == NULL) {
221 		if (preen)
222 			printf("%s: ", cdevname());
223 		errexit("BAD SUPER BLOCK OR IFILE INODE NOT FOUND\n");
224 	}
225 	if ((lp = getdisklabel((char *) NULL, fsreadfd)) != NULL)
226 		dev_bsize = secsize = lp->d_secsize;
227 	else
228 		dev_bsize = secsize = DEV_BSIZE;
229 
230         /* Resize buffer cache now that we have a superblock to guess from. */
231         bufrehash((fs->lfs_segtabsz + maxino / fs->lfs_ifpb) << 4);
232 
233 	if (fs->lfs_pflags & LFS_PF_CLEAN) {
234 		if (doskipclean) {
235 			if (!quiet)
236 				pwarn("%sile system is clean; not checking\n",
237 				      preen ? "f" : "** F");
238 			return (-1);
239 		}
240 		if (!preen)
241 			pwarn("** File system is already clean\n");
242 	}
243 
244 	if (idaddr) {
245 		daddr_t tdaddr;
246 		SEGSUM *sp;
247 		FINFO *fp;
248 		int bc;
249 
250 		if (debug)
251 			pwarn("adjusting offset, serial for -i 0x%lx\n",
252 				(unsigned long)idaddr);
253 		tdaddr = sntod(fs, dtosn(fs, idaddr));
254 		if (sntod(fs, dtosn(fs, tdaddr)) == tdaddr) {
255 			if (tdaddr == fs->lfs_start)
256 				tdaddr += btofsb(fs, LFS_LABELPAD);
257 			for (i = 0; i < LFS_MAXNUMSB; i++) {
258 				if (fs->lfs_sboffs[i] == tdaddr)
259 					tdaddr += btofsb(fs, LFS_SBPAD);
260 				if (fs->lfs_sboffs[i] > tdaddr)
261 					break;
262 			}
263 		}
264 		fs->lfs_offset = tdaddr;
265 		if (debug)
266 			pwarn("begin with offset/serial 0x%x/%d\n",
267 				(int)fs->lfs_offset, (int)fs->lfs_serial);
268 		while (tdaddr < idaddr) {
269 			bread(fs->lfs_devvp, fsbtodb(fs, tdaddr),
270 			      fs->lfs_sumsize,
271 			      NULL, &bp);
272 			sp = (SEGSUM *)bp->b_data;
273 			if (sp->ss_sumsum != cksum(&sp->ss_datasum,
274 						   fs->lfs_sumsize -
275 						   sizeof(sp->ss_sumsum))) {
276 				brelse(bp, 0);
277 				if (debug)
278 					printf("bad cksum at %x\n",
279 					       (unsigned)tdaddr);
280 				break;
281 			}
282 			fp = (FINFO *)(sp + 1);
283 			bc = howmany(sp->ss_ninos, INOPB(fs)) <<
284 				(fs->lfs_version > 1 ? fs->lfs_ffshift :
285 						       fs->lfs_bshift);
286 			for (i = 0; i < sp->ss_nfinfo; i++) {
287 				bc += fp->fi_lastlength + ((fp->fi_nblocks - 1)
288 					<< fs->lfs_bshift);
289 				fp = (FINFO *)(fp->fi_blocks + fp->fi_nblocks);
290 			}
291 
292 			tdaddr += btofsb(fs, bc) + 1;
293 			fs->lfs_offset = tdaddr;
294 			fs->lfs_serial = sp->ss_serial + 1;
295 			brelse(bp, 0);
296 		}
297 
298 		/*
299 		 * Set curseg, nextseg appropriately -- inlined from
300 		 * lfs_newseg()
301 		 */
302 		curseg = dtosn(fs, fs->lfs_offset);
303 		fs->lfs_curseg = sntod(fs, curseg);
304 		for (sn = curseg + fs->lfs_interleave;;) {
305 			sn = (sn + 1) % fs->lfs_nseg;
306 			if (sn == curseg)
307 				errx(1, "init: no clean segments");
308 			LFS_SEGENTRY(sup, fs, sn, bp);
309 			isdirty = sup->su_flags & SEGUSE_DIRTY;
310 			brelse(bp, 0);
311 
312 			if (!isdirty)
313 				break;
314 		}
315 
316 		/* Skip superblock if necessary */
317 		for (i = 0; i < LFS_MAXNUMSB; i++)
318 			if (fs->lfs_offset == fs->lfs_sboffs[i])
319 				fs->lfs_offset += btofsb(fs, LFS_SBPAD);
320 
321 		++fs->lfs_nactive;
322 		fs->lfs_nextseg = sntod(fs, sn);
323 		if (debug) {
324 			pwarn("offset = 0x%" PRIx32 ", serial = %" PRId64 "\n",
325 				fs->lfs_offset, fs->lfs_serial);
326 			pwarn("curseg = %" PRIx32 ", nextseg = %" PRIx32 "\n",
327 				fs->lfs_curseg, fs->lfs_nextseg);
328 		}
329 
330 		if (!nflag && !skipclean) {
331 			fs->lfs_idaddr = idaddr;
332 			fsmodified = 1;
333 			sbdirty();
334 		}
335 	}
336 
337 	if (debug) {
338 		pwarn("idaddr    = 0x%lx\n", idaddr ? (unsigned long)idaddr :
339 			(unsigned long)fs->lfs_idaddr);
340 		pwarn("dev_bsize = %lu\n", dev_bsize);
341 		pwarn("lfs_bsize = %lu\n", (unsigned long) fs->lfs_bsize);
342 		pwarn("lfs_fsize = %lu\n", (unsigned long) fs->lfs_fsize);
343 		pwarn("lfs_frag  = %lu\n", (unsigned long) fs->lfs_frag);
344 		pwarn("lfs_inopb = %lu\n", (unsigned long) fs->lfs_inopb);
345 	}
346 	if (fs->lfs_version == 1)
347 		maxfsblock = fs->lfs_size * (fs->lfs_bsize / dev_bsize);
348 	else
349 		maxfsblock = fs->lfs_size;
350 	maxfilesize = calcmaxfilesize(fs->lfs_bshift);
351 	if (/* fs->lfs_minfree < 0 || */ fs->lfs_minfree > 99) {
352 		pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
353 		    fs->lfs_minfree);
354 		if (reply("SET TO DEFAULT") == 1) {
355 			fs->lfs_minfree = 10;
356 			sbdirty();
357 		}
358 	}
359 	if (fs->lfs_bmask != fs->lfs_bsize - 1) {
360 		pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK (SHOULD BE 0x%x)",
361 		    (unsigned int) fs->lfs_bmask,
362 		    (unsigned int) fs->lfs_bsize - 1);
363 		fs->lfs_bmask = fs->lfs_bsize - 1;
364 		if (preen)
365 			printf(" (FIXED)\n");
366 		if (preen || reply("FIX") == 1) {
367 			sbdirty();
368 		}
369 	}
370 	if (fs->lfs_ffmask != fs->lfs_fsize - 1) {
371 		pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK",
372 		    fs->lfs_ffmask);
373 		fs->lfs_ffmask = fs->lfs_fsize - 1;
374 		if (preen)
375 			printf(" (FIXED)\n");
376 		if (preen || reply("FIX") == 1) {
377 			sbdirty();
378 		}
379 	}
380 	if (fs->lfs_fbmask != (1 << fs->lfs_fbshift) - 1) {
381 		pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK",
382 		    fs->lfs_ffmask);
383 		fs->lfs_fbmask = (1 << fs->lfs_fbshift) - 1;
384 		if (preen)
385 			printf(" (FIXED)\n");
386 		if (preen || reply("FIX") == 1) {
387 			sbdirty();
388 		}
389 	}
390 	if (fs->lfs_maxfilesize != maxfilesize) {
391 		pwarn(
392 		    "INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK (SHOULD BE %llu WITH BSHIFT %d)",
393 		    (unsigned long long) fs->lfs_maxfilesize,
394 		    (unsigned long long) maxfilesize, (int)fs->lfs_bshift);
395 		if (preen)
396 			printf(" (FIXED)\n");
397 		if (preen || reply("FIX") == 1) {
398 			fs->lfs_maxfilesize = maxfilesize;
399 			sbdirty();
400 		}
401 	}
402 	if (fs->lfs_maxsymlinklen != MAXSYMLINKLEN_UFS1) {
403 		pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK",
404 		    fs->lfs_maxsymlinklen);
405 		fs->lfs_maxsymlinklen = MAXSYMLINKLEN_UFS1;
406 		if (preen)
407 			printf(" (FIXED)\n");
408 		if (preen || reply("FIX") == 1) {
409 			sbdirty();
410 		}
411 	}
412 
413 	/*
414 	 * Read in the Ifile; we'll be using it a lot.
415 	 * XXX If the Ifile is corrupted we are in bad shape.  We need to
416 	 * XXX run through the segment headers of the entire disk to
417 	 * XXX reconstruct the inode table, then pretend all segments are
418 	 * XXX dirty while we do the rest.
419 	 */
420 	ivp = fs->lfs_ivnode;
421 	maxino = ((VTOI(ivp)->i_ffs1_size - (fs->lfs_cleansz + fs->lfs_segtabsz)
422 		* fs->lfs_bsize) / fs->lfs_bsize) * fs->lfs_ifpb;
423 	if (debug)
424 		pwarn("maxino    = %llu\n", (unsigned long long)maxino);
425 	for (i = 0; i < VTOI(ivp)->i_ffs1_size; i += fs->lfs_bsize) {
426 		bread(ivp, i >> fs->lfs_bshift, fs->lfs_bsize, NOCRED, &bp);
427 		/* XXX check B_ERROR */
428 		brelse(bp, 0);
429 	}
430 
431 	/*
432 	 * allocate and initialize the necessary maps
433 	 */
434 	din_table = ecalloc(maxino, sizeof(*din_table));
435 	seg_table = ecalloc(fs->lfs_nseg, sizeof(SEGUSE));
436 	/* Get segment flags */
437 	for (i = 0; i < fs->lfs_nseg; i++) {
438 		LFS_SEGENTRY(sup, fs, i, bp);
439 		seg_table[i].su_flags = sup->su_flags & ~SEGUSE_ACTIVE;
440 		if (preen)
441 			seg_table[i].su_nbytes = sup->su_nbytes;
442 		brelse(bp, 0);
443 	}
444 
445 	/* Initialize Ifile entry */
446 	din_table[fs->lfs_ifile] = fs->lfs_idaddr;
447 	seg_table[dtosn(fs, fs->lfs_idaddr)].su_nbytes += DINODE1_SIZE;
448 
449 #ifndef VERBOSE_BLOCKMAP
450 	bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
451 	blockmap = ecalloc(bmapsize, sizeof(char));
452 #else
453 	bmapsize = maxfsblock * sizeof(ino_t);
454 	blockmap = ecalloc(maxfsblock, sizeof(ino_t));
455 #endif
456 	statemap = ecalloc(maxino, sizeof(char));
457 	typemap = ecalloc(maxino, sizeof(char));
458 	lncntp = ecalloc(maxino, sizeof(int16_t));
459 
460 	if (preen) {
461 		n_files = fs->lfs_nfiles;
462 		n_blks  = fs->lfs_dsize - fs->lfs_bfree;
463 		numdirs = maxino;
464 		inplast = 0;
465 		listmax = numdirs + 10;
466 		inpsort = ecalloc(listmax, sizeof(struct inoinfo *));
467 		inphead = ecalloc(numdirs, sizeof(struct inoinfo *));
468 	}
469 
470 	return (1);
471 
472 	ckfini(0);
473 	return (0);
474 }
475 
476 static struct disklabel *
477 getdisklabel(const char *s, int fd)
478 {
479 	static struct disklabel lab;
480 
481 	if (ioctl(fd, DIOCGDINFO, (char *) &lab) < 0) {
482 		if (s == NULL)
483 			return ((struct disklabel *) NULL);
484 		pwarn("ioctl (GCINFO): %s\n", strerror(errno));
485 		return NULL;
486 	}
487 	return (&lab);
488 }
489