xref: /titanic_44/usr/src/cmd/fs.d/ufs/fsck/setup.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7 /*	  All Rights Reserved  	*/
8 
9 /*
10  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms are permitted
14  * provided that: (1) source distributions retain this entire copyright
15  * notice and comment, and (2) distributions including binaries display
16  * the following acknowledgement:  ``This product includes software
17  * developed by the University of California, Berkeley and its contributors''
18  * in the documentation or other materials provided with the distribution
19  * and in all advertising materials mentioning features or use of this
20  * software. Neither the name of the University nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #define	DKTYPENAMES
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/sysmacros.h>
37 #include <sys/mntent.h>
38 #include <sys/mnttab.h>
39 #include <sys/dkio.h>
40 #include <sys/filio.h>
41 #include <sys/isa_defs.h>	/* for ENDIAN defines */
42 
43 #define	bcopy(f, t, n)    memcpy(t, f, n)
44 #define	bzero(s, n)	memset(s, 0, n)
45 #define	bcmp(s, d, n)	memcmp(s, d, n)
46 
47 #define	index(s, r)	strchr(s, r)
48 #define	rindex(s, r)	strrchr(s, r)
49 
50 #include <sys/int_const.h>
51 #include <sys/fs/ufs_fs.h>
52 #include <sys/vnode.h>
53 #include <sys/fs/ufs_inode.h>
54 #include <sys/fs/ufs_log.h>
55 #include <sys/stat.h>
56 #include <sys/file.h>
57 #include <sys/fcntl.h>
58 #include <string.h>
59 #include <unistd.h>
60 #include <ustat.h>
61 #include <fcntl.h>
62 
63 #include "fsck.h"
64 #include <sys/vfstab.h>
65 #include <sys/ustat.h>
66 #include "roll_log.h"
67 
68 struct bufarea asblk;
69 #define	altsblock (*asblk.b_un.b_fs)
70 #define	POWEROF2(num)	(((num) & ((num) - 1)) == 0)
71 
72 static void badsb(int, char *);
73 static int checksb(int);
74 
75 struct shadowclientinfo *shadowclientinfo = NULL;
76 struct shadowclientinfo *attrclientinfo = NULL;
77 int maxshadowclients = 1024;
78 
79 /*
80  * The size of a cylinder group is calculated by CGSIZE. The maximum size
81  * is limited by the fact that cylinder groups are at most one block.
82  * Its size is derived from the size of the maps maintained in the
83  * cylinder group and the (struct cg) size.
84  */
85 #define	CGSIZE(fs) \
86 	/* base cg */	  (sizeof (struct cg) + \
87 	/* blktot size */ (fs)->fs_cpg * sizeof (long) + \
88 	/* blks size */	  (fs)->fs_cpg * (fs)->fs_nrpos * sizeof (short) + \
89 	/* inode map */	  howmany((fs)->fs_ipg, NBBY) + \
90 	/* block map */	  howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
91 
92 extern int	mflag;
93 extern char 	hotroot;
94 extern char	*mount_point;
95 
96 static int
97 read_super_block()
98 {
99 	int fd;
100 
101 	if (mount_point) {
102 		fd = open(mount_point, O_RDONLY);
103 		if (fd == -1) {
104 			perror("fsck: open mount point error");
105 			exit(39);
106 		}
107 		/* get the latest super block */
108 		if (ioctl(fd, _FIOGETSUPERBLOCK, &sblock)) {
109 			perror("fsck: ioctl _FIOGETSUPERBLOCK error");
110 			exit(39);
111 		}
112 		close(fd);
113 	} else {
114 		(void) bread(fsreadfd, (char *)&sblock,
115 			bflag != 0 ? (diskaddr_t)bflag : (diskaddr_t)SBLOCK,
116 			(long)SBSIZE);
117 	}
118 
119 	/*
120 	 * rudimental consistency checks
121 	 */
122 	if ((sblock.fs_magic != FS_MAGIC) &&
123 		(sblock.fs_magic != MTB_UFS_MAGIC)) {
124 		badsb(1, "MAGIC NUMBER WRONG");
125 		return (0);
126 	}
127 	if (sblock.fs_magic == MTB_UFS_MAGIC &&
128 		(sblock.fs_version > MTB_UFS_VERSION_1 ||
129 		sblock.fs_version < MTB_UFS_VERSION_MIN)) {
130 		badsb(1, "UNRECOGNIZED VERSION");
131 		return (0);
132 	}
133 	if (sblock.fs_ncg < 1) {
134 		badsb(1, "NCG OUT OF RANGE");
135 		return (0);
136 	}
137 	if (sblock.fs_cpg < 1) {
138 		badsb(1, "CPG OUT OF RANGE");
139 		return (0);
140 	}
141 	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
142 		(sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
143 		badsb(1, "NCYL IS INCONSISTENT WITH NCG*CPG");
144 		return (0);
145 	}
146 	if (sblock.fs_sbsize < 0 || sblock.fs_sbsize > SBSIZE) {
147 		badsb(1, "SIZE TOO LARGE");
148 		return (0);
149 	}
150 
151 	return (1);
152 }
153 
154 void
155 flush_fs()
156 {
157 	int fd;
158 
159 	if (mount_point) {
160 		fd = open(mount_point, O_RDONLY);
161 		if (fd == -1) {
162 			perror("fsck: open mount point error");
163 			exit(39);
164 		}
165 		if (ioctl(fd, _FIOFFS, NULL)) { /* flush file system */
166 			perror("fsck: ioctl _FIOFFS error");
167 			exit(39);
168 		}
169 		close(fd);
170 	}
171 }
172 
173 /*
174  * Roll the embedded log, if any, and set up the global variables
175  * islog, islogok, and ismdd.
176  */
177 static int
178 logsetup(char *devstr)
179 {
180 	void		*buf;
181 	struct dk_cinfo	dkcinfo;
182 	extent_block_t	*ebp;
183 	ml_unit_t	*ul;
184 	ml_odunit_t	*ud;
185 	void		*ud_buf;
186 	int		badlog;
187 
188 	ismdd = islog = islogok = 0;
189 	if (bflag)
190 		return (1); /* can't roll log while alternate sb specified */
191 
192 	/* Roll the log, if any */
193 	sblock.fs_logbno = 0;
194 	badlog = 0;
195 	if (!read_super_block())
196 		return (0);
197 
198 	/*
199 	 * Roll the log in 3 cases:
200 	 * 1. If it's unmounted (mount_point == NULL) and it's not marked
201 	 *    as fully rolled (sblock.fs_rolled != FS_ALL_ROLLED)
202 	 * 2. If it's mounted and anything other than a sanity
203 	 *    check fsck (mflag) is being done, as we have the current
204 	 *    super block. Note, only a sanity check is done for
205 	 *    root/usr at boot. If a roll were done then the expensive
206 	 *    ufs_flush() gets called, leading to a slower boot.
207 	 * 3. If anything other then a sanity check (mflag) is being done
208 	 *    to a mounted filesystem while it is in read-only state
209 	 *    (e.g. root during early boot stages) we have to detect this
210 	 *    and have to roll the log as well. NB. the read-only mount
211 	 *    will flip fs_clean from FSLOG to FSSTABLE and marks the
212 	 *    log as FS_NEED_ROLL.
213 	 */
214 	if (sblock.fs_logbno &&
215 	    (((mount_point == NULL) && (sblock.fs_rolled != FS_ALL_ROLLED)) ||
216 	    (mount_point && !mflag))) {
217 		int roll_log_err = 0;
218 
219 		if (sblock.fs_ronly && (sblock.fs_clean == FSSTABLE) &&
220 			(sblock.fs_state + sblock.fs_time == FSOKAY)) {
221 			/*
222 			 * roll the log without a mount
223 			 */
224 			flush_fs();
225 		}
226 		if (sblock.fs_clean == FSLOG &&
227 			(sblock.fs_state + sblock.fs_time == FSOKAY)) {
228 			if (rl_roll_log(devstr) != RL_SUCCESS)
229 				roll_log_err = 1;
230 		}
231 		if (roll_log_err) {
232 			(void) printf("Can't roll the log for %s.\n", devstr);
233 			/*
234 			 * There are two cases where we want to set
235 			 * an error code and return:
236 			 *  - We're preening
237 			 *  - We're not on a live root and the user
238 			 *    chose *not* to ignore the log
239 			 * Otherwise, we want to mark the log as bad
240 			 * and continue to check the filesystem.  This
241 			 * has the side effect of destroying the log.
242 			 */
243 			if (preen || (!hotroot &&
244 			    reply(
245 			"DISCARDING THE LOG MAY DISCARD PENDING TRANSACTIONS.\n"
246 					"DISCARD THE LOG AND CONTINUE") == 0)) {
247 				exitstat = 39;
248 				return (0);
249 			}
250 			++badlog;
251 		}
252 	}
253 
254 	/* MDD (disksuite) device */
255 	if (ioctl(fsreadfd, DKIOCINFO, &dkcinfo) == 0)
256 		if (dkcinfo.dki_ctype == DKC_MD)
257 			++ismdd;
258 
259 	/* Logging UFS may be enabled */
260 	if (sblock.fs_logbno) {
261 		++islog;
262 
263 		/* log is not okay; check the fs */
264 		if (FSOKAY != (sblock.fs_state + sblock.fs_time))
265 			return (1);
266 
267 		/*
268 		 * If logging or (stable and mounted) then continue
269 		 */
270 		if ((sblock.fs_clean != FSLOG) &&
271 		    ((sblock.fs_clean != FSSTABLE) || !(mount_point)))
272 			return (1);
273 
274 		/* get the log allocation block */
275 		buf = malloc((size_t)dev_bsize);
276 		if (buf == (void *) NULL) {
277 			return (1);
278 		}
279 		ud_buf = malloc((size_t)dev_bsize);
280 		if (ud_buf == (void *) NULL) {
281 			free(buf);
282 			return (1);
283 		}
284 		(void) bread(fsreadfd, buf,
285 		    logbtodb(&sblock, sblock.fs_logbno),
286 		    (long)dev_bsize);
287 		ebp = (extent_block_t *)buf;
288 
289 		/* log allocation block is not okay; check the fs */
290 		if (ebp->type != LUFS_EXTENTS) {
291 			free(buf);
292 			free(ud_buf);
293 			return (1);
294 		}
295 
296 		/* get the log state block(s) */
297 		if (bread(fsreadfd, ud_buf,
298 		    (logbtodb(&sblock, ebp->extents[0].pbno)),
299 		    (long)dev_bsize)) {
300 			(void) bread(fsreadfd, ud_buf,
301 			(logbtodb(&sblock, ebp->extents[0].pbno)) + 1,
302 			(long)dev_bsize);
303 		}
304 		ud = (ml_odunit_t *)ud_buf;
305 		ul = (ml_unit_t *)malloc(sizeof (*ul));
306 		if (ul == NULL) {
307 			free(buf);
308 			free(ud_buf);
309 			return (1);
310 		}
311 		ul->un_ondisk = *ud;
312 
313 		/* log state is okay; don't need to check the fs */
314 		if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) &&
315 		    (ul->un_version == LUFS_VERSION_LATEST) &&
316 		    (ul->un_badlog == 0) && (!badlog))
317 			++islogok;
318 		free(ud_buf);
319 		free(buf);
320 		free(ul);
321 	} else if (ismdd) {
322 		/* if it is a logging device and there are no errors */
323 		if (ioctl(fsreadfd, _FIOISLOG, NULL) == 0) {
324 			islog++;
325 			if (ioctl(fsreadfd, _FIOISLOGOK, NULL) == 0)
326 				islogok++;
327 		}
328 	}
329 
330 	return (1);
331 }
332 
333 char *
334 setup(char *dev)
335 {
336 	dev_t rootdev;
337 	int size, i, j;
338 	int64_t bmapsize;
339 	struct stat64 statb;
340 	static char devstr[MAXPATHLEN];
341 	char *raw, *rawname(), *unrawname();
342 	void write_altsb();
343 	struct ustat ustatb;
344 	caddr_t sip;
345 	int mountchk;
346 
347 	havesb = 0;
348 	if (stat64("/", &statb) < 0)
349 		errexit("Can't stat root\n");
350 	rootdev = statb.st_dev;
351 
352 	devname = devstr;
353 	strncpy(devstr, dev, sizeof (devstr));
354 restat:
355 	if (stat64(devstr, &statb) < 0) {
356 		printf("Can't stat %s\n", devstr);
357 		exitstat = 34;
358 		return (0);
359 	}
360 	/*
361 	 * A mount point is specified. But the mount point doesn't
362 	 * match entries in the /etc/vfstab.
363 	 * Search mnttab, because if the fs is error locked, it is
364 	 * allowed to be fsck'd while mounted.
365 	 */
366 	if ((statb.st_mode & S_IFMT) == S_IFDIR) {
367 		if (errorlocked) {
368 			FILE		*mnttab;
369 			struct mnttab	 mnt, mntpref,
370 					*mntp = &mnt,
371 					*mpref = &mntpref;
372 
373 			if ((mnttab = fopen(MNTTAB, "r")) == NULL) {
374 				printf("Can't open %s\n", MNTTAB);
375 				perror(MNTTAB);
376 				return (0);
377 			}
378 
379 			mntnull(mpref);
380 			mpref->mnt_fstype = malloc(strlen(MNTTYPE_UFS)+1);
381 			mpref->mnt_mountp = malloc(strlen(devstr)+1);
382 			strcpy(mpref->mnt_fstype, MNTTYPE_UFS);
383 			strcpy(mpref->mnt_mountp, devstr);
384 			mntnull(mntp);
385 
386 			if (getmntany(mnttab, mntp, mpref) == 0) {
387 				raw = rawname(unrawname(mntp->mnt_special));
388 				strcpy(devstr, raw);
389 				fclose(mnttab);
390 				goto restat;
391 			}
392 			fclose(mnttab);
393 		}
394 		printf("%s is not a block or character device\n", dev);
395 		return (0);
396 	}
397 
398 	if ((statb.st_mode & S_IFMT) == S_IFBLK) {
399 		if (rootdev == statb.st_rdev) {
400 			mount_point = "/";
401 			hotroot++;
402 		} else if (ustat(statb.st_rdev, &ustatb) == 0 && !errorlocked) {
403 			printf("%s is a mounted file system, ignored\n", dev);
404 			exitstat = 33;
405 			return (0);
406 		}
407 	}
408 	if ((statb.st_mode & S_IFMT) == S_IFDIR) {
409 		FILE *vfstab;
410 		struct vfstab vfsbuf;
411 		/*
412 		 * Check vfstab for a mount point with this name
413 		 */
414 		if ((vfstab = fopen(VFSTAB, "r")) == NULL) {
415 			errexit("Can't open checklist file: %s\n", VFSTAB);
416 		}
417 		while (getvfsent(vfstab, &vfsbuf) == NULL) {
418 			if (strcmp(devstr, vfsbuf.vfs_mountp) == 0) {
419 				if (strcmp(vfsbuf.vfs_fstype,
420 				    MNTTYPE_UFS) != 0) {
421 					/*
422 					 * found the entry but it is not a
423 					 * ufs filesystem, don't check it
424 					 */
425 					fclose(vfstab);
426 					return (0);
427 				}
428 				strcpy(devstr, vfsbuf.vfs_special);
429 				if (rflag) {
430 					raw = rawname(
431 					    unrawname(vfsbuf.vfs_special));
432 					strcpy(devstr, raw);
433 				}
434 				goto restat;
435 			}
436 		}
437 		fclose(vfstab);
438 
439 	} else if (((statb.st_mode & S_IFMT) != S_IFBLK) &&
440 	    ((statb.st_mode & S_IFMT) != S_IFCHR)) {
441 		if (preen)
442 			pwarn("file is not a block or character device.\n");
443 		else if (reply("file is not a block or character device; OK")
444 		    == 0)
445 			return (0);
446 		/*
447 		 * To fsck regular files (fs images)
448 		 * we need to clear the rflag since
449 		 * regular files don't have raw names.  --CW
450 		 */
451 		rflag = 0;
452 	}
453 
454 	if (mountchk = mounted(devstr)) {
455 		if (rflag) {
456 			mountedfs++;
457 			/*
458 			 * Get confirmation we should continue UNLESS:
459 			 * this is the root (since that is always
460 			 * mounted), we are running in preen mode, we
461 			 * are running in "just say no" mode, the fs is
462 			 * mounted read-only, or we are running in check
463 			 * only mode.
464 			 */
465 			if (rootdev != statb.st_rdev &&	!preen && !nflag &&
466 			    !mflag && mountchk != 2) {
467 				if (reply("FILE SYSTEM IS CURRENTLY MOUNTED."
468 				    "  CONTINUE") == 0) {
469 					exitstat = 33;
470 					return (0);
471 				}
472 			}
473 		} else {
474 			printf("%s is mounted, fsck on BLOCK device ignored\n",
475 				devstr);
476 			exit(33);
477 		}
478 		if (!errorlocked)
479 			sync();	/* call sync, only when devstr's mounted */
480 	}
481 	if (rflag) {
482 		char blockname[MAXPATHLEN];
483 		/*
484 		 * For root device check, must check
485 		 * block devices.
486 		 */
487 		strcpy(blockname, devstr);
488 		if (stat64(unrawname(blockname), &statb) < 0) {
489 			printf("Can't stat %s\n", blockname);
490 			exitstat = 34;
491 			return (0);
492 		}
493 	}
494 	if (rootdev == statb.st_rdev) {
495 		hotroot++;
496 		mount_point = "/";
497 	}
498 	if ((fsreadfd = open64(devstr, O_RDONLY)) < 0) {
499 		printf("Can't open %s\n", devstr);
500 		exitstat = 34;
501 		return (0);
502 	}
503 	if (preen == 0 || debug != 0)
504 		printf("** %s", devstr);
505 
506 	if (errorlocked) {
507 		if (debug && elock_combuf)
508 			printf(" error-lock comment: \"%s\" ", elock_combuf);
509 		fflag = 1;
510 	}
511 	pid = getpid();
512 	if (nflag || (fswritefd = open64(devstr, O_WRONLY)) < 0) {
513 		fswritefd = -1;
514 		if (preen && !debug)
515 			pfatal("(NO WRITE ACCESS)\n");
516 		printf(" (NO WRITE)");
517 	}
518 	if (preen == 0)
519 		printf("\n");
520 	else if (debug)
521 		printf(" pid %d\n", pid);
522 	if (debug && (hotroot || mountedfs)) {
523 		printf("** %s", devstr);
524 		if (hotroot)
525 			printf(" is root fs%s",
526 				mountedfs || errorlocked? " and": "");
527 		if (mountedfs)
528 			printf(" is mounted%s", errorlocked? " and": "");
529 		if (errorlocked)
530 			printf(" is error-locked");
531 
532 		printf(".\n");
533 	}
534 	fsmodified = 0;
535 	if (errorlocked)
536 		isdirty = 1;
537 	lfdir = 0;
538 	initbarea(&sblk);
539 	initbarea(&asblk);
540 	sblk.b_un.b_buf = malloc(SBSIZE);
541 	asblk.b_un.b_buf = malloc(SBSIZE);
542 	if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
543 		errexit("cannot allocate space for superblock\n");
544 	dev_bsize = secsize = DEV_BSIZE;
545 
546 	/* Check log state (embedded and SDS) */
547 	if (!logsetup(devstr))
548 		return (0);
549 
550 	/*
551 	 * Flush fs if we're going to do anything other than a sanity check.
552 	 * Note, if logging then the fs was flushed if needed in logsetup().
553 	 */
554 	if (!islog && !mflag)
555 		flush_fs();
556 
557 	if (!read_super_block()) /* re-read sb after possibly rolling the log */
558 		return (0);
559 	/*
560 	 * Check the superblock, looking for alternates if necessary
561 	 */
562 	if (checksb(1) == 0)
563 		return (0);
564 	maxfsblock = sblock.fs_size;
565 	maxino = sblock.fs_ncg * sblock.fs_ipg;
566 	/*
567 	 * Check and potentially fix certain fields in the super block.
568 	 */
569 	if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
570 		pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
571 		if (reply("SET TO DEFAULT") == 1) {
572 			sblock.fs_optim = FS_OPTTIME;
573 			sbdirty();
574 		}
575 	}
576 	if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
577 		pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
578 			sblock.fs_minfree);
579 		if (reply("SET TO DEFAULT") == 1) {
580 			sblock.fs_minfree = 10;
581 			sbdirty();
582 		}
583 	}
584 	if (cvtflag) {
585 		if (sblock.fs_postblformat == FS_42POSTBLFMT) {
586 			/*
587 			 * Requested to convert from old format to new format
588 			 */
589 			if (preen)
590 				pwarn("CONVERTING TO NEW FILE SYSTEM FORMAT\n");
591 			else if (!reply("CONVERT TO NEW FILE SYSTEM FORMAT"))
592 				return (0);
593 			isconvert = 1;
594 			sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
595 			sblock.fs_nrpos = 8;
596 			sblock.fs_npsect = sblock.fs_nsect;
597 			sblock.fs_postbloff =
598 			    (char *)(&sblock.fs_opostbl[0][0]) -
599 			    (char *)(&sblock.fs_link);
600 			sblock.fs_rotbloff = &sblock.fs_space[0] -
601 			    (uchar_t *)(&sblock.fs_link);
602 			sblock.fs_cgsize =
603 				fragroundup(&sblock, CGSIZE(&sblock));
604 			/*
605 			 * Planning now for future expansion.
606 			 */
607 #if defined(_BIG_ENDIAN)
608 				sblock.fs_qbmask.val[0] = 0;
609 				sblock.fs_qbmask.val[1] = ~sblock.fs_bmask;
610 				sblock.fs_qfmask.val[0] = 0;
611 				sblock.fs_qfmask.val[1] = ~sblock.fs_fmask;
612 #endif
613 #if defined(_LITTLE_ENDIAN)
614 				sblock.fs_qbmask.val[0] = ~sblock.fs_bmask;
615 				sblock.fs_qbmask.val[1] = 0;
616 				sblock.fs_qfmask.val[0] = ~sblock.fs_fmask;
617 				sblock.fs_qfmask.val[1] = 0;
618 #endif
619 			/* make mountable */
620 			sblock.fs_state = FSOKAY - sblock.fs_time;
621 			sblock.fs_clean = FSCLEAN;
622 			sbdirty();
623 			write_altsb(fswritefd);
624 		} else if (sblock.fs_postblformat == FS_DYNAMICPOSTBLFMT) {
625 			/*
626 			 * Requested to convert from new format to old format
627 			 */
628 			if (sblock.fs_nrpos != 8 || sblock.fs_ipg > 2048 ||
629 			    sblock.fs_cpg > 32 || sblock.fs_cpc > 16) {
630 				printf(
631 				"PARAMETERS OF CURRENT FILE SYSTEM DO NOT\n\t");
632 				errexit(
633 				"ALLOW CONVERSION TO OLD FILE SYSTEM FORMAT\n");
634 			}
635 			if (preen)
636 				pwarn("CONVERTING TO OLD FILE SYSTEM FORMAT\n");
637 			else if (!reply("CONVERT TO OLD FILE SYSTEM FORMAT"))
638 				return (0);
639 			isconvert = 1;
640 			sblock.fs_postblformat = FS_42POSTBLFMT;
641 			sblock.fs_cgsize = fragroundup(&sblock,
642 			    sizeof (struct ocg) + howmany(sblock.fs_fpg, NBBY));
643 			sblock.fs_npsect = 0;
644 			/* make mountable */
645 			sblock.fs_state = FSOKAY - sblock.fs_time;
646 			sblock.fs_clean = FSCLEAN;
647 			sbdirty();
648 			write_altsb(fswritefd);
649 		} else {
650 			errexit("UNKNOWN FILE SYSTEM FORMAT\n");
651 		}
652 	}
653 	if (errorlocked) {
654 		/* do this right away to prevent any other fscks on this fs */
655 		switch (sblock.fs_clean) {
656 		case FSBAD:
657 			break;
658 		case FSFIX:
659 			if (preen)
660 				errexit("ERROR-LOCKED; MARKED \"FSFIX\"\n");
661 			if (reply("marked FSFIX, CONTINUE") == 0)
662 				return (0);
663 			break;
664 		case FSCLEAN:
665 			if (preen)
666 				errexit("ERROR-LOCKED; MARKED \"FSCLEAN\"\n");
667 			if (reply("marked FSCLEAN, CONTINUE") == 0)
668 				return (0);
669 			break;
670 		default:
671 			if (preen) {
672 				if (debug)
673 				pwarn("ERRORLOCKED; NOT MARKED \"FSBAD\"\n");
674 				else
675 				errexit("ERRORLOCKED; NOT MARKED \"FSBAD\"\n");
676 			} else {
677 	if (reply("error-locked, but not marked \"FSBAD\"; CONTINUE") == 0)
678 					return (0);
679 			}
680 			break;
681 		}
682 
683 		if (!do_errorlock(LOCKFS_ELOCK)) {
684 			if (preen)
685 				return (0);
686 			if (reply("error-lock reset failed; CONTINUE") == 0)
687 				return (0);
688 		}
689 
690 		sblock.fs_state = FSOKAY - (long)sblock.fs_time;
691 		sblock.fs_clean = FSFIX;
692 		sbdirty();
693 		write_altsb(fswritefd);
694 	}
695 	/*
696 	 * read in the summary info.
697 	 */
698 	sip = calloc(1, sblock.fs_cssize);
699 	if (sip == NULL)
700 		errexit("cannot allocate space for cylinder group summary\n");
701 	sblock.fs_u.fs_csp = (struct csum *)((void *)sip);
702 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
703 		size = sblock.fs_cssize - i < sblock.fs_bsize ?
704 		    sblock.fs_cssize - i : sblock.fs_bsize;
705 		if (bread(fsreadfd, sip,
706 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
707 		    (long)size) != 0)
708 			return (0);
709 		sip += size;
710 	}
711 	/*
712 	 * if not error-locked,
713 	 *   not bad log, not forced, preening, not converting, and is clean;
714 	 *   stop checking
715 	 */
716 	if (!errorlocked &&
717 	    ((!islog || islogok) &&
718 	    (fflag == 0) && preen && (isconvert == 0) &&
719 	    (FSOKAY == (sblock.fs_state + sblock.fs_time)) &&
720 	    ((sblock.fs_clean == FSLOG && islog) ||
721 	    ((sblock.fs_clean == FSCLEAN) || (sblock.fs_clean == FSSTABLE))))) {
722 		iscorrupt = 0;
723 		printclean();
724 		return (0);
725 	}
726 	/*
727 	 * allocate and initialize the necessary maps
728 	 */
729 	bmapsize = roundup(howmany((uint64_t)maxfsblock, NBBY),
730 	    sizeof (short));
731 	blockmap = calloc((size_t)bmapsize, sizeof (char));
732 	if (blockmap == NULL) {
733 		printf("cannot alloc %lld bytes for blockmap\n", bmapsize);
734 		goto badsb;
735 	}
736 	statemap = calloc((size_t)(maxino + 1), sizeof (char));
737 	if (statemap == NULL) {
738 		printf("cannot alloc %d bytes for statemap\n", maxino + 1);
739 		goto badsb;
740 	}
741 	lncntp = (short *)calloc((unsigned)(maxino + 1), sizeof (short));
742 	if (lncntp == NULL) {
743 		printf("cannot alloc %d bytes for lncntp\n",
744 		    (maxino + 1) * sizeof (short));
745 		goto badsb;
746 	}
747 	numdirs = sblock.fs_cstotal.cs_ndir;
748 	listmax = numdirs + 10;
749 	inpsort = (struct inoinfo **)calloc((unsigned)listmax,
750 	    sizeof (struct inoinfo *));
751 	inphead = (struct inoinfo **)calloc((unsigned)numdirs,
752 	    sizeof (struct inoinfo *));
753 	if (inpsort == NULL || inphead == NULL) {
754 		printf("cannot alloc %d bytes for inphead\n",
755 		    numdirs * sizeof (struct inoinfo *));
756 		goto badsb;
757 	}
758 	numacls = numdirs;
759 	aclmax = numdirs + 10;
760 	aclpsort = (struct aclinfo **)calloc((unsigned)aclmax,
761 	    sizeof (struct aclinfo *));
762 	aclphead = (struct aclinfo **)calloc((unsigned)numacls,
763 	    sizeof (struct aclinfo *));
764 	if (aclpsort == NULL || aclphead == NULL) {
765 		printf("cannot alloc %d bytes for aclphead\n",
766 		    numacls * sizeof (struct inoinfo *));
767 		goto badsb;
768 	}
769 	aclplast = 0L;
770 	inplast = 0L;
771 	bufinit();
772 	return (devstr);
773 
774 badsb:
775 	ckfini();
776 	exitstat = 39;
777 	return (0);
778 }
779 
780 /*
781  *  mkfs limits the size of the inode map to be no more than a third of
782  *  the cylinder group space.  We'll use that value for sanity checking
783  *  the superblock's inode per group value.
784  */
785 #define	MAXIpG	(roundup(sblock.fs_bsize * NBBY / 3, sblock.fs_inopb))
786 
787 /*
788  * Check the super block and its summary info.
789  */
790 static int
791 checksb(int listerr)
792 {
793 	/*
794 	 * When the fs check is successfully completed, the alternate super
795 	 * block at sblk.b_bno will be overwritten by ckfini() with the
796 	 * repaired super block.
797 	 */
798 	sblk.b_bno = bflag ? bflag : SBOFF / dev_bsize;
799 	sblk.b_size = SBSIZE;
800 
801 	/*
802 	 *  Add some extra hardening checks per bug 1253090. Also sanity
803 	 *  check some of the values we are going to use later in allocation
804 	 *  requests.
805 	 */
806 	if (sblock.fs_cstotal.cs_ndir < 1 ||
807 	    sblock.fs_cstotal.cs_ndir > sblock.fs_ncg * sblock.fs_ipg) {
808 		badsb(listerr, "NUMBER OF DIRECTORIES OUT OF RANGE");
809 		return (0);
810 	}
811 
812 	if (sblock.fs_nrpos <= 0 || sblock.fs_postbloff < 0 ||
813 	    sblock.fs_cpc < 0 ||
814 	    (sblock.fs_postbloff +
815 		(sblock.fs_nrpos * sblock.fs_cpc * sizeof (short))) >
816 	    sblock.fs_sbsize) {
817 		badsb(listerr, "ROTATIONAL POSITION TABLE SIZE OUT OF RANGE");
818 		return (0);
819 	}
820 
821 	if (sblock.fs_cssize !=
822 		fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum))) {
823 		badsb(listerr, "SIZE OF CYLINDER GROUP SUMMARY AREA WRONG");
824 		return (0);
825 	}
826 
827 	if (sblock.fs_inopb != (sblock.fs_bsize / sizeof (struct dinode))) {
828 		badsb(listerr, "INOPB NONSENSICAL RELATIVE TO BSIZE");
829 		return (0);
830 	}
831 
832 	if (sblock.fs_bsize != (sblock.fs_frag * sblock.fs_fsize)) {
833 		badsb(listerr, "FRAGS PER BLOCK OR FRAG SIZE WRONG");
834 		return (0);
835 	}
836 
837 	if (sblock.fs_dsize >= sblock.fs_size) {
838 		badsb(listerr, "NUMBER OF DATA BLOCKS OUT OF RANGE");
839 		return (0);
840 	}
841 
842 	/*
843 	 *  Check that the number of inodes per group isn't less than or
844 	 *  equal to zero.  Also makes sure it isn't more than the
845 	 *  maximum number mkfs enforces.
846 	 */
847 	if (sblock.fs_ipg <= 0 || sblock.fs_ipg > MAXIpG) {
848 		badsb(listerr, "INODES PER GROUP OUT OF RANGE");
849 		return (0);
850 	}
851 
852 	/*
853 	 * Set all possible fields that could differ, then do check
854 	 * of whole super block against an alternate super block.
855 	 * When an alternate super-block is specified this check is skipped.
856 	 */
857 	getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1),
858 	    sblock.fs_sbsize);
859 	if (asblk.b_errs)
860 		return (0);
861 	if (bflag) {
862 		/*
863 		 * Invalidate clean flag and state information
864 		 */
865 		sblock.fs_clean = FSACTIVE;
866 		sblock.fs_state = (long)sblock.fs_time;
867 		sblock.fs_reclaim = 0;
868 		sbdirty();
869 		havesb = 1;
870 		return (1);
871 	}
872 	/*
873 	 * fsck should ignore deleted files because the reclaim thread
874 	 * will run at mount and reclaim them
875 	 */
876 	isreclaim = (sblock.fs_reclaim & (FS_RECLAIMING | FS_RECLAIM));
877 	willreclaim = (isreclaim && islog && islogok && !fflag);
878 
879 	altsblock.fs_link = sblock.fs_link;
880 	altsblock.fs_rolled = sblock.fs_rolled;
881 	altsblock.fs_time = sblock.fs_time;
882 	altsblock.fs_state = sblock.fs_state;
883 	altsblock.fs_cstotal = sblock.fs_cstotal;
884 	altsblock.fs_cgrotor = sblock.fs_cgrotor;
885 	altsblock.fs_fmod = sblock.fs_fmod;
886 	altsblock.fs_clean = sblock.fs_clean;
887 	altsblock.fs_ronly = sblock.fs_ronly;
888 	altsblock.fs_flags = sblock.fs_flags;
889 	altsblock.fs_maxcontig = sblock.fs_maxcontig;
890 	altsblock.fs_minfree = sblock.fs_minfree;
891 	altsblock.fs_optim = sblock.fs_optim;
892 	altsblock.fs_rotdelay = sblock.fs_rotdelay;
893 	altsblock.fs_maxbpg = sblock.fs_maxbpg;
894 	altsblock.fs_logbno = sblock.fs_logbno;
895 	altsblock.fs_reclaim = sblock.fs_reclaim;
896 	altsblock.fs_si = sblock.fs_si;
897 	bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt,
898 		sizeof (sblock.fs_fsmnt));
899 	bcopy((char *)sblock.fs_u.fs_csp_pad, (char *)altsblock.fs_u.fs_csp_pad,
900 		sizeof (sblock.fs_u.fs_csp_pad));
901 	/*
902 	 * The following should not have to be copied.
903 	 */
904 	altsblock.fs_fsbtodb = sblock.fs_fsbtodb;
905 	altsblock.fs_npsect = sblock.fs_npsect;
906 	altsblock.fs_nrpos = sblock.fs_nrpos;
907 	if (bcmp((char *)&sblock, (char *)&altsblock,
908 	    (size_t)sblock.fs_sbsize)) {
909 		badsb(listerr, "BAD VALUES IN SUPER BLOCK"); return (0);
910 	}
911 	havesb = 1;
912 	return (1);
913 }
914 
915 static void
916 badsb(int listerr, char *s)
917 {
918 	if (!listerr)
919 		return;
920 	if (preen)
921 		printf("%s: ", devname);
922 	printf("BAD SUPER BLOCK: %s\n", s);
923 	pwarn("USE AN ALTERNATE SUPER-BLOCK TO SUPPLY NEEDED INFORMATION;\n");
924 	pwarn("eg. fsck [-F ufs] -o b=# [special ...] \n");
925 	pfatal("where # is the alternate super block. SEE fsck_ufs(1M). \n");
926 	exitstat = 39;
927 }
928 
929 /*
930  * Write out the super block into each of the alternate super blocks.
931  */
932 void
933 write_altsb(int fd)
934 {
935 	int cylno;
936 
937 	for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
938 		bwrite(fd, (char *)&sblock, fsbtodb(&sblock,
939 			cgsblock(&sblock, cylno)), sblock.fs_sbsize);
940 }
941