xref: /freebsd/tools/diag/prtblknos/prtblknos.c (revision 52f72944b8f5abb2386eae924357dee8aea17d5b)
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 <sys/disklabel.h>
31 #include <sys/time.h>
32 
33 #include <ufs/ufs/dinode.h>
34 #include <ufs/ffs/fs.h>
35 
36 #include <err.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include <stdint.h>
43 #include <unistd.h>
44 
45 union dinode {
46 	struct ufs1_dinode *dp1;
47 	struct ufs2_dinode *dp2;
48 };
49 struct fs *sbp;
50 char *fsname;
51 int fd;
52 
53 void indirprt(int level, int blksperindir, int lbn, ufs2_daddr_t blkno,
54 	int lastlbn);
55 void printblk(int lbn, ufs2_daddr_t blkno, int numblks, int lastlbn);
56 
57 /*
58  * Possible superblock locations ordered from most to least likely.
59  */
60 static int sblock_try[] = SBLOCKSEARCH;
61 
62 int
63 main(argc, argv)
64 	int argc;
65 	char *argv[];
66 {
67 	int i, len, lbn, frags, inonum, numblks, blksperindir;
68 	char sblock[SBLOCKSIZE], ibuf[MAXBSIZE];
69 	ufs2_daddr_t blkno;
70 	off_t size, offset;
71 	union dinode dp;
72 
73 	if (argc < 3) {
74 		(void)fprintf(stderr,"usage: prtblknos filesystem inode ...\n");
75 		exit(1);
76 	}
77 
78 	fsname = *++argv;
79 
80 	/* get the superblock. */
81 	if ((fd = open(fsname, O_RDONLY, 0)) < 0)
82 		err(1, "%s", fsname);
83 	for (i = 0; sblock_try[i] != -1; i++) {
84 		if (lseek(fd, sblock_try[i], SEEK_SET) < 0)
85 			err(1, "lseek: %s", fsname);
86 		if (read(fd, sblock, (long)SBLOCKSIZE) != SBLOCKSIZE)
87 			err(1, "can't read superblock: %s", fsname);
88 		sbp = (struct fs *)sblock;
89 		if ((sbp->fs_magic == FS_UFS1_MAGIC ||
90 		     (sbp->fs_magic == FS_UFS2_MAGIC &&
91 		      sbp->fs_sblockloc == sblock_try[i])) &&
92 		    sbp->fs_bsize <= MAXBSIZE &&
93 		    sbp->fs_bsize >= sizeof(struct fs))
94 			break;
95 	}
96 	if (sblock_try[i] == -1)
97 		errx(1, "Cannot find file system superblock\n");
98 
99 	/* remaining arguments are inode numbers. */
100 	while (*++argv) {
101 		/* get the inode number. */
102 		if ((inonum = atoi(*argv)) <= 0)
103 			errx(1, "%s is not a valid inode number", *argv);
104 		(void)printf("%d:", inonum);
105 
106 		/* read in the appropriate block. */
107 		offset = ino_to_fsba(sbp, inonum);	/* inode to fs blk */
108 		offset = fsbtodb(sbp, offset);		/* fs blk disk blk */
109 		offset *= DEV_BSIZE;			/* disk blk to bytes */
110 
111 		/* seek and read the block */
112 		if (lseek(fd, offset, SEEK_SET) < 0)
113 			err(1, "%s", fsname);
114 		if (read(fd, ibuf, sbp->fs_bsize) != sbp->fs_bsize)
115 			err(1, "%s", fsname);
116 
117 		/* get the inode within the block. */
118 		if (sbp->fs_magic == FS_UFS1_MAGIC) {
119 			dp.dp1 = &((struct ufs1_dinode *)(ibuf))
120 			    [ino_to_fsbo(sbp, inonum)];
121 			size = dp.dp1->di_size;
122 		} else {
123 			dp.dp2 = &((struct ufs2_dinode *)(ibuf))
124 			    [ino_to_fsbo(sbp, inonum)];
125 			size = dp.dp2->di_size;
126 		}
127 
128 		numblks = howmany(size, sbp->fs_bsize);
129 		if (numblks == 0) {
130 			printf(" empty file\n");
131 			continue;
132 		}
133 		len = numblks < UFS_NDADDR ? numblks : UFS_NDADDR;
134 		for (i = 0; i < len; i++) {
135 			if (i < numblks - 1)
136 				frags = sbp->fs_frag;
137 			else
138 				frags = howmany(size % sbp->fs_bsize,
139 						  sbp->fs_fsize);
140 			if (sbp->fs_magic == FS_UFS1_MAGIC)
141 				blkno = dp.dp1->di_db[i];
142 			else
143 				blkno = dp.dp2->di_db[i];
144 			printblk(i, blkno, frags, numblks);
145 		}
146 
147 		blksperindir = 1;
148 		len = numblks - UFS_NDADDR;
149 		lbn = UFS_NDADDR;
150 		for (i = 0; len > 0 && i < UFS_NIADDR; i++) {
151 			if (sbp->fs_magic == FS_UFS1_MAGIC)
152 				blkno = dp.dp1->di_ib[i];
153 			else
154 				blkno = dp.dp2->di_ib[i];
155 			indirprt(i, blksperindir, lbn, blkno, numblks);
156 			blksperindir *= NINDIR(sbp);
157 			lbn += blksperindir;
158 			len -= blksperindir;
159 		}
160 
161 		/* dummy print to flush out last extent */
162 		printblk(numblks, 0, frags, 0);
163 	}
164 	(void)close(fd);
165 	exit(0);
166 }
167 
168 void
169 indirprt(level, blksperindir, lbn, blkno, lastlbn)
170 	int level;
171 	int blksperindir;
172 	int lbn;
173 	ufs2_daddr_t blkno;
174 	int lastlbn;
175 {
176 	char indir[MAXBSIZE];
177 	off_t offset;
178 	int i, last;
179 
180 	printblk(lbn, blkno, sbp->fs_frag, -level);
181 	/* read in the indirect block. */
182 	offset = fsbtodb(sbp, blkno);		/* fs blk disk blk */
183 	offset *= DEV_BSIZE;			/* disk blk to bytes */
184 	if (lseek(fd, offset, SEEK_SET) < 0)
185 		err(1, "%s", fsname);
186 	if (read(fd, indir, sbp->fs_bsize) != sbp->fs_bsize)
187 		err(1, "%s", fsname);
188 	last = howmany(lastlbn - lbn, blksperindir) < NINDIR(sbp) ?
189 	    howmany(lastlbn - lbn, blksperindir) : NINDIR(sbp);
190 	if (blksperindir == 1) {
191 		for (i = 0; i < last; i++) {
192 			if (sbp->fs_magic == FS_UFS1_MAGIC)
193 				blkno = ((ufs1_daddr_t *)indir)[i];
194 			else
195 				blkno = ((ufs2_daddr_t *)indir)[i];
196 			printblk(lbn + i, blkno, sbp->fs_frag, lastlbn);
197 		}
198 		return;
199 	}
200 	for (i = 0; i < last; i++) {
201 		if (sbp->fs_magic == FS_UFS1_MAGIC)
202 			blkno = ((ufs1_daddr_t *)indir)[i];
203 		else
204 			blkno = ((ufs2_daddr_t *)indir)[i];
205 		indirprt(level - 1, blksperindir / NINDIR(sbp),
206 		    lbn + blksperindir * i, blkno, lastlbn);
207 	}
208 }
209 
210 char *
211 distance(lastblk, firstblk)
212 	daddr_t lastblk;
213 	daddr_t firstblk;
214 {
215 	daddr_t delta;
216 	int firstcg, lastcg;
217 	static char buf[100];
218 
219 	if (lastblk == 0)
220 		return ("");
221 	delta = firstblk - lastblk - 1;
222 	firstcg = dtog(sbp, firstblk);
223 	lastcg = dtog(sbp, lastblk);
224 	if (firstcg == lastcg) {
225 		snprintf(buf, 100, " distance %jd", (intmax_t)delta);
226 		return (&buf[0]);
227 	}
228 	snprintf(buf, 100, " cg %d blk %jd to cg %d blk %jd",
229 	    lastcg, dtogd(sbp, lastblk), firstcg, dtogd(sbp, firstblk));
230 	return (&buf[0]);
231 }
232 
233 
234 char *indirname[UFS_NIADDR] = { "First", "Second", "Third" };
235 
236 void
237 printblk(lbn, blkno, numblks, lastlbn)
238 	int lbn;
239 	ufs2_daddr_t blkno;
240 	int numblks;
241 	int lastlbn;
242 {
243 	static int seq;
244 	static daddr_t lastindirblk, lastblk, firstblk;
245 
246 	if (lastlbn <= 0)
247 		goto flush;
248 	if (seq == 0) {
249 		seq = 1;
250 		firstblk = blkno;
251 		return;
252 	}
253 	if (lbn == 0) {
254 		seq = 1;
255 		lastblk = 0;
256 		firstblk = blkno;
257 		lastindirblk = 0;
258 		return;
259 	}
260 	if (lbn < lastlbn && ((firstblk == 0 && blkno == 0) ||
261 	    (firstblk == BLK_NOCOPY && blkno == BLK_NOCOPY) ||
262 	    (firstblk == BLK_SNAP && blkno == BLK_SNAP) ||
263 	    blkno == firstblk + seq * numblks)) {
264 		seq++;
265 		return;
266 	}
267 flush:
268 	if (seq == 0)
269 		goto prtindir;
270 	if (firstblk <= BLK_SNAP) {
271 		if (seq == 1)
272 			printf("\tlbn %d %s\n", lbn - seq,
273 			    firstblk == 0 ? "hole" :
274 			    firstblk == BLK_NOCOPY ? "nocopy" :
275 			    "snapblk");
276 		else
277 			printf("\tlbn %d-%d %s\n",
278 			    lbn - seq, lbn - 1,
279 			    firstblk == 0 ? "hole" :
280 			    firstblk == BLK_NOCOPY ? "nocopy" :
281 			    "snapblk");
282 	} else if (seq == 1) {
283 		if (numblks == 1)
284 			printf("\tlbn %d blkno %jd%s\n", lbn - seq,
285 			    (intmax_t)firstblk, distance(lastblk, firstblk));
286 		else
287 			printf("\tlbn %d blkno %jd-%jd%s\n", lbn - seq,
288 			    (intmax_t)firstblk,
289 			    (intmax_t)(firstblk + numblks - 1),
290 			    distance(lastblk, firstblk));
291 		lastblk = firstblk + numblks - 1;
292 	} else {
293 		printf("\tlbn %d-%d blkno %jd-%jd%s\n", lbn - seq, lbn - 1,
294 		    (intmax_t)firstblk, (intmax_t)(firstblk +
295 		    (seq - 1) * sbp->fs_frag + numblks - 1),
296 		    distance(lastblk, firstblk));
297 		lastblk = firstblk + (seq - 1) * sbp->fs_frag + numblks - 1;
298 	}
299 	if (lastlbn > 0 || blkno == 0) {
300 		seq = 1;
301 		firstblk = blkno;
302 		return;
303 	}
304 prtindir:
305 	if (seq != 0 && (sbp->fs_metaspace == 0 || lastindirblk == 0))
306 		lastindirblk = lastblk;
307 	printf("%s-level indirect, blkno %jd-%jd%s\n", indirname[-lastlbn],
308 	    (intmax_t)blkno, (intmax_t)(blkno + numblks - 1),
309 	    distance(lastindirblk, blkno));
310 	lastindirblk = blkno + numblks - 1;
311 	if (sbp->fs_metaspace == 0)
312 		lastblk = lastindirblk;
313 	seq = 0;
314 }
315