xref: /freebsd/tools/diag/prtblknos/prtblknos.c (revision 84b3c4547afa496b37e86c5e649e99237c8afc6e)
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  * $FreeBSD$
27  */
28 
29 #include <sys/param.h>
30 #include <ufs/ffs/fs.h>
31 
32 #include <err.h>
33 #include <stdio.h>
34 #include <libufs.h>
35 
36 union dinode {
37 	struct ufs1_dinode dp1;
38 	struct ufs2_dinode dp2;
39 };
40 
41 void prtblknos(struct uufsd *disk, union dinode *dp);
42 
43 static const char *distance(struct fs *, ufs2_daddr_t, ufs2_daddr_t);
44 static void  printblk(struct fs *, ufs_lbn_t, ufs2_daddr_t, int, ufs_lbn_t);
45 static void  indirprt(struct uufsd *, int, ufs_lbn_t, ufs_lbn_t, ufs2_daddr_t,
46 		ufs_lbn_t);
47 
48 void
49 prtblknos(disk, dp)
50 	struct uufsd *disk;
51 	union dinode *dp;
52 {
53 	int i, mode, frags;
54 	ufs_lbn_t lbn, lastlbn, len, blksperindir;
55 	ufs2_daddr_t blkno;
56 	struct fs *fs;
57 	off_t size;
58 
59 	fs = (struct fs *)&disk->d_sb;
60 	if (fs->fs_magic == FS_UFS1_MAGIC) {
61 		size = dp->dp1.di_size;
62 		mode = dp->dp1.di_mode;
63 	} else {
64 		size = dp->dp2.di_size;
65 		mode = dp->dp2.di_mode;
66 	}
67 	switch (mode & IFMT) {
68 	default:
69 		printf("unknown inode type 0%d\n", (mode & IFMT));
70 		return;
71 	case 0:
72 		printf("unallocated inode\n");
73 		return;
74 	case IFIFO:
75 		printf("fifo\n");
76 		return;
77 	case IFCHR:
78 		printf("character device\n");
79 		return;
80 	case IFBLK:
81 		printf("block device\n");
82 		return;
83 	case IFSOCK:
84 		printf("socket\n");
85 		return;
86 	case IFWHT:
87 		printf("whiteout\n");
88 		return;
89 	case IFLNK:
90 		if (size == 0) {
91 			printf("empty symbolic link\n");
92 			return;
93 		}
94 		if (size < fs->fs_maxsymlinklen) {
95 			printf("symbolic link referencing %s\n",
96 			    (fs->fs_magic == FS_UFS1_MAGIC) ?
97 			    (char *)dp->dp1.di_db :
98 			    (char *)dp->dp2.di_db);
99 			return;
100 		}
101 		printf("symbolic link\n");
102 		break;
103 	case IFREG:
104 		if (size == 0) {
105 			printf("empty file\n");
106 			return;
107 		}
108 		printf("regular file, size %jd\n", (intmax_t)size);
109 		break;
110 	case IFDIR:
111 		if (size == 0) {
112 			printf("empty directory\n");
113 			return;
114 		}
115 		printf("directory, size %jd\n", (intmax_t)size);
116 		break;
117 	}
118 	lastlbn = howmany(size, fs->fs_bsize);
119 	len = lastlbn < UFS_NDADDR ? lastlbn : UFS_NDADDR;
120 	for (i = 0; i < len; i++) {
121 		if (i < lastlbn - 1)
122 			frags = fs->fs_frag;
123 		else
124 			frags = howmany(size - (lastlbn - 1) * fs->fs_bsize,
125 					  fs->fs_fsize);
126 		if (fs->fs_magic == FS_UFS1_MAGIC)
127 			blkno = dp->dp1.di_db[i];
128 		else
129 			blkno = dp->dp2.di_db[i];
130 		printblk(fs, i, blkno, frags, lastlbn);
131 	}
132 
133 	blksperindir = 1;
134 	len = lastlbn - UFS_NDADDR;
135 	lbn = UFS_NDADDR;
136 	for (i = 0; len > 0 && i < UFS_NIADDR; i++) {
137 		if (fs->fs_magic == FS_UFS1_MAGIC)
138 			blkno = dp->dp1.di_ib[i];
139 		else
140 			blkno = dp->dp2.di_ib[i];
141 		indirprt(disk, i, blksperindir, lbn, blkno, lastlbn);
142 		blksperindir *= NINDIR(fs);
143 		lbn += blksperindir;
144 		len -= blksperindir;
145 	}
146 
147 	/* dummy print to flush out last extent */
148 	printblk(fs, lastlbn, 0, frags, 0);
149 }
150 
151 static void
152 indirprt(disk, level, blksperindir, lbn, blkno, lastlbn)
153 	struct uufsd *disk;
154 	int level;
155 	ufs_lbn_t blksperindir;
156 	ufs_lbn_t lbn;
157 	ufs2_daddr_t blkno;
158 	ufs_lbn_t lastlbn;
159 {
160 	char indir[MAXBSIZE];
161 	struct fs *fs;
162 	ufs_lbn_t i, last;
163 
164 	fs = (struct fs *)&disk->d_sb;
165 	if (blkno == 0) {
166 		printblk(fs, lbn, blkno,
167 		    blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn);
168 		return;
169 	}
170 	printblk(fs, lbn, blkno, fs->fs_frag, -level);
171 	/* read in the indirect block. */
172 	if (bread(disk, fsbtodb(fs, blkno), indir, fs->fs_bsize) == -1) {
173 		warn("Read of indirect block %jd failed", (intmax_t)blkno);
174 		/* List the unreadable part as a hole */
175 		printblk(fs, lbn, 0,
176 		    blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn);
177 		return;
178 	}
179 	last = howmany(lastlbn - lbn, blksperindir) < NINDIR(fs) ?
180 	    howmany(lastlbn - lbn, blksperindir) : NINDIR(fs);
181 	if (blksperindir == 1) {
182 		for (i = 0; i < last; i++) {
183 			if (fs->fs_magic == FS_UFS1_MAGIC)
184 				blkno = ((ufs1_daddr_t *)indir)[i];
185 			else
186 				blkno = ((ufs2_daddr_t *)indir)[i];
187 			printblk(fs, lbn + i, blkno, fs->fs_frag, lastlbn);
188 		}
189 		return;
190 	}
191 	for (i = 0; i < last; i++) {
192 		if (fs->fs_magic == FS_UFS1_MAGIC)
193 			blkno = ((ufs1_daddr_t *)indir)[i];
194 		else
195 			blkno = ((ufs2_daddr_t *)indir)[i];
196 		indirprt(disk, level - 1, blksperindir / NINDIR(fs),
197 		    lbn + blksperindir * i, blkno, lastlbn);
198 	}
199 }
200 
201 static const char *
202 distance(fs, lastblk, firstblk)
203 	struct fs *fs;
204 	ufs2_daddr_t lastblk;
205 	ufs2_daddr_t firstblk;
206 {
207 	ufs2_daddr_t delta;
208 	int firstcg, lastcg;
209 	static char buf[100];
210 
211 	if (lastblk == 0)
212 		return ("");
213 	delta = firstblk - lastblk - 1;
214 	firstcg = dtog(fs, firstblk);
215 	lastcg = dtog(fs, lastblk);
216 	if (firstcg == lastcg) {
217 		snprintf(buf, 100, " distance %jd", (intmax_t)delta);
218 		return (&buf[0]);
219 	}
220 	snprintf(buf, 100, " cg %d blk %jd to cg %d blk %jd",
221 	    lastcg, (intmax_t)dtogd(fs, lastblk), firstcg,
222 	    (intmax_t)dtogd(fs, firstblk));
223 	return (&buf[0]);
224 }
225 
226 
227 static const char *indirname[UFS_NIADDR] = { "First", "Second", "Third" };
228 
229 static void
230 printblk(fs, lbn, blkno, numfrags, lastlbn)
231 	struct fs *fs;
232 	ufs_lbn_t lbn;
233 	ufs2_daddr_t blkno;
234 	int numfrags;
235 	ufs_lbn_t lastlbn;
236 {
237 	static int seq;
238 	static ufs2_daddr_t totfrags, lastindirblk, lastblk, firstblk;
239 
240 	if (lastlbn <= 0)
241 		goto flush;
242 	if (seq == 0) {
243 		seq = howmany(numfrags, fs->fs_frag);
244 		totfrags = numfrags;
245 		firstblk = blkno;
246 		return;
247 	}
248 	if (lbn == 0) {
249 		seq = howmany(numfrags, fs->fs_frag);
250 		totfrags = numfrags;
251 		lastblk = 0;
252 		firstblk = blkno;
253 		lastindirblk = 0;
254 		return;
255 	}
256 	if (lbn < lastlbn && ((firstblk == 0 && blkno == 0) ||
257 	    (firstblk == BLK_NOCOPY && blkno == BLK_NOCOPY) ||
258 	    (firstblk == BLK_SNAP && blkno == BLK_SNAP) ||
259 	    blkno == firstblk + seq * fs->fs_frag)) {
260 		seq += howmany(numfrags, fs->fs_frag);
261 		totfrags += numfrags;
262 		return;
263 	}
264 flush:
265 	if (seq == 0)
266 		goto prtindir;
267 	if (firstblk <= BLK_SNAP) {
268 		if (seq == 1)
269 			printf("\tlbn %jd %s\n", (intmax_t)(lbn - seq),
270 			    firstblk == 0 ? "hole" :
271 			    firstblk == BLK_NOCOPY ? "nocopy" :
272 			    "snapblk");
273 		else
274 			printf("\tlbn %jd-%jd %s\n",
275 			    (intmax_t)lbn - seq, (intmax_t)lbn - 1,
276 			    firstblk == 0 ? "hole" :
277 			    firstblk == BLK_NOCOPY ? "nocopy" :
278 			    "snapblk");
279 	} else if (seq == 1) {
280 		if (totfrags == 1)
281 			printf("\tlbn %jd blkno %jd%s\n", (intmax_t)(lbn - seq),
282 			   (intmax_t)firstblk, distance(fs, lastblk, firstblk));
283 		else
284 			printf("\tlbn %jd blkno %jd-%jd%s\n",
285 			    (intmax_t)(lbn - seq), (intmax_t)firstblk,
286 			    (intmax_t)(firstblk + totfrags - 1),
287 			    distance(fs, lastblk, firstblk));
288 		lastblk = firstblk + totfrags - 1;
289 	} else {
290 		printf("\tlbn %jd-%jd blkno %jd-%jd%s\n", (intmax_t)(lbn - seq),
291 		    (intmax_t)(lbn - 1), (intmax_t)firstblk,
292 		    (intmax_t)(firstblk + totfrags - 1),
293 		    distance(fs, lastblk, firstblk));
294 		lastblk = firstblk + totfrags - 1;
295 	}
296 	if (lastlbn > 0 || blkno == 0) {
297 		seq = 1;
298 		totfrags = numfrags;
299 		firstblk = blkno;
300 		return;
301 	}
302 prtindir:
303 	if (seq != 0 && (fs->fs_metaspace == 0 || lastindirblk == 0))
304 		lastindirblk = lastblk;
305 	printf("%s-level indirect, blkno %jd-%jd%s\n", indirname[-lastlbn],
306 	    (intmax_t)blkno, (intmax_t)(blkno + numfrags - 1),
307 	    distance(fs, lastindirblk, blkno));
308 	lastindirblk = blkno + numfrags - 1;
309 	if (fs->fs_metaspace == 0)
310 		lastblk = lastindirblk;
311 	seq = 0;
312 }
313