8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / fs.d / ufs / fsck / setup.c
blobe95eae6aa043cd9fdfc17b2b5376de8683435458
1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
9 /*
10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11 * All rights reserved.
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.
28 #define DKTYPENAMES
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <malloc.h>
33 #include <limits.h>
34 #include <wait.h>
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/sysmacros.h>
38 #include <sys/mntent.h>
39 #include <sys/dkio.h>
40 #include <sys/filio.h>
41 #include <sys/isa_defs.h> /* for ENDIAN defines */
42 #include <sys/int_const.h>
43 #include <sys/fs/ufs_fs.h>
44 #include <sys/vnode.h>
45 #include <sys/fs/ufs_fs.h>
46 #include <sys/fs/ufs_inode.h>
47 #include <sys/fs/ufs_log.h>
48 #include <sys/stat.h>
49 #include <sys/fcntl.h>
50 #include <string.h>
51 #include <unistd.h>
52 #include <fcntl.h>
53 #include <sys/vfstab.h>
54 #include "roll_log.h"
55 #include "fsck.h"
58 * The size of a cylinder group is calculated by CGSIZE. The maximum size
59 * is limited by the fact that cylinder groups are at most one block.
60 * Its size is derived from the size of the maps maintained in the
61 * cylinder group and the (struct cg) size.
63 #define CGSIZE(fs) \
64 /* base cg */ (sizeof (struct cg) + \
65 /* blktot size */ (fs)->fs_cpg * sizeof (int32_t) + \
66 /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof (short) + \
67 /* inode map */ howmany((fs)->fs_ipg, NBBY) + \
68 /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
70 #define altsblock (*asblk.b_un.b_fs)
71 #define POWEROF2(num) (((num) & ((num) - 1)) == 0)
74 * Methods of determining where alternate superblocks should
75 * be. MAX_SB_STYLES must be the last one, and the others need
76 * to be positive.
78 typedef enum {
79 MKFS_STYLE = 1, NEWFS_STYLE, MAX_SB_STYLES
80 } calcsb_t;
82 static caddr_t calcsb_names[] = {
83 "<UNKNOWN>", "MKFS", "NEWFS", "<OUT OF RANGE>"
86 struct shadowclientinfo *shadowclientinfo = NULL;
87 struct shadowclientinfo *attrclientinfo = NULL;
88 int maxshadowclients = 1024; /* allocation size, not limit */
90 static void badsb(int, caddr_t);
91 static int calcsb(calcsb_t, caddr_t, int, struct fs *);
92 static int checksb(int);
93 static void flush_fs(void);
94 static void sblock_init(void);
95 static void uncreate_maps(void);
97 static int
98 read_super_block(int listerr)
100 int fd;
101 caddr_t err;
103 if (mount_point != NULL) {
104 fd = open(mount_point, O_RDONLY);
105 if (fd == -1) {
106 errexit("fsck: open mount point error: %s",
107 strerror(errno));
108 /* NOTREACHED */
110 /* get the latest super block */
111 if (ioctl(fd, _FIOGETSUPERBLOCK, &sblock)) {
112 errexit("fsck: ioctl _FIOGETSUPERBLOCK error: %s",
113 strerror(errno));
114 /* NOTREACHED */
116 (void) close(fd);
117 } else {
118 (void) fsck_bread(fsreadfd, (caddr_t)&sblock,
119 bflag != 0 ? (diskaddr_t)bflag : (diskaddr_t)SBLOCK,
120 SBSIZE);
124 * Don't let trash from the disk trip us up later
125 * in ungetsummaryinfo().
127 sblock.fs_u.fs_csp = NULL;
130 * Rudimentary consistency checks. Can't really call
131 * checksb() here, because there may be outstanding
132 * deltas that still need to be applied.
134 if ((sblock.fs_magic != FS_MAGIC) &&
135 (sblock.fs_magic != MTB_UFS_MAGIC)) {
136 err = "MAGIC NUMBER WRONG";
137 goto fail;
139 if (sblock.fs_magic == FS_MAGIC &&
140 (sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
141 sblock.fs_version != UFS_VERSION_MIN)) {
142 err = "UNRECOGNIZED VERSION";
143 goto fail;
145 if (sblock.fs_magic == MTB_UFS_MAGIC &&
146 (sblock.fs_version > MTB_UFS_VERSION_1 ||
147 sblock.fs_version < MTB_UFS_VERSION_MIN)) {
148 err = "UNRECOGNIZED VERSION";
149 goto fail;
151 if (sblock.fs_ncg < 1) {
152 err = "NCG OUT OF RANGE";
153 goto fail;
155 if (sblock.fs_cpg < 1) {
156 err = "CPG OUT OF RANGE";
157 goto fail;
159 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
160 (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
161 err = "NCYL IS INCONSISTENT WITH NCG*CPG";
162 goto fail;
164 if (sblock.fs_sbsize < 0 || sblock.fs_sbsize > SBSIZE) {
165 err = "SIZE OUT OF RANGE";
166 goto fail;
169 return (1);
171 fail:
172 badsb(listerr, err);
173 return (0);
176 static void
177 flush_fs()
179 int fd;
181 if (mount_point != NULL) {
182 fd = open(mount_point, O_RDONLY);
183 if (fd == -1) {
184 errexit("fsck: open mount point error: %s",
185 strerror(errno));
186 /* NOTREACHED */
188 if (ioctl(fd, _FIOFFS, NULL)) { /* flush file system */
189 errexit("fsck: ioctl _FIOFFS error: %s",
190 strerror(errno));
191 /* NOTREACHED */
193 (void) close(fd);
198 * Roll the embedded log, if any, and set up the global variables
199 * islog and islogok.
201 static int
202 logsetup(caddr_t devstr)
204 void *buf;
205 extent_block_t *ebp;
206 ml_unit_t *ul;
207 ml_odunit_t *ud;
208 void *ud_buf;
209 int badlog;
211 islog = islogok = 0;
212 if (bflag != 0)
213 return (1); /* can't roll log while alternate sb specified */
216 * Roll the log, if any. A bad sb implies we'll be using
217 * an alternate sb as far as logging goes, so just fail back
218 * to the caller if we can't read the default sb. Suppress
219 * complaints, because the caller will be reading the same
220 * superblock again and running full verification on it, so
221 * whatever is bad will be reported then.
223 sblock.fs_logbno = 0;
224 badlog = 0;
225 if (!read_super_block(0))
226 return (1);
229 * Roll the log in 3 cases:
230 * 1. If it's unmounted (mount_point == NULL) and it's not marked
231 * as fully rolled (sblock.fs_rolled != FS_ALL_ROLLED)
232 * 2. If it's mounted and anything other than a sanity
233 * check fsck (mflag) is being done, as we have the current
234 * super block. Note, only a sanity check is done for
235 * root/usr at boot. If a roll were done then the expensive
236 * ufs_flush() gets called, leading to a slower boot.
237 * 3. If anything other then a sanity check (mflag) is being done
238 * to a mounted filesystem while it is in read-only state
239 * (e.g. root during early boot stages) we have to detect this
240 * and have to roll the log as well. NB. the read-only mount
241 * will flip fs_clean from FSLOG to FSSTABLE and marks the
242 * log as FS_NEED_ROLL.
244 if (sblock.fs_logbno &&
245 (((mount_point == NULL) && (sblock.fs_rolled != FS_ALL_ROLLED)) ||
246 ((mount_point != NULL) && !mflag))) {
247 int roll_log_err = 0;
249 if (sblock.fs_ronly && (sblock.fs_clean == FSSTABLE) &&
250 (sblock.fs_state + sblock.fs_time == FSOKAY)) {
252 * roll the log without a mount
254 flush_fs();
256 if (sblock.fs_clean == FSLOG &&
257 (sblock.fs_state + sblock.fs_time == FSOKAY)) {
258 if (rl_roll_log(devstr) != RL_SUCCESS)
259 roll_log_err = 1;
261 if (roll_log_err) {
262 (void) printf("Can't roll the log for %s.\n", devstr);
264 * There are two cases where we want to set
265 * an error code and return:
266 * - We're preening
267 * - We're not on a live root and the user
268 * chose *not* to ignore the log
269 * Otherwise, we want to mark the log as bad
270 * and continue to check the filesystem. This
271 * has the side effect of destroying the log.
273 if (preen || (!hotroot &&
274 reply(
275 "DISCARDING THE LOG MAY DISCARD PENDING TRANSACTIONS.\n"
276 "DISCARD THE LOG AND CONTINUE") == 0)) {
277 exitstat = EXERRFATAL;
278 return (0);
280 ++badlog;
284 /* Logging UFS may be enabled */
285 if (sblock.fs_logbno) {
286 ++islog;
288 /* log is not okay; check the fs */
289 if (FSOKAY != (sblock.fs_state + sblock.fs_time))
290 return (1);
293 * If logging or (stable and mounted) then continue
295 if (!((sblock.fs_clean == FSLOG) ||
296 (sblock.fs_clean == FSSTABLE) && (mount_point != NULL)))
297 return (1);
299 /* get the log allocation block */
300 buf = malloc(dev_bsize);
301 if (buf == NULL) {
302 return (1);
304 ud_buf = malloc(dev_bsize);
305 if (ud_buf == NULL) {
306 free(buf);
307 return (1);
309 (void) fsck_bread(fsreadfd, buf,
310 logbtodb(&sblock, sblock.fs_logbno),
311 dev_bsize);
312 ebp = (extent_block_t *)buf;
314 /* log allocation block is not okay; check the fs */
315 if (ebp->type != LUFS_EXTENTS) {
316 free(buf);
317 free(ud_buf);
318 return (1);
321 /* get the log state block(s) */
322 if (fsck_bread(fsreadfd, ud_buf,
323 (logbtodb(&sblock, ebp->extents[0].pbno)),
324 dev_bsize)) {
325 (void) fsck_bread(fsreadfd, ud_buf,
326 (logbtodb(&sblock, ebp->extents[0].pbno)) + 1,
327 dev_bsize);
329 ud = (ml_odunit_t *)ud_buf;
330 ul = (ml_unit_t *)malloc(sizeof (*ul));
331 if (ul == NULL) {
332 free(buf);
333 free(ud_buf);
334 return (1);
336 ul->un_ondisk = *ud;
338 /* log state is okay; don't need to check the fs */
339 if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) &&
340 (ul->un_version == LUFS_VERSION_LATEST) &&
341 (ul->un_badlog == 0) && (!badlog)) {
342 ++islogok;
344 free(ud_buf);
345 free(buf);
346 free(ul);
349 return (1);
353 * - given a pathname, determine the pathname to actually check
354 * - if a directory
355 * - if it is in mnttab, set devstr to the special (block) name
356 * - if it is in vfstab, set devstr to the special (block) name
357 * - if it has not been found, bail
358 * - a file is used as-is, clear rflag
359 * - a device is converted to block version (so can search mnttab)
361 static void
362 derive_devstr(const caddr_t dev, caddr_t devstr, size_t str_size)
364 mode_t mode;
365 struct stat statb;
367 if (stat(dev, &statb) < 0) {
368 exitstat = EXNOSTAT;
369 errexit("fsck: could not stat %s: %s", dev, strerror(errno));
372 mode = statb.st_mode & S_IFMT;
373 switch (mode) {
374 case S_IFDIR:
376 * The check_*() routines update devstr with the name.
378 devstr[0] = '\0';
379 if (!(check_mnttab(dev, devstr, str_size) ||
380 check_vfstab(dev, devstr, str_size))) {
381 exitstat = EXBADPARM;
382 errexit(
383 "fsck: could not find mountpoint %s in mnttab nor vfstab",
384 dev);
386 break;
387 case S_IFREG:
388 rflag = 0;
389 (void) strlcpy(devstr, dev, str_size);
390 break;
391 case S_IFCHR:
392 case S_IFBLK:
393 (void) strlcpy(devstr, unrawname(dev), str_size);
394 break;
395 default:
396 exitstat = EXBADPARM;
397 errexit("fsck: %s must be a mountpoint, device, or file", dev);
398 /* NOTREACHED */
403 * Reports the index of the magic filesystem that mntp names.
404 * If it does not correspond any of them, returns zero (hence
405 * the backwards loop).
407 static int
408 which_corefs(const caddr_t mntp)
410 int corefs;
412 for (corefs = MAGIC_LIMIT - 1; corefs > 0; corefs--)
413 if (strcmp(mntp, magic_fs[corefs]) == 0)
414 break;
416 return (corefs);
420 * - set mount_point to NULL
421 * - if name is mounted (search mnttab)
422 * - if it is a device, clear rflag
423 * - if mounted on /, /usr, or /var, set corefs
424 * - if corefs and read-only, set hotroot and continue
425 * - if errorlocked, continue
426 * - if preening, bail
427 * - ask user whether to continue, bail if not
428 * - if it is a device and not mounted and rflag, convert
429 * name to raw version
431 static int
432 check_mount_state(caddr_t devstr, size_t str_size)
434 int corefs = 0;
435 int is_dev = 0;
436 struct stat statb;
438 if (stat(devstr, &statb) < 0) {
439 exitstat = EXNOSTAT;
440 errexit("fsck: could not stat %s: %s", devstr, strerror(errno));
442 if (S_ISCHR(statb.st_mode) || S_ISBLK(statb.st_mode))
443 is_dev = 1;
446 * mounted() will update mount_point when returning true.
448 mount_point = NULL;
449 if ((mountedfs = mounted(devstr, devstr, str_size)) != M_NOMNT) {
450 if (is_dev)
451 rflag = 0;
452 corefs = which_corefs(mount_point);
453 if (corefs && (mountedfs == M_RO)) {
454 hotroot++;
455 } else if (errorlocked) {
456 goto carry_on;
457 } else if (preen) {
458 exitstat = EXMOUNTED;
459 pfatal("%s IS CURRENTLY MOUNTED%s.",
460 devstr, mountedfs == M_RW ? " READ/WRITE" : "");
461 } else {
462 if (!nflag && !mflag) {
463 pwarn("%s IS CURRENTLY MOUNTED READ/%s.",
464 devstr, mountedfs == M_RW ? "WRITE" :
465 "ONLY");
466 if (reply("CONTINUE") == 0) {
467 exitstat = EXMOUNTED;
468 errexit("Program terminated");
472 } else if (is_dev && rflag) {
473 (void) strlcpy(devstr, rawname(devstr), str_size);
476 carry_on:
477 return (corefs);
480 static int
481 open_and_intro(caddr_t devstr, int corefs)
483 int retval = 0;
485 if ((fsreadfd = open64(devstr, O_RDONLY)) < 0) {
486 (void) printf("Can't open %s: %s\n", devstr, strerror(errno));
487 exitstat = EXNOSTAT;
488 retval = -1;
489 goto finish;
491 if (!preen || debug != 0)
492 (void) printf("** %s", devstr);
494 if (errorlocked) {
495 if (debug && elock_combuf != NULL)
496 (void) printf(" error-lock comment: \"%s\" ",
497 elock_combuf);
498 fflag = 1;
500 pid = getpid();
501 if (nflag || roflag || (fswritefd = open64(devstr, O_WRONLY)) < 0) {
502 fswritefd = -1;
503 if (preen && !debug)
504 pfatal("(NO WRITE ACCESS)\n");
505 (void) printf(" (NO WRITE)");
507 if (!preen)
508 (void) printf("\n");
509 else if (debug)
510 (void) printf(" pid %d\n", pid);
511 if (debug && (hotroot || (mountedfs != M_NOMNT))) {
512 (void) printf("** %s", devstr);
513 if (hotroot)
514 (void) printf(" is %s fs", magic_fs[corefs]);
515 if (mountedfs != M_NOMNT)
516 (void) printf(" and is mounted read-%s",
517 (mountedfs == M_RO) ? "only" : "write");
518 if (errorlocked)
519 (void) printf(" and is error-locked");
521 (void) printf(".\n");
524 finish:
525 return (retval);
528 static int
529 find_superblock(caddr_t devstr)
531 int cg = 0;
532 int retval = 0;
533 int first;
534 int found;
535 calcsb_t style;
536 struct fs proto;
539 * Check the superblock, looking for alternates if necessary.
540 * In more-recent times, some UFS instances get created with
541 * only the first ten and last ten superblock backups. Since
542 * if we can't get the necessary information from any of those,
543 * the odds are also against us for the ones in between, we'll
544 * just look at those twenty to save time.
546 if (!read_super_block(1) || !checksb(1)) {
547 if (bflag || preen) {
548 retval = -1;
549 goto finish;
551 for (style = MKFS_STYLE; style < MAX_SB_STYLES; style++) {
552 if (reply("LOOK FOR ALTERNATE SUPERBLOCKS WITH %s",
553 calcsb_names[style]) == 0)
554 continue;
555 first = 1;
556 found = 0;
557 if (!calcsb(style, devstr, fsreadfd, &proto)) {
558 cg = proto.fs_ncg;
559 continue;
561 if (debug) {
562 (void) printf(
563 "debug: calcsb(%s) gave fpg %d, cgoffset %d, ",
564 calcsb_names[style],
565 proto.fs_fpg, proto.fs_cgoffset);
566 (void) printf("cgmask 0x%x, sblk %d, ncg %d\n",
567 proto.fs_cgmask, proto.fs_sblkno,
568 proto.fs_ncg);
570 for (cg = 0; cg < proto.fs_ncg; cg++) {
571 bflag = fsbtodb(&proto, cgsblock(&proto, cg));
572 if (debug)
573 (void) printf(
574 "debug: trying block %lld\n",
575 (longlong_t)bflag);
576 if (read_super_block(0) && checksb(0)) {
577 (void) printf(
578 "FOUND ALTERNATE SUPERBLOCK %d WITH %s\n",
579 bflag, calcsb_names[style]);
580 if (reply(
581 "USE ALTERNATE SUPERBLOCK") == 1) {
582 found = 1;
583 break;
586 if (first && (cg >= 9)) {
587 first = 0;
588 if (proto.fs_ncg <= 9)
589 cg = proto.fs_ncg;
590 else if (proto.fs_ncg <= 19)
591 cg = 9;
592 else
593 cg = proto.fs_ncg - 10;
597 if (found)
598 break;
602 * Didn't find one? Try to fake it.
604 if (style >= MAX_SB_STYLES) {
605 pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED.\n");
606 for (style = MKFS_STYLE; style < MAX_SB_STYLES;
607 style++) {
608 if (reply("USE GENERIC SUPERBLOCK FROM %s",
609 calcsb_names[style]) == 1 &&
610 calcsb(style, devstr, fsreadfd, &sblock)) {
611 break;
615 * We got something from mkfs/newfs, so use it.
617 if (style < MAX_SB_STYLES) {
618 proto.fs_ncg = sblock.fs_ncg;
619 bflag = 0;
624 * Still no luck? Tell the user they're on their own.
626 if (style >= MAX_SB_STYLES) {
627 pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED. "
628 "YOU MUST USE THE -o b OPTION\n"
629 "TO FSCK TO SPECIFY THE LOCATION OF A VALID "
630 "ALTERNATE SUPERBLOCK TO\n"
631 "SUPPLY NEEDED INFORMATION; SEE fsck(1M).\n");
632 bflag = 0;
633 retval = -1;
634 goto finish;
638 * Need to make sure a human really wants us to use
639 * this. -y mode could've gotten us this far, so
640 * we need to ask something that has to be answered
641 * in the negative.
643 * Note that we can't get here when preening.
645 if (!found) {
646 pwarn("CALCULATED GENERIC SUPERBLOCK WITH %s\n",
647 calcsb_names[style]);
648 } else {
649 pwarn("FOUND ALTERNATE SUPERBLOCK AT %d USING %s\n",
650 bflag, calcsb_names[style]);
652 pwarn("If filesystem was created with manually-specified ");
653 pwarn("geometry, using\nauto-discovered superblock may ");
654 pwarn("result in irrecoverable damage to\nfilesystem and ");
655 pwarn("user data.\n");
656 if (reply("CANCEL FILESYSTEM CHECK") == 1) {
657 if (cg >= 0) {
658 pwarn("Please verify that the indicated block "
659 "contains a proper\nsuperblock for the "
660 "filesystem (see fsdb(1M)).\n");
661 if (yflag)
662 pwarn("\nFSCK was running in YES "
663 "mode. If you wish to run in "
664 "that mode using\nthe alternate "
665 "superblock, run "
666 "`fsck -y -o b=%d %s'.\n",
667 bflag, devstr);
669 retval = -1;
670 goto finish;
674 * Pretend we found it as an alternate, so everything
675 * gets updated when we clean up at the end.
677 if (!found) {
678 havesb = 1;
679 sblk.b_bno = fsbtodb(&sblock, cgsblock(&sblock, 0));
680 bwrite(fswritefd, (caddr_t)&sblock, SBLOCK, SBSIZE);
681 write_altsb(fswritefd);
685 finish:
686 return (retval);
690 * Check and potentially fix certain fields in the super block.
692 static void
693 fixup_superblock(void)
696 * Kernel looks for FS_OPTTIME, and assumes that if that's not
697 * what's there, it must be FS_OPTSPACE, so not fixing does not
698 * require setting iscorrupt.
700 if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
701 pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
702 if (reply("SET TO DEFAULT") == 1) {
703 sblock.fs_optim = FS_OPTTIME;
704 sbdirty();
707 if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
708 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
709 sblock.fs_minfree);
710 if (reply("SET TO DEFAULT") == 1) {
711 sblock.fs_minfree = 10;
712 sbdirty();
713 } else if (sblock.fs_minfree < 0) {
715 * Kernel uses minfree without verification,
716 * and a negative value would do bad things.
718 iscorrupt = 1;
723 static int
724 initial_error_state_adjust(void)
726 int retval = 0;
728 /* do this right away to prevent any other fscks on this fs */
729 switch (sblock.fs_clean) {
730 case FSBAD:
731 break;
732 case FSFIX:
733 if (preen)
734 errexit("ERROR-LOCKED; MARKED \"FSFIX\"\n");
735 if (reply("marked FSFIX, CONTINUE") == 0) {
736 retval = -1;
737 goto finish;
739 break;
740 case FSCLEAN:
741 if (preen)
742 errexit("ERROR-LOCKED; MARKED \"FSCLEAN\"\n");
743 if (reply("marked FSCLEAN, CONTINUE") == 0) {
744 retval = -1;
745 goto finish;
747 break;
748 default:
749 if (preen) {
750 if (debug)
751 pwarn("ERRORLOCKED; NOT MARKED \"FSBAD\"\n");
752 else
753 errexit("ERRORLOCKED; NOT MARKED \"FSBAD\"\n");
754 } else {
755 (void) printf("error-locked but not marked \"FSBAD\";");
756 if (reply(" CONTINUE") == 0) {
757 retval = -1;
758 goto finish;
761 break;
764 if (!do_errorlock(LOCKFS_ELOCK)) {
765 if (preen) {
766 retval = -1;
767 goto finish;
769 if (reply("error-lock reset failed; CONTINUE") == 0) {
770 retval = -1;
771 goto finish;
775 sblock.fs_state = FSOKAY - (long)sblock.fs_time;
776 sblock.fs_clean = FSFIX;
777 sbdirty();
778 write_altsb(fswritefd);
780 finish:
781 return (retval);
784 static void
785 getsummaryinfo(void)
787 size_t size;
788 int failed;
789 int asked;
790 int i, j;
791 caddr_t sip;
794 * read in the summary info.
796 sblock.fs_u.fs_csp = calloc(1, sblock.fs_cssize);
797 if (sblock.fs_u.fs_csp == NULL)
798 errexit(
799 "cannot allocate %u bytes for cylinder group summary info\n",
800 (unsigned)sblock.fs_cssize);
801 sip = (caddr_t)sblock.fs_u.fs_csp;
802 asked = 0;
803 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
804 size = sblock.fs_cssize - i < sblock.fs_bsize ?
805 sblock.fs_cssize - i : sblock.fs_bsize;
806 failed = fsck_bread(fsreadfd, sip,
807 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
808 size);
809 if (failed && !asked) {
810 pfatal("BAD SUMMARY INFORMATION");
811 if (reply("CONTINUE") == 0) {
812 ckfini();
813 exit(EXFNDERRS);
815 asked = 1;
817 sip += size;
822 * Reverses the effects of getsummaryinfo().
824 static void
825 ungetsummaryinfo(void)
827 if ((sblk.b_un.b_fs != NULL) &&
828 (sblk.b_un.b_fs->fs_u.fs_csp != NULL)) {
829 free(sblk.b_un.b_fs->fs_u.fs_csp);
830 sblk.b_un.b_fs->fs_u.fs_csp = NULL;
835 * Allocate and initialize the global tables.
836 * It is the responsibility of the caller to clean up and allocations
837 * if an error is returned.
839 static int
840 create_and_init_maps(void)
842 int64_t bmapsize;
843 int retval = 0;
845 maxfsblock = sblock.fs_size;
846 maxino = sblock.fs_ncg * sblock.fs_ipg;
848 bmapsize = roundup(howmany((uint64_t)maxfsblock, NBBY),
849 sizeof (short));
850 blockmap = calloc((size_t)bmapsize, sizeof (char));
851 if (blockmap == NULL) {
852 (void) printf("cannot alloc %lld bytes for blockmap\n",
853 (longlong_t)bmapsize);
854 retval = -1;
855 goto finish;
857 statemap = calloc((size_t)(maxino + 1), sizeof (*statemap));
858 if (statemap == NULL) {
859 (void) printf("cannot alloc %lld bytes for statemap\n",
860 (longlong_t)(maxino + 1) * sizeof (*statemap));
861 retval = -1;
862 goto finish;
864 lncntp = (short *)calloc((size_t)(maxino + 1), sizeof (short));
865 if (lncntp == NULL) {
866 (void) printf("cannot alloc %lld bytes for lncntp\n",
867 (longlong_t)(maxino + 1) * sizeof (short));
868 retval = -1;
869 goto finish;
873 * If we had to fake up a superblock, it won't show that there
874 * are any directories at all. This causes problems when we
875 * use numdirs to calculate hash keys, so use something at least
876 * vaguely plausible.
878 numdirs = sblock.fs_cstotal.cs_ndir;
879 if (numdirs == 0)
880 numdirs = sblock.fs_ipg * sblock.fs_ncg / 2;
881 listmax = numdirs + 10;
882 inpsort = (struct inoinfo **)calloc((unsigned)listmax,
883 sizeof (struct inoinfo *));
884 inphead = (struct inoinfo **)calloc((unsigned)numdirs,
885 sizeof (struct inoinfo *));
886 if (inpsort == NULL || inphead == NULL) {
887 (void) printf("cannot alloc %lld bytes for inphead\n",
888 (longlong_t)numdirs * sizeof (struct inoinfo *));
889 retval = -1;
890 goto finish;
892 if (debug) {
893 if (listmax > ULONG_MAX)
894 errexit("create_and_init_maps: listmax overflowed\n");
895 if (numdirs > ULONG_MAX)
896 errexit("create_and_init_maps: numdirs overflowed\n");
899 numacls = numdirs;
900 aclmax = numdirs + 10;
901 aclpsort = (struct inoinfo **)calloc((unsigned)aclmax,
902 sizeof (struct inoinfo *));
903 aclphead = (struct inoinfo **)calloc((unsigned)numacls,
904 sizeof (struct inoinfo *));
905 if (aclpsort == NULL || aclphead == NULL) {
906 (void) printf("cannot alloc %lld bytes for aclphead\n",
907 (longlong_t)numacls * sizeof (struct inoinfo *));
908 retval = -1;
909 goto finish;
911 if (debug) {
912 if (aclmax > ULONG_MAX)
913 errexit("create_and_init_maps: aclmax overflowed\n");
914 if (numacls > ULONG_MAX)
915 errexit("create_and_init_maps: numacls overflowed\n");
917 aclplast = 0L;
918 inplast = 0L;
920 finish:
921 return (retval);
924 caddr_t
925 setup(caddr_t dev)
927 int corefs;
928 static char devstr[MAXPATHLEN + 1];
930 havesb = 0;
931 devname = devstr;
933 derive_devstr(dev, devstr, sizeof (devstr));
934 errorlocked = is_errorlocked(devstr);
935 corefs = check_mount_state(devstr, sizeof (devstr));
937 sblock_init();
939 if (open_and_intro(devstr, corefs) == -1)
940 goto cleanup;
942 if (mflag && mounted(devstr, devstr,
943 sizeof (devstr)) == M_RW)
944 return (devstr);
947 * Check log state
949 if (!logsetup(devstr))
950 goto cleanup;
953 * Flush fs if we're going to do anything other than a sanity check.
954 * Note, if logging then the fs was already flushed in logsetup().
956 if (!islog && !mflag)
957 flush_fs();
959 if (find_superblock(devstr) == -1)
960 goto cleanup;
962 fixup_superblock();
964 if (errorlocked &&
965 (initial_error_state_adjust() == -1))
966 goto cleanup;
969 * asblk could be dirty because we found a mismatch between
970 * the primary superblock and one of its backups in checksb().
972 if (asblk.b_dirty && !bflag) {
973 (void) memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
974 flush(fswritefd, &asblk);
977 getsummaryinfo();
980 * if not error-locked, using the standard superblock,
981 * not bad log, not forced, preening, and is clean;
982 * stop checking
984 if (!errorlocked && (bflag == 0) &&
985 ((!islog || islogok) &&
986 (fflag == 0) && preen &&
987 (FSOKAY == (sblock.fs_state + sblock.fs_time)) &&
988 ((sblock.fs_clean == FSLOG && islog) ||
989 ((sblock.fs_clean == FSCLEAN) || (sblock.fs_clean == FSSTABLE))))) {
990 iscorrupt = 0;
991 printclean();
992 goto cleanup;
995 if (create_and_init_maps() == -1)
996 goto nomaps;
998 bufinit();
999 return (devstr);
1001 nomaps:
1002 ckfini();
1003 exitstat = EXERRFATAL;
1004 /* FALLTHROUGH */
1006 cleanup:
1007 unbufinit();
1008 uncreate_maps();
1009 ungetsummaryinfo();
1012 * Can't get rid of the superblock buffer, because our
1013 * caller references it to generate the summary statistics.
1016 return (NULL);
1020 * Undoes the allocations in create_and_init_maps()
1022 static void
1023 uncreate_maps(void)
1026 * No ordering dependency amongst these, so they are here in
1027 * the same order they were calculated.
1029 if (blockmap != NULL)
1030 free(blockmap);
1031 if (statemap != NULL)
1032 free(statemap);
1033 if (lncntp != NULL)
1034 free(lncntp);
1035 if (inpsort != NULL)
1036 free(inpsort);
1037 if (inphead != NULL)
1038 free(inphead);
1039 if (aclpsort != NULL)
1040 free(aclpsort);
1041 if (aclphead != NULL)
1042 free(aclphead);
1046 * mkfs limits the size of the inode map to be no more than a third of
1047 * the cylinder group space. We'll use that value for sanity checking
1048 * the superblock's inode per group value.
1050 #define MAXIpG (roundup(sblock.fs_bsize * NBBY / 3, sblock.fs_inopb))
1053 * Check the super block and its summary info.
1055 static int
1056 checksb(int listerr)
1058 caddr_t err;
1061 * When the fs check is successfully completed, the alternate super
1062 * block at sblk.b_bno will be overwritten by ckfini() with the
1063 * repaired super block.
1065 sblk.b_bno = bflag ? bflag : (SBOFF / dev_bsize);
1066 sblk.b_size = SBSIZE;
1069 * Sanity-check some of the values we are going to use later
1070 * in allocation requests.
1072 if (sblock.fs_cstotal.cs_ndir < 1 ||
1073 sblock.fs_cstotal.cs_ndir > sblock.fs_ncg * sblock.fs_ipg) {
1074 if (verbose)
1075 (void) printf(
1076 "Found %d directories, should be between 1 and %d inclusive.\n",
1077 sblock.fs_cstotal.cs_ndir,
1078 sblock.fs_ncg * sblock.fs_ipg);
1079 err = "NUMBER OF DIRECTORIES OUT OF RANGE";
1080 goto failedsb;
1083 if (sblock.fs_nrpos <= 0 || sblock.fs_postbloff < 0 ||
1084 sblock.fs_cpc < 0 ||
1085 (sblock.fs_postbloff +
1086 (sblock.fs_nrpos * sblock.fs_cpc * sizeof (short))) >
1087 sblock.fs_sbsize) {
1088 err = "ROTATIONAL POSITION TABLE SIZE OUT OF RANGE";
1089 goto failedsb;
1092 if (sblock.fs_cssize !=
1093 fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum))) {
1094 err = "SIZE OF CYLINDER GROUP SUMMARY AREA WRONG";
1095 goto failedsb;
1098 if (sblock.fs_inopb != (sblock.fs_bsize / sizeof (struct dinode))) {
1099 err = "INOPB NONSENSICAL RELATIVE TO BSIZE";
1100 goto failedsb;
1103 if (sblock.fs_bsize > MAXBSIZE) {
1104 err = "BLOCK SIZE LARGER THAN MAXIMUM SUPPORTED";
1105 goto failedsb;
1108 if (sblock.fs_bsize != (sblock.fs_frag * sblock.fs_fsize)) {
1109 err = "FRAGS PER BLOCK OR FRAG SIZE WRONG";
1110 goto failedsb;
1113 if (sblock.fs_dsize >= sblock.fs_size) {
1114 err = "NUMBER OF DATA BLOCKS OUT OF RANGE";
1115 goto failedsb;
1118 #if 0
1119 if (sblock.fs_size >
1120 (sblock.fs_nsect * sblock.fs_ntrak * sblock.fs_ncyl)) {
1121 err = "FILESYSTEM SIZE LARGER THAN DEVICE";
1122 goto failedsb;
1124 #endif
1127 * Check that the number of inodes per group isn't less than or
1128 * equal to zero. Also makes sure it isn't more than the
1129 * maximum number mkfs enforces.
1131 if (sblock.fs_ipg <= 0 || sblock.fs_ipg > MAXIpG) {
1132 err = "INODES PER GROUP OUT OF RANGE";
1133 goto failedsb;
1136 if (sblock.fs_cgsize > sblock.fs_bsize) {
1137 err = "CG HEADER LARGER THAN ONE BLOCK";
1138 goto failedsb;
1142 * Set all possible fields that could differ, then do check
1143 * of whole super block against an alternate super block.
1144 * When an alternate super-block is specified this check is skipped.
1146 (void) getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1),
1147 (size_t)sblock.fs_sbsize);
1148 if (asblk.b_errs != 0) {
1149 brelse(&asblk);
1150 return (0);
1152 if (bflag != 0) {
1154 * Invalidate clean flag and state information.
1155 * Note that we couldn't return until after the
1156 * above getblk(), because we're going to want to
1157 * update asblk when everything's done.
1159 sblock.fs_clean = FSACTIVE;
1160 sblock.fs_state = (long)sblock.fs_time;
1161 sblock.fs_reclaim = 0;
1162 sbdirty();
1163 havesb = 1;
1164 return (1);
1166 altsblock.fs_link = sblock.fs_link;
1167 altsblock.fs_rolled = sblock.fs_rolled;
1168 altsblock.fs_time = sblock.fs_time;
1169 altsblock.fs_state = sblock.fs_state;
1170 altsblock.fs_cstotal = sblock.fs_cstotal;
1171 altsblock.fs_cgrotor = sblock.fs_cgrotor;
1172 altsblock.fs_fmod = sblock.fs_fmod;
1173 altsblock.fs_clean = sblock.fs_clean;
1174 altsblock.fs_ronly = sblock.fs_ronly;
1175 altsblock.fs_flags = sblock.fs_flags;
1176 altsblock.fs_maxcontig = sblock.fs_maxcontig;
1177 altsblock.fs_minfree = sblock.fs_minfree;
1178 altsblock.fs_optim = sblock.fs_optim;
1179 altsblock.fs_rotdelay = sblock.fs_rotdelay;
1180 altsblock.fs_maxbpg = sblock.fs_maxbpg;
1181 altsblock.fs_logbno = sblock.fs_logbno;
1182 altsblock.fs_reclaim = sblock.fs_reclaim;
1183 altsblock.fs_si = sblock.fs_si;
1184 (void) memmove((void *)altsblock.fs_fsmnt, (void *)sblock.fs_fsmnt,
1185 sizeof (sblock.fs_fsmnt));
1187 * The following should not have to be copied.
1189 (void) memmove((void *)altsblock.fs_u.fs_csp_pad,
1190 (void *)sblock.fs_u.fs_csp_pad, sizeof (sblock.fs_u.fs_csp_pad));
1191 altsblock.fs_fsbtodb = sblock.fs_fsbtodb;
1192 altsblock.fs_npsect = sblock.fs_npsect;
1193 altsblock.fs_nrpos = sblock.fs_nrpos;
1194 if (memcmp((void *)&sblock, (void *)&altsblock,
1195 (size_t)sblock.fs_sbsize) != 0) {
1196 err = "BAD VALUES IN SUPER BLOCK";
1197 goto failedsb;
1199 havesb = 1;
1200 return (1);
1202 failedsb:
1203 badsb(listerr, err);
1204 return (0);
1207 static void
1208 badsb(int listerr, caddr_t s)
1210 if (!listerr)
1211 return;
1212 if (preen)
1213 (void) printf("%s: ", devname);
1214 (void) printf("BAD SUPERBLOCK AT BLOCK %d: %s\n",
1215 bflag != 0 ? bflag : SBLOCK, s);
1216 if (preen) {
1217 pwarn(
1218 "USE AN ALTERNATE SUPERBLOCK TO SUPPLY NEEDED INFORMATION;\n");
1219 pwarn("e.g. fsck [-F ufs] -o b=# [special ...] \n");
1220 exitstat = EXERRFATAL;
1221 pfatal(
1222 "where # is the alternate super block. SEE fsck_ufs(1M). \n");
1224 /* we're expected to return if not preening */
1228 * Write out the super block into each of the alternate super blocks.
1230 void
1231 write_altsb(int fd)
1233 int cylno;
1235 for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
1236 bwrite(fd, (caddr_t)&sblock, fsbtodb(&sblock,
1237 cgsblock(&sblock, cylno)), sblock.fs_sbsize);
1240 static void
1241 sblock_init(void)
1243 fsmodified = 0;
1244 if (errorlocked)
1245 isdirty = 1;
1246 lfdir = 0;
1247 initbarea(&sblk);
1248 initbarea(&asblk);
1251 * May have buffer left over from previous filesystem check.
1253 if (sblk.b_un.b_buf == NULL)
1254 sblk.b_un.b_buf = calloc(1, SBSIZE);
1255 if (asblk.b_un.b_buf == NULL)
1256 asblk.b_un.b_buf = calloc(1, SBSIZE);
1257 if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
1258 errexit("cannot allocate space for superblock\n");
1260 * Could get the actual sector size from the device here,
1261 * but considering how much would need to change in the rest
1262 * of the system before it'd be a problem for us, it's not
1263 * worth worrying about right now.
1265 dev_bsize = secsize = DEV_BSIZE;
1269 * Calculate a prototype superblock based on information in the disk label.
1270 * When done the cgsblock macro can be calculated and the fs_ncg field
1271 * can be used. Do NOT attempt to use other macros without verifying that
1272 * their needed information is available!
1274 * In BSD, the disk label includes all sorts of useful information,
1275 * like cpg. Solaris doesn't have that, and deriving it (as well as
1276 * some other parameters) is difficult. Rather than duplicate the
1277 * code, just ask mkfs what it would've come up with by default.
1278 * Ideally, we'd just link in the code, but given the source base
1279 * involved, it's more practical to just get a binary dump.
1281 * The one minor drawback to the above approach is that newfs and mkfs
1282 * will produce vastly different layouts for the same partition if
1283 * they're allowed to default everything. So, if the superblock that
1284 * mkfs gives us doesn't work for guessing where the alternates are,
1285 * we need to try newfs.
1287 static int
1288 calcsb(calcsb_t style, caddr_t dev, int devfd, struct fs *fs)
1290 #define FROM_CHILD 0
1291 #define TO_FSCK 1
1292 #define CMD_IDX 0
1293 #define DEV_IDX 3
1294 #define SIZE_IDX 4
1296 int child_pipe[2];
1297 caddr_t mkfsline[] = {
1298 "", /* CMD_IDX */
1299 "-o",
1300 "calcbinsb,N",
1301 NULL, /* DEV_IDX */
1302 NULL, /* SIZE_IDX */
1303 NULL
1305 caddr_t newfsline[] = {
1306 "", /* CMD_IDX */
1307 "-B",
1308 "-N",
1309 NULL, /* DEV_IDX */
1310 NULL
1312 int pending, transferred;
1313 caddr_t *cmdline;
1314 caddr_t target;
1315 caddr_t sizestr = NULL;
1316 caddr_t path_old, path_new, mkfs_dir, mkfs_path, newfs_path;
1317 caddr_t slash;
1318 diskaddr_t size;
1319 int devnull;
1321 switch (style) {
1322 case MKFS_STYLE:
1323 if (debug)
1324 (void) printf("calcsb() going with style MKFS\n");
1325 cmdline = mkfsline;
1326 break;
1327 case NEWFS_STYLE:
1328 if (debug)
1329 (void) printf("calcsb() going with style NEWFS\n");
1330 cmdline = newfsline;
1331 break;
1332 default:
1333 if (debug)
1334 (void) printf("calcsb() doesn't undestand style %d\n",
1335 style);
1336 return (0);
1339 cmdline[DEV_IDX] = dev;
1342 * Normally, only use the stock versions of the utilities.
1343 * However, if we're debugging, the odds are that we're
1344 * using experimental versions of them as well, so allow
1345 * some flexibility.
1347 mkfs_path = getenv("MKFS_PATH");
1348 if (!debug || (mkfs_path == NULL))
1349 mkfs_path = MKFS_PATH;
1351 newfs_path = getenv("NEWFS_PATH");
1352 if (!debug || (newfs_path == NULL))
1353 newfs_path = NEWFS_PATH;
1355 if (style == MKFS_STYLE) {
1356 cmdline[CMD_IDX] = mkfs_path;
1358 size = getdisksize(dev, devfd);
1359 if (size == 0)
1360 return (0);
1362 (void) fsck_asprintf(&sizestr, "%lld", (longlong_t)size);
1363 cmdline[SIZE_IDX] = sizestr;
1364 } else if (style == NEWFS_STYLE) {
1366 * Make sure that newfs will find the right version of mkfs.
1368 cmdline[CMD_IDX] = newfs_path;
1369 path_old = getenv("PATH");
1370 /* mkfs_path is always initialized, despite lint's concerns */
1371 mkfs_dir = strdup(mkfs_path);
1372 if (mkfs_dir == NULL)
1373 return (0);
1375 * If no location data for mkfs, don't need to do
1376 * anything about PATH.
1378 slash = strrchr(mkfs_dir, '/');
1379 if (slash != NULL) {
1381 * Just want the dir, so discard the executable name.
1383 *slash = '\0';
1386 * newfs uses system() to find mkfs, so make sure
1387 * that the one we want to use is first on the
1388 * list. Don't free path_new upon success, as it
1389 * has become part of the environment.
1391 (void) fsck_asprintf(&path_new, "PATH=%s:%s",
1392 mkfs_dir, path_old);
1393 if (putenv(path_new) != 0) {
1394 free(mkfs_dir);
1395 free(path_new);
1396 return (0);
1399 free(mkfs_dir);
1400 } else {
1402 * Bad search style, quietly return failure.
1404 if (debug) {
1405 (void) printf("calcsb: got bad style number %d\n",
1406 (int)style);
1408 return (0);
1411 if (pipe(child_pipe) < 0) {
1412 pfatal("calcsb: could not create pipe: %s\n", strerror(errno));
1413 if (sizestr != NULL)
1414 free(sizestr);
1415 return (0);
1418 switch (fork()) {
1419 case -1:
1420 pfatal("calcsb: fork failed: %s\n", strerror(errno));
1421 if (sizestr != NULL)
1422 free(sizestr);
1423 return (0);
1424 case 0:
1425 if (dup2(child_pipe[TO_FSCK], fileno(stdout)) < 0) {
1426 (void) printf(
1427 "calcsb: could not rename file descriptor: %s\n",
1428 strerror(errno));
1429 exit(EXBADPARM);
1431 devnull = open("/dev/null", O_WRONLY);
1432 if (devnull == -1) {
1433 (void) printf("calcsb: could not open /dev/null: %s\n",
1434 strerror(errno));
1435 exit(EXBADPARM);
1437 if (dup2(devnull, fileno(stderr)) < 0) {
1438 (void) printf(
1439 "calcsb: could not rename file descriptor: %s\n",
1440 strerror(errno));
1441 exit(EXBADPARM);
1443 (void) close(child_pipe[FROM_CHILD]);
1444 (void) execv(cmdline[CMD_IDX], cmdline);
1445 (void) printf("calcsb: could not exec %s: %s\n",
1446 cmdline[CMD_IDX], strerror(errno));
1447 exit(EXBADPARM);
1448 /* NOTREACHED */
1449 default:
1450 break;
1453 (void) close(child_pipe[TO_FSCK]);
1454 if (sizestr != NULL)
1455 free(sizestr);
1457 pending = sizeof (struct fs);
1458 target = (caddr_t)fs;
1459 do {
1460 transferred = read(child_pipe[FROM_CHILD], target, pending);
1461 pending -= transferred;
1462 target += transferred;
1463 } while ((pending > 0) && (transferred > 0));
1465 if (pending > 0) {
1466 if (transferred < 0)
1467 pfatal(
1468 "calcsb: binary read of superblock from %s failed: %s\n",
1469 (style == MKFS_STYLE) ? "mkfs" : "newfs",
1470 (transferred < 0) ? strerror(errno) : "");
1471 else
1472 pfatal(
1473 "calcsb: short read of superblock from %s\n",
1474 (style == MKFS_STYLE) ? "mkfs" : "newfs");
1475 return (0);
1478 (void) close(child_pipe[FROM_CHILD]);
1479 (void) wait(NULL);
1481 if ((fs->fs_magic != FS_MAGIC) &&
1482 (fs->fs_magic != MTB_UFS_MAGIC))
1483 return (0);
1485 return (1);