GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/fsdb/../../sbin/fsck_ffs/setup.c Lines: 0 399 0.0 %
Date: 2017-11-07 Branches: 0 374 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: setup.c,v 1.63 2016/09/09 15:37:15 tb Exp $	*/
2
/*	$NetBSD: setup.c,v 1.27 1996/09/27 22:45:19 christos Exp $	*/
3
4
/*
5
 * Copyright (c) 1980, 1986, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/param.h>	/* MAXBSIZE DEV_BSIZE roundup */
34
#define DKTYPENAMES
35
#include <sys/time.h>
36
#include <ufs/ufs/dinode.h>
37
#include <ufs/ffs/fs.h>
38
#include <sys/stat.h>
39
#include <sys/ioctl.h>
40
#include <sys/dkio.h>
41
#include <sys/disklabel.h>
42
43
#include <errno.h>
44
#include <fcntl.h>
45
#include <stdio.h>
46
#include <stdlib.h>
47
#include <unistd.h>
48
#include <string.h>
49
#include <util.h>
50
#include <limits.h>
51
#include <ctype.h>
52
#include <err.h>
53
54
#include "fsck.h"
55
#include "extern.h"
56
#include "fsutil.h"
57
58
#define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
59
60
#define altsblock (*asblk.b_un.b_fs)
61
#define POWEROF2(num)	(((num) & ((num) - 1)) == 0)
62
63
void badsb(int, char *);
64
int calcsb(char *, int, struct fs *, struct disklabel *, uint32_t);
65
static struct disklabel *getdisklabel(char *, int);
66
static int readsb(int);
67
static int cmpsb(struct fs *, struct fs *);
68
static char rdevname[PATH_MAX];
69
70
long numdirs, listmax, inplast;
71
72
/*
73
 * Possible locations for the superblock.
74
 */
75
static const int sbtry[] = SBLOCKSEARCH;
76
/* locations the 1st alternate sb can be at */
77
static const int altsbtry[] = { 32, 64, 128, 144, 160, 192, 256 };
78
79
int
80
setup(char *dev, int isfsdb)
81
{
82
	long cg, size, asked, i, j;
83
	size_t bmapsize;
84
	struct disklabel *lp;
85
	off_t sizepb;
86
	struct stat statb;
87
	struct fs proto;
88
	int doskipclean;
89
	int32_t maxsymlinklen, nindir, inopb;
90
	u_int64_t maxfilesize;
91
	char *realdev;
92
93
	havesb = 0;
94
	fswritefd = fsreadfd = -1;
95
	doskipclean = skipclean;
96
	if ((fsreadfd = opendev(dev, O_RDONLY, 0, &realdev)) < 0) {
97
		printf("Can't open %s: %s\n", dev, strerror(errno));
98
		return (0);
99
	}
100
	if (strncmp(dev, realdev, PATH_MAX) != 0) {
101
		blockcheck(unrawname(realdev));
102
		strlcpy(rdevname, realdev, sizeof(rdevname));
103
		setcdevname(rdevname, dev, preen);
104
105
		if (isfsdb || !hotroot())
106
			if (pledge("stdio rpath wpath getpw tty disklabel",
107
			    NULL) == -1)
108
				err(1, "pledge");
109
	}
110
	if (fstat(fsreadfd, &statb) < 0) {
111
		printf("Can't stat %s: %s\n", realdev, strerror(errno));
112
		close(fsreadfd);
113
		return (0);
114
	}
115
	if (!S_ISCHR(statb.st_mode)) {
116
		pfatal("%s is not a character device", realdev);
117
		if (reply("CONTINUE") == 0) {
118
			close(fsreadfd);
119
			return (0);
120
		}
121
	}
122
	if (preen == 0) {
123
		printf("** %s", realdev);
124
		if (strncmp(dev, realdev, PATH_MAX) != 0)
125
			printf(" (%s)", dev);
126
	}
127
	if (nflag || (fswritefd = opendev(dev, O_WRONLY, 0, NULL)) < 0) {
128
		fswritefd = -1;
129
		if (preen)
130
			pfatal("NO WRITE ACCESS");
131
		printf(" (NO WRITE)");
132
	}
133
	if (preen == 0)
134
		printf("\n");
135
	fsmodified = 0;
136
	lfdir = 0;
137
	initbarea(&sblk);
138
	initbarea(&asblk);
139
	sblk.b_un.b_buf = malloc(SBSIZE);
140
	asblk.b_un.b_buf = malloc(SBSIZE);
141
	if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
142
		errexit("cannot allocate space for superblock\n");
143
	if ((lp = getdisklabel(NULL, fsreadfd)) != NULL)
144
		secsize = lp->d_secsize;
145
	else
146
		secsize = DEV_BSIZE;
147
148
	if (isfsdb) {
149
		if (pledge("stdio rpath getpw tty flock cpath wpath", NULL) == -1)
150
			err(1, "pledge");
151
	} else if (!hotroot()) {
152
#ifndef SMALL
153
		if (pledge("stdio getpw flock rpath cpath wpath", NULL) == -1)
154
			err(1, "pledge");
155
#else
156
		if (pledge("stdio flock rpath cpath wpath", NULL) == -1)
157
			err(1, "pledge");
158
#endif
159
	}
160
161
	/*
162
	 * Read in the superblock, looking for alternates if necessary
163
	 */
164
	if (readsb(1) == 0) {
165
		if (bflag || preen ||
166
		    calcsb(realdev, fsreadfd, &proto, lp, SBLOCK_UFS1) == 0)
167
			return(0);
168
		if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
169
			return (0);
170
		for (i = 0; i < sizeof(altsbtry) / sizeof(altsbtry[0]); i++) {
171
			bflag = altsbtry[i];
172
			/* proto partially setup by calcsb */
173
			if (readsb(0) != 0 &&
174
			    proto.fs_fsize == sblock.fs_fsize &&
175
			    proto.fs_bsize == sblock.fs_bsize)
176
				goto found;
177
		}
178
		for (cg = 0; cg < proto.fs_ncg; cg++) {
179
			bflag = fsbtodb(&proto, cgsblock(&proto, cg));
180
			if (readsb(0) != 0 &&
181
			    proto.fs_fsize == sblock.fs_fsize &&
182
			    proto.fs_bsize == sblock.fs_bsize)
183
				goto found;
184
		}
185
		calcsb(realdev, fsreadfd, &proto, lp, SBLOCK_UFS2);
186
		for (cg = 0; cg < proto.fs_ncg; cg++) {
187
			bflag = fsbtodb(&proto, cgsblock(&proto, cg));
188
			if (readsb(0) != 0 &&
189
			    proto.fs_fsize == sblock.fs_fsize &&
190
			    proto.fs_bsize == sblock.fs_bsize)
191
				goto found;
192
		}
193
		if (cg >= proto.fs_ncg) {
194
			printf("%s %s\n%s %s\n%s %s\n",
195
			    "SEARCH FOR ALTERNATE SUPER-BLOCK",
196
			    "FAILED. YOU MUST USE THE",
197
			    "-b OPTION TO FSCK_FFS TO SPECIFY THE",
198
			    "LOCATION OF AN ALTERNATE",
199
			    "SUPER-BLOCK TO SUPPLY NEEDED",
200
			    "INFORMATION; SEE fsck_ffs(8).");
201
			return(0);
202
		}
203
found:
204
		doskipclean = 0;
205
		pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
206
	}
207
	if (debug)
208
		printf("clean = %d\n", sblock.fs_clean);
209
	if (sblock.fs_clean & FS_ISCLEAN) {
210
		if (doskipclean) {
211
			pwarn("%sile system is clean; not checking\n",
212
			    preen ? "f" : "** F");
213
			return (-1);
214
		}
215
		if (!preen)
216
			pwarn("** File system is already clean\n");
217
	}
218
	maxfsblock = sblock.fs_size;
219
	maxino = sblock.fs_ncg * sblock.fs_ipg;
220
	sizepb = sblock.fs_bsize;
221
	maxfilesize = sblock.fs_bsize * NDADDR - 1;
222
	for (i = 0; i < NIADDR; i++) {
223
		sizepb *= NINDIR(&sblock);
224
		maxfilesize += sizepb;
225
	}
226
	/*
227
	 * Check and potentially fix certain fields in the super block.
228
	 */
229
	if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
230
		pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
231
		if (reply("SET TO DEFAULT") == 1) {
232
			sblock.fs_optim = FS_OPTTIME;
233
			sbdirty();
234
		}
235
	}
236
	if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
237
		pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
238
		    sblock.fs_minfree);
239
		if (reply("SET TO DEFAULT") == 1) {
240
			sblock.fs_minfree = 10;
241
			sbdirty();
242
		}
243
	}
244
	if (sblock.fs_npsect < sblock.fs_nsect ||
245
	    sblock.fs_npsect > sblock.fs_nsect*2) {
246
		pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
247
		    sblock.fs_npsect);
248
		sblock.fs_npsect = sblock.fs_nsect;
249
		if (preen)
250
			printf(" (FIXED)\n");
251
		if (preen || reply("SET TO DEFAULT") == 1) {
252
			sbdirty();
253
			dirty(&asblk);
254
		}
255
	}
256
	if (sblock.fs_bmask != ~(sblock.fs_bsize - 1)) {
257
		pwarn("INCORRECT BMASK=%x IN SUPERBLOCK",
258
		    sblock.fs_bmask);
259
		sblock.fs_bmask = ~(sblock.fs_bsize - 1);
260
		if (preen)
261
			printf(" (FIXED)\n");
262
		if (preen || reply("FIX") == 1) {
263
			sbdirty();
264
			dirty(&asblk);
265
		}
266
	}
267
	if (sblock.fs_fmask != ~(sblock.fs_fsize - 1)) {
268
		pwarn("INCORRECT FMASK=%x IN SUPERBLOCK",
269
		    sblock.fs_fmask);
270
		sblock.fs_fmask = ~(sblock.fs_fsize - 1);
271
		if (preen)
272
			printf(" (FIXED)\n");
273
		if (preen || reply("FIX") == 1) {
274
			sbdirty();
275
			dirty(&asblk);
276
		}
277
	}
278
	if (1 << sblock.fs_bshift != sblock.fs_bsize) {
279
		pwarn("INCORRECT BSHIFT=%d IN SUPERBLOCK", sblock.fs_bshift);
280
		sblock.fs_bshift = ffs(sblock.fs_bsize) - 1;
281
		if (preen)
282
			printf(" (FIXED)\n");
283
		if (preen || reply("FIX") == 1) {
284
			sbdirty();
285
			dirty(&asblk);
286
		}
287
	}
288
	if (1 << sblock.fs_fshift != sblock.fs_fsize) {
289
		pwarn("INCORRECT FSHIFT=%d IN SUPERBLOCK", sblock.fs_fshift);
290
		sblock.fs_fshift = ffs(sblock.fs_fsize) - 1;
291
		if (preen)
292
			printf(" (FIXED)\n");
293
		if (preen || reply("FIX") == 1) {
294
			sbdirty();
295
			dirty(&asblk);
296
		}
297
	}
298
	if (sblock.fs_inodefmt < FS_44INODEFMT) {
299
		pwarn("Format of filesystem is too old.\n");
300
		pwarn("Must update to modern format using a version of fsck\n");
301
		pfatal("from before release 5.0 with the command ``fsck -c 2''\n");
302
		exit(8);
303
	}
304
	if (sblock.fs_maxfilesize != maxfilesize) {
305
		pwarn("INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK",
306
		    (unsigned long long)sblock.fs_maxfilesize);
307
		sblock.fs_maxfilesize = maxfilesize;
308
		if (preen)
309
			printf(" (FIXED)\n");
310
		if (preen || reply("FIX") == 1) {
311
			sbdirty();
312
			dirty(&asblk);
313
		}
314
	}
315
	maxsymlinklen = sblock.fs_magic == FS_UFS1_MAGIC ?
316
	    MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2;
317
	if (sblock.fs_maxsymlinklen != maxsymlinklen) {
318
		pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK",
319
		    sblock.fs_maxsymlinklen);
320
		sblock.fs_maxsymlinklen = maxsymlinklen;
321
		if (preen)
322
			printf(" (FIXED)\n");
323
		if (preen || reply("FIX") == 1) {
324
			sbdirty();
325
			dirty(&asblk);
326
		}
327
	}
328
	if (sblock.fs_qbmask != ~sblock.fs_bmask) {
329
		pwarn("INCORRECT QBMASK=%lx IN SUPERBLOCK",
330
		    (unsigned long)sblock.fs_qbmask);
331
		sblock.fs_qbmask = ~sblock.fs_bmask;
332
		if (preen)
333
			printf(" (FIXED)\n");
334
		if (preen || reply("FIX") == 1) {
335
			sbdirty();
336
			dirty(&asblk);
337
		}
338
	}
339
	if (sblock.fs_qfmask != ~sblock.fs_fmask) {
340
		pwarn("INCORRECT QFMASK=%lx IN SUPERBLOCK",
341
		    (unsigned long)sblock.fs_qfmask);
342
		sblock.fs_qfmask = ~sblock.fs_fmask;
343
		if (preen)
344
			printf(" (FIXED)\n");
345
		if (preen || reply("FIX") == 1) {
346
			sbdirty();
347
			dirty(&asblk);
348
		}
349
	}
350
	if (sblock.fs_cgsize != fragroundup(&sblock, CGSIZE(&sblock))) {
351
		pwarn("INCONSISTENT CGSIZE=%d\n", sblock.fs_cgsize);
352
		sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
353
		if (preen)
354
			printf(" (FIXED)\n");
355
		if (preen || reply("FIX") == 1) {
356
			sbdirty();
357
			dirty(&asblk);
358
		}
359
	}
360
	if (sblock.fs_magic == FS_UFS2_MAGIC)
361
		inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode);
362
	else
363
		inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode);
364
	if (INOPB(&sblock) != inopb) {
365
		pwarn("INCONSISTENT INOPB=%d\n", INOPB(&sblock));
366
		sblock.fs_inopb = inopb;
367
		if (preen)
368
			printf(" (FIXED)\n");
369
		if (preen || reply("FIX") == 1) {
370
			sbdirty();
371
			dirty(&asblk);
372
		}
373
	}
374
	if (sblock.fs_magic == FS_UFS2_MAGIC)
375
		nindir = sblock.fs_bsize / sizeof(int64_t);
376
	else
377
		nindir = sblock.fs_bsize / sizeof(int32_t);
378
	if (NINDIR(&sblock) != nindir) {
379
		pwarn("INCONSISTENT NINDIR=%d\n", NINDIR(&sblock));
380
		sblock.fs_nindir = nindir;
381
		if (preen)
382
			printf(" (FIXED)\n");
383
		if (preen || reply("FIX") == 1) {
384
			sbdirty();
385
			dirty(&asblk);
386
		}
387
	}
388
	if (asblk.b_dirty && !bflag) {
389
		memcpy(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
390
		flush(fswritefd, &asblk);
391
	}
392
	/*
393
	 * read in the summary info.
394
	 */
395
	asked = 0;
396
	sblock.fs_csp = calloc(1, sblock.fs_cssize);
397
	if (sblock.fs_csp == NULL) {
398
		printf("cannot alloc %u bytes for cylinder group summary area\n",
399
		    (unsigned)sblock.fs_cssize);
400
		goto badsblabel;
401
	}
402
	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
403
		size = sblock.fs_cssize - i < sblock.fs_bsize ?
404
		    sblock.fs_cssize - i : sblock.fs_bsize;
405
		if (bread(fsreadfd, (char *)sblock.fs_csp + i,
406
		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
407
		    size) != 0 && !asked) {
408
			pfatal("BAD SUMMARY INFORMATION");
409
			if (reply("CONTINUE") == 0) {
410
				ckfini(0);
411
				errexit("%s", "");
412
			}
413
			asked++;
414
		}
415
	}
416
	/*
417
	 * allocate and initialize the necessary maps
418
	 */
419
	bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
420
	blockmap = calloc(bmapsize, sizeof(char));
421
	if (blockmap == NULL) {
422
		printf("cannot alloc %zu bytes for blockmap\n", bmapsize);
423
		goto badsblabel;
424
	}
425
	inostathead = calloc((unsigned)(sblock.fs_ncg),
426
	    sizeof(struct inostatlist));
427
	if (inostathead == NULL) {
428
		printf("cannot alloc %zu bytes for inostathead\n",
429
		    (unsigned)sblock.fs_ncg * sizeof(struct inostatlist));
430
		goto badsblabel;
431
	}
432
	numdirs = MAXIMUM(sblock.fs_cstotal.cs_ndir, 128);
433
	inplast = 0;
434
	listmax = numdirs + 10;
435
	inpsort = calloc((unsigned)listmax, sizeof(struct inoinfo *));
436
	if (inpsort == NULL) {
437
		printf("cannot alloc %zu bytes for inpsort\n",
438
		    (unsigned)listmax * sizeof(struct inoinfo *));
439
		goto badsblabel;
440
	}
441
	inphead = calloc((unsigned)numdirs, sizeof(struct inoinfo *));
442
	if (inphead == NULL) {
443
		printf("cannot alloc %zu bytes for inphead\n",
444
		    (unsigned)numdirs * sizeof(struct inoinfo *));
445
		goto badsblabel;
446
	}
447
	bufinit();
448
	if (sblock.fs_flags & FS_DOSOFTDEP)
449
		usedsoftdep = 1;
450
	else
451
		usedsoftdep = 0;
452
	return (1);
453
454
badsblabel:
455
	ckfini(0);
456
	return (0);
457
}
458
459
/*
460
 * Read in the super block and its summary info.
461
 */
462
static int
463
readsb(int listerr)
464
{
465
	daddr_t super = 0;
466
	int i;
467
468
	if (bflag) {
469
		super = bflag;
470
471
		if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0)
472
			return (0);
473
474
		if (sblock.fs_magic != FS_UFS1_MAGIC &&
475
		    sblock.fs_magic != FS_UFS2_MAGIC) {
476
			badsb(listerr, "MAGIC NUMBER WRONG");
477
			return (0);
478
		}
479
	} else {
480
		for (i = 0; sbtry[i] != -1; i++) {
481
			super = sbtry[i] / DEV_BSIZE;
482
483
			if (bread(fsreadfd, (char *)&sblock, super,
484
			    (long)SBSIZE) != 0)
485
				return (0);
486
487
			if (sblock.fs_magic != FS_UFS1_MAGIC &&
488
			    sblock.fs_magic != FS_UFS2_MAGIC)
489
				continue; /* Not a superblock */
490
491
			/*
492
			 * Do not look for an FFS1 file system at SBLOCK_UFS2.
493
			 * Doing so will find the wrong super-block for file
494
			 * systems with 64k block size.
495
			 */
496
			if (sblock.fs_magic == FS_UFS1_MAGIC &&
497
			    sbtry[i] == SBLOCK_UFS2)
498
				continue;
499
500
			if (sblock.fs_magic == FS_UFS2_MAGIC &&
501
			    sblock.fs_sblockloc != sbtry[i])
502
				continue; /* Not a superblock */
503
504
			break;
505
		}
506
507
		if (sbtry[i] == -1) {
508
			badsb(listerr, "MAGIC NUMBER WRONG");
509
			return (0);
510
		}
511
	}
512
513
	sblk.b_bno = super;
514
	sblk.b_size = SBSIZE;
515
516
	/*
517
	 * run a few consistency checks of the super block
518
	 */
519
	if (sblock.fs_ncg < 1) {
520
		badsb(listerr, "NCG OUT OF RANGE");
521
		return (0);
522
	}
523
	if (sblock.fs_cpg < 1) {
524
		badsb(listerr, "CPG OUT OF RANGE");
525
		return (0);
526
	}
527
	if (sblock.fs_magic == FS_UFS1_MAGIC) {
528
		if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
529
		    (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
530
			badsb(listerr, "NCYL LESS THAN NCG*CPG");
531
			return (0);
532
		}
533
	}
534
	if (sblock.fs_sbsize > SBSIZE) {
535
		badsb(listerr, "SBSIZE PREPOSTEROUSLY LARGE");
536
		return (0);
537
	}
538
539
	if (!POWEROF2(sblock.fs_bsize) || sblock.fs_bsize < MINBSIZE ||
540
	    sblock.fs_bsize > MAXBSIZE) {
541
		badsb(listerr, "ILLEGAL BLOCK SIZE IN SUPERBLOCK");
542
		return (0);
543
	}
544
545
	if (!POWEROF2(sblock.fs_fsize) || sblock.fs_fsize > sblock.fs_bsize ||
546
	    sblock.fs_fsize < sblock.fs_bsize / MAXFRAG) {
547
		badsb(listerr, "ILLEGAL FRAGMENT SIZE IN SUPERBLOCK");
548
		return (0);
549
	}
550
551
	if (bflag)
552
		goto out;
553
	getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
554
	if (asblk.b_errs)
555
		return (0);
556
	if (cmpsb(&sblock, &altsblock)) {
557
		if (debug) {
558
			long *nlp, *olp, *endlp;
559
560
			printf("superblock mismatches\n");
561
			nlp = (long *)&altsblock;
562
			olp = (long *)&sblock;
563
			endlp = olp + (sblock.fs_sbsize / sizeof *olp);
564
			for ( ; olp < endlp; olp++, nlp++) {
565
				if (*olp == *nlp)
566
					continue;
567
				printf("offset %d, original %ld, alternate %ld\n",
568
				    (int)(olp - (long *)&sblock), *olp, *nlp);
569
			}
570
		}
571
		badsb(listerr,
572
		    "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN LAST ALTERNATE");
573
		return (0);
574
	}
575
out:
576
	if (sblock.fs_magic == FS_UFS1_MAGIC) {
577
		sblock.fs_time = sblock.fs_ffs1_time;
578
		sblock.fs_size = sblock.fs_ffs1_size;
579
		sblock.fs_dsize = sblock.fs_ffs1_dsize;
580
		sblock.fs_csaddr = sblock.fs_ffs1_csaddr;
581
		sblock.fs_cstotal.cs_ndir = sblock.fs_ffs1_cstotal.cs_ndir;
582
		sblock.fs_cstotal.cs_nbfree = sblock.fs_ffs1_cstotal.cs_nbfree;
583
		sblock.fs_cstotal.cs_nifree = sblock.fs_ffs1_cstotal.cs_nifree;
584
		sblock.fs_cstotal.cs_nffree = sblock.fs_ffs1_cstotal.cs_nffree;
585
	}
586
	havesb = 1;
587
	return (1);
588
}
589
590
void
591
badsb(int listerr, char *s)
592
{
593
594
	if (!listerr)
595
		return;
596
	if (preen)
597
		printf("%s: ", cdevname());
598
	pfatal("BAD SUPER BLOCK: %s\n", s);
599
}
600
601
/*
602
 * Calculate a prototype superblock based on information in the disk label.
603
 * When done the cgsblock macro can be calculated and the fs_ncg field
604
 * can be used. Do NOT attempt to use other macros without verifying that
605
 * their needed information is available!
606
 */
607
int
608
calcsb(char *dev, int devfd, struct fs *fs, struct disklabel *lp,
609
    uint32_t sblockloc)
610
{
611
	struct partition *pp;
612
	char *cp;
613
	int i;
614
615
	cp = strchr(dev, '\0');
616
	if ((cp == NULL || (cp[-1] < 'a' || cp[-1] >= 'a' + MAXPARTITIONS)) &&
617
	    !isdigit((unsigned char)cp[-1])) {
618
		pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
619
		return (0);
620
	}
621
	cp--;
622
	if (lp == NULL)
623
		pfatal("%s: CANNOT READ DISKLABEL\n", dev);
624
	if (isdigit((unsigned char)*cp))
625
		pp = &lp->d_partitions[0];
626
	else
627
		pp = &lp->d_partitions[*cp - 'a'];
628
	if (pp->p_fstype != FS_BSDFFS) {
629
		pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n",
630
		    dev, pp->p_fstype < FSMAXTYPES ?
631
		    fstypenames[pp->p_fstype] : "unknown");
632
		return (0);
633
	}
634
	memset(fs, 0, sizeof(struct fs));
635
	fs->fs_fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock);
636
	fs->fs_frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock);
637
	fs->fs_fpg = pp->p_cpg * fs->fs_frag;
638
	fs->fs_bsize = fs->fs_fsize * fs->fs_frag;
639
	fs->fs_nspf = DL_SECTOBLK(lp, fs->fs_fsize / lp->d_secsize);
640
	for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1)
641
		fs->fs_fsbtodb++;
642
	/*
643
	 * fs->fs_size is in fragments, DL_GETPSIZE() is in disk sectors
644
	 * and fs_nspf is in DEV_BSIZE blocks. Shake well.
645
	 */
646
	fs->fs_size = DL_SECTOBLK(lp, DL_GETPSIZE(pp)) / fs->fs_nspf;
647
	fs->fs_ncg = howmany(fs->fs_size, fs->fs_fpg);
648
	/* we can't use lp->d_sbsize, it is the max sb size */
649
	fs->fs_sblkno = roundup(
650
		howmany(sblockloc + SBSIZE, fs->fs_fsize),
651
		fs->fs_frag);
652
653
	return (1);
654
}
655
656
static struct disklabel *
657
getdisklabel(char *s, int fd)
658
{
659
	static struct disklabel lab;
660
661
	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
662
		if (s == NULL)
663
			return (NULL);
664
		pwarn("ioctl (GCINFO): %s\n", strerror(errno));
665
		errexit("%s: can't read disk label\n", s);
666
	}
667
	return (&lab);
668
}
669
670
/*
671
 * Compare two superblocks
672
 */
673
static int
674
cmpsb(struct fs *sb, struct fs *asb)
675
{
676
	/*
677
	 * Only compare fields which should be the same, and ignore ones
678
	 * likely to change to ensure future compatibility.
679
	 */
680
	if (asb->fs_sblkno != sb->fs_sblkno ||
681
	    asb->fs_cblkno != sb->fs_cblkno ||
682
	    asb->fs_iblkno != sb->fs_iblkno ||
683
	    asb->fs_dblkno != sb->fs_dblkno ||
684
	    asb->fs_cgoffset != sb->fs_cgoffset ||
685
	    asb->fs_cgmask != sb->fs_cgmask ||
686
	    asb->fs_ncg != sb->fs_ncg ||
687
	    asb->fs_bsize != sb->fs_bsize ||
688
	    asb->fs_fsize != sb->fs_fsize ||
689
	    asb->fs_frag != sb->fs_frag ||
690
	    asb->fs_bmask != sb->fs_bmask ||
691
	    asb->fs_fmask != sb->fs_fmask ||
692
	    asb->fs_bshift != sb->fs_bshift ||
693
	    asb->fs_fshift != sb->fs_fshift ||
694
	    asb->fs_fragshift != sb->fs_fragshift ||
695
	    asb->fs_fsbtodb != sb->fs_fsbtodb ||
696
	    asb->fs_sbsize != sb->fs_sbsize ||
697
	    asb->fs_nindir != sb->fs_nindir ||
698
	    asb->fs_inopb != sb->fs_inopb ||
699
	    asb->fs_cssize != sb->fs_cssize ||
700
	    asb->fs_cpg != sb->fs_cpg ||
701
	    asb->fs_ipg != sb->fs_ipg ||
702
	    asb->fs_fpg != sb->fs_fpg ||
703
	    asb->fs_magic != sb->fs_magic)
704
		    return (1);
705
	/* they're the same */
706
	return (0);
707
}