xref: /freebsd/tools/diag/prtblknos/prtblknos.c (revision 5b13fa79)
116c0c8eeSKirk McKusick /*
216c0c8eeSKirk McKusick  * Copyright (c) 1998, 2003, 2013, 2018 Marshall Kirk McKusick.
316c0c8eeSKirk McKusick  * All Rights Reserved.
416c0c8eeSKirk McKusick  *
516c0c8eeSKirk McKusick  * Redistribution and use in source and binary forms, with or without
616c0c8eeSKirk McKusick  * modification, are permitted provided that the following conditions
716c0c8eeSKirk McKusick  * are met:
816c0c8eeSKirk McKusick  * 1. Redistributions of source code must retain the above copyright
916c0c8eeSKirk McKusick  *    notice, this list of conditions and the following disclaimer.
1016c0c8eeSKirk McKusick  * 2. Redistributions in binary form must reproduce the above copyright
1116c0c8eeSKirk McKusick  *    notice, this list of conditions and the following disclaimer in the
1216c0c8eeSKirk McKusick  *    documentation and/or other materials provided with the distribution.
1316c0c8eeSKirk McKusick  *
1416c0c8eeSKirk McKusick  * THIS SOFTWARE IS PROVIDED BY MARSHALL KIRK MCKUSICK ``AS IS'' AND
1516c0c8eeSKirk McKusick  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1616c0c8eeSKirk McKusick  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1716c0c8eeSKirk McKusick  * ARE DISCLAIMED.  IN NO EVENT SHALL MARSHALL KIRK MCKUSICK BE LIABLE
1816c0c8eeSKirk McKusick  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1916c0c8eeSKirk McKusick  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2016c0c8eeSKirk McKusick  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2116c0c8eeSKirk McKusick  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2216c0c8eeSKirk McKusick  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2316c0c8eeSKirk McKusick  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2416c0c8eeSKirk McKusick  * SUCH DAMAGE.
2516c0c8eeSKirk McKusick  *
2616c0c8eeSKirk McKusick  * $FreeBSD$
2716c0c8eeSKirk McKusick  */
2816c0c8eeSKirk McKusick 
2916c0c8eeSKirk McKusick #include <sys/param.h>
3016c0c8eeSKirk McKusick #include <ufs/ffs/fs.h>
3116c0c8eeSKirk McKusick 
3216c0c8eeSKirk McKusick #include <err.h>
3316c0c8eeSKirk McKusick #include <stdio.h>
3468d7185bSKirk McKusick #include <string.h>
350e3f58b6SKirk McKusick #include <libufs.h>
3616c0c8eeSKirk McKusick 
3768d7185bSKirk McKusick #ifdef PRTBLKNOS
3816c0c8eeSKirk McKusick union dinode {
390e3f58b6SKirk McKusick 	struct ufs1_dinode dp1;
400e3f58b6SKirk McKusick 	struct ufs2_dinode dp2;
4116c0c8eeSKirk McKusick };
4268d7185bSKirk McKusick extern struct uufsd disk;
4368d7185bSKirk McKusick #else /* used by fsdb */
4468d7185bSKirk McKusick #include <fsck.h>
4568d7185bSKirk McKusick static struct bufarea *bp;
4668d7185bSKirk McKusick #endif
4716c0c8eeSKirk McKusick 
4868d7185bSKirk McKusick void prtblknos(struct fs *fs, union dinode *dp);
4916c0c8eeSKirk McKusick 
50d3009da8SKirk McKusick static const char *distance(struct fs *, ufs2_daddr_t, ufs2_daddr_t);
51d3009da8SKirk McKusick static void  printblk(struct fs *, ufs_lbn_t, ufs2_daddr_t, int, ufs_lbn_t);
5268d7185bSKirk McKusick static void  indirprt(struct fs *, int, ufs_lbn_t, ufs_lbn_t, ufs2_daddr_t,
53d3009da8SKirk McKusick 		ufs_lbn_t);
5416c0c8eeSKirk McKusick 
550e3f58b6SKirk McKusick void
5668d7185bSKirk McKusick prtblknos(fs, dp)
5768d7185bSKirk McKusick 	struct fs *fs;
580e3f58b6SKirk McKusick 	union dinode *dp;
5916c0c8eeSKirk McKusick {
60d3009da8SKirk McKusick 	int i, mode, frags;
61d3009da8SKirk McKusick 	ufs_lbn_t lbn, lastlbn, len, blksperindir;
6216c0c8eeSKirk McKusick 	ufs2_daddr_t blkno;
630e3f58b6SKirk McKusick 	off_t size;
6416c0c8eeSKirk McKusick 
6515e4030eSKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC) {
660e3f58b6SKirk McKusick 		size = dp->dp1.di_size;
6715e4030eSKirk McKusick 		mode = dp->dp1.di_mode;
6815e4030eSKirk McKusick 	} else {
690e3f58b6SKirk McKusick 		size = dp->dp2.di_size;
7015e4030eSKirk McKusick 		mode = dp->dp2.di_mode;
7115e4030eSKirk McKusick 	}
7215e4030eSKirk McKusick 	switch (mode & IFMT) {
73d3009da8SKirk McKusick 	default:
74d3009da8SKirk McKusick 		printf("unknown inode type 0%d\n", (mode & IFMT));
75d3009da8SKirk McKusick 		return;
76d3009da8SKirk McKusick 	case 0:
77d3009da8SKirk McKusick 		printf("unallocated inode\n");
78d3009da8SKirk McKusick 		return;
7915e4030eSKirk McKusick 	case IFIFO:
8015e4030eSKirk McKusick 		printf("fifo\n");
8115e4030eSKirk McKusick 		return;
8215e4030eSKirk McKusick 	case IFCHR:
8315e4030eSKirk McKusick 		printf("character device\n");
8415e4030eSKirk McKusick 		return;
8515e4030eSKirk McKusick 	case IFBLK:
8615e4030eSKirk McKusick 		printf("block device\n");
8715e4030eSKirk McKusick 		return;
8815e4030eSKirk McKusick 	case IFSOCK:
8915e4030eSKirk McKusick 		printf("socket\n");
9015e4030eSKirk McKusick 		return;
9115e4030eSKirk McKusick 	case IFWHT:
9215e4030eSKirk McKusick 		printf("whiteout\n");
9315e4030eSKirk McKusick 		return;
9415e4030eSKirk McKusick 	case IFLNK:
9515e4030eSKirk McKusick 		if (size == 0) {
9615e4030eSKirk McKusick 			printf("empty symbolic link\n");
9715e4030eSKirk McKusick 			return;
9815e4030eSKirk McKusick 		}
9915e4030eSKirk McKusick 		if (size < fs->fs_maxsymlinklen) {
10015e4030eSKirk McKusick 			printf("symbolic link referencing %s\n",
10115e4030eSKirk McKusick 			    (fs->fs_magic == FS_UFS1_MAGIC) ?
1025b13fa79SJessica Clarke 			    dp->dp1.di_shortlink :
1035b13fa79SJessica Clarke 			    dp->dp2.di_shortlink);
10415e4030eSKirk McKusick 			return;
10515e4030eSKirk McKusick 		}
10615e4030eSKirk McKusick 		printf("symbolic link\n");
10715e4030eSKirk McKusick 		break;
10815e4030eSKirk McKusick 	case IFREG:
10915e4030eSKirk McKusick 		if (size == 0) {
11016c0c8eeSKirk McKusick 			printf("empty file\n");
1110e3f58b6SKirk McKusick 			return;
11216c0c8eeSKirk McKusick 		}
113d3009da8SKirk McKusick 		printf("regular file, size %jd\n", (intmax_t)size);
11415e4030eSKirk McKusick 		break;
11515e4030eSKirk McKusick 	case IFDIR:
11615e4030eSKirk McKusick 		if (size == 0) {
11715e4030eSKirk McKusick 			printf("empty directory\n");
11815e4030eSKirk McKusick 			return;
11915e4030eSKirk McKusick 		}
120d3009da8SKirk McKusick 		printf("directory, size %jd\n", (intmax_t)size);
12115e4030eSKirk McKusick 		break;
12215e4030eSKirk McKusick 	}
123d3009da8SKirk McKusick 	lastlbn = howmany(size, fs->fs_bsize);
124d3009da8SKirk McKusick 	len = lastlbn < UFS_NDADDR ? lastlbn : UFS_NDADDR;
12516c0c8eeSKirk McKusick 	for (i = 0; i < len; i++) {
126d3009da8SKirk McKusick 		if (i < lastlbn - 1)
1270e3f58b6SKirk McKusick 			frags = fs->fs_frag;
12816c0c8eeSKirk McKusick 		else
12928ac2238SKirk McKusick 			frags = howmany(size - (lastlbn - 1) * fs->fs_bsize,
1300e3f58b6SKirk McKusick 					  fs->fs_fsize);
1310e3f58b6SKirk McKusick 		if (fs->fs_magic == FS_UFS1_MAGIC)
1320e3f58b6SKirk McKusick 			blkno = dp->dp1.di_db[i];
13316c0c8eeSKirk McKusick 		else
1340e3f58b6SKirk McKusick 			blkno = dp->dp2.di_db[i];
135d3009da8SKirk McKusick 		printblk(fs, i, blkno, frags, lastlbn);
13616c0c8eeSKirk McKusick 	}
13716c0c8eeSKirk McKusick 
13816c0c8eeSKirk McKusick 	blksperindir = 1;
139d3009da8SKirk McKusick 	len = lastlbn - UFS_NDADDR;
14016c0c8eeSKirk McKusick 	lbn = UFS_NDADDR;
14116c0c8eeSKirk McKusick 	for (i = 0; len > 0 && i < UFS_NIADDR; i++) {
1420e3f58b6SKirk McKusick 		if (fs->fs_magic == FS_UFS1_MAGIC)
1430e3f58b6SKirk McKusick 			blkno = dp->dp1.di_ib[i];
14416c0c8eeSKirk McKusick 		else
1450e3f58b6SKirk McKusick 			blkno = dp->dp2.di_ib[i];
14668d7185bSKirk McKusick 		indirprt(fs, i, blksperindir, lbn, blkno, lastlbn);
1470e3f58b6SKirk McKusick 		blksperindir *= NINDIR(fs);
14816c0c8eeSKirk McKusick 		lbn += blksperindir;
14916c0c8eeSKirk McKusick 		len -= blksperindir;
15016c0c8eeSKirk McKusick 	}
15116c0c8eeSKirk McKusick 
15216c0c8eeSKirk McKusick 	/* dummy print to flush out last extent */
153d3009da8SKirk McKusick 	printblk(fs, lastlbn, 0, frags, 0);
15416c0c8eeSKirk McKusick }
15516c0c8eeSKirk McKusick 
1560e3f58b6SKirk McKusick static void
15768d7185bSKirk McKusick indirprt(fs, level, blksperindir, lbn, blkno, lastlbn)
15868d7185bSKirk McKusick 	struct fs *fs;
15916c0c8eeSKirk McKusick 	int level;
160d3009da8SKirk McKusick 	ufs_lbn_t blksperindir;
161d3009da8SKirk McKusick 	ufs_lbn_t lbn;
16216c0c8eeSKirk McKusick 	ufs2_daddr_t blkno;
163d3009da8SKirk McKusick 	ufs_lbn_t lastlbn;
16416c0c8eeSKirk McKusick {
16516c0c8eeSKirk McKusick 	char indir[MAXBSIZE];
166d3009da8SKirk McKusick 	ufs_lbn_t i, last;
16716c0c8eeSKirk McKusick 
16815e4030eSKirk McKusick 	if (blkno == 0) {
16915e4030eSKirk McKusick 		printblk(fs, lbn, blkno,
17015e4030eSKirk McKusick 		    blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn);
17115e4030eSKirk McKusick 		return;
17215e4030eSKirk McKusick 	}
1730e3f58b6SKirk McKusick 	printblk(fs, lbn, blkno, fs->fs_frag, -level);
17416c0c8eeSKirk McKusick 	/* read in the indirect block. */
17568d7185bSKirk McKusick #ifdef PRTBLKNOS
17668d7185bSKirk McKusick 	if (bread(&disk, fsbtodb(fs, blkno), indir, fs->fs_bsize) == -1) {
17768d7185bSKirk McKusick #else /* used by fsdb */
17868d7185bSKirk McKusick 	bp = getdatablk(blkno, fs->fs_bsize, BT_LEVEL1 + level);
17968d7185bSKirk McKusick 	if (bp->b_errs == 0) {
18068d7185bSKirk McKusick 		memcpy(indir, bp->b_un.b_buf, fs->fs_bsize);
18168d7185bSKirk McKusick 	} else {
18268d7185bSKirk McKusick #endif
183c343fa81SKirk McKusick 		warn("Read of indirect block %jd failed", (intmax_t)blkno);
184c343fa81SKirk McKusick 		/* List the unreadable part as a hole */
185c343fa81SKirk McKusick 		printblk(fs, lbn, 0,
186c343fa81SKirk McKusick 		    blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn);
187c343fa81SKirk McKusick 		return;
188c343fa81SKirk McKusick 	}
1890e3f58b6SKirk McKusick 	last = howmany(lastlbn - lbn, blksperindir) < NINDIR(fs) ?
1900e3f58b6SKirk McKusick 	    howmany(lastlbn - lbn, blksperindir) : NINDIR(fs);
19116c0c8eeSKirk McKusick 	if (blksperindir == 1) {
19216c0c8eeSKirk McKusick 		for (i = 0; i < last; i++) {
1930e3f58b6SKirk McKusick 			if (fs->fs_magic == FS_UFS1_MAGIC)
19416c0c8eeSKirk McKusick 				blkno = ((ufs1_daddr_t *)indir)[i];
19516c0c8eeSKirk McKusick 			else
19616c0c8eeSKirk McKusick 				blkno = ((ufs2_daddr_t *)indir)[i];
1970e3f58b6SKirk McKusick 			printblk(fs, lbn + i, blkno, fs->fs_frag, lastlbn);
19816c0c8eeSKirk McKusick 		}
19916c0c8eeSKirk McKusick 		return;
20016c0c8eeSKirk McKusick 	}
20116c0c8eeSKirk McKusick 	for (i = 0; i < last; i++) {
2020e3f58b6SKirk McKusick 		if (fs->fs_magic == FS_UFS1_MAGIC)
20316c0c8eeSKirk McKusick 			blkno = ((ufs1_daddr_t *)indir)[i];
20416c0c8eeSKirk McKusick 		else
20516c0c8eeSKirk McKusick 			blkno = ((ufs2_daddr_t *)indir)[i];
20668d7185bSKirk McKusick 		indirprt(fs, level - 1, blksperindir / NINDIR(fs),
20716c0c8eeSKirk McKusick 		    lbn + blksperindir * i, blkno, lastlbn);
20816c0c8eeSKirk McKusick 	}
20916c0c8eeSKirk McKusick }
21016c0c8eeSKirk McKusick 
211d3009da8SKirk McKusick static const char *
2120e3f58b6SKirk McKusick distance(fs, lastblk, firstblk)
2130e3f58b6SKirk McKusick 	struct fs *fs;
214d3009da8SKirk McKusick 	ufs2_daddr_t lastblk;
215d3009da8SKirk McKusick 	ufs2_daddr_t firstblk;
21616c0c8eeSKirk McKusick {
217d3009da8SKirk McKusick 	ufs2_daddr_t delta;
21816c0c8eeSKirk McKusick 	int firstcg, lastcg;
21916c0c8eeSKirk McKusick 	static char buf[100];
22016c0c8eeSKirk McKusick 
22116c0c8eeSKirk McKusick 	if (lastblk == 0)
22216c0c8eeSKirk McKusick 		return ("");
22316c0c8eeSKirk McKusick 	delta = firstblk - lastblk - 1;
2240e3f58b6SKirk McKusick 	firstcg = dtog(fs, firstblk);
2250e3f58b6SKirk McKusick 	lastcg = dtog(fs, lastblk);
22616c0c8eeSKirk McKusick 	if (firstcg == lastcg) {
22716c0c8eeSKirk McKusick 		snprintf(buf, 100, " distance %jd", (intmax_t)delta);
22816c0c8eeSKirk McKusick 		return (&buf[0]);
22916c0c8eeSKirk McKusick 	}
23016c0c8eeSKirk McKusick 	snprintf(buf, 100, " cg %d blk %jd to cg %d blk %jd",
231f33fbc18SKirk McKusick 	    lastcg, (intmax_t)dtogd(fs, lastblk), firstcg,
232f33fbc18SKirk McKusick 	    (intmax_t)dtogd(fs, firstblk));
23316c0c8eeSKirk McKusick 	return (&buf[0]);
23416c0c8eeSKirk McKusick }
23516c0c8eeSKirk McKusick 
23616c0c8eeSKirk McKusick 
237d3009da8SKirk McKusick static const char *indirname[UFS_NIADDR] = { "First", "Second", "Third" };
23816c0c8eeSKirk McKusick 
2390e3f58b6SKirk McKusick static void
240d3009da8SKirk McKusick printblk(fs, lbn, blkno, numfrags, lastlbn)
2410e3f58b6SKirk McKusick 	struct fs *fs;
242d3009da8SKirk McKusick 	ufs_lbn_t lbn;
24316c0c8eeSKirk McKusick 	ufs2_daddr_t blkno;
244d3009da8SKirk McKusick 	int numfrags;
245d3009da8SKirk McKusick 	ufs_lbn_t lastlbn;
24616c0c8eeSKirk McKusick {
24716c0c8eeSKirk McKusick 	static int seq;
248d3009da8SKirk McKusick 	static ufs2_daddr_t totfrags, lastindirblk, lastblk, firstblk;
24916c0c8eeSKirk McKusick 
25016c0c8eeSKirk McKusick 	if (lastlbn <= 0)
25116c0c8eeSKirk McKusick 		goto flush;
25216c0c8eeSKirk McKusick 	if (seq == 0) {
253d3009da8SKirk McKusick 		seq = howmany(numfrags, fs->fs_frag);
254d3009da8SKirk McKusick 		totfrags = numfrags;
25516c0c8eeSKirk McKusick 		firstblk = blkno;
25616c0c8eeSKirk McKusick 		return;
25716c0c8eeSKirk McKusick 	}
25816c0c8eeSKirk McKusick 	if (lbn == 0) {
259d3009da8SKirk McKusick 		seq = howmany(numfrags, fs->fs_frag);
260d3009da8SKirk McKusick 		totfrags = numfrags;
26116c0c8eeSKirk McKusick 		lastblk = 0;
26216c0c8eeSKirk McKusick 		firstblk = blkno;
26316c0c8eeSKirk McKusick 		lastindirblk = 0;
26416c0c8eeSKirk McKusick 		return;
26516c0c8eeSKirk McKusick 	}
26616c0c8eeSKirk McKusick 	if (lbn < lastlbn && ((firstblk == 0 && blkno == 0) ||
26716c0c8eeSKirk McKusick 	    (firstblk == BLK_NOCOPY && blkno == BLK_NOCOPY) ||
26816c0c8eeSKirk McKusick 	    (firstblk == BLK_SNAP && blkno == BLK_SNAP) ||
26915e4030eSKirk McKusick 	    blkno == firstblk + seq * fs->fs_frag)) {
270d3009da8SKirk McKusick 		seq += howmany(numfrags, fs->fs_frag);
271d3009da8SKirk McKusick 		totfrags += numfrags;
27216c0c8eeSKirk McKusick 		return;
27316c0c8eeSKirk McKusick 	}
27416c0c8eeSKirk McKusick flush:
27516c0c8eeSKirk McKusick 	if (seq == 0)
27616c0c8eeSKirk McKusick 		goto prtindir;
27716c0c8eeSKirk McKusick 	if (firstblk <= BLK_SNAP) {
27816c0c8eeSKirk McKusick 		if (seq == 1)
279d3009da8SKirk McKusick 			printf("\tlbn %jd %s\n", (intmax_t)(lbn - seq),
28016c0c8eeSKirk McKusick 			    firstblk == 0 ? "hole" :
28116c0c8eeSKirk McKusick 			    firstblk == BLK_NOCOPY ? "nocopy" :
28216c0c8eeSKirk McKusick 			    "snapblk");
28316c0c8eeSKirk McKusick 		else
284d3009da8SKirk McKusick 			printf("\tlbn %jd-%jd %s\n",
285d3009da8SKirk McKusick 			    (intmax_t)lbn - seq, (intmax_t)lbn - 1,
28616c0c8eeSKirk McKusick 			    firstblk == 0 ? "hole" :
28716c0c8eeSKirk McKusick 			    firstblk == BLK_NOCOPY ? "nocopy" :
28816c0c8eeSKirk McKusick 			    "snapblk");
28916c0c8eeSKirk McKusick 	} else if (seq == 1) {
290d3009da8SKirk McKusick 		if (totfrags == 1)
291d3009da8SKirk McKusick 			printf("\tlbn %jd blkno %jd%s\n", (intmax_t)(lbn - seq),
2920e3f58b6SKirk McKusick 			   (intmax_t)firstblk, distance(fs, lastblk, firstblk));
29316c0c8eeSKirk McKusick 		else
294d3009da8SKirk McKusick 			printf("\tlbn %jd blkno %jd-%jd%s\n",
295d3009da8SKirk McKusick 			    (intmax_t)(lbn - seq), (intmax_t)firstblk,
296d3009da8SKirk McKusick 			    (intmax_t)(firstblk + totfrags - 1),
2970e3f58b6SKirk McKusick 			    distance(fs, lastblk, firstblk));
298d3009da8SKirk McKusick 		lastblk = firstblk + totfrags - 1;
29916c0c8eeSKirk McKusick 	} else {
300d3009da8SKirk McKusick 		printf("\tlbn %jd-%jd blkno %jd-%jd%s\n", (intmax_t)(lbn - seq),
301d3009da8SKirk McKusick 		    (intmax_t)(lbn - 1), (intmax_t)firstblk,
302d3009da8SKirk McKusick 		    (intmax_t)(firstblk + totfrags - 1),
3030e3f58b6SKirk McKusick 		    distance(fs, lastblk, firstblk));
304d3009da8SKirk McKusick 		lastblk = firstblk + totfrags - 1;
30516c0c8eeSKirk McKusick 	}
30616c0c8eeSKirk McKusick 	if (lastlbn > 0 || blkno == 0) {
30716c0c8eeSKirk McKusick 		seq = 1;
308d3009da8SKirk McKusick 		totfrags = numfrags;
30916c0c8eeSKirk McKusick 		firstblk = blkno;
31016c0c8eeSKirk McKusick 		return;
31116c0c8eeSKirk McKusick 	}
31216c0c8eeSKirk McKusick prtindir:
3130e3f58b6SKirk McKusick 	if (seq != 0 && (fs->fs_metaspace == 0 || lastindirblk == 0))
31416c0c8eeSKirk McKusick 		lastindirblk = lastblk;
31516c0c8eeSKirk McKusick 	printf("%s-level indirect, blkno %jd-%jd%s\n", indirname[-lastlbn],
316d3009da8SKirk McKusick 	    (intmax_t)blkno, (intmax_t)(blkno + numfrags - 1),
3170e3f58b6SKirk McKusick 	    distance(fs, lastindirblk, blkno));
318d3009da8SKirk McKusick 	lastindirblk = blkno + numfrags - 1;
3190e3f58b6SKirk McKusick 	if (fs->fs_metaspace == 0)
32016c0c8eeSKirk McKusick 		lastblk = lastindirblk;
32116c0c8eeSKirk McKusick 	seq = 0;
32216c0c8eeSKirk McKusick }
323