dumplfs.c revision 1.15
1/*	$NetBSD: dumplfs.c,v 1.15 2000/06/25 21:36:16 perseant 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. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/cdefs.h>
37
38#ifndef lint
39__COPYRIGHT(
40"@(#) Copyright (c) 1991, 1993\n\
41	The Regents of the University of California.  All rights reserved.\n");
42#endif /* not lint */
43
44#ifndef lint
45#if 0
46static char sccsid[] = "@(#)dumplfs.c	8.5 (Berkeley) 5/24/95";
47#else
48__RCSID("$NetBSD: dumplfs.c,v 1.15 2000/06/25 21:36:16 perseant Exp $");
49#endif
50#endif /* not lint */
51
52#include <sys/param.h>
53#include <sys/ucred.h>
54#include <sys/mount.h>
55#include <sys/time.h>
56
57#include <ufs/ufs/dinode.h>
58#include <ufs/lfs/lfs.h>
59
60#include <err.h>
61#include <errno.h>
62#include <fcntl.h>
63#include <fstab.h>
64#include <stdlib.h>
65#include <stdio.h>
66#include <string.h>
67#include <unistd.h>
68#include "extern.h"
69
70static void	addseg __P((char *));
71static void	dump_cleaner_info __P((struct lfs *, void *));
72static void	dump_dinode __P((struct dinode *));
73static void	dump_ifile __P((int, struct lfs *, int, int));
74static int	dump_ipage_ifile __P((int, IFILE *, int));
75static int	dump_ipage_segusage __P((struct lfs *, int, IFILE *, int));
76static void	dump_segment __P((int, int, daddr_t, struct lfs *, int));
77static int	dump_sum __P((int, struct lfs *, SEGSUM *, int, daddr_t));
78static void	dump_super __P((struct lfs *));
79static void	usage __P((void));
80
81int		main __P((int, char *[]));
82
83extern u_long	cksum __P((void *, size_t));
84
85typedef struct seglist SEGLIST;
86struct seglist {
87        SEGLIST *next;
88	int num;
89};
90SEGLIST	*seglist;
91
92int daddr_shift;
93char *special;
94
95/* Segment Usage formats */
96#define print_suheader \
97	(void)printf("segnum\tflags\tnbytes\tninos\tnsums\tlastmod\n")
98
99#define print_suentry(i, sp) \
100	(void)printf("%d\t%c%c%c\t%d\t%d\t%d\t%s", i, \
101	    (((sp)->su_flags & SEGUSE_ACTIVE) ? 'A' : ' '), \
102	    (((sp)->su_flags & SEGUSE_DIRTY) ? 'D' : 'C'), \
103	    (((sp)->su_flags & SEGUSE_SUPERBLOCK) ? 'S' : ' '), \
104	    (sp)->su_nbytes, (sp)->su_ninos, (sp)->su_nsums, \
105	    ctime((time_t *)&(sp)->su_lastmod))
106
107/* Ifile formats */
108#define print_iheader \
109	(void)printf("inum\tstatus\tversion\tdaddr\t\tfreeptr\n")
110#define print_ientry(i, ip) \
111	if (ip->if_daddr == LFS_UNUSED_DADDR) \
112		(void)printf("%d\tFREE\t%d\t \t\t%d\n", \
113		    i, ip->if_version, ip->if_nextfree); \
114	else \
115		(void)printf("%d\tINUSE\t%d\t%8X    \n", \
116		    i, ip->if_version, ip->if_daddr)
117
118int
119main(argc, argv)
120	int argc;
121	char *argv[];
122{
123	struct lfs lfs_sb1, lfs_sb2, *lfs_master;
124	daddr_t seg_addr, idaddr, sbdaddr;
125	int ch, do_allsb, do_ientries, fd, segnum;
126
127	do_allsb = 0;
128	do_ientries = 0;
129	idaddr = 0x0;
130	sbdaddr = 0x0;
131	while ((ch = getopt(argc, argv, "ab:iI:s:")) != -1)
132		switch(ch) {
133		case 'a':		/* Dump all superblocks */
134			do_allsb = 1;
135			break;
136		case 'b':		/* Use this superblock */
137			sbdaddr = strtol(optarg, NULL, 0);
138			break;
139		case 'i':		/* Dump ifile entries */
140			do_ientries = 1;
141			break;
142		case 'I':		/* Use this ifile inode */
143			idaddr = strtol(optarg, NULL, 0);
144			break;
145		case 's':		/* Dump out these segments */
146			addseg(optarg);
147			break;
148		default:
149			usage();
150		}
151	argc -= optind;
152	argv += optind;
153
154	if (argc != 1)
155		usage();
156
157	special = argv[0];
158	if ((fd = open(special, O_RDONLY, 0)) < 0)
159		err(1, "%s", special);
160
161	if (sbdaddr == 0x0) {
162		/* Read the first superblock */
163		get(fd, LFS_LABELPAD, &(lfs_sb1.lfs_dlfs), sizeof(struct dlfs));
164		daddr_shift = lfs_sb1.lfs_bshift - lfs_sb1.lfs_fsbtodb;
165
166		/*
167	 	* Read the second superblock and figure out which check point is
168	 	* most up to date.
169	 	*/
170		get(fd,
171	    	lfs_sb1.lfs_sboffs[1] << daddr_shift, &(lfs_sb2.lfs_dlfs), sizeof(struct dlfs));
172
173		lfs_master = &lfs_sb1;
174		if (lfs_sb1.lfs_tstamp > lfs_sb2.lfs_tstamp) {
175			lfs_master = &lfs_sb2;
176			sbdaddr = lfs_sb1.lfs_sboffs[1] << daddr_shift;
177		} else
178			sbdaddr = btodb(LFS_LABELPAD);
179	} else {
180		/* Read the first superblock */
181		get(fd, dbtob(sbdaddr), &(lfs_sb1.lfs_dlfs), sizeof(struct dlfs));
182		daddr_shift = lfs_sb1.lfs_bshift - lfs_sb1.lfs_fsbtodb;
183		lfs_master = &lfs_sb1;
184	}
185
186	(void)printf("Master Superblock at 0x%x:\n", sbdaddr);
187	dump_super(lfs_master);
188
189	dump_ifile(fd, lfs_master, do_ientries, idaddr);
190
191	if (seglist != NULL)
192		for (; seglist != NULL; seglist = seglist->next) {
193			seg_addr = lfs_master->lfs_sboffs[0] + seglist->num *
194			    (lfs_master->lfs_ssize << lfs_master->lfs_fsbtodb);
195			dump_segment(fd,
196			    seglist->num, seg_addr, lfs_master, do_allsb);
197		}
198	else
199		for (segnum = 0, seg_addr = lfs_master->lfs_sboffs[0];
200		    segnum < lfs_master->lfs_nseg; segnum++, seg_addr +=
201		    lfs_master->lfs_ssize << lfs_master->lfs_fsbtodb)
202			dump_segment(fd,
203			    segnum, seg_addr, lfs_master, do_allsb);
204
205	(void)close(fd);
206	exit(0);
207}
208
209/*
210 * We are reading all the blocks of an inode and dumping out the ifile table.
211 * This code could be tighter, but this is a first pass at getting the stuff
212 * printed out rather than making this code incredibly efficient.
213 */
214static void
215dump_ifile(fd, lfsp, do_ientries, addr)
216	int fd;
217	struct lfs *lfsp;
218	int do_ientries;
219	daddr_t addr;
220{
221	IFILE *ipage;
222	struct dinode *dip, *dpage;
223	daddr_t *addrp, *dindir, *iaddrp, *indir;
224	int block_limit, i, inum, j, nblocks, psize;
225
226	psize = lfsp->lfs_bsize;
227	if (!addr)
228		addr = lfsp->lfs_idaddr;
229
230	if (!(dpage = malloc(psize)))
231		err(1, "malloc");
232	get(fd, addr << daddr_shift, dpage, psize);
233
234	for (dip = dpage + INOPB(lfsp) - 1; dip >= dpage; --dip)
235		if (dip->di_inumber == LFS_IFILE_INUM)
236			break;
237
238	if (dip < dpage)
239		errx(1, "unable to locate ifile inode at disk address 0x%x",
240		     addr);
241
242	(void)printf("\nIFILE inode\n");
243	dump_dinode(dip);
244
245	(void)printf("\nIFILE contents\n");
246	nblocks = dip->di_size >> lfsp->lfs_bshift;
247	block_limit = MIN(nblocks, NDADDR);
248
249	/* Get the direct block */
250	if ((ipage = malloc(psize)) == NULL)
251		err(1, "malloc");
252	for (inum = 0, addrp = dip->di_db, i = 0; i < block_limit;
253	    i++, addrp++) {
254		get(fd, *addrp << daddr_shift, ipage, psize);
255		if (i < lfsp->lfs_cleansz) {
256			dump_cleaner_info(lfsp, ipage);
257			print_suheader;
258			continue;
259		}
260
261		if (i < (lfsp->lfs_segtabsz + lfsp->lfs_cleansz)) {
262			inum = dump_ipage_segusage(lfsp, inum, ipage,
263			    lfsp->lfs_sepb);
264			if (!inum) {
265				if(!do_ientries)
266					goto e0;
267				else
268					print_iheader;
269			}
270		} else
271			inum = dump_ipage_ifile(inum, ipage, lfsp->lfs_ifpb);
272
273	}
274
275	if (nblocks <= NDADDR)
276		goto e0;
277
278	/* Dump out blocks off of single indirect block */
279	if (!(indir = malloc(psize)))
280		err(1, "malloc");
281	get(fd, dip->di_ib[0] << daddr_shift, indir, psize);
282	block_limit = MIN(i + lfsp->lfs_nindir, nblocks);
283	for (addrp = indir; i < block_limit; i++, addrp++) {
284		if (*addrp == LFS_UNUSED_DADDR)
285			break;
286		get(fd, *addrp << daddr_shift,ipage, psize);
287		if (i < lfsp->lfs_cleansz) {
288			dump_cleaner_info(lfsp, ipage);
289			continue;
290		} else
291			i -= lfsp->lfs_cleansz;
292
293		if (i < lfsp->lfs_segtabsz) {
294			inum = dump_ipage_segusage(lfsp, inum, ipage,
295			    lfsp->lfs_sepb);
296			if (!inum) {
297				if(!do_ientries)
298					goto e1;
299				else
300					print_iheader;
301			}
302		} else
303			inum = dump_ipage_ifile(inum, ipage, lfsp->lfs_ifpb);
304	}
305
306	if (nblocks <= lfsp->lfs_nindir * lfsp->lfs_ifpb)
307		goto e1;
308
309	/* Get the double indirect block */
310	if (!(dindir = malloc(psize)))
311		err(1, "malloc");
312	get(fd, dip->di_ib[1] << daddr_shift, dindir, psize);
313	for (iaddrp = dindir, j = 0; j < lfsp->lfs_nindir; j++, iaddrp++) {
314		if (*iaddrp == LFS_UNUSED_DADDR)
315			break;
316		get(fd, *iaddrp << daddr_shift, indir, psize);
317		block_limit = MIN(i + lfsp->lfs_nindir, nblocks);
318		for (addrp = indir; i < block_limit; i++, addrp++) {
319			if (*addrp == LFS_UNUSED_DADDR)
320				break;
321			get(fd, *addrp << daddr_shift, ipage, psize);
322			if (i < lfsp->lfs_cleansz) {
323				dump_cleaner_info(lfsp, ipage);
324				continue;
325			} else
326				i -= lfsp->lfs_cleansz;
327
328			if (i < lfsp->lfs_segtabsz) {
329				inum = dump_ipage_segusage(lfsp,
330				    inum, ipage, lfsp->lfs_sepb);
331				if (!inum) {
332					if(!do_ientries)
333						goto e2;
334					else
335						print_iheader;
336				}
337			} else
338				inum = dump_ipage_ifile(inum,
339				    ipage, lfsp->lfs_ifpb);
340		}
341	}
342e2:	free(dindir);
343e1:	free(indir);
344e0:	free(dpage);
345	free(ipage);
346}
347
348static int
349dump_ipage_ifile(i, pp, tot)
350	int i;
351	IFILE *pp;
352	int tot;
353{
354	IFILE *ip;
355	int cnt, max;
356
357	max = i + tot;
358
359	for (ip = pp, cnt = i; cnt < max; cnt++, ip++)
360		print_ientry(cnt, ip);
361	return (max);
362}
363
364static int
365dump_ipage_segusage(lfsp, i, pp, tot)
366	struct lfs *lfsp;
367	int i;
368	IFILE *pp;
369	int tot;
370{
371	SEGUSE *sp;
372	int cnt, max;
373	struct seglist *slp;
374
375	max = i + tot;
376	for (sp = (SEGUSE *)pp, cnt = i;
377	     cnt < lfsp->lfs_nseg && cnt < max; cnt++, sp++) {
378		if (seglist == NULL)
379			print_suentry(cnt, sp);
380		else {
381			for (slp = seglist; slp != NULL; slp = slp->next)
382				if (cnt == slp->num) {
383					print_suentry(cnt, sp);
384					break;
385				}
386		}
387	}
388	if (max >= lfsp->lfs_nseg)
389		return (0);
390	else
391		return (max);
392}
393
394static void
395dump_dinode(dip)
396	struct dinode *dip;
397{
398	int i;
399	time_t at, mt, ct;
400
401	at = dip->di_atime;
402	mt = dip->di_mtime;
403	ct = dip->di_ctime;
404
405	(void)printf("%s%d\t%s%d\t%s%d\t%s%d\t%s%qu\n",
406		"mode  ", dip->di_mode,
407		"nlink ", dip->di_nlink,
408		"uid   ", dip->di_uid,
409		"gid   ", dip->di_gid,
410		"size  ", (long long)dip->di_size);
411	(void)printf("%s%s%s%s%s%s",
412		"atime ", ctime(&at),
413		"mtime ", ctime(&mt),
414		"ctime ", ctime(&ct));
415	(void)printf("inum  %d\n", dip->di_inumber);
416	(void)printf("Direct Addresses\n");
417	for (i = 0; i < NDADDR; i++) {
418		(void)printf("\t0x%x", dip->di_db[i]);
419		if ((i % 6) == 5)
420			(void)printf("\n");
421	}
422	for (i = 0; i < NIADDR; i++)
423		(void)printf("\t0x%x", dip->di_ib[i]);
424	(void)printf("\n");
425}
426
427static int
428dump_sum(fd, lfsp, sp, segnum, addr)
429	struct lfs *lfsp;
430	SEGSUM *sp;
431	int fd, segnum;
432	daddr_t addr;
433{
434	FINFO *fp;
435	daddr_t *dp;
436	int i, j;
437	int ck;
438	int numbytes;
439	struct dinode *inop;
440
441	if (sp->ss_magic != SS_MAGIC ||
442	    sp->ss_sumsum != (ck = cksum(&sp->ss_datasum,
443	    LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum)))) {
444		/* Don't print "corrupt" if we're just too close to the edge */
445		if (datosn(lfsp, addr + fsbtodb(lfsp, lfsp->lfs_bsize)) ==
446		    datosn(lfsp, addr))
447			(void)printf("dumplfs: %s %d address 0x%x\n",
448		                     "corrupt summary block; segment", segnum,
449				     addr);
450		return(0);
451	}
452
453	(void)printf("Segment Summary Info at 0x%x\n", addr);
454	(void)printf("    %s0x%x\t%s%d\t%s%d\t%s%c%c\n    %s0x%x\t%s0x%x",
455		"next     ", sp->ss_next,
456		"nfinfo   ", sp->ss_nfinfo,
457		"ninos    ", sp->ss_ninos,
458		"flags    ", (sp->ss_flags & SS_DIROP) ? 'D' : '-',
459			     (sp->ss_flags & SS_CONT)  ? 'C' : '-',
460		"sumsum   ", sp->ss_sumsum,
461		"datasum  ", sp->ss_datasum );
462	(void)printf("\tcreate   %s", ctime((time_t *)&sp->ss_create));
463
464	/* Dump out inode disk addresses */
465	dp = (daddr_t *)sp;
466	dp += LFS_SUMMARY_SIZE / sizeof(daddr_t);
467	inop = malloc(1 << lfsp->lfs_bshift);
468	printf("    Inode addresses:");
469	numbytes = 0;
470	for (dp--, i = 0; i < sp->ss_ninos; dp--) {
471		numbytes += lfsp->lfs_bsize;	/* add bytes for inode block */
472		printf("\t0x%x {", *dp);
473		get(fd, *dp << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb), inop,
474		    (1 << lfsp->lfs_bshift));
475		for (j = 0; i < sp->ss_ninos && j < INOPB(lfsp); j++, i++) {
476			if (j > 0)
477				(void)printf(", ");
478			(void)printf("%d", inop[j].di_inumber);
479		}
480		(void)printf("}");
481		if (((i/INOPB(lfsp)) % 4) == 3)
482			(void)printf("\n");
483	}
484	free(inop);
485
486	printf("\n");
487	for (fp = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo; i++) {
488		(void)printf("    FINFO for inode: %d version %d nblocks %d lastlength %d\n",
489		    fp->fi_ino, fp->fi_version, fp->fi_nblocks,
490		    fp->fi_lastlength);
491		dp = &(fp->fi_blocks[0]);
492		for (j = 0; j < fp->fi_nblocks; j++, dp++) {
493			(void)printf("\t%d", *dp);
494			if ((j % 8) == 7)
495				(void)printf("\n");
496			if (j == fp->fi_nblocks - 1)
497				numbytes += fp->fi_lastlength;
498			else
499				numbytes += lfsp->lfs_bsize;
500		}
501		if ((j % 8) != 0)
502			(void)printf("\n");
503		fp = (FINFO *)dp;
504	}
505	return (numbytes);
506}
507
508static void
509dump_segment(fd, segnum, addr, lfsp, dump_sb)
510	int fd, segnum;
511	daddr_t addr;
512	struct lfs *lfsp;
513	int dump_sb;
514{
515	struct lfs lfs_sb, *sbp;
516	SEGSUM *sump;
517	char sumblock[LFS_SUMMARY_SIZE];
518	int did_one, nbytes, sb;
519	off_t sum_offset;
520	daddr_t new_addr;
521
522	(void)printf("\nSEGMENT %d (Disk Address 0x%x)\n",
523	    /* addr >> (lfsp->lfs_segshift - daddr_shift), */
524		datosn(lfsp, addr),
525		addr);
526	sum_offset = (addr << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb));
527
528	sb = 0;
529	did_one = 0;
530	do {
531		get(fd, sum_offset, sumblock, LFS_SUMMARY_SIZE);
532		sump = (SEGSUM *)sumblock;
533		if (sump->ss_sumsum != cksum (&sump->ss_datasum,
534			LFS_SUMMARY_SIZE - sizeof(sump->ss_sumsum))) {
535			sbp = (struct lfs *)sump;
536			if ((sb = (sbp->lfs_magic == LFS_MAGIC))) {
537				if (dump_sb)  {
538					get(fd, sum_offset, &(lfs_sb.lfs_dlfs),
539					    sizeof(struct dlfs));
540					(void)printf("\nSuperblock at 0x%x:\n",
541						   (unsigned)btodb(sum_offset));
542					dump_super(&lfs_sb);
543					(void)printf("%s","\n");
544				}
545				sum_offset += LFS_SBPAD;
546			} else if (did_one)
547				break;
548			else {
549				printf("Segment at 0x%x corrupt\n", addr);
550				break;
551			}
552		} else {
553			nbytes = dump_sum(fd, lfsp, sump, segnum, sum_offset >>
554			     (lfsp->lfs_bshift - lfsp->lfs_fsbtodb));
555			if (nbytes)
556				sum_offset += LFS_SUMMARY_SIZE + nbytes;
557			else
558				sum_offset = 0;
559			did_one = 1;
560		}
561		/* If the segment ends right on a boundary, it still ends */
562		new_addr = sum_offset >> (lfsp->lfs_bshift - lfsp->lfs_fsbtodb);
563		if (datosn(lfsp, new_addr) != datosn(lfsp, addr))
564			break;
565	} while (sum_offset);
566
567	return;
568}
569
570static void
571dump_super(lfsp)
572	struct lfs *lfsp;
573{
574	int i;
575
576	(void)printf("%s0x%x\t%s0x%x\t%s%d\t%s%d\n",
577		"magic    ", lfsp->lfs_magic,
578		"version  ", lfsp->lfs_version,
579		"size     ", lfsp->lfs_size,
580		"ssize    ", lfsp->lfs_ssize);
581	(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
582		"dsize    ", lfsp->lfs_dsize,
583		"bsize    ", lfsp->lfs_bsize,
584		"fsize    ", lfsp->lfs_fsize,
585		"frag     ", lfsp->lfs_frag);
586
587	(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
588		"minfree  ", lfsp->lfs_minfree,
589		"inopb    ", lfsp->lfs_inopb,
590		"ifpb     ", lfsp->lfs_ifpb,
591		"nindir   ", lfsp->lfs_nindir);
592
593	(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
594		"nseg     ", lfsp->lfs_nseg,
595		"nspf     ", lfsp->lfs_nspf,
596		"cleansz  ", lfsp->lfs_cleansz,
597		"segtabsz ", lfsp->lfs_segtabsz);
598
599	(void)printf("%s0x%x\t%s%d\t%s0x%qX\t%s%d\n",
600		"segmask  ", lfsp->lfs_segmask,
601		"segshift ", lfsp->lfs_segshift,
602		"bmask    ", (long long)lfsp->lfs_bmask,
603		"bshift   ", lfsp->lfs_bshift);
604
605	(void)printf("%s0x%qX\t\t%s%d\t%s0x%qX\t%s%u\n",
606		"ffmask   ", (long long)lfsp->lfs_ffmask,
607		"ffshift  ", lfsp->lfs_ffshift,
608		"fbmask   ", (long long)lfsp->lfs_fbmask,
609		"fbshift  ", lfsp->lfs_fbshift);
610
611	(void)printf("%s%d\t%s%d\t%s0x%x\t%s0x%qx\n",
612		"sushift  ", lfsp->lfs_sushift,
613		"fsbtodb  ", lfsp->lfs_fsbtodb,
614		"cksum    ", lfsp->lfs_cksum,
615		"maxfilesize  ", (long long)lfsp->lfs_maxfilesize);
616
617	(void)printf("Superblock disk addresses:\t");
618	for (i = 0; i < LFS_MAXNUMSB; i++) {
619		(void)printf(" 0x%x", lfsp->lfs_sboffs[i]);
620		if ( i == (LFS_MAXNUMSB >> 1))
621			(void)printf("\n\t\t\t\t");
622	}
623	(void)printf("\n");
624
625	(void)printf("Checkpoint Info\n");
626	(void)printf("%s%d\t%s0x%x\t%s%d\n",
627		"free     ", lfsp->lfs_free,
628		"idaddr   ", lfsp->lfs_idaddr,
629		"ifile    ", lfsp->lfs_ifile);
630	(void)printf("%s%d\t%s%d\t%s%d\n",
631		"bfree    ", lfsp->lfs_bfree,
632		"avail    ", lfsp->lfs_avail,
633		"uinodes  ", lfsp->lfs_uinodes);
634	(void)printf("%s%d\t%s0x%x\t%s0x%x\n%s0x%x\t%s0x%x\t",
635		"nfiles   ", lfsp->lfs_nfiles,
636		"lastseg  ", lfsp->lfs_lastseg,
637		"nextseg  ", lfsp->lfs_nextseg,
638		"curseg   ", lfsp->lfs_curseg,
639		"offset   ", lfsp->lfs_offset);
640	(void)printf("tstamp   %s", ctime((time_t *)&lfsp->lfs_tstamp));
641#if 0  /* This is no longer stored on disk! --ks */
642	(void)printf("\nIn-Memory Information\n");
643	(void)printf("%s%d\t%s0x%x\t%s%d%s%d\t%s%d\n",
644		"seglock  ", lfsp->lfs_seglock,
645		"iocount  ", lfsp->lfs_iocount,
646		"writer   ", lfsp->lfs_writer,
647		"dirops   ", lfsp->lfs_dirops,
648		"doifile  ", lfsp->lfs_doifile);
649	(void)printf("%s%d\t%s%d\t%s0x%x\t%s%d\n",
650		"nactive  ", lfsp->lfs_nactive,
651		"fmod     ", lfsp->lfs_fmod,
652		"clean    ", lfsp->lfs_clean,
653		"ronly    ", lfsp->lfs_ronly);
654#endif
655}
656
657static void
658addseg(arg)
659	char *arg;
660{
661	SEGLIST *p;
662
663	if ((p = malloc(sizeof(SEGLIST))) == NULL)
664		err(1, "malloc");
665	p->next = seglist;
666	p->num = atoi(arg);
667	seglist = p;
668}
669
670static void
671dump_cleaner_info(lfsp, ipage)
672	struct lfs *lfsp;
673	void *ipage;
674{
675	CLEANERINFO *cip;
676
677	cip = (CLEANERINFO *)ipage;
678	(void)printf("segments clean\t%d\tsegments dirty\t%d\n\n",
679	    cip->clean, cip->dirty);
680}
681
682static void
683usage()
684{
685	(void)fprintf(stderr, "usage: dumplfs [-ai] [-s segnum] file\n");
686	exit(1);
687}
688