Home | History | Annotate | Line # | Download | only in dumplfs
dumplfs.c revision 1.64
      1 /*	$NetBSD: dumplfs.c,v 1.64 2018/06/15 15:16:05 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1991, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 
     34 #ifndef lint
     35 __COPYRIGHT("@(#) Copyright (c) 1991, 1993\
     36  The Regents of the University of California.  All rights reserved.");
     37 #endif /* not lint */
     38 
     39 #ifndef lint
     40 #if 0
     41 static char sccsid[] = "@(#)dumplfs.c	8.5 (Berkeley) 5/24/95";
     42 #else
     43 __RCSID("$NetBSD: dumplfs.c,v 1.64 2018/06/15 15:16:05 christos Exp $");
     44 #endif
     45 #endif /* not lint */
     46 
     47 #include <sys/param.h>
     48 #include <sys/ucred.h>
     49 #include <sys/mount.h>
     50 #include <sys/time.h>
     51 
     52 #include <ufs/lfs/lfs.h>
     53 #include <ufs/lfs/lfs_accessors.h>
     54 
     55 #include <err.h>
     56 #include <errno.h>
     57 #include <fcntl.h>
     58 #include <fstab.h>
     59 #include <stdbool.h>
     60 #include <stdlib.h>
     61 #include <stdio.h>
     62 #include <string.h>
     63 #include <unistd.h>
     64 #include <util.h>
     65 #include "extern.h"
     66 
     67 static void	addseg(char *);
     68 static void	dump_cleaner_info(struct lfs *, void *);
     69 static void	dump_dinode(struct lfs *, union lfs_dinode *);
     70 static void	dump_ifile(int, struct lfs *, int, int, daddr_t);
     71 static int	dump_ipage_ifile(struct lfs *, int, char *, int);
     72 static int	dump_ipage_segusage(struct lfs *, int, char *, int);
     73 static void	dump_segment(int, int, daddr_t, struct lfs *, int);
     74 static int	dump_sum(int, struct lfs *, SEGSUM *, int, daddr_t);
     75 static void	dump_super(struct lfs *);
     76 static void	usage(void);
     77 
     78 extern uint32_t	cksum(void *, size_t);
     79 
     80 typedef struct seglist SEGLIST;
     81 struct seglist {
     82         SEGLIST *next;
     83 	int num;
     84 };
     85 SEGLIST	*seglist;
     86 
     87 char *special;
     88 
     89 /* Segment Usage formats */
     90 #define print_suheader \
     91 	(void)printf("segnum\tflags\tnbytes\tninos\tnsums\tlastmod\n")
     92 
     93 static inline void
     94 print_suentry(int i, SEGUSE *sp, struct lfs *fs)
     95 {
     96 	time_t t;
     97 	char flags[4] = "   ";
     98 
     99 	if (sp->su_flags & SEGUSE_ACTIVE)
    100 		flags[0] = 'A';
    101 	if (sp->su_flags & SEGUSE_DIRTY)
    102 		flags[1] = 'D';
    103 	else
    104 		flags[1] = 'C';
    105 	if (sp->su_flags & SEGUSE_SUPERBLOCK)
    106 		flags[2] = 'S';
    107 
    108 	t = (lfs_sb_getversion(fs) == 1 ? sp->su_olastmod : sp->su_lastmod);
    109 
    110 	printf("%d\t%s\t%d\t%d\t%d\t%s", i, flags,
    111 		sp->su_nbytes, sp->su_ninos, sp->su_nsums,
    112 		ctime(&t));
    113 }
    114 
    115 /* Ifile formats */
    116 #define print_iheader \
    117 	(void)printf("inum\tstatus\tversion\tdaddr\t\tfreeptr\n")
    118 
    119 static inline void
    120 print_ientry(int i, struct lfs *lfsp, IFILE *ip)
    121 {
    122 	uint32_t version;
    123 	daddr_t daddr;
    124 	ino_t nextfree;
    125 
    126 	version = lfs_if_getversion(lfsp, ip);
    127 	daddr = lfs_if_getdaddr(lfsp, ip);
    128 	nextfree = lfs_if_getnextfree(lfsp, ip);
    129 
    130 	if (daddr == LFS_UNUSED_DADDR)
    131 		printf("%d\tFREE\t%u\t \t\t%ju\n", i, version,
    132 		    (uintmax_t)nextfree);
    133 	else
    134 		printf("%d\tINUSE\t%u\t%8jX\t%s\n",
    135 		    i, version, (intmax_t)daddr,
    136 		    nextfree == LFS_ORPHAN_NEXTFREE ? "FFFFFFFF" : "-");
    137 }
    138 
    139 /*
    140  * Set the is64 and dobyteswap fields of struct lfs. Note that the
    141  * magic number (and version) fields are necessarily at the same place
    142  * in all superblock versions, so we can read it via u_32 without
    143  * getting confused.
    144  */
    145 static void
    146 identify(struct lfs *fs)
    147 {
    148 	unsigned magic;
    149 
    150 	magic = fs->lfs_dlfs_u.u_32.dlfs_magic;
    151 	switch (magic) {
    152 	    case LFS_MAGIC:
    153 		fs->lfs_is64 = false;
    154 		fs->lfs_dobyteswap = false;
    155 		break;
    156 	    case LFS_MAGIC_SWAPPED:
    157 		fs->lfs_is64 = false;
    158 		fs->lfs_dobyteswap = true;
    159 		break;
    160 	    case LFS64_MAGIC:
    161 		fs->lfs_is64 = true;
    162 		fs->lfs_dobyteswap = false;
    163 		break;
    164 	    case LFS64_MAGIC_SWAPPED:
    165 		fs->lfs_is64 = true;
    166 		fs->lfs_dobyteswap = true;
    167 		break;
    168 	    default:
    169 		warnx("Superblock magic number 0x%x not known; "
    170 		      "assuming 32-bit, native-endian", magic);
    171 		fs->lfs_is64 = false;
    172 		fs->lfs_dobyteswap = false;
    173 		break;
    174 	}
    175 }
    176 
    177 #define fsbtobyte(fs, b)	lfs_fsbtob((fs), (off_t)((b)))
    178 
    179 int datasum_check = 0;
    180 
    181 int
    182 main(int argc, char **argv)
    183 {
    184 	struct lfs lfs_sb1, lfs_sb2, *lfs_master;
    185 	daddr_t seg_addr, idaddr, sbdaddr;
    186 	int ch, do_allsb, do_ientries, do_segentries, fd, segnum;
    187 	void *sbuf;
    188 
    189 	do_allsb = 0;
    190 	do_ientries = 0;
    191 	do_segentries = 0;
    192 	idaddr = 0x0;
    193 	sbdaddr = 0x0;
    194 	while ((ch = getopt(argc, argv, "ab:diI:Ss:")) != -1)
    195 		switch(ch) {
    196 		case 'a':		/* Dump all superblocks */
    197 			do_allsb = 1;
    198 			break;
    199 		case 'b':		/* Use this superblock */
    200 			sbdaddr = strtol(optarg, NULL, 0);
    201 			break;
    202 		case 'd':
    203 			datasum_check = 1;
    204 			break;
    205 		case 'i':		/* Dump ifile entries */
    206 			do_ientries = !do_ientries;
    207 			break;
    208 		case 'I':		/* Use this ifile inode */
    209 			idaddr = strtol(optarg, NULL, 0);
    210 			break;
    211 		case 'S':
    212 			do_segentries = !do_segentries;
    213 			break;
    214 		case 's':		/* Dump out these segments */
    215 			addseg(optarg);
    216 			break;
    217 		default:
    218 			usage();
    219 		}
    220 	argc -= optind;
    221 	argv += optind;
    222 
    223 	if (argc != 1)
    224 		usage();
    225 
    226 	special = argv[0];
    227 	if ((fd = open(special, O_RDONLY, 0)) < 0)
    228 		err(1, "%s", special);
    229 
    230 	sbuf = emalloc(LFS_SBPAD);
    231 	if (sbdaddr == 0x0) {
    232 		/* Read the proto-superblock */
    233 		__CTASSERT(sizeof(struct dlfs) == sizeof(struct dlfs64));
    234 		get(fd, LFS_LABELPAD, sbuf, LFS_SBPAD);
    235 		memcpy(&lfs_sb1.lfs_dlfs_u, sbuf, sizeof(struct dlfs));
    236 		identify(&lfs_sb1);
    237 
    238 		/* If that wasn't the real first sb, get the real first sb */
    239 		if (lfs_sb_getversion(&lfs_sb1) > 1 &&
    240 		    lfs_sb_getsboff(&lfs_sb1, 0) > lfs_btofsb(&lfs_sb1, LFS_LABELPAD)) {
    241 			get(fd, lfs_fsbtob(&lfs_sb1, lfs_sb_getsboff(&lfs_sb1, 0)),
    242 			    &lfs_sb1.lfs_dlfs_u, sizeof(struct dlfs));
    243 			identify(&lfs_sb1);
    244 		}
    245 
    246 		/*
    247 	 	* Read the second superblock and figure out which check point is
    248 	 	* most up to date.
    249 	 	*/
    250 		get(fd,
    251 		    fsbtobyte(&lfs_sb1, lfs_sb_getsboff(&lfs_sb1, 1)),
    252 		    sbuf, LFS_SBPAD);
    253 		memcpy(&lfs_sb2.lfs_dlfs_u, sbuf, sizeof(struct dlfs));
    254 		identify(&lfs_sb2);
    255 
    256 		lfs_master = &lfs_sb1;
    257 		if (lfs_sb_getversion(&lfs_sb1) > 1) {
    258 			if (lfs_sb_getserial(&lfs_sb1) > lfs_sb_getserial(&lfs_sb2)) {
    259 				lfs_master = &lfs_sb2;
    260 				sbdaddr = lfs_sb_getsboff(&lfs_sb1, 1);
    261 			} else
    262 				sbdaddr = lfs_sb_getsboff(&lfs_sb1, 0);
    263 		} else {
    264 			if (lfs_sb_getotstamp(&lfs_sb1) > lfs_sb_getotstamp(&lfs_sb2)) {
    265 				lfs_master = &lfs_sb2;
    266 				sbdaddr = lfs_sb_getsboff(&lfs_sb1, 1);
    267 			} else
    268 				sbdaddr = lfs_sb_getsboff(&lfs_sb1, 0);
    269 		}
    270 	} else {
    271 		/* Read the first superblock */
    272 		get(fd, dbtob((off_t)sbdaddr), sbuf, LFS_SBPAD);
    273 		memcpy(&lfs_sb1.lfs_dlfs_u, sbuf, sizeof(struct dlfs));
    274 		identify(&lfs_sb1);
    275 		lfs_master = &lfs_sb1;
    276 	}
    277 
    278 	free(sbuf);
    279 
    280 	/* Compatibility */
    281 	if (lfs_sb_getversion(lfs_master) == 1) {
    282 		lfs_sb_setsumsize(lfs_master, LFS_V1_SUMMARY_SIZE);
    283 		lfs_sb_setibsize(lfs_master, lfs_sb_getbsize(lfs_master));
    284 		lfs_sb_sets0addr(lfs_master, lfs_sb_getsboff(lfs_master, 0));
    285 		lfs_sb_settstamp(lfs_master, lfs_sb_getotstamp(lfs_master));
    286 		lfs_sb_setfsbtodb(lfs_master, 0);
    287 	}
    288 
    289 	(void)printf("Master LFS%d superblock at 0x%llx:\n",
    290 	    lfs_master->lfs_is64 ? 64 : 32, (long long)sbdaddr);
    291 	dump_super(lfs_master);
    292 
    293 	dump_ifile(fd, lfs_master, do_ientries, do_segentries, idaddr);
    294 
    295 	if (seglist != NULL)
    296 		for (; seglist != NULL; seglist = seglist->next) {
    297 			seg_addr = lfs_sntod(lfs_master, seglist->num);
    298 			dump_segment(fd, seglist->num, seg_addr, lfs_master,
    299 				     do_allsb);
    300 		}
    301 	else
    302 		for (segnum = 0, seg_addr = lfs_sntod(lfs_master, 0);
    303 		     segnum < lfs_sb_getnseg(lfs_master);
    304 		     segnum++, seg_addr = lfs_sntod(lfs_master, segnum))
    305 			dump_segment(fd, segnum, seg_addr, lfs_master,
    306 				     do_allsb);
    307 
    308 	(void)close(fd);
    309 	exit(0);
    310 }
    311 
    312 /*
    313  * We are reading all the blocks of an inode and dumping out the ifile table.
    314  * This code could be tighter, but this is a first pass at getting the stuff
    315  * printed out rather than making this code incredibly efficient.
    316  */
    317 static void
    318 dump_ifile(int fd, struct lfs *lfsp, int do_ientries, int do_segentries, daddr_t addr)
    319 {
    320 	char *ipage;
    321 	char *dpage;
    322 	union lfs_dinode *dip = NULL;
    323 	void *dindir, *indir;
    324 	unsigned offset;
    325 	daddr_t thisblock;
    326 	daddr_t pdb;
    327 	int block_limit, i, inum, j, nblocks, psize;
    328 
    329 	psize = lfs_sb_getbsize(lfsp);
    330 	if (!addr)
    331 		addr = lfs_sb_getidaddr(lfsp);
    332 
    333 	dpage = emalloc(psize);
    334 	get(fd, fsbtobyte(lfsp, addr), dpage, psize);
    335 
    336 	dip = NULL;
    337 	for (i = LFS_INOPB(lfsp); i-- > 0; ) {
    338 		dip = DINO_IN_BLOCK(lfsp, dpage, i);
    339 		if (lfs_dino_getinumber(lfsp, dip) == LFS_IFILE_INUM)
    340 			break;
    341 	}
    342 
    343 	/* just in case */
    344 	if (dip == NULL) {
    345 		warnx("this volume apparently has zero inodes per block");
    346 		return;
    347 	}
    348 
    349 	if (lfs_dino_getinumber(lfsp, dip) != LFS_IFILE_INUM) {
    350 		warnx("unable to locate ifile inode at disk address 0x%jx",
    351 		     (uintmax_t)addr);
    352 		return;
    353 	}
    354 
    355 	(void)printf("\nIFILE inode\n");
    356 	dump_dinode(lfsp, dip);
    357 
    358 	(void)printf("\nIFILE contents\n");
    359 	nblocks = lfs_dino_getsize(lfsp, dip) >> lfs_sb_getbshift(lfsp);
    360 	block_limit = MIN(nblocks, ULFS_NDADDR);
    361 
    362 	/* Get the direct block */
    363 	ipage = emalloc(psize);
    364 	for (inum = 0, i = 0; i < block_limit; i++) {
    365 		pdb = lfs_dino_getdb(lfsp, dip, i);
    366 		get(fd, fsbtobyte(lfsp, pdb), ipage, psize);
    367 		if (i < lfs_sb_getcleansz(lfsp)) {
    368 			dump_cleaner_info(lfsp, ipage);
    369 			if (do_segentries)
    370 				print_suheader;
    371 			continue;
    372 		}
    373 
    374 		if (i < (lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp))) {
    375 			if (do_segentries)
    376 				inum = dump_ipage_segusage(lfsp, inum, ipage,
    377 							   lfs_sb_getsepb(lfsp));
    378 			else
    379 				inum = (i < lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp) - 1);
    380 			if (!inum) {
    381 				if(!do_ientries)
    382 					goto e0;
    383 				else
    384 					print_iheader;
    385 			}
    386 		} else
    387 			inum = dump_ipage_ifile(lfsp, inum, ipage, lfs_sb_getifpb(lfsp));
    388 	}
    389 
    390 	if (nblocks <= ULFS_NDADDR)
    391 		goto e0;
    392 
    393 	/* Dump out blocks off of single indirect block */
    394 	indir = emalloc(psize);
    395 	get(fd, fsbtobyte(lfsp, lfs_dino_getib(lfsp, dip, 0)), indir, psize);
    396 	block_limit = MIN(i + lfs_sb_getnindir(lfsp), nblocks);
    397 	for (offset = 0; i < block_limit; i++, offset++) {
    398 		thisblock = lfs_iblock_get(lfsp, indir, offset);
    399 		if (thisblock == LFS_UNUSED_DADDR)
    400 			break;
    401 		get(fd, fsbtobyte(lfsp, thisblock), ipage, psize);
    402 		if (i < lfs_sb_getcleansz(lfsp)) {
    403 			dump_cleaner_info(lfsp, ipage);
    404 			continue;
    405 		}
    406 
    407 		if (i < lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp)) {
    408 			if (do_segentries)
    409 				inum = dump_ipage_segusage(lfsp, inum, ipage,
    410 							   lfs_sb_getsepb(lfsp));
    411 			else
    412 				inum = (i < lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp) - 1);
    413 			if (!inum) {
    414 				if(!do_ientries)
    415 					goto e1;
    416 				else
    417 					print_iheader;
    418 			}
    419 		} else
    420 			inum = dump_ipage_ifile(lfsp, inum, ipage, lfs_sb_getifpb(lfsp));
    421 	}
    422 
    423 	if (nblocks <= ULFS_NDADDR + lfs_sb_getnindir(lfsp))
    424 		goto e1;
    425 
    426 	/* Get the double indirect block */
    427 	dindir = emalloc(psize);
    428 	get(fd, fsbtobyte(lfsp, lfs_dino_getib(lfsp, dip, 1)), dindir, psize);
    429 	for (j = 0; j < lfs_sb_getnindir(lfsp); j++) {
    430 		thisblock = lfs_iblock_get(lfsp, dindir, j);
    431 		if (thisblock == LFS_UNUSED_DADDR)
    432 			break;
    433 		get(fd, fsbtobyte(lfsp, thisblock), indir, psize);
    434 		block_limit = MIN(i + lfs_sb_getnindir(lfsp), nblocks);
    435 		for (offset = 0; i < block_limit; i++, offset++) {
    436 			thisblock = lfs_iblock_get(lfsp, indir, offset);
    437 			if (thisblock == LFS_UNUSED_DADDR)
    438 				break;
    439 			get(fd, fsbtobyte(lfsp, thisblock), ipage, psize);
    440 			if (i < lfs_sb_getcleansz(lfsp)) {
    441 				dump_cleaner_info(lfsp, ipage);
    442 				continue;
    443 			}
    444 
    445 			if (i < lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp)) {
    446 				if (do_segentries)
    447 					inum = dump_ipage_segusage(lfsp,
    448 						 inum, ipage, lfs_sb_getsepb(lfsp));
    449 				else
    450 					inum = (i < lfs_sb_getsegtabsz(lfsp) +
    451 						lfs_sb_getcleansz(lfsp) - 1);
    452 				if (!inum) {
    453 					if(!do_ientries)
    454 						goto e2;
    455 					else
    456 						print_iheader;
    457 				}
    458 			} else
    459 				inum = dump_ipage_ifile(lfsp, inum,
    460 				    ipage, lfs_sb_getifpb(lfsp));
    461 		}
    462 	}
    463 e2:	free(dindir);
    464 e1:	free(indir);
    465 e0:	free(dpage);
    466 	free(ipage);
    467 }
    468 
    469 static int
    470 dump_ipage_ifile(struct lfs *lfsp, int i, char *pp, int tot)
    471 {
    472 	char *ip;
    473 	int cnt, max, entsize;
    474 
    475 	if (lfsp->lfs_is64)
    476 		entsize = sizeof(IFILE64);
    477 	if (lfs_sb_getversion(lfsp) > 1)
    478 		entsize = sizeof(IFILE32);
    479 	else
    480 		entsize = sizeof(IFILE_V1);
    481 	max = i + tot;
    482 
    483 	for (ip = pp, cnt = i; cnt < max; cnt++, ip += entsize)
    484 		print_ientry(cnt, lfsp, (IFILE *)ip);
    485 	return (max);
    486 }
    487 
    488 static int
    489 dump_ipage_segusage(struct lfs *lfsp, int i, char *pp, int tot)
    490 {
    491 	SEGUSE *sp;
    492 	int cnt, max;
    493 	struct seglist *slp;
    494 
    495 	max = i + tot;
    496 	for (sp = (SEGUSE *)pp, cnt = i;
    497 	     cnt < lfs_sb_getnseg(lfsp) && cnt < max; cnt++) {
    498 		if (seglist == NULL)
    499 			print_suentry(cnt, sp, lfsp);
    500 		else {
    501 			for (slp = seglist; slp != NULL; slp = slp->next)
    502 				if (cnt == slp->num) {
    503 					print_suentry(cnt, sp, lfsp);
    504 					break;
    505 				}
    506 		}
    507 		if (lfs_sb_getversion(lfsp) > 1)
    508 			++sp;
    509 		else
    510 			sp = (SEGUSE *)((SEGUSE_V1 *)sp + 1);
    511 	}
    512 	if (max >= lfs_sb_getnseg(lfsp))
    513 		return (0);
    514 	else
    515 		return (max);
    516 }
    517 
    518 static void
    519 dump_dinode(struct lfs *fs, union lfs_dinode *dip)
    520 {
    521 	int i;
    522 	time_t at, mt, ct;
    523 
    524 	at = lfs_dino_getatime(fs, dip);
    525 	mt = lfs_dino_getmtime(fs, dip);
    526 	ct = lfs_dino_getctime(fs, dip);
    527 
    528 	(void)printf("    %so%o\t%s%d\t%s%d\t%s%d\t%s%ju\n",
    529 		"mode  ", lfs_dino_getmode(fs, dip),
    530 		"nlink ", lfs_dino_getnlink(fs, dip),
    531 		"uid   ", lfs_dino_getuid(fs, dip),
    532 		"gid   ", lfs_dino_getgid(fs, dip),
    533 		"size  ", (uintmax_t)lfs_dino_getsize(fs, dip));
    534 	(void)printf("    %s%s", "atime ", ctime(&at));
    535 	(void)printf("    %s%s", "mtime ", ctime(&mt));
    536 	(void)printf("    %s%s", "ctime ", ctime(&ct));
    537 	(void)printf("    inum  %ju\n",
    538 		(uintmax_t)lfs_dino_getinumber(fs, dip));
    539 	(void)printf("    Direct Addresses\n");
    540 	for (i = 0; i < ULFS_NDADDR; i++) {
    541 		(void)printf("\t0x%jx", (intmax_t)lfs_dino_getdb(fs, dip, i));
    542 		if ((i % 6) == 5)
    543 			(void)printf("\n");
    544 	}
    545 	(void)printf("    Indirect Addresses\n");
    546 	for (i = 0; i < ULFS_NIADDR; i++)
    547 		(void)printf("\t0x%jx", (intmax_t)lfs_dino_getib(fs, dip, i));
    548 	(void)printf("\n");
    549 }
    550 
    551 static int
    552 dump_sum(int fd, struct lfs *lfsp, SEGSUM *sp, int segnum, daddr_t addr)
    553 {
    554 	FINFO *fp;
    555 	IINFO *iip, *iip2;
    556 	union lfs_blocks fipblocks;
    557 	int i, j, acc;
    558 	int ck;
    559 	int numbytes, numblocks;
    560 	char *datap;
    561 	char *diblock;
    562 	union lfs_dinode *dip;
    563 	size_t el_size;
    564 	u_int32_t datasum;
    565 	u_int32_t ssflags;
    566 	time_t t;
    567 	char *buf;
    568 	size_t sumstart;
    569 
    570 	sumstart = lfs_ss_getsumstart(lfsp);
    571 	if (lfs_ss_getmagic(lfsp, sp) != SS_MAGIC ||
    572 	    lfs_ss_getsumsum(lfsp, sp) != (ck = cksum((char *)sp + sumstart,
    573 	    lfs_sb_getsumsize(lfsp) - sumstart))) {
    574 		/* Don't print "corrupt" if we're just too close to the edge */
    575 		if (lfs_dtosn(lfsp, addr + LFS_FSBTODB(lfsp, 1)) ==
    576 		    lfs_dtosn(lfsp, addr))
    577 			(void)printf("dumplfs: %s %d address 0x%llx\n",
    578 		                     "corrupt summary block; segment", segnum,
    579 				     (long long)addr);
    580 		return -1;
    581 	}
    582 	if (lfs_sb_getversion(lfsp) > 1 && lfs_ss_getident(lfsp, sp) != lfs_sb_getident(lfsp)) {
    583 		(void)printf("dumplfs: %s %d address 0x%llx\n",
    584 	                     "summary from a former life; segment", segnum,
    585 			     (long long)addr);
    586 		return -1;
    587 	}
    588 
    589 	(void)printf("Segment Summary Info at 0x%llx\n", (long long)addr);
    590 	ssflags = lfs_ss_getflags(lfsp, sp);
    591 	(void)printf("    %s0x%jx\t%s%d\t%s%d\t%s%c%c%c%c\n    %s0x%x\t%s0x%x",
    592 		"next     ", (intmax_t)lfs_ss_getnext(lfsp, sp),
    593 		"nfinfo   ", lfs_ss_getnfinfo(lfsp, sp),
    594 		"ninos    ", lfs_ss_getninos(lfsp, sp),
    595 		"flags    ", (ssflags & SS_DIROP) ? 'D' : '-',
    596 			     (ssflags & SS_CONT)  ? 'C' : '-',
    597 			     (ssflags & SS_CLEAN)  ? 'L' : '-',
    598 			     (ssflags & SS_RFW)  ? 'R' : '-',
    599 		"sumsum   ", lfs_ss_getsumsum(lfsp, sp),
    600 		"datasum  ", lfs_ss_getdatasum(lfsp, sp));
    601 	if (lfs_sb_getversion(lfsp) == 1) {
    602 		t = lfs_ss_getocreate(lfsp, sp);
    603 		(void)printf("\tcreate   %s\n", ctime(&t));
    604 	} else {
    605 		t = lfs_ss_getcreate(lfsp, sp);
    606 		(void)printf("\tcreate   %s", ctime(&t));
    607 		(void)printf("    roll_id  %-8x", lfs_ss_getident(lfsp, sp));
    608 		(void)printf("   serial   %lld\n",
    609 			     (long long)lfs_ss_getserial(lfsp, sp));
    610 	}
    611 
    612 	/* Dump out inode disk addresses */
    613 	iip = SEGSUM_IINFOSTART(lfsp, sp);
    614 	diblock = emalloc(lfs_sb_getbsize(lfsp));
    615 	printf("    Inode addresses:");
    616 	numbytes = 0;
    617 	numblocks = 0;
    618 	for (i = 0; i < lfs_ss_getninos(lfsp, sp); iip = NEXTLOWER_IINFO(lfsp, iip)) {
    619 		++numblocks;
    620 		numbytes += lfs_sb_getibsize(lfsp);	/* add bytes for inode block */
    621 		printf("\t0x%jx {", (intmax_t)lfs_ii_getblock(lfsp, iip));
    622 		get(fd, fsbtobyte(lfsp, lfs_ii_getblock(lfsp, iip)), diblock, lfs_sb_getibsize(lfsp));
    623 		for (j = 0; i < lfs_ss_getninos(lfsp, sp) && j < LFS_INOPB(lfsp); j++, i++) {
    624 			if (j > 0)
    625 				(void)printf(", ");
    626 			dip = DINO_IN_BLOCK(lfsp, diblock, j);
    627 			(void)printf("%juv%d", lfs_dino_getinumber(lfsp, dip),
    628 				     lfs_dino_getgen(lfsp, dip));
    629 		}
    630 		(void)printf("}");
    631 		if (((i/LFS_INOPB(lfsp)) % 4) == 3)
    632 			(void)printf("\n");
    633 	}
    634 	free(diblock);
    635 
    636 	printf("\n");
    637 
    638 	fp = SEGSUM_FINFOBASE(lfsp, sp);
    639 	for (i = 0; i < lfs_ss_getnfinfo(lfsp, sp); i++) {
    640 		(void)printf("    FINFO for inode: %ju version %u nblocks %u lastlength %u\n",
    641 		    (uintmax_t)lfs_fi_getino(lfsp, fp),
    642 		    lfs_fi_getversion(lfsp, fp),
    643 		    lfs_fi_getnblocks(lfsp, fp),
    644 		    lfs_fi_getlastlength(lfsp, fp));
    645 		lfs_blocks_fromfinfo(lfsp, &fipblocks, fp);
    646 		numblocks += lfs_fi_getnblocks(lfsp, fp);
    647 		for (j = 0; j < lfs_fi_getnblocks(lfsp, fp); j++) {
    648 			(void)printf("\t%jd",
    649 			    (intmax_t)lfs_blocks_get(lfsp, &fipblocks, j));
    650 			if ((j % 8) == 7)
    651 				(void)printf("\n");
    652 			if (j == lfs_fi_getnblocks(lfsp, fp) - 1)
    653 				numbytes += lfs_fi_getlastlength(lfsp, fp);
    654 			else
    655 				numbytes += lfs_sb_getbsize(lfsp);
    656 		}
    657 		if ((j % 8) != 0)
    658 			(void)printf("\n");
    659 		fp = NEXT_FINFO(lfsp, fp);
    660 	}
    661 
    662 	if (datasum_check == 0)
    663 		return (numbytes);
    664 
    665 	/*
    666 	 * Now that we know the number of blocks, run back through and
    667 	 * compute the data checksum.  (A bad data checksum is not enough
    668 	 * to prevent us from continuing, but it odes merit a warning.)
    669 	 */
    670 	iip2 = SEGSUM_IINFOSTART(lfsp, sp);
    671 	fp = SEGSUM_FINFOBASE(lfsp, sp);
    672 	if (lfs_sb_getversion(lfsp) == 1) {
    673 		el_size = sizeof(unsigned long);
    674 	} else {
    675 		el_size = sizeof(u_int32_t);
    676 	}
    677 	datap = ecalloc(numblocks, el_size);
    678 
    679 	acc = 0;
    680 	addr += lfs_btofsb(lfsp, lfs_sb_getsumsize(lfsp));
    681 	buf = emalloc(lfs_sb_getbsize(lfsp));
    682 	for (i = 0; i < lfs_ss_getnfinfo(lfsp, sp); i++) {
    683 		while (addr == lfs_ii_getblock(lfsp, iip2)) {
    684 			get(fd, fsbtobyte(lfsp, addr), buf, lfs_sb_getibsize(lfsp));
    685 			memcpy(datap + acc * el_size, buf, el_size);
    686 			addr += lfs_btofsb(lfsp, lfs_sb_getibsize(lfsp));
    687 			iip2 = NEXTLOWER_IINFO(lfsp, iip2);
    688 			++acc;
    689 		}
    690 		for (j = 0; j < lfs_fi_getnblocks(lfsp, fp); j++) {
    691 			get(fd, fsbtobyte(lfsp, addr), buf, lfs_sb_getfsize(lfsp));
    692 			memcpy(datap + acc * el_size, buf, el_size);
    693 			if (j == lfs_fi_getnblocks(lfsp, fp) - 1)
    694 				addr += lfs_btofsb(lfsp, lfs_fi_getlastlength(lfsp, fp));
    695 			else
    696 				addr += lfs_btofsb(lfsp, lfs_sb_getbsize(lfsp));
    697 			++acc;
    698 		}
    699 		fp = NEXT_FINFO(lfsp, fp);
    700 	}
    701 	while (addr == lfs_ii_getblock(lfsp, iip2)) {
    702 		get(fd, fsbtobyte(lfsp, addr), buf, lfs_sb_getibsize(lfsp));
    703 		memcpy(datap + acc * el_size, buf, el_size);
    704 		addr += lfs_btofsb(lfsp, lfs_sb_getibsize(lfsp));
    705 		iip2 = NEXTLOWER_IINFO(lfsp, iip2);
    706 		++acc;
    707 	}
    708 	free(buf);
    709 	if (acc != numblocks)
    710 		printf("** counted %d blocks but should have been %d\n",
    711 		     acc, numblocks);
    712 	datasum = cksum(datap, numblocks * el_size);
    713 	if (datasum != lfs_ss_getdatasum(lfsp, sp))
    714 		printf("** computed datasum 0x%lx does not match given datasum 0x%lx\n", (unsigned long)datasum, (unsigned long)lfs_ss_getdatasum(lfsp, sp));
    715 	free(datap);
    716 
    717 	return (numbytes);
    718 }
    719 
    720 static void
    721 dump_segment(int fd, int segnum, daddr_t addr, struct lfs *lfsp, int dump_sb)
    722 {
    723 	struct lfs lfs_sb, *sbp;
    724 	SEGSUM *sump;
    725 	size_t sumstart;
    726 	char *sumblock;
    727 	int did_one, nbytes, sb;
    728 	off_t sum_offset;
    729 	daddr_t new_addr;
    730 
    731 	(void)printf("\nSEGMENT %lld (Disk Address 0x%llx)\n",
    732 		     (long long)lfs_dtosn(lfsp, addr), (long long)addr);
    733 	sum_offset = fsbtobyte(lfsp, addr);
    734 	sumblock = emalloc(lfs_sb_getsumsize(lfsp));
    735 
    736 	if (lfs_sb_getversion(lfsp) > 1 && segnum == 0) {
    737 		if (lfs_fsbtob(lfsp, lfs_sb_gets0addr(lfsp)) < LFS_LABELPAD) {
    738 			/* First segment eats the disklabel */
    739 			sum_offset += lfs_fragroundup(lfsp, LFS_LABELPAD) -
    740 				      lfs_fsbtob(lfsp, lfs_sb_gets0addr(lfsp));
    741 			addr += lfs_btofsb(lfsp, lfs_fragroundup(lfsp, LFS_LABELPAD)) -
    742 				lfs_sb_gets0addr(lfsp);
    743 			printf("Disklabel at 0x0\n");
    744 		}
    745 	}
    746 
    747 	sb = 0;
    748 	did_one = 0;
    749 	do {
    750 		get(fd, sum_offset, sumblock, lfs_sb_getsumsize(lfsp));
    751 		sump = (SEGSUM *)sumblock;
    752 		sumstart = lfs_ss_getsumstart(lfsp);
    753 		if ((lfs_sb_getversion(lfsp) > 1 &&
    754 		     lfs_ss_getident(lfsp, sump) != lfs_sb_getident(lfsp)) ||
    755 		    lfs_ss_getsumsum(lfsp, sump) !=
    756 		      cksum((char *)sump + sumstart,
    757 			    lfs_sb_getsumsize(lfsp) - sumstart)) {
    758 			sbp = (struct lfs *)sump;
    759 			if ((sb = (sbp->lfs_dlfs_u.u_32.dlfs_magic == LFS_MAGIC))) {
    760 				printf("Superblock at 0x%x\n",
    761 				       (unsigned)lfs_btofsb(lfsp, sum_offset));
    762 				if (dump_sb)  {
    763 					__CTASSERT(sizeof(struct dlfs) ==
    764 						   sizeof(struct dlfs64));
    765 					get(fd, sum_offset, &(lfs_sb.lfs_dlfs_u),
    766 					    sizeof(struct dlfs));
    767 					dump_super(&lfs_sb);
    768 				}
    769 				if (lfs_sb_getversion(lfsp) > 1)
    770 					sum_offset += lfs_fragroundup(lfsp, LFS_SBPAD);
    771 				else
    772 					sum_offset += LFS_SBPAD;
    773 			} else if (did_one)
    774 				break;
    775 			else {
    776 				printf("Segment at 0x%llx empty or corrupt\n",
    777                                        (long long)addr);
    778 				break;
    779 			}
    780 		} else {
    781 			nbytes = dump_sum(fd, lfsp, sump, segnum,
    782 				lfs_btofsb(lfsp, sum_offset));
    783 			if (nbytes >= 0)
    784 				sum_offset += lfs_sb_getsumsize(lfsp) + nbytes;
    785 			else
    786 				sum_offset = 0;
    787 			did_one = 1;
    788 		}
    789 		/* If the segment ends right on a boundary, it still ends */
    790 		new_addr = lfs_btofsb(lfsp, sum_offset);
    791 		/* printf("end daddr = 0x%lx\n", (long)new_addr); */
    792 		if (lfs_dtosn(lfsp, new_addr) != lfs_dtosn(lfsp, addr))
    793 			break;
    794 	} while (sum_offset);
    795 
    796 	free(sumblock);
    797 }
    798 
    799 static void
    800 dump_super(struct lfs *lfsp)
    801 {
    802 	time_t stamp;
    803 	int i;
    804 
    805  	(void)printf("    %s0x%-8x  %s0x%-8x  %s%-10ju\n",
    806  		     "magic    ", lfsp->lfs_dlfs_u.u_32.dlfs_magic,
    807  		     "version  ", lfs_sb_getversion(lfsp),
    808  		     "size     ", (uintmax_t)lfs_sb_getsize(lfsp));
    809  	(void)printf("    %s%-10d  %s%-10ju  %s%-10d\n",
    810  		     "ssize    ", lfs_sb_getssize(lfsp),
    811  		     "dsize    ", (uintmax_t)lfs_sb_getdsize(lfsp),
    812  		     "bsize    ", lfs_sb_getbsize(lfsp));
    813  	(void)printf("    %s%-10d  %s%-10d  %s%-10d\n",
    814  		     "fsize    ", lfs_sb_getfsize(lfsp),
    815  		     "frag     ", lfs_sb_getfrag(lfsp),
    816  		     "minfree  ", lfs_sb_getminfree(lfsp));
    817  	(void)printf("    %s%-10d  %s%-10d  %s%-10d\n",
    818  		     "inopb    ", lfs_sb_getinopb(lfsp),
    819  		     "ifpb     ", lfs_sb_getifpb(lfsp),
    820  		     "nindir   ", lfs_sb_getnindir(lfsp));
    821  	(void)printf("    %s%-10d  %s%-10d  %s%-10d\n",
    822  		     "nseg     ", lfs_sb_getnseg(lfsp),
    823  		     "sepb     ", lfs_sb_getsepb(lfsp),
    824  		     "cleansz  ", lfs_sb_getcleansz(lfsp));
    825  	(void)printf("    %s%-10d  %s0x%-8x  %s%-10d\n",
    826  		     "segtabsz ", lfs_sb_getsegtabsz(lfsp),
    827  		     "segmask  ", lfs_sb_getsegmask(lfsp),
    828  		     "segshift ", lfs_sb_getsegshift(lfsp));
    829  	(void)printf("    %s0x%-8jx  %s%-10d  %s0x%-8jX\n",
    830  		     "bmask    ", (uintmax_t)lfs_sb_getbmask(lfsp),
    831  		     "bshift   ", lfs_sb_getbshift(lfsp),
    832  		     "ffmask   ", (uintmax_t)lfs_sb_getffmask(lfsp));
    833  	(void)printf("    %s%-10d  %s0x%-8jx  %s%u\n",
    834  		     "ffshift  ", lfs_sb_getffshift(lfsp),
    835  		     "fbmask   ", (uintmax_t)lfs_sb_getfbmask(lfsp),
    836  		     "fbshift  ", lfs_sb_getfbshift(lfsp));
    837 
    838  	(void)printf("    %s%-10d  %s%-10d  %s0x%-8x\n",
    839  		     "sushift  ", lfs_sb_getsushift(lfsp),
    840  		     "fsbtodb  ", lfs_sb_getfsbtodb(lfsp),
    841  		     "cksum    ", lfs_sb_getcksum(lfsp));
    842  	(void)printf("    %s%-10d  %s%-10d  %s%-10d\n",
    843  		     "nclean   ", lfs_sb_getnclean(lfsp),
    844  		     "dmeta    ", lfs_sb_getdmeta(lfsp),
    845  		     "minfreeseg ", lfs_sb_getminfreeseg(lfsp));
    846  	(void)printf("    %s0x%-8x  %s%-9d %s%-10d\n",
    847  		     "roll_id  ", lfs_sb_getident(lfsp),
    848  		     "interleave ", lfs_sb_getinterleave(lfsp),
    849  		     "sumsize  ", lfs_sb_getsumsize(lfsp));
    850  	(void)printf("    %s%-10jd  %s0x%-8jx\n",
    851 		     "seg0addr ", (intmax_t)lfs_sb_gets0addr(lfsp),
    852  		     "maxfilesize  ", (uintmax_t)lfs_sb_getmaxfilesize(lfsp));
    853 
    854 
    855  	(void)printf("  Superblock disk addresses:\n    ");
    856   	for (i = 0; i < LFS_MAXNUMSB; i++) {
    857  		(void)printf(" 0x%-8jx", (intmax_t)lfs_sb_getsboff(lfsp, i));
    858  		if (i == (LFS_MAXNUMSB >> 1))
    859  			(void)printf("\n    ");
    860   	}
    861   	(void)printf("\n");
    862 
    863  	(void)printf("  Checkpoint Info\n");
    864  	(void)printf("    %s%-10ju  %s0x%-8jx\n",
    865  		     "freehd   ", (uintmax_t)lfs_sb_getfreehd(lfsp),
    866  		     "idaddr   ", (intmax_t)lfs_sb_getidaddr(lfsp));
    867  	(void)printf("    %s%-10d  %s%-10jd  %s%-10jd\n",
    868  		     "uinodes  ", lfs_sb_getuinodes(lfsp),
    869  		     "bfree    ", (intmax_t)lfs_sb_getbfree(lfsp),
    870  		     "avail    ", (intmax_t)lfs_sb_getavail(lfsp));
    871  	(void)printf("    %s%-10ju  %s0x%-8jx  %s0x%-8jx\n",
    872  		     "nfiles   ", (uintmax_t)lfs_sb_getnfiles(lfsp),
    873  		     "lastseg  ", (uintmax_t)lfs_sb_getlastseg(lfsp),
    874  		     "nextseg  ", (uintmax_t)lfs_sb_getnextseg(lfsp));
    875  	(void)printf("    %s0x%-8jx  %s0x%-8jx  %s%-10ju\n",
    876  		     "curseg   ", (uintmax_t)lfs_sb_getcurseg(lfsp),
    877  		     "offset   ", (uintmax_t)lfs_sb_getoffset(lfsp),
    878 		     "serial   ", (uintmax_t)lfs_sb_getserial(lfsp));
    879 	stamp = lfs_sb_gettstamp(lfsp);
    880  	(void)printf("    tstamp   %s", ctime(&stamp));
    881 
    882 	if (!lfsp->lfs_is64) {
    883 		(void)printf("  32-bit only derived or constant fields\n");
    884 		(void)printf("    %s%-10u\n",
    885  		     "ifile    ", lfs_sb_getifile(lfsp));
    886 	}
    887 }
    888 
    889 static void
    890 addseg(char *arg)
    891 {
    892 	SEGLIST *p;
    893 
    894 	p = emalloc(sizeof(*p));
    895 	p->next = seglist;
    896 	p->num = atoi(arg);
    897 	seglist = p;
    898 }
    899 
    900 static void
    901 dump_cleaner_info(struct lfs *lfsp, void *ipage)
    902 {
    903 	CLEANERINFO *cip;
    904 
    905 	cip = (CLEANERINFO *)ipage;
    906 	if (lfs_sb_getversion(lfsp) > 1) {
    907 		(void)printf("free_head %ju\n",
    908 			     (uintmax_t)lfs_ci_getfree_head(lfsp, cip));
    909 		(void)printf("free_tail %ju\n",
    910 			     (uintmax_t)lfs_ci_getfree_tail(lfsp, cip));
    911 	}
    912 	(void)printf("clean\t%u\tdirty\t%u\n",
    913 		     lfs_ci_getclean(lfsp, cip), lfs_ci_getdirty(lfsp, cip));
    914 	(void)printf("bfree\t%jd\tavail\t%jd\n\n",
    915 		     (intmax_t)lfs_ci_getbfree(lfsp, cip),
    916 		     (intmax_t)lfs_ci_getavail(lfsp, cip));
    917 }
    918 
    919 static void
    920 usage(void)
    921 {
    922 	(void)fprintf(stderr, "usage: dumplfs [-adiS] [-b blkno] [-I blkno] [-s segno] filesys|device\n");
    923 	exit(1);
    924 }
    925