xref: /freebsd/tools/diag/prtblknos/prtblknos.c (revision 1719886f6d08408b834d270c59ffcfd821c8f63a)
1 /*
2  * Copyright (c) 1998, 2003, 2013, 2018 Marshall Kirk McKusick.
3  * All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY MARSHALL KIRK MCKUSICK ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL MARSHALL KIRK MCKUSICK BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/param.h>
28 #include <ufs/ffs/fs.h>
29 
30 #include <err.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <libufs.h>
34 
35 #ifdef PRTBLKNOS
36 union dinode {
37 	struct ufs1_dinode dp1;
38 	struct ufs2_dinode dp2;
39 };
40 extern struct uufsd disk;
41 #else /* used by fsdb */
42 #include <fsck.h>
43 static struct bufarea *bp;
44 #endif
45 
46 void prtblknos(struct fs *fs, union dinode *dp);
47 
48 static const char *distance(struct fs *, ufs2_daddr_t, ufs2_daddr_t);
49 static void  printblk(struct fs *, ufs_lbn_t, ufs2_daddr_t, int, ufs_lbn_t);
50 static void  indirprt(struct fs *, int, ufs_lbn_t, ufs_lbn_t, ufs2_daddr_t,
51 		ufs_lbn_t);
52 
53 void
54 prtblknos(struct fs *fs, union dinode *dp)
55 {
56 	int i, mode, frags;
57 	ufs_lbn_t lbn, lastlbn, len, blksperindir;
58 	ufs2_daddr_t blkno;
59 	off_t size;
60 
61 	if (fs->fs_magic == FS_UFS1_MAGIC) {
62 		size = dp->dp1.di_size;
63 		mode = dp->dp1.di_mode;
64 	} else {
65 		size = dp->dp2.di_size;
66 		mode = dp->dp2.di_mode;
67 	}
68 	switch (mode & IFMT) {
69 	default:
70 		printf("unknown inode type 0%d\n", (mode & IFMT));
71 		return;
72 	case 0:
73 		printf("unallocated inode\n");
74 		return;
75 	case IFIFO:
76 		printf("fifo\n");
77 		return;
78 	case IFCHR:
79 		printf("character device\n");
80 		return;
81 	case IFBLK:
82 		printf("block device\n");
83 		return;
84 	case IFSOCK:
85 		printf("socket\n");
86 		return;
87 	case IFWHT:
88 		printf("whiteout\n");
89 		return;
90 	case IFLNK:
91 		if (size == 0) {
92 			printf("empty symbolic link\n");
93 			return;
94 		}
95 		if (size < fs->fs_maxsymlinklen) {
96 			printf("symbolic link referencing %s\n",
97 			    (fs->fs_magic == FS_UFS1_MAGIC) ?
98 			    dp->dp1.di_shortlink :
99 			    dp->dp2.di_shortlink);
100 			return;
101 		}
102 		printf("symbolic link\n");
103 		break;
104 	case IFREG:
105 		if (size == 0) {
106 			printf("empty file\n");
107 			return;
108 		}
109 		printf("regular file, size %jd\n", (intmax_t)size);
110 		break;
111 	case IFDIR:
112 		if (size == 0) {
113 			printf("empty directory\n");
114 			return;
115 		}
116 		printf("directory, size %jd\n", (intmax_t)size);
117 		break;
118 	}
119 	lastlbn = howmany(size, fs->fs_bsize);
120 	len = lastlbn < UFS_NDADDR ? lastlbn : UFS_NDADDR;
121 	for (i = 0; i < len; i++) {
122 		if (i < lastlbn - 1)
123 			frags = fs->fs_frag;
124 		else
125 			frags = howmany(size - (lastlbn - 1) * fs->fs_bsize,
126 					  fs->fs_fsize);
127 		if (fs->fs_magic == FS_UFS1_MAGIC)
128 			blkno = dp->dp1.di_db[i];
129 		else
130 			blkno = dp->dp2.di_db[i];
131 		printblk(fs, i, blkno, frags, lastlbn);
132 	}
133 
134 	blksperindir = 1;
135 	len = lastlbn - UFS_NDADDR;
136 	lbn = UFS_NDADDR;
137 	for (i = 0; len > 0 && i < UFS_NIADDR; i++) {
138 		if (fs->fs_magic == FS_UFS1_MAGIC)
139 			blkno = dp->dp1.di_ib[i];
140 		else
141 			blkno = dp->dp2.di_ib[i];
142 		indirprt(fs, i, blksperindir, lbn, blkno, lastlbn);
143 		blksperindir *= NINDIR(fs);
144 		lbn += blksperindir;
145 		len -= blksperindir;
146 	}
147 
148 	/* dummy print to flush out last extent */
149 	printblk(fs, lastlbn, 0, frags, 0);
150 }
151 
152 static void
153 indirprt(struct fs *fs, int level, ufs_lbn_t blksperindir, ufs_lbn_t lbn,
154 	ufs2_daddr_t blkno, ufs_lbn_t lastlbn)
155 {
156 	char indir[MAXBSIZE];
157 	ufs_lbn_t i, last;
158 
159 	if (blkno == 0) {
160 		printblk(fs, lbn, blkno,
161 		    blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn);
162 		return;
163 	}
164 	printblk(fs, lbn, blkno, fs->fs_frag, -level);
165 	/* read in the indirect block. */
166 #ifdef PRTBLKNOS
167 	if (bread(&disk, fsbtodb(fs, blkno), indir, fs->fs_bsize) == -1) {
168 #else /* used by fsdb */
169 	bp = getdatablk(blkno, fs->fs_bsize, BT_LEVEL1 + level);
170 	if (bp->b_errs == 0) {
171 		memcpy(indir, bp->b_un.b_buf, fs->fs_bsize);
172 	} else {
173 #endif
174 		warn("Read of indirect block %jd failed", (intmax_t)blkno);
175 		/* List the unreadable part as a hole */
176 		printblk(fs, lbn, 0,
177 		    blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn);
178 		return;
179 	}
180 	last = howmany(lastlbn - lbn, blksperindir) < NINDIR(fs) ?
181 	    howmany(lastlbn - lbn, blksperindir) : NINDIR(fs);
182 	if (blksperindir == 1) {
183 		for (i = 0; i < last; i++) {
184 			if (fs->fs_magic == FS_UFS1_MAGIC)
185 				blkno = ((ufs1_daddr_t *)indir)[i];
186 			else
187 				blkno = ((ufs2_daddr_t *)indir)[i];
188 			printblk(fs, lbn + i, blkno, fs->fs_frag, lastlbn);
189 		}
190 		return;
191 	}
192 	for (i = 0; i < last; i++) {
193 		if (fs->fs_magic == FS_UFS1_MAGIC)
194 			blkno = ((ufs1_daddr_t *)indir)[i];
195 		else
196 			blkno = ((ufs2_daddr_t *)indir)[i];
197 		indirprt(fs, level - 1, blksperindir / NINDIR(fs),
198 		    lbn + blksperindir * i, blkno, lastlbn);
199 	}
200 }
201 
202 static const char *
203 distance(struct fs *fs, ufs2_daddr_t lastblk, ufs2_daddr_t firstblk)
204 {
205 	ufs2_daddr_t delta;
206 	int firstcg, lastcg;
207 	static char buf[100];
208 
209 	if (lastblk == 0)
210 		return ("");
211 	delta = firstblk - lastblk - 1;
212 	firstcg = dtog(fs, firstblk);
213 	lastcg = dtog(fs, lastblk);
214 	if (firstcg == lastcg) {
215 		snprintf(buf, 100, " distance %jd", (intmax_t)delta);
216 		return (&buf[0]);
217 	}
218 	snprintf(buf, 100, " cg %d blk %jd to cg %d blk %jd",
219 	    lastcg, (intmax_t)dtogd(fs, lastblk), firstcg,
220 	    (intmax_t)dtogd(fs, firstblk));
221 	return (&buf[0]);
222 }
223 
224 
225 static const char *indirname[UFS_NIADDR] = { "First", "Second", "Third" };
226 
227 static void
228 printblk(struct fs *fs, ufs_lbn_t lbn, ufs2_daddr_t blkno, int numfrags,
229 	ufs_lbn_t lastlbn)
230 {
231 	static int seq;
232 	static ufs2_daddr_t totfrags, lastindirblk, lastblk, firstblk;
233 
234 	if (lastlbn <= 0)
235 		goto flush;
236 	if (seq == 0) {
237 		seq = howmany(numfrags, fs->fs_frag);
238 		totfrags = numfrags;
239 		firstblk = blkno;
240 		return;
241 	}
242 	if (lbn == 0) {
243 		seq = howmany(numfrags, fs->fs_frag);
244 		totfrags = numfrags;
245 		lastblk = 0;
246 		firstblk = blkno;
247 		lastindirblk = 0;
248 		return;
249 	}
250 	if (lbn < lastlbn && ((firstblk == 0 && blkno == 0) ||
251 	    (firstblk == BLK_NOCOPY && blkno == BLK_NOCOPY) ||
252 	    (firstblk == BLK_SNAP && blkno == BLK_SNAP) ||
253 	    blkno == firstblk + seq * fs->fs_frag)) {
254 		seq += howmany(numfrags, fs->fs_frag);
255 		totfrags += numfrags;
256 		return;
257 	}
258 flush:
259 	if (seq == 0)
260 		goto prtindir;
261 	if (firstblk <= BLK_SNAP) {
262 		if (seq == 1)
263 			printf("\tlbn %jd %s\n", (intmax_t)(lbn - seq),
264 			    firstblk == 0 ? "hole" :
265 			    firstblk == BLK_NOCOPY ? "nocopy" :
266 			    "snapblk");
267 		else
268 			printf("\tlbn %jd-%jd %s\n",
269 			    (intmax_t)lbn - seq, (intmax_t)lbn - 1,
270 			    firstblk == 0 ? "hole" :
271 			    firstblk == BLK_NOCOPY ? "nocopy" :
272 			    "snapblk");
273 	} else if (seq == 1) {
274 		if (totfrags == 1)
275 			printf("\tlbn %jd blkno %jd%s\n", (intmax_t)(lbn - seq),
276 			   (intmax_t)firstblk, distance(fs, lastblk, firstblk));
277 		else
278 			printf("\tlbn %jd blkno %jd-%jd%s\n",
279 			    (intmax_t)(lbn - seq), (intmax_t)firstblk,
280 			    (intmax_t)(firstblk + totfrags - 1),
281 			    distance(fs, lastblk, firstblk));
282 		lastblk = firstblk + totfrags - 1;
283 	} else {
284 		printf("\tlbn %jd-%jd blkno %jd-%jd%s\n", (intmax_t)(lbn - seq),
285 		    (intmax_t)(lbn - 1), (intmax_t)firstblk,
286 		    (intmax_t)(firstblk + totfrags - 1),
287 		    distance(fs, lastblk, firstblk));
288 		lastblk = firstblk + totfrags - 1;
289 	}
290 	if (lastlbn > 0 || blkno == 0) {
291 		seq = 1;
292 		totfrags = numfrags;
293 		firstblk = blkno;
294 		return;
295 	}
296 prtindir:
297 	if (seq != 0 && (fs->fs_metaspace == 0 || lastindirblk == 0))
298 		lastindirblk = lastblk;
299 	printf("%s-level indirect, blkno %jd-%jd%s\n", indirname[-lastlbn],
300 	    (intmax_t)blkno, (intmax_t)(blkno + numfrags - 1),
301 	    distance(fs, lastindirblk, blkno));
302 	lastindirblk = blkno + numfrags - 1;
303 	if (fs->fs_metaspace == 0)
304 		lastblk = lastindirblk;
305 	seq = 0;
306 }
307