xref: /original-bsd/sbin/dumplfs/dumplfs.c (revision f89407e4)
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.10 (Berkeley) 07/19/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 e1;
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("\t%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("\t%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 %lx\n",
364 		    "corrupt summary block; segment", segnum, addr);
365 
366 	(void)printf("Segment Summary Info\n");
367 	(void)printf("\t%s%X\t%s%d\t%s%d\t%s%X\t%s%X\n",
368 		"next     ", sp->ss_next,
369 		"nfinfo   ", sp->ss_nfinfo,
370 		"ninos    ", sp->ss_ninos,
371 		"sumsum   ", sp->ss_sumsum,
372 		"datasum  ", sp->ss_datasum );
373 	(void)printf("\tcreate   %s", ctime((time_t *)&sp->ss_create));
374 
375 	numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
376 
377 	/* Dump out inode disk addresses */
378 	dp = (daddr_t *)sp;
379 	dp += LFS_SUMMARY_SIZE / sizeof(daddr_t);
380 	inop = malloc(1 << lfsp->lfs_bshift);
381 	printf("\tInode addresses:");
382 	for (dp--, i = 0; i < sp->ss_ninos; dp--) {
383 		printf("\t%X {", *dp);
384 		get(fd, *dp << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb), inop,
385 		    (1 << lfsp->lfs_bshift));
386 		for (j = 0; i < sp->ss_ninos && j < INOPB(lfsp); j++, i++) {
387 			if (j > 0)
388 				(void)printf(", ");
389 			(void)printf("%d", inop[j].di_inum);
390 		}
391 		(void)printf("}");
392 		if (((i/INOPB(lfsp)) % 4) == 3)
393 			(void)printf("\n");
394 	}
395 	free(inop);
396 
397 	printf("\n");
398 	for (fp = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo; i++) {
399 		numblocks += fp->fi_nblocks;
400 		(void)printf("File Info for file: %d version %d nblocks %d\n",
401 		    fp->fi_ino, fp->fi_version, fp->fi_nblocks);
402 		dp = &(fp->fi_blocks[0]);
403 		for (j = 0; j < fp->fi_nblocks; j++, dp++) {
404 			(void)printf("\t%d", *dp);
405 			if ((j % 8) == 7)
406 				(void)printf("\n");
407 		}
408 		if ((j % 8) != 0)
409 			(void)printf("\n");
410 		fp = (FINFO *)dp;
411 	}
412 	return (numblocks);
413 }
414 
415 static void
416 dump_segment(fd, segnum, addr, lfsp, dump_sb)
417 	int fd, segnum;
418 	daddr_t addr;
419 	struct lfs *lfsp;
420 	int dump_sb;
421 {
422 	struct lfs lfs_sb, *sbp;
423 	SEGSUM *sump;
424 	char sumblock[LFS_SUMMARY_SIZE];
425 	int did_one, nblocks, sb;
426 	off_t sum_offset, super_off;
427 
428 	(void)printf("\nSegment Number %d (Disk Address %X)\n",
429 	    addr >> (lfsp->lfs_segshift - daddr_shift), addr);
430 	sum_offset = (addr << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb));
431 
432 	sb = 0;
433 	did_one = 0;
434 	do {
435 		get(fd, sum_offset, sumblock, LFS_SUMMARY_SIZE);
436 		sump = (SEGSUM *)sumblock;
437 		if (sump->ss_sumsum != cksum (&sump->ss_datasum,
438 			LFS_SUMMARY_SIZE - sizeof(sump->ss_sumsum))) {
439 			sbp = (struct lfs *)sump;
440 			if (sb = (sbp->lfs_magic == LFS_MAGIC)) {
441 				super_off = sum_offset;
442 				sum_offset += LFS_SBPAD;
443 			} else if (did_one)
444 				break;
445 			else {
446 				printf("Segment at %X corrupt\n", addr);
447 				break;
448 			}
449 		} else {
450 			nblocks = dump_sum(fd, lfsp, sump, segnum, addr);
451 			if (nblocks)
452 				sum_offset += LFS_SUMMARY_SIZE +
453 					(nblocks << lfsp->lfs_bshift);
454 			else
455 				sum_offset = 0;
456 			did_one = 1;
457 		}
458 	} while (sum_offset);
459 
460 	if (dump_sb && sb)  {
461 		get(fd, super_off, &lfs_sb, sizeof(struct lfs));
462 		dump_super(&lfs_sb);
463 	}
464 	return;
465 }
466 
467 static void
468 dump_super(lfsp)
469 	struct lfs *lfsp;
470 {
471 	int i;
472 
473 	(void)printf("%s%X\t%s%X\t%s%d\t%s%d\n",
474 		"magic    ", lfsp->lfs_magic,
475 		"version  ", lfsp->lfs_version,
476 		"size     ", lfsp->lfs_size,
477 		"ssize    ", lfsp->lfs_ssize);
478 	(void)printf("%s%d\t%s%d\t%s%d\t%s%d\n",
479 		"dsize    ", lfsp->lfs_dsize,
480 		"bsize    ", lfsp->lfs_bsize,
481 		"fsize    ", lfsp->lfs_fsize,
482 		"frag     ", lfsp->lfs_frag);
483 
484 	(void)printf("%s%d\t%s%d\t%s%d\t%s%d\n",
485 		"minfree  ", lfsp->lfs_minfree,
486 		"inopb    ", lfsp->lfs_inopb,
487 		"ifpb     ", lfsp->lfs_ifpb,
488 		"nindir   ", lfsp->lfs_nindir);
489 
490 	(void)printf("%s%d\t%s%d\t%s%d\t%s%d\n",
491 		"nseg     ", lfsp->lfs_nseg,
492 		"nspf     ", lfsp->lfs_nspf,
493 		"cleansz  ", lfsp->lfs_cleansz,
494 		"segtabsz ", lfsp->lfs_segtabsz);
495 
496 	(void)printf("%s%X\t%s%d\t%s%X\t%s%d\n",
497 		"segmask  ", lfsp->lfs_segmask,
498 		"segshift ", lfsp->lfs_segshift,
499 		"bmask    ", lfsp->lfs_bmask,
500 		"bshift   ", lfsp->lfs_bshift);
501 
502 	(void)printf("%s%X\t%s%d\t%s%X\t%s%d\n",
503 		"ffmask   ", lfsp->lfs_ffmask,
504 		"ffshift  ", lfsp->lfs_ffshift,
505 		"fbmask   ", lfsp->lfs_fbmask,
506 		"fbshift  ", lfsp->lfs_fbshift);
507 
508 	(void)printf("%s%d\t%s%X\t%qd\n",
509 		"fsbtodb  ", lfsp->lfs_fsbtodb,
510 		"cksum    ", lfsp->lfs_cksum,
511 		"maxfilesize  ", lfsp->lfs_maxfilesize);
512 
513 	(void)printf("Superblock disk addresses:");
514 	for (i = 0; i < LFS_MAXNUMSB; i++)
515 		(void)printf(" %X", lfsp->lfs_sboffs[i]);
516 	(void)printf("\n");
517 
518 	(void)printf("Checkpoint Info\n");
519 	(void)printf("%s%d\t%s%X\t%s%d\n",
520 		"free     ", lfsp->lfs_free,
521 		"idaddr   ", lfsp->lfs_idaddr,
522 		"ifile    ", lfsp->lfs_ifile);
523 	(void)printf("%s%X\t%s%d\t%s%X\t%s%X\t%s%X\t%s%X\n",
524 		"bfree    ", lfsp->lfs_bfree,
525 		"nfiles   ", lfsp->lfs_nfiles,
526 		"lastseg  ", lfsp->lfs_lastseg,
527 		"nextseg  ", lfsp->lfs_nextseg,
528 		"curseg   ", lfsp->lfs_curseg,
529 		"offset   ", lfsp->lfs_offset);
530 	(void)printf("tstamp   %s", ctime((time_t *)&lfsp->lfs_tstamp));
531 	(void)printf("In-Memory Information\n");
532 	(void)printf("%s%d\t%s%X\t%s%d\t%s%d\t%s%d\n",
533 		"seglock  ", lfsp->lfs_seglock,
534 		"iocount  ", lfsp->lfs_iocount,
535 		"writer   ", lfsp->lfs_writer,
536 		"dirops   ", lfsp->lfs_dirops,
537 		"doifile  ", lfsp->lfs_doifile );
538 	(void)printf("%s%d\t%s%X\t%s%d\n",
539 		"fmod     ", lfsp->lfs_fmod,
540 		"clean    ", lfsp->lfs_clean,
541 		"ronly    ", lfsp->lfs_ronly);
542 }
543 
544 static void
545 addseg(arg)
546 	char *arg;
547 {
548 	SEGLIST *p;
549 
550 	if ((p = malloc(sizeof(SEGLIST))) == NULL)
551 		err("%s", strerror(errno));
552 	p->next = seglist;
553 	p->num = atoi(arg);
554 	seglist = p;
555 }
556 
557 static void
558 dump_cleaner_info(lfsp, ipage)
559 	struct lfs *lfsp;
560 	void *ipage;
561 {
562 	CLEANERINFO *cip;
563 
564 	cip = (CLEANERINFO *)ipage;
565 	(void)printf("Cleaner Info\nclean\t%d\tdirty\t%d\n",
566 	    cip->clean, cip->dirty);
567 }
568 
569 static void
570 usage()
571 {
572 	(void)fprintf(stderr, "usage: dumplfs [-ai] [-s segnum] file\n");
573 	exit(1);
574 }
575