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