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
36union dinode {
37	struct ufs1_dinode dp1;
38	struct ufs2_dinode dp2;
39};
40
41void prtblknos(struct uufsd *disk, union dinode *dp);
42
43static const char *distance(struct fs *, ufs2_daddr_t, ufs2_daddr_t);
44static void  printblk(struct fs *, ufs_lbn_t, ufs2_daddr_t, int, ufs_lbn_t);
45static void  indirprt(struct uufsd *, int, ufs_lbn_t, ufs_lbn_t, ufs2_daddr_t,
46		ufs_lbn_t);
47
48void
49prtblknos(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
151static void
152indirprt(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
201static const char *
202distance(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
227static const char *indirname[UFS_NIADDR] = { "First", "Second", "Third" };
228
229static void
230printblk(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	}
264flush:
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	}
302prtindir:
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