xref: /freebsd/tools/diag/prtblknos/prtblknos.c (revision c343fa81)
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>
340e3f58b6SKirk McKusick #include <libufs.h>
3516c0c8eeSKirk McKusick 
3616c0c8eeSKirk McKusick union dinode {
370e3f58b6SKirk McKusick 	struct ufs1_dinode dp1;
380e3f58b6SKirk McKusick 	struct ufs2_dinode dp2;
3916c0c8eeSKirk McKusick };
4016c0c8eeSKirk McKusick 
410e3f58b6SKirk McKusick void prtblknos(struct uufsd *disk, union dinode *dp);
4216c0c8eeSKirk McKusick 
430e3f58b6SKirk McKusick static void  indirprt(struct uufsd *, int, int, int, ufs2_daddr_t, int);
440e3f58b6SKirk McKusick static char *distance(struct fs *, daddr_t, daddr_t);
450e3f58b6SKirk McKusick static void  printblk(struct fs *, int, ufs2_daddr_t, int, int);
4616c0c8eeSKirk McKusick 
470e3f58b6SKirk McKusick void
480e3f58b6SKirk McKusick prtblknos(disk, dp)
490e3f58b6SKirk McKusick 	struct uufsd *disk;
500e3f58b6SKirk McKusick 	union dinode *dp;
5116c0c8eeSKirk McKusick {
5215e4030eSKirk McKusick 	int i, len, lbn, mode, frags, numblks, blksperindir;
5316c0c8eeSKirk McKusick 	ufs2_daddr_t blkno;
540e3f58b6SKirk McKusick 	struct fs *fs;
550e3f58b6SKirk McKusick 	off_t size;
5616c0c8eeSKirk McKusick 
570e3f58b6SKirk McKusick 	fs = (struct fs *)&disk->d_sb;
5815e4030eSKirk McKusick 	if (fs->fs_magic == FS_UFS1_MAGIC) {
590e3f58b6SKirk McKusick 		size = dp->dp1.di_size;
6015e4030eSKirk McKusick 		mode = dp->dp1.di_mode;
6115e4030eSKirk McKusick 	} else {
620e3f58b6SKirk McKusick 		size = dp->dp2.di_size;
6315e4030eSKirk McKusick 		mode = dp->dp2.di_mode;
6415e4030eSKirk McKusick 	}
6515e4030eSKirk McKusick 	switch (mode & IFMT) {
6615e4030eSKirk McKusick 	case IFIFO:
6715e4030eSKirk McKusick 		printf("fifo\n");
6815e4030eSKirk McKusick 		return;
6915e4030eSKirk McKusick 	case IFCHR:
7015e4030eSKirk McKusick 		printf("character device\n");
7115e4030eSKirk McKusick 		return;
7215e4030eSKirk McKusick 	case IFBLK:
7315e4030eSKirk McKusick 		printf("block device\n");
7415e4030eSKirk McKusick 		return;
7515e4030eSKirk McKusick 	case IFSOCK:
7615e4030eSKirk McKusick 		printf("socket\n");
7715e4030eSKirk McKusick 		return;
7815e4030eSKirk McKusick 	case IFWHT:
7915e4030eSKirk McKusick 		printf("whiteout\n");
8015e4030eSKirk McKusick 		return;
8115e4030eSKirk McKusick 	case IFLNK:
8215e4030eSKirk McKusick 		if (size == 0) {
8315e4030eSKirk McKusick 			printf("empty symbolic link\n");
8415e4030eSKirk McKusick 			return;
8515e4030eSKirk McKusick 		}
8615e4030eSKirk McKusick 		if (size < fs->fs_maxsymlinklen) {
8715e4030eSKirk McKusick 			printf("symbolic link referencing %s\n",
8815e4030eSKirk McKusick 			    (fs->fs_magic == FS_UFS1_MAGIC) ?
8915e4030eSKirk McKusick 			    (char *)dp->dp1.di_db :
9015e4030eSKirk McKusick 			    (char *)dp->dp2.di_db);
9115e4030eSKirk McKusick 			return;
9215e4030eSKirk McKusick 		}
9315e4030eSKirk McKusick 		printf("symbolic link\n");
9415e4030eSKirk McKusick 		break;
9515e4030eSKirk McKusick 	case IFREG:
9615e4030eSKirk McKusick 		if (size == 0) {
9716c0c8eeSKirk McKusick 			printf("empty file\n");
980e3f58b6SKirk McKusick 			return;
9916c0c8eeSKirk McKusick 		}
10015e4030eSKirk McKusick 		printf("regular file, size %ld\n", size);
10115e4030eSKirk McKusick 		break;
10215e4030eSKirk McKusick 	case IFDIR:
10315e4030eSKirk McKusick 		if (size == 0) {
10415e4030eSKirk McKusick 			printf("empty directory\n");
10515e4030eSKirk McKusick 			return;
10615e4030eSKirk McKusick 		}
10715e4030eSKirk McKusick 		printf("directory, size %ld\n", size);
10815e4030eSKirk McKusick 		break;
10915e4030eSKirk McKusick 	}
11015e4030eSKirk McKusick 	numblks = howmany(size, fs->fs_bsize);
11116c0c8eeSKirk McKusick 	len = numblks < UFS_NDADDR ? numblks : UFS_NDADDR;
11216c0c8eeSKirk McKusick 	for (i = 0; i < len; i++) {
11316c0c8eeSKirk McKusick 		if (i < numblks - 1)
1140e3f58b6SKirk McKusick 			frags = fs->fs_frag;
11516c0c8eeSKirk McKusick 		else
1160e3f58b6SKirk McKusick 			frags = howmany(size % fs->fs_bsize,
1170e3f58b6SKirk McKusick 					  fs->fs_fsize);
1180e3f58b6SKirk McKusick 		if (fs->fs_magic == FS_UFS1_MAGIC)
1190e3f58b6SKirk McKusick 			blkno = dp->dp1.di_db[i];
12016c0c8eeSKirk McKusick 		else
1210e3f58b6SKirk McKusick 			blkno = dp->dp2.di_db[i];
1220e3f58b6SKirk McKusick 		printblk(fs, i, blkno, frags, numblks);
12316c0c8eeSKirk McKusick 	}
12416c0c8eeSKirk McKusick 
12516c0c8eeSKirk McKusick 	blksperindir = 1;
12616c0c8eeSKirk McKusick 	len = numblks - UFS_NDADDR;
12716c0c8eeSKirk McKusick 	lbn = UFS_NDADDR;
12816c0c8eeSKirk McKusick 	for (i = 0; len > 0 && i < UFS_NIADDR; i++) {
1290e3f58b6SKirk McKusick 		if (fs->fs_magic == FS_UFS1_MAGIC)
1300e3f58b6SKirk McKusick 			blkno = dp->dp1.di_ib[i];
13116c0c8eeSKirk McKusick 		else
1320e3f58b6SKirk McKusick 			blkno = dp->dp2.di_ib[i];
1330e3f58b6SKirk McKusick 		indirprt(disk, i, blksperindir, lbn, blkno, numblks);
1340e3f58b6SKirk McKusick 		blksperindir *= NINDIR(fs);
13516c0c8eeSKirk McKusick 		lbn += blksperindir;
13616c0c8eeSKirk McKusick 		len -= blksperindir;
13716c0c8eeSKirk McKusick 	}
13816c0c8eeSKirk McKusick 
13916c0c8eeSKirk McKusick 	/* dummy print to flush out last extent */
1400e3f58b6SKirk McKusick 	printblk(fs, numblks, 0, frags, 0);
14116c0c8eeSKirk McKusick }
14216c0c8eeSKirk McKusick 
1430e3f58b6SKirk McKusick static void
1440e3f58b6SKirk McKusick indirprt(disk, level, blksperindir, lbn, blkno, lastlbn)
1450e3f58b6SKirk McKusick 	struct uufsd *disk;
14616c0c8eeSKirk McKusick 	int level;
14716c0c8eeSKirk McKusick 	int blksperindir;
14816c0c8eeSKirk McKusick 	int lbn;
14916c0c8eeSKirk McKusick 	ufs2_daddr_t blkno;
15016c0c8eeSKirk McKusick 	int lastlbn;
15116c0c8eeSKirk McKusick {
15216c0c8eeSKirk McKusick 	char indir[MAXBSIZE];
1530e3f58b6SKirk McKusick 	struct fs *fs;
15416c0c8eeSKirk McKusick 	int i, last;
15516c0c8eeSKirk McKusick 
1560e3f58b6SKirk McKusick 	fs = (struct fs *)&disk->d_sb;
15715e4030eSKirk McKusick 	if (blkno == 0) {
15815e4030eSKirk McKusick 		printblk(fs, lbn, blkno,
15915e4030eSKirk McKusick 		    blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn);
16015e4030eSKirk McKusick 		return;
16115e4030eSKirk McKusick 	}
1620e3f58b6SKirk McKusick 	printblk(fs, lbn, blkno, fs->fs_frag, -level);
16316c0c8eeSKirk McKusick 	/* read in the indirect block. */
164c343fa81SKirk McKusick 	if (bread(disk, fsbtodb(fs, blkno), indir, fs->fs_bsize) == -1) {
165c343fa81SKirk McKusick 		warn("Read of indirect block %jd failed", (intmax_t)blkno);
166c343fa81SKirk McKusick 		/* List the unreadable part as a hole */
167c343fa81SKirk McKusick 		printblk(fs, lbn, 0,
168c343fa81SKirk McKusick 		    blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn);
169c343fa81SKirk McKusick 		return;
170c343fa81SKirk McKusick 	}
1710e3f58b6SKirk McKusick 	last = howmany(lastlbn - lbn, blksperindir) < NINDIR(fs) ?
1720e3f58b6SKirk McKusick 	    howmany(lastlbn - lbn, blksperindir) : NINDIR(fs);
17316c0c8eeSKirk McKusick 	if (blksperindir == 1) {
17416c0c8eeSKirk McKusick 		for (i = 0; i < last; i++) {
1750e3f58b6SKirk McKusick 			if (fs->fs_magic == FS_UFS1_MAGIC)
17616c0c8eeSKirk McKusick 				blkno = ((ufs1_daddr_t *)indir)[i];
17716c0c8eeSKirk McKusick 			else
17816c0c8eeSKirk McKusick 				blkno = ((ufs2_daddr_t *)indir)[i];
1790e3f58b6SKirk McKusick 			printblk(fs, lbn + i, blkno, fs->fs_frag, lastlbn);
18016c0c8eeSKirk McKusick 		}
18116c0c8eeSKirk McKusick 		return;
18216c0c8eeSKirk McKusick 	}
18316c0c8eeSKirk McKusick 	for (i = 0; i < last; i++) {
1840e3f58b6SKirk McKusick 		if (fs->fs_magic == FS_UFS1_MAGIC)
18516c0c8eeSKirk McKusick 			blkno = ((ufs1_daddr_t *)indir)[i];
18616c0c8eeSKirk McKusick 		else
18716c0c8eeSKirk McKusick 			blkno = ((ufs2_daddr_t *)indir)[i];
1880e3f58b6SKirk McKusick 		indirprt(disk, level - 1, blksperindir / NINDIR(fs),
18916c0c8eeSKirk McKusick 		    lbn + blksperindir * i, blkno, lastlbn);
19016c0c8eeSKirk McKusick 	}
19116c0c8eeSKirk McKusick }
19216c0c8eeSKirk McKusick 
1930e3f58b6SKirk McKusick static char *
1940e3f58b6SKirk McKusick distance(fs, lastblk, firstblk)
1950e3f58b6SKirk McKusick 	struct fs *fs;
19616c0c8eeSKirk McKusick 	daddr_t lastblk;
19716c0c8eeSKirk McKusick 	daddr_t firstblk;
19816c0c8eeSKirk McKusick {
19916c0c8eeSKirk McKusick 	daddr_t delta;
20016c0c8eeSKirk McKusick 	int firstcg, lastcg;
20116c0c8eeSKirk McKusick 	static char buf[100];
20216c0c8eeSKirk McKusick 
20316c0c8eeSKirk McKusick 	if (lastblk == 0)
20416c0c8eeSKirk McKusick 		return ("");
20516c0c8eeSKirk McKusick 	delta = firstblk - lastblk - 1;
2060e3f58b6SKirk McKusick 	firstcg = dtog(fs, firstblk);
2070e3f58b6SKirk McKusick 	lastcg = dtog(fs, lastblk);
20816c0c8eeSKirk McKusick 	if (firstcg == lastcg) {
20916c0c8eeSKirk McKusick 		snprintf(buf, 100, " distance %jd", (intmax_t)delta);
21016c0c8eeSKirk McKusick 		return (&buf[0]);
21116c0c8eeSKirk McKusick 	}
21216c0c8eeSKirk McKusick 	snprintf(buf, 100, " cg %d blk %jd to cg %d blk %jd",
213f33fbc18SKirk McKusick 	    lastcg, (intmax_t)dtogd(fs, lastblk), firstcg,
214f33fbc18SKirk McKusick 	    (intmax_t)dtogd(fs, firstblk));
21516c0c8eeSKirk McKusick 	return (&buf[0]);
21616c0c8eeSKirk McKusick }
21716c0c8eeSKirk McKusick 
21816c0c8eeSKirk McKusick 
2190e3f58b6SKirk McKusick static char *indirname[UFS_NIADDR] = { "First", "Second", "Third" };
22016c0c8eeSKirk McKusick 
2210e3f58b6SKirk McKusick static void
2220e3f58b6SKirk McKusick printblk(fs, lbn, blkno, numblks, lastlbn)
2230e3f58b6SKirk McKusick 	struct fs *fs;
22416c0c8eeSKirk McKusick 	int lbn;
22516c0c8eeSKirk McKusick 	ufs2_daddr_t blkno;
22616c0c8eeSKirk McKusick 	int numblks;
22716c0c8eeSKirk McKusick 	int lastlbn;
22816c0c8eeSKirk McKusick {
22916c0c8eeSKirk McKusick 	static int seq;
23016c0c8eeSKirk McKusick 	static daddr_t lastindirblk, lastblk, firstblk;
23116c0c8eeSKirk McKusick 
23216c0c8eeSKirk McKusick 	if (lastlbn <= 0)
23316c0c8eeSKirk McKusick 		goto flush;
23416c0c8eeSKirk McKusick 	if (seq == 0) {
23515e4030eSKirk McKusick 		seq = howmany(numblks, fs->fs_frag);
23616c0c8eeSKirk McKusick 		firstblk = blkno;
23716c0c8eeSKirk McKusick 		return;
23816c0c8eeSKirk McKusick 	}
23916c0c8eeSKirk McKusick 	if (lbn == 0) {
24015e4030eSKirk McKusick 		seq = howmany(numblks, fs->fs_frag);
24116c0c8eeSKirk McKusick 		lastblk = 0;
24216c0c8eeSKirk McKusick 		firstblk = blkno;
24316c0c8eeSKirk McKusick 		lastindirblk = 0;
24416c0c8eeSKirk McKusick 		return;
24516c0c8eeSKirk McKusick 	}
24616c0c8eeSKirk McKusick 	if (lbn < lastlbn && ((firstblk == 0 && blkno == 0) ||
24716c0c8eeSKirk McKusick 	    (firstblk == BLK_NOCOPY && blkno == BLK_NOCOPY) ||
24816c0c8eeSKirk McKusick 	    (firstblk == BLK_SNAP && blkno == BLK_SNAP) ||
24915e4030eSKirk McKusick 	    blkno == firstblk + seq * fs->fs_frag)) {
25015e4030eSKirk McKusick 		seq += howmany(numblks, fs->fs_frag);
25116c0c8eeSKirk McKusick 		return;
25216c0c8eeSKirk McKusick 	}
25316c0c8eeSKirk McKusick flush:
25416c0c8eeSKirk McKusick 	if (seq == 0)
25516c0c8eeSKirk McKusick 		goto prtindir;
25616c0c8eeSKirk McKusick 	if (firstblk <= BLK_SNAP) {
25716c0c8eeSKirk McKusick 		if (seq == 1)
25816c0c8eeSKirk McKusick 			printf("\tlbn %d %s\n", lbn - seq,
25916c0c8eeSKirk McKusick 			    firstblk == 0 ? "hole" :
26016c0c8eeSKirk McKusick 			    firstblk == BLK_NOCOPY ? "nocopy" :
26116c0c8eeSKirk McKusick 			    "snapblk");
26216c0c8eeSKirk McKusick 		else
26316c0c8eeSKirk McKusick 			printf("\tlbn %d-%d %s\n",
26416c0c8eeSKirk McKusick 			    lbn - seq, lbn - 1,
26516c0c8eeSKirk McKusick 			    firstblk == 0 ? "hole" :
26616c0c8eeSKirk McKusick 			    firstblk == BLK_NOCOPY ? "nocopy" :
26716c0c8eeSKirk McKusick 			    "snapblk");
26816c0c8eeSKirk McKusick 	} else if (seq == 1) {
26916c0c8eeSKirk McKusick 		if (numblks == 1)
27016c0c8eeSKirk McKusick 			printf("\tlbn %d blkno %jd%s\n", lbn - seq,
2710e3f58b6SKirk McKusick 			   (intmax_t)firstblk, distance(fs, lastblk, firstblk));
27216c0c8eeSKirk McKusick 		else
27316c0c8eeSKirk McKusick 			printf("\tlbn %d blkno %jd-%jd%s\n", lbn - seq,
27416c0c8eeSKirk McKusick 			    (intmax_t)firstblk,
27516c0c8eeSKirk McKusick 			    (intmax_t)(firstblk + numblks - 1),
2760e3f58b6SKirk McKusick 			    distance(fs, lastblk, firstblk));
27716c0c8eeSKirk McKusick 		lastblk = firstblk + numblks - 1;
27816c0c8eeSKirk McKusick 	} else {
27916c0c8eeSKirk McKusick 		printf("\tlbn %d-%d blkno %jd-%jd%s\n", lbn - seq, lbn - 1,
28016c0c8eeSKirk McKusick 		    (intmax_t)firstblk, (intmax_t)(firstblk +
2810e3f58b6SKirk McKusick 		    (seq - 1) * fs->fs_frag + numblks - 1),
2820e3f58b6SKirk McKusick 		    distance(fs, lastblk, firstblk));
2830e3f58b6SKirk McKusick 		lastblk = firstblk + (seq - 1) * fs->fs_frag + numblks - 1;
28416c0c8eeSKirk McKusick 	}
28516c0c8eeSKirk McKusick 	if (lastlbn > 0 || blkno == 0) {
28616c0c8eeSKirk McKusick 		seq = 1;
28716c0c8eeSKirk McKusick 		firstblk = blkno;
28816c0c8eeSKirk McKusick 		return;
28916c0c8eeSKirk McKusick 	}
29016c0c8eeSKirk McKusick prtindir:
2910e3f58b6SKirk McKusick 	if (seq != 0 && (fs->fs_metaspace == 0 || lastindirblk == 0))
29216c0c8eeSKirk McKusick 		lastindirblk = lastblk;
29316c0c8eeSKirk McKusick 	printf("%s-level indirect, blkno %jd-%jd%s\n", indirname[-lastlbn],
29416c0c8eeSKirk McKusick 	    (intmax_t)blkno, (intmax_t)(blkno + numblks - 1),
2950e3f58b6SKirk McKusick 	    distance(fs, lastindirblk, blkno));
29616c0c8eeSKirk McKusick 	lastindirblk = blkno + numblks - 1;
2970e3f58b6SKirk McKusick 	if (fs->fs_metaspace == 0)
29816c0c8eeSKirk McKusick 		lastblk = lastindirblk;
29916c0c8eeSKirk McKusick 	seq = 0;
30016c0c8eeSKirk McKusick }
301