xref: /original-bsd/sbin/dumplfs/dumplfs.c (revision b31c5a61)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)dumplfs.c	5.11 (Berkeley) 07/21/92";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/ucred.h>
20 #include <sys/mount.h>
21 #include <sys/time.h>
22 
23 #include <ufs/ufs/dinode.h>
24 #include <ufs/lfs/lfs.h>
25 
26 #include <fcntl.h>
27 #include <fstab.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include "extern.h"
34 
35 static void	addseg __P((char *));
36 static void	dump_cleaner_info __P((struct lfs *, void *));
37 static void	dump_dinode __P((struct dinode *));
38 static void	dump_ifile __P((int, struct lfs *, int));
39 static int	dump_ipage_ifile __P((int, IFILE *, int));
40 static int	dump_ipage_segusage __P((struct lfs *, int, IFILE *, int));
41 static void	dump_segment __P((int, int, daddr_t, struct lfs *, int));
42 static int	dump_sum __P((int, struct lfs *, SEGSUM *, int, daddr_t));
43 static void	dump_super __P((struct lfs *));
44 static void	usage __P((void));
45 
46 typedef struct seglist SEGLIST;
47 struct seglist {
48         SEGLIST *next;
49 	int num;
50 };
51 SEGLIST	*seglist;
52 
53 int daddr_shift;
54 char *special;
55 
56 /* Segment Usage formats */
57 #define print_suheader \
58 	(void)printf("segnum\tstatus\tnbytes\t\tlastmod\n")
59 
60 #define print_suentry(i, sp) \
61 	(void)printf("%d\t%c%c%c\t%d\t%s", i, \
62 	    (((sp)->su_flags & SEGUSE_ACTIVE) ? 'A' : ' '), \
63 	    (((sp)->su_flags & SEGUSE_DIRTY) ? 'D' : 'C'), \
64 	    (((sp)->su_flags & SEGUSE_SUPERBLOCK) ? 'S' : ' '), \
65 	    (sp)->su_nbytes, ctime((time_t *)&(sp)->su_lastmod))
66 
67 /* Ifile formats */
68 #define print_iheader \
69 	(void)printf("inum\tstatus\tversion\tdaddr\t\tfreeptr\n")
70 #define print_ientry(i, ip) \
71 	if (ip->if_daddr == LFS_UNUSED_DADDR) \
72 		(void)printf("%d\tFREE\t%d\t \t\t%d\n", \
73 		    i, ip->if_version, ip->if_nextfree); \
74 	else \
75 		(void)printf("%d\tINUSE\t%d\t%8X    \n", \
76 		    i, ip->if_version, ip->if_daddr)
77 int
78 main(argc, argv)
79 	int argc;
80 	char *argv[];
81 {
82 	struct lfs lfs_sb1, lfs_sb2, *lfs_master;
83 	daddr_t seg_addr;
84 	int ch, do_allsb, do_ientries, fd, segnum;
85 
86 	do_allsb = 0;
87 	do_ientries = 0;
88 	while ((ch = getopt(argc, argv, "ais:")) != EOF)
89 		switch(ch) {
90 		case 'a':		/* Dump all superblocks */
91 			do_allsb = 1;
92 			break;
93 		case 'i':		/* Dump ifile entries */
94 			do_ientries = 1;
95 			break;
96 		case 's':		/* Dump out these segments */
97 			addseg(optarg);
98 			break;
99 		default:
100 			usage();
101 		}
102 	argc -= optind;
103 	argv += optind;
104 
105 	if (argc != 1)
106 		usage();
107 
108 	special = argv[0];
109 	if ((fd = open(special, O_RDONLY, 0)) < 0)
110 		err("%s: %s", special, strerror(errno));
111 
112 	/* Read the first superblock */
113 	get(fd, LFS_LABELPAD, &lfs_sb1, sizeof(struct lfs));
114 	daddr_shift = lfs_sb1.lfs_bshift - lfs_sb1.lfs_fsbtodb;
115 
116 	/*
117 	 * Read the second superblock and figure out which check point is
118 	 * most up to date.
119 	 */
120 	get(fd,
121 	    lfs_sb1.lfs_sboffs[1] << daddr_shift, &lfs_sb2, sizeof(struct lfs));
122 
123 	lfs_master = &lfs_sb1;
124 	if (lfs_sb1.lfs_tstamp < lfs_sb2.lfs_tstamp)
125 		lfs_master = &lfs_sb2;
126 
127 	(void)printf("Master Superblock:\n");
128 	dump_super(lfs_master);
129 
130 	dump_ifile(fd, lfs_master, do_ientries);
131 
132 	if (seglist != NULL)
133 		for (; seglist != NULL; seglist = seglist->next) {
134 			seg_addr = lfs_master->lfs_sboffs[0] + seglist->num *
135 			    (lfs_master->lfs_ssize << lfs_master->lfs_fsbtodb);
136 			dump_segment(fd,
137 			    seglist->num, seg_addr, lfs_master, do_allsb);
138 		}
139 	else
140 		for (segnum = 0, seg_addr = lfs_master->lfs_sboffs[0];
141 		    segnum < lfs_master->lfs_nseg; segnum++, seg_addr +=
142 		    lfs_master->lfs_ssize << lfs_master->lfs_fsbtodb)
143 			dump_segment(fd,
144 			    segnum, seg_addr, lfs_master, do_allsb);
145 
146 	(void)close(fd);
147 	exit(0);
148 }
149 
150 /*
151  * We are reading all the blocks of an inode and dumping out the ifile table.
152  * This code could be tighter, but this is a first pass at getting the stuff
153  * printed out rather than making this code incredibly efficient.
154  */
155 static void
156 dump_ifile(fd, lfsp, do_ientries)
157 	int fd;
158 	struct lfs *lfsp;
159 	int do_ientries;
160 {
161 	IFILE *ipage;
162 	struct dinode *dip, *dpage;
163 	daddr_t addr, *addrp, *dindir, *iaddrp, *indir;
164 	int block_limit, i, inum, j, nblocks, nsupb, psize;
165 
166 	psize = lfsp->lfs_bsize;
167 	addr = lfsp->lfs_idaddr;
168 
169 	if (!(dip = dpage = malloc(psize)))
170 		err("%s", strerror(errno));
171 	get(fd, addr << daddr_shift, dip, psize);
172 
173 	for (i = 0; i < lfsp->lfs_inopb; i++, dip++)
174 		if (dip->di_inum == LFS_IFILE_INUM)
175 			break;
176 
177 	if (i >= lfsp->lfs_inopb)
178 		err("unable to locate ifile inode");
179 
180 	(void)printf("\nIFILE inode\n");
181 	dump_dinode(dip);
182 
183 	(void)printf("\nIFILE contents\n");
184 	nblocks = dip->di_size >> lfsp->lfs_bshift;
185 	block_limit = MIN(nblocks, NDADDR);
186 
187 	/* Get the direct block */
188 	if ((ipage = malloc(psize)) == NULL)
189 		err("%s", strerror(errno));
190 	for (inum = 0, addrp = dip->di_db, i = 0; i < block_limit;
191 	    i++, addrp++) {
192 		get(fd, *addrp << daddr_shift, ipage, psize);
193 		if (i < lfsp->lfs_cleansz) {
194 			dump_cleaner_info(lfsp, ipage);
195 			print_suheader;
196 			continue;
197 		}
198 
199 		if (i < (lfsp->lfs_segtabsz + lfsp->lfs_cleansz)) {
200 			inum = dump_ipage_segusage(lfsp, inum, ipage,
201 			    lfsp->lfs_sepb);
202 			if (!inum)
203 				if(!do_ientries)
204 					goto e0;
205 				else
206 					print_iheader;
207 		} else
208 			inum = dump_ipage_ifile(inum, ipage, lfsp->lfs_ifpb);
209 
210 	}
211 
212 	if (nblocks <= NDADDR)
213 		goto e0;
214 
215 	/* Dump out blocks off of single indirect block */
216 	if (!(indir = malloc(psize)))
217 		err("%s", strerror(errno));
218 	get(fd, dip->di_ib[0] << daddr_shift, indir, psize);
219 	block_limit = MIN(i + lfsp->lfs_nindir, nblocks);
220 	for (addrp = indir; i < block_limit; i++, addrp++) {
221 		if (*addrp == LFS_UNUSED_DADDR)
222 			break;
223 		get(fd, *addrp << daddr_shift,ipage, psize);
224 		if (i < lfsp->lfs_cleansz) {
225 			dump_cleaner_info(lfsp, ipage);
226 			continue;
227 		} else
228 			i -= lfsp->lfs_cleansz;
229 
230 		if (i < lfsp->lfs_segtabsz) {
231 			inum = dump_ipage_segusage(lfsp, inum, ipage,
232 			    lfsp->lfs_sepb);
233 			if (!inum)
234 				if(!do_ientries)
235 					goto e1;
236 				else
237 					print_iheader;
238 		} else
239 			inum = dump_ipage_ifile(inum, ipage, lfsp->lfs_ifpb);
240 	}
241 
242 	if (nblocks <= lfsp->lfs_nindir * lfsp->lfs_ifpb)
243 		goto e1;
244 
245 	/* Get the double indirect block */
246 	if (!(dindir = malloc(psize)))
247 		err("%s", strerror(errno));
248 	get(fd, dip->di_ib[1] << daddr_shift, dindir, psize);
249 	for (iaddrp = dindir, j = 0; j < lfsp->lfs_nindir; j++, iaddrp++) {
250 		if (*iaddrp == LFS_UNUSED_DADDR)
251 			break;
252 		get(fd, *iaddrp << daddr_shift, indir, psize);
253 		block_limit = MIN(i + lfsp->lfs_nindir, nblocks);
254 		for (addrp = indir; i < block_limit; i++, addrp++) {
255 			if (*addrp == LFS_UNUSED_DADDR)
256 				break;
257 			get(fd, *addrp << daddr_shift, ipage, psize);
258 			if (i < lfsp->lfs_cleansz) {
259 				dump_cleaner_info(lfsp, ipage);
260 				continue;
261 			} else
262 				i -= lfsp->lfs_cleansz;
263 
264 			if (i < lfsp->lfs_segtabsz) {
265 				inum = dump_ipage_segusage(lfsp,
266 				    inum, ipage, lfsp->lfs_sepb);
267 				if (!inum)
268 					if(!do_ientries)
269 						goto e2;
270 					else
271 						print_iheader;
272 			} else
273 				inum = dump_ipage_ifile(inum,
274 				    ipage, lfsp->lfs_ifpb);
275 		}
276 	}
277 e2:	free(dindir);
278 e1:	free(indir);
279 e0:	free(dpage);
280 	free(ipage);
281 }
282 
283 static int
284 dump_ipage_ifile(i, pp, tot)
285 	int i;
286 	IFILE *pp;
287 	int tot;
288 {
289 	IFILE *ip;
290 	int cnt, max;
291 
292 	max = i + tot;
293 
294 	for (ip = pp, cnt = i; cnt < max; cnt++, ip++)
295 		print_ientry(cnt, ip);
296 	return (max);
297 }
298 
299 static int
300 dump_ipage_segusage(lfsp, i, pp, tot)
301 	struct lfs *lfsp;
302 	int i;
303 	IFILE *pp;
304 	int tot;
305 {
306 	SEGUSE *sp;
307 	int cnt, max;
308 
309 	max = i + tot;
310 	for (sp = (SEGUSE *)pp, cnt = i;
311 	     cnt < lfsp->lfs_nseg && cnt < max; cnt++, sp++)
312 		print_suentry(cnt, sp);
313 	if (max >= lfsp->lfs_nseg)
314 		return (0);
315 	else
316 		return (max);
317 }
318 
319 static void
320 dump_dinode(dip)
321 	struct dinode *dip;
322 {
323 	int i;
324 
325 	(void)printf("%s%d\t%s%d\t%s%d\t%s%d\t%s%d\n",
326 		"mode  ", dip->di_mode,
327 		"nlink ", dip->di_nlink,
328 		"uid   ", dip->di_uid,
329 		"gid   ", dip->di_gid,
330 		"size  ", dip->di_size);
331 	(void)printf("%s%s%s%s%s%s",
332 		"atime ", ctime(&dip->di_atime.ts_sec),
333 		"mtime ", ctime(&dip->di_mtime.ts_sec),
334 		"ctime ", ctime(&dip->di_ctime.ts_sec));
335 	(void)printf("inum  %d\n", dip->di_inum);
336 	(void)printf("Direct Addresses\n");
337 	for (i = 0; i < NDADDR; i++) {
338 		(void)printf("\t0x%X", dip->di_db[i]);
339 		if ((i % 6) == 5)
340 			(void)printf("\n");
341 	}
342 	for (i = 0; i < NIADDR; i++)
343 		(void)printf("\t0x%X", dip->di_ib[i]);
344 	(void)printf("\n");
345 }
346 
347 static int
348 dump_sum(fd, lfsp, sp, segnum, addr)
349 	struct lfs *lfsp;
350 	SEGSUM *sp;
351 	int fd, segnum;
352 	daddr_t addr;
353 {
354 	FINFO *fp;
355 	long *dp;
356 	int i, j;
357 	int ck;
358 	int numblocks;
359 	struct dinode *inop;
360 
361 	if (sp->ss_sumsum != (ck = cksum(&sp->ss_datasum,
362 	    LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum)))) {
363 		(void)printf("dumplfs: %s %d address 0x%lx\n",
364 		    "corrupt summary block; segment", segnum, addr);
365 		return(0);
366 	}
367 
368 	(void)printf("Segment Summary Info at 0x%lx\n", addr);
369 	(void)printf("    %s0x%X\t%s%d\t%s%d\n    %s0x%X\t%s0x%X",
370 		"next     ", sp->ss_next,
371 		"nfinfo   ", sp->ss_nfinfo,
372 		"ninos    ", sp->ss_ninos,
373 		"sumsum   ", sp->ss_sumsum,
374 		"datasum  ", sp->ss_datasum );
375 	(void)printf("\tcreate   %s", ctime((time_t *)&sp->ss_create));
376 
377 	numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
378 
379 	/* Dump out inode disk addresses */
380 	dp = (daddr_t *)sp;
381 	dp += LFS_SUMMARY_SIZE / sizeof(daddr_t);
382 	inop = malloc(1 << lfsp->lfs_bshift);
383 	printf("    Inode addresses:");
384 	for (dp--, i = 0; i < sp->ss_ninos; dp--) {
385 		printf("\t0x%X {", *dp);
386 		get(fd, *dp << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb), inop,
387 		    (1 << lfsp->lfs_bshift));
388 		for (j = 0; i < sp->ss_ninos && j < INOPB(lfsp); j++, i++) {
389 			if (j > 0)
390 				(void)printf(", ");
391 			(void)printf("%d", inop[j].di_inum);
392 		}
393 		(void)printf("}");
394 		if (((i/INOPB(lfsp)) % 4) == 3)
395 			(void)printf("\n");
396 	}
397 	free(inop);
398 
399 	printf("\n");
400 	for (fp = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo; i++) {
401 		numblocks += fp->fi_nblocks;
402 		(void)printf("    FINFO for inode: %d version %d nblocks %d\n",
403 		    fp->fi_ino, fp->fi_version, fp->fi_nblocks);
404 		dp = &(fp->fi_blocks[0]);
405 		for (j = 0; j < fp->fi_nblocks; j++, dp++) {
406 			(void)printf("\t%d", *dp);
407 			if ((j % 8) == 7)
408 				(void)printf("\n");
409 		}
410 		if ((j % 8) != 0)
411 			(void)printf("\n");
412 		fp = (FINFO *)dp;
413 	}
414 	return (numblocks);
415 }
416 
417 static void
418 dump_segment(fd, segnum, addr, lfsp, dump_sb)
419 	int fd, segnum;
420 	daddr_t addr;
421 	struct lfs *lfsp;
422 	int dump_sb;
423 {
424 	struct lfs lfs_sb, *sbp;
425 	SEGSUM *sump;
426 	char sumblock[LFS_SUMMARY_SIZE];
427 	int did_one, nblocks, sb;
428 	off_t sum_offset, super_off;
429 
430 	(void)printf("\nSEGMENT %d (Disk Address 0x%X)\n",
431 	    addr >> (lfsp->lfs_segshift - daddr_shift), addr);
432 	sum_offset = (addr << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb));
433 
434 	sb = 0;
435 	did_one = 0;
436 	do {
437 		get(fd, sum_offset, sumblock, LFS_SUMMARY_SIZE);
438 		sump = (SEGSUM *)sumblock;
439 		if (sump->ss_sumsum != cksum (&sump->ss_datasum,
440 			LFS_SUMMARY_SIZE - sizeof(sump->ss_sumsum))) {
441 			sbp = (struct lfs *)sump;
442 			if (sb = (sbp->lfs_magic == LFS_MAGIC)) {
443 				super_off = sum_offset;
444 				sum_offset += LFS_SBPAD;
445 			} else if (did_one)
446 				break;
447 			else {
448 				printf("Segment at 0x%X corrupt\n", addr);
449 				break;
450 			}
451 		} else {
452 			nblocks = dump_sum(fd, lfsp, sump, segnum, sum_offset >>
453 			     (lfsp->lfs_bshift - lfsp->lfs_fsbtodb));
454 			if (nblocks)
455 				sum_offset += LFS_SUMMARY_SIZE +
456 					(nblocks << lfsp->lfs_bshift);
457 			else
458 				sum_offset = 0;
459 			did_one = 1;
460 		}
461 	} while (sum_offset);
462 
463 	if (dump_sb && sb)  {
464 		get(fd, super_off, &lfs_sb, sizeof(struct lfs));
465 		dump_super(&lfs_sb);
466 	}
467 	return;
468 }
469 
470 static void
471 dump_super(lfsp)
472 	struct lfs *lfsp;
473 {
474 	int i;
475 
476 	(void)printf("%s0x%X\t%s0x%X\t%s%d\t%s%d\n",
477 		"magic    ", lfsp->lfs_magic,
478 		"version  ", lfsp->lfs_version,
479 		"size     ", lfsp->lfs_size,
480 		"ssize    ", lfsp->lfs_ssize);
481 	(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
482 		"dsize    ", lfsp->lfs_dsize,
483 		"bsize    ", lfsp->lfs_bsize,
484 		"fsize    ", lfsp->lfs_fsize,
485 		"frag     ", lfsp->lfs_frag);
486 
487 	(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
488 		"minfree  ", lfsp->lfs_minfree,
489 		"inopb    ", lfsp->lfs_inopb,
490 		"ifpb     ", lfsp->lfs_ifpb,
491 		"nindir   ", lfsp->lfs_nindir);
492 
493 	(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
494 		"nseg     ", lfsp->lfs_nseg,
495 		"nspf     ", lfsp->lfs_nspf,
496 		"cleansz  ", lfsp->lfs_cleansz,
497 		"segtabsz ", lfsp->lfs_segtabsz);
498 
499 	(void)printf("%s0x%X\t%s%d\t%s0x%X\t%s%d\n",
500 		"segmask  ", lfsp->lfs_segmask,
501 		"segshift ", lfsp->lfs_segshift,
502 		"bmask    ", lfsp->lfs_bmask,
503 		"bshift   ", lfsp->lfs_bshift);
504 
505 	(void)printf("%s0x%X\t\t%s%d\t%s0x%X\t%s%d\n",
506 		"ffmask   ", lfsp->lfs_ffmask,
507 		"ffshift  ", lfsp->lfs_ffshift,
508 		"fbmask   ", lfsp->lfs_fbmask,
509 		"fbshift  ", lfsp->lfs_fbshift);
510 
511 	(void)printf("%s%d\t\t%s0x%X\t%s0x%qx\n",
512 		"fsbtodb  ", lfsp->lfs_fsbtodb,
513 		"cksum    ", lfsp->lfs_cksum,
514 		"maxfilesize  ", lfsp->lfs_maxfilesize);
515 
516 	(void)printf("Superblock disk addresses:\t");
517 	for (i = 0; i < LFS_MAXNUMSB; i++) {
518 		(void)printf(" 0x%X", lfsp->lfs_sboffs[i]);
519 		if ( i == (LFS_MAXNUMSB >> 1))
520 			(void)printf("\n\t\t\t\t");
521 	}
522 	(void)printf("\n");
523 
524 	(void)printf("Checkpoint Info\n");
525 	(void)printf("%s%d\t%s0x%X\t%s%d\n",
526 		"free     ", lfsp->lfs_free,
527 		"idaddr   ", lfsp->lfs_idaddr,
528 		"ifile    ", lfsp->lfs_ifile);
529 	(void)printf("%s0x%X\t%s%d\t%s0x%X\t%s0x%X\n%s0x%X\t%s0x%X\t",
530 		"bfree    ", lfsp->lfs_bfree,
531 		"nfiles   ", lfsp->lfs_nfiles,
532 		"lastseg  ", lfsp->lfs_lastseg,
533 		"nextseg  ", lfsp->lfs_nextseg,
534 		"curseg   ", lfsp->lfs_curseg,
535 		"offset   ", lfsp->lfs_offset);
536 	(void)printf("tstamp   %s", ctime((time_t *)&lfsp->lfs_tstamp));
537 	(void)printf("\nIn-Memory Information\n");
538 	(void)printf("%s%d\t%s0x%X\t%s%d\t%s%d\t%s%d\n",
539 		"seglock  ", lfsp->lfs_seglock,
540 		"iocount  ", lfsp->lfs_iocount,
541 		"writer   ", lfsp->lfs_writer,
542 		"dirops   ", lfsp->lfs_dirops,
543 		"doifile  ", lfsp->lfs_doifile );
544 	(void)printf("%s%d\t%s0x%X\t%s%d\n",
545 		"fmod     ", lfsp->lfs_fmod,
546 		"clean    ", lfsp->lfs_clean,
547 		"ronly    ", lfsp->lfs_ronly);
548 }
549 
550 static void
551 addseg(arg)
552 	char *arg;
553 {
554 	SEGLIST *p;
555 
556 	if ((p = malloc(sizeof(SEGLIST))) == NULL)
557 		err("%s", strerror(errno));
558 	p->next = seglist;
559 	p->num = atoi(arg);
560 	seglist = p;
561 }
562 
563 static void
564 dump_cleaner_info(lfsp, ipage)
565 	struct lfs *lfsp;
566 	void *ipage;
567 {
568 	CLEANERINFO *cip;
569 
570 	cip = (CLEANERINFO *)ipage;
571 	(void)printf("segments clean\t%d\tsegments dirty\t%d\n\n",
572 	    cip->clean, cip->dirty);
573 }
574 
575 static void
576 usage()
577 {
578 	(void)fprintf(stderr, "usage: dumplfs [-ai] [-s segnum] file\n");
579 	exit(1);
580 }
581