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