116c0c8eeSKirk McKusick /*
216c0c8eeSKirk McKusick * Copyright (c) 1998, 2003, 2013, 2018 Marshall Kirk McKusick.
316c0c8eeSKirk McKusick * All Rights Reserved.
416c0c8eeSKirk McKusick *
516c0c8eeSKirk McKusick * Redistribution and use in source and binary forms, with or without
616c0c8eeSKirk McKusick * modification, are permitted provided that the following conditions
716c0c8eeSKirk McKusick * are met:
816c0c8eeSKirk McKusick * 1. Redistributions of source code must retain the above copyright
916c0c8eeSKirk McKusick * notice, this list of conditions and the following disclaimer.
1016c0c8eeSKirk McKusick * 2. Redistributions in binary form must reproduce the above copyright
1116c0c8eeSKirk McKusick * notice, this list of conditions and the following disclaimer in the
1216c0c8eeSKirk McKusick * documentation and/or other materials provided with the distribution.
1316c0c8eeSKirk McKusick *
1416c0c8eeSKirk McKusick * THIS SOFTWARE IS PROVIDED BY MARSHALL KIRK MCKUSICK ``AS IS'' AND
1516c0c8eeSKirk McKusick * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1616c0c8eeSKirk McKusick * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1716c0c8eeSKirk McKusick * ARE DISCLAIMED. IN NO EVENT SHALL MARSHALL KIRK MCKUSICK BE LIABLE
1816c0c8eeSKirk McKusick * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1916c0c8eeSKirk McKusick * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2016c0c8eeSKirk McKusick * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2116c0c8eeSKirk McKusick * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2216c0c8eeSKirk McKusick * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2316c0c8eeSKirk McKusick * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2416c0c8eeSKirk McKusick * SUCH DAMAGE.
2516c0c8eeSKirk McKusick */
2616c0c8eeSKirk McKusick
2716c0c8eeSKirk McKusick #include <sys/param.h>
2816c0c8eeSKirk McKusick #include <ufs/ffs/fs.h>
2916c0c8eeSKirk McKusick
3016c0c8eeSKirk McKusick #include <err.h>
3116c0c8eeSKirk McKusick #include <stdio.h>
3268d7185bSKirk McKusick #include <string.h>
330e3f58b6SKirk McKusick #include <libufs.h>
3416c0c8eeSKirk McKusick
3568d7185bSKirk McKusick #ifdef PRTBLKNOS
3616c0c8eeSKirk McKusick union dinode {
370e3f58b6SKirk McKusick struct ufs1_dinode dp1;
380e3f58b6SKirk McKusick struct ufs2_dinode dp2;
3916c0c8eeSKirk McKusick };
4068d7185bSKirk McKusick extern struct uufsd disk;
4168d7185bSKirk McKusick #else /* used by fsdb */
4268d7185bSKirk McKusick #include <fsck.h>
4368d7185bSKirk McKusick static struct bufarea *bp;
4468d7185bSKirk McKusick #endif
4516c0c8eeSKirk McKusick
4668d7185bSKirk McKusick void prtblknos(struct fs *fs, union dinode *dp);
4716c0c8eeSKirk McKusick
48d3009da8SKirk McKusick static const char *distance(struct fs *, ufs2_daddr_t, ufs2_daddr_t);
49d3009da8SKirk McKusick static void printblk(struct fs *, ufs_lbn_t, ufs2_daddr_t, int, ufs_lbn_t);
5068d7185bSKirk McKusick static void indirprt(struct fs *, int, ufs_lbn_t, ufs_lbn_t, ufs2_daddr_t,
51d3009da8SKirk McKusick ufs_lbn_t);
5216c0c8eeSKirk McKusick
530e3f58b6SKirk McKusick void
prtblknos(struct fs * fs,union dinode * dp)54e5d0d1c5SKirk McKusick prtblknos(struct fs *fs, union dinode *dp)
5516c0c8eeSKirk McKusick {
56d3009da8SKirk McKusick int i, mode, frags;
57d3009da8SKirk McKusick ufs_lbn_t lbn, lastlbn, len, blksperindir;
5816c0c8eeSKirk McKusick ufs2_daddr_t blkno;
590e3f58b6SKirk McKusick off_t size;
6016c0c8eeSKirk McKusick
6115e4030eSKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) {
620e3f58b6SKirk McKusick size = dp->dp1.di_size;
6315e4030eSKirk McKusick mode = dp->dp1.di_mode;
6415e4030eSKirk McKusick } else {
650e3f58b6SKirk McKusick size = dp->dp2.di_size;
6615e4030eSKirk McKusick mode = dp->dp2.di_mode;
6715e4030eSKirk McKusick }
6815e4030eSKirk McKusick switch (mode & IFMT) {
69d3009da8SKirk McKusick default:
70d3009da8SKirk McKusick printf("unknown inode type 0%d\n", (mode & IFMT));
71d3009da8SKirk McKusick return;
72d3009da8SKirk McKusick case 0:
73d3009da8SKirk McKusick printf("unallocated inode\n");
74d3009da8SKirk McKusick return;
7515e4030eSKirk McKusick case IFIFO:
7615e4030eSKirk McKusick printf("fifo\n");
7715e4030eSKirk McKusick return;
7815e4030eSKirk McKusick case IFCHR:
7915e4030eSKirk McKusick printf("character device\n");
8015e4030eSKirk McKusick return;
8115e4030eSKirk McKusick case IFBLK:
8215e4030eSKirk McKusick printf("block device\n");
8315e4030eSKirk McKusick return;
8415e4030eSKirk McKusick case IFSOCK:
8515e4030eSKirk McKusick printf("socket\n");
8615e4030eSKirk McKusick return;
8715e4030eSKirk McKusick case IFWHT:
8815e4030eSKirk McKusick printf("whiteout\n");
8915e4030eSKirk McKusick return;
9015e4030eSKirk McKusick case IFLNK:
9115e4030eSKirk McKusick if (size == 0) {
9215e4030eSKirk McKusick printf("empty symbolic link\n");
9315e4030eSKirk McKusick return;
9415e4030eSKirk McKusick }
9515e4030eSKirk McKusick if (size < fs->fs_maxsymlinklen) {
9615e4030eSKirk McKusick printf("symbolic link referencing %s\n",
9715e4030eSKirk McKusick (fs->fs_magic == FS_UFS1_MAGIC) ?
985b13fa79SJessica Clarke dp->dp1.di_shortlink :
995b13fa79SJessica Clarke dp->dp2.di_shortlink);
10015e4030eSKirk McKusick return;
10115e4030eSKirk McKusick }
10215e4030eSKirk McKusick printf("symbolic link\n");
10315e4030eSKirk McKusick break;
10415e4030eSKirk McKusick case IFREG:
10515e4030eSKirk McKusick if (size == 0) {
10616c0c8eeSKirk McKusick printf("empty file\n");
1070e3f58b6SKirk McKusick return;
10816c0c8eeSKirk McKusick }
109d3009da8SKirk McKusick printf("regular file, size %jd\n", (intmax_t)size);
11015e4030eSKirk McKusick break;
11115e4030eSKirk McKusick case IFDIR:
11215e4030eSKirk McKusick if (size == 0) {
11315e4030eSKirk McKusick printf("empty directory\n");
11415e4030eSKirk McKusick return;
11515e4030eSKirk McKusick }
116d3009da8SKirk McKusick printf("directory, size %jd\n", (intmax_t)size);
11715e4030eSKirk McKusick break;
11815e4030eSKirk McKusick }
119d3009da8SKirk McKusick lastlbn = howmany(size, fs->fs_bsize);
120d3009da8SKirk McKusick len = lastlbn < UFS_NDADDR ? lastlbn : UFS_NDADDR;
12116c0c8eeSKirk McKusick for (i = 0; i < len; i++) {
122d3009da8SKirk McKusick if (i < lastlbn - 1)
1230e3f58b6SKirk McKusick frags = fs->fs_frag;
12416c0c8eeSKirk McKusick else
12528ac2238SKirk McKusick frags = howmany(size - (lastlbn - 1) * fs->fs_bsize,
1260e3f58b6SKirk McKusick fs->fs_fsize);
1270e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC)
1280e3f58b6SKirk McKusick blkno = dp->dp1.di_db[i];
12916c0c8eeSKirk McKusick else
1300e3f58b6SKirk McKusick blkno = dp->dp2.di_db[i];
131d3009da8SKirk McKusick printblk(fs, i, blkno, frags, lastlbn);
13216c0c8eeSKirk McKusick }
13316c0c8eeSKirk McKusick
13416c0c8eeSKirk McKusick blksperindir = 1;
135d3009da8SKirk McKusick len = lastlbn - UFS_NDADDR;
13616c0c8eeSKirk McKusick lbn = UFS_NDADDR;
13716c0c8eeSKirk McKusick for (i = 0; len > 0 && i < UFS_NIADDR; i++) {
1380e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC)
1390e3f58b6SKirk McKusick blkno = dp->dp1.di_ib[i];
14016c0c8eeSKirk McKusick else
1410e3f58b6SKirk McKusick blkno = dp->dp2.di_ib[i];
14268d7185bSKirk McKusick indirprt(fs, i, blksperindir, lbn, blkno, lastlbn);
1430e3f58b6SKirk McKusick blksperindir *= NINDIR(fs);
14416c0c8eeSKirk McKusick lbn += blksperindir;
14516c0c8eeSKirk McKusick len -= blksperindir;
14616c0c8eeSKirk McKusick }
14716c0c8eeSKirk McKusick
14816c0c8eeSKirk McKusick /* dummy print to flush out last extent */
149d3009da8SKirk McKusick printblk(fs, lastlbn, 0, frags, 0);
15016c0c8eeSKirk McKusick }
15116c0c8eeSKirk McKusick
1520e3f58b6SKirk McKusick static void
indirprt(struct fs * fs,int level,ufs_lbn_t blksperindir,ufs_lbn_t lbn,ufs2_daddr_t blkno,ufs_lbn_t lastlbn)153e5d0d1c5SKirk McKusick indirprt(struct fs *fs, int level, ufs_lbn_t blksperindir, ufs_lbn_t lbn,
154e5d0d1c5SKirk McKusick ufs2_daddr_t blkno, ufs_lbn_t lastlbn)
15516c0c8eeSKirk McKusick {
15616c0c8eeSKirk McKusick char indir[MAXBSIZE];
157d3009da8SKirk McKusick ufs_lbn_t i, last;
15816c0c8eeSKirk McKusick
15915e4030eSKirk McKusick if (blkno == 0) {
16015e4030eSKirk McKusick printblk(fs, lbn, blkno,
16115e4030eSKirk McKusick blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn);
16215e4030eSKirk McKusick return;
16315e4030eSKirk McKusick }
1640e3f58b6SKirk McKusick printblk(fs, lbn, blkno, fs->fs_frag, -level);
16516c0c8eeSKirk McKusick /* read in the indirect block. */
16668d7185bSKirk McKusick #ifdef PRTBLKNOS
16768d7185bSKirk McKusick if (bread(&disk, fsbtodb(fs, blkno), indir, fs->fs_bsize) == -1) {
16868d7185bSKirk McKusick #else /* used by fsdb */
16968d7185bSKirk McKusick bp = getdatablk(blkno, fs->fs_bsize, BT_LEVEL1 + level);
17068d7185bSKirk McKusick if (bp->b_errs == 0) {
17168d7185bSKirk McKusick memcpy(indir, bp->b_un.b_buf, fs->fs_bsize);
17268d7185bSKirk McKusick } else {
17368d7185bSKirk McKusick #endif
174c343fa81SKirk McKusick warn("Read of indirect block %jd failed", (intmax_t)blkno);
175c343fa81SKirk McKusick /* List the unreadable part as a hole */
176c343fa81SKirk McKusick printblk(fs, lbn, 0,
177c343fa81SKirk McKusick blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn);
178c343fa81SKirk McKusick return;
179c343fa81SKirk McKusick }
1800e3f58b6SKirk McKusick last = howmany(lastlbn - lbn, blksperindir) < NINDIR(fs) ?
1810e3f58b6SKirk McKusick howmany(lastlbn - lbn, blksperindir) : NINDIR(fs);
18216c0c8eeSKirk McKusick if (blksperindir == 1) {
18316c0c8eeSKirk McKusick for (i = 0; i < last; i++) {
1840e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC)
18516c0c8eeSKirk McKusick blkno = ((ufs1_daddr_t *)indir)[i];
18616c0c8eeSKirk McKusick else
18716c0c8eeSKirk McKusick blkno = ((ufs2_daddr_t *)indir)[i];
1880e3f58b6SKirk McKusick printblk(fs, lbn + i, blkno, fs->fs_frag, lastlbn);
18916c0c8eeSKirk McKusick }
19016c0c8eeSKirk McKusick return;
19116c0c8eeSKirk McKusick }
19216c0c8eeSKirk McKusick for (i = 0; i < last; i++) {
1930e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC)
19416c0c8eeSKirk McKusick blkno = ((ufs1_daddr_t *)indir)[i];
19516c0c8eeSKirk McKusick else
19616c0c8eeSKirk McKusick blkno = ((ufs2_daddr_t *)indir)[i];
19768d7185bSKirk McKusick indirprt(fs, level - 1, blksperindir / NINDIR(fs),
19816c0c8eeSKirk McKusick lbn + blksperindir * i, blkno, lastlbn);
19916c0c8eeSKirk McKusick }
20016c0c8eeSKirk McKusick }
20116c0c8eeSKirk McKusick
202d3009da8SKirk McKusick static const char *
203e5d0d1c5SKirk McKusick distance(struct fs *fs, ufs2_daddr_t lastblk, ufs2_daddr_t firstblk)
20416c0c8eeSKirk McKusick {
205d3009da8SKirk McKusick ufs2_daddr_t delta;
20616c0c8eeSKirk McKusick int firstcg, lastcg;
20716c0c8eeSKirk McKusick static char buf[100];
20816c0c8eeSKirk McKusick
20916c0c8eeSKirk McKusick if (lastblk == 0)
21016c0c8eeSKirk McKusick return ("");
21116c0c8eeSKirk McKusick delta = firstblk - lastblk - 1;
2120e3f58b6SKirk McKusick firstcg = dtog(fs, firstblk);
2130e3f58b6SKirk McKusick lastcg = dtog(fs, lastblk);
21416c0c8eeSKirk McKusick if (firstcg == lastcg) {
21516c0c8eeSKirk McKusick snprintf(buf, 100, " distance %jd", (intmax_t)delta);
21616c0c8eeSKirk McKusick return (&buf[0]);
21716c0c8eeSKirk McKusick }
21816c0c8eeSKirk McKusick snprintf(buf, 100, " cg %d blk %jd to cg %d blk %jd",
219f33fbc18SKirk McKusick lastcg, (intmax_t)dtogd(fs, lastblk), firstcg,
220f33fbc18SKirk McKusick (intmax_t)dtogd(fs, firstblk));
22116c0c8eeSKirk McKusick return (&buf[0]);
22216c0c8eeSKirk McKusick }
22316c0c8eeSKirk McKusick
22416c0c8eeSKirk McKusick
225d3009da8SKirk McKusick static const char *indirname[UFS_NIADDR] = { "First", "Second", "Third" };
22616c0c8eeSKirk McKusick
2270e3f58b6SKirk McKusick static void
228e5d0d1c5SKirk McKusick printblk(struct fs *fs, ufs_lbn_t lbn, ufs2_daddr_t blkno, int numfrags,
229e5d0d1c5SKirk McKusick ufs_lbn_t lastlbn)
23016c0c8eeSKirk McKusick {
23116c0c8eeSKirk McKusick static int seq;
232d3009da8SKirk McKusick static ufs2_daddr_t totfrags, lastindirblk, lastblk, firstblk;
23316c0c8eeSKirk McKusick
23416c0c8eeSKirk McKusick if (lastlbn <= 0)
23516c0c8eeSKirk McKusick goto flush;
23616c0c8eeSKirk McKusick if (seq == 0) {
237d3009da8SKirk McKusick seq = howmany(numfrags, fs->fs_frag);
238d3009da8SKirk McKusick totfrags = numfrags;
23916c0c8eeSKirk McKusick firstblk = blkno;
24016c0c8eeSKirk McKusick return;
24116c0c8eeSKirk McKusick }
24216c0c8eeSKirk McKusick if (lbn == 0) {
243d3009da8SKirk McKusick seq = howmany(numfrags, fs->fs_frag);
244d3009da8SKirk McKusick totfrags = numfrags;
24516c0c8eeSKirk McKusick lastblk = 0;
24616c0c8eeSKirk McKusick firstblk = blkno;
24716c0c8eeSKirk McKusick lastindirblk = 0;
24816c0c8eeSKirk McKusick return;
24916c0c8eeSKirk McKusick }
25016c0c8eeSKirk McKusick if (lbn < lastlbn && ((firstblk == 0 && blkno == 0) ||
25116c0c8eeSKirk McKusick (firstblk == BLK_NOCOPY && blkno == BLK_NOCOPY) ||
25216c0c8eeSKirk McKusick (firstblk == BLK_SNAP && blkno == BLK_SNAP) ||
25315e4030eSKirk McKusick blkno == firstblk + seq * fs->fs_frag)) {
254d3009da8SKirk McKusick seq += howmany(numfrags, fs->fs_frag);
255d3009da8SKirk McKusick totfrags += numfrags;
25616c0c8eeSKirk McKusick return;
25716c0c8eeSKirk McKusick }
25816c0c8eeSKirk McKusick flush:
25916c0c8eeSKirk McKusick if (seq == 0)
26016c0c8eeSKirk McKusick goto prtindir;
26116c0c8eeSKirk McKusick if (firstblk <= BLK_SNAP) {
26216c0c8eeSKirk McKusick if (seq == 1)
263d3009da8SKirk McKusick printf("\tlbn %jd %s\n", (intmax_t)(lbn - seq),
26416c0c8eeSKirk McKusick firstblk == 0 ? "hole" :
26516c0c8eeSKirk McKusick firstblk == BLK_NOCOPY ? "nocopy" :
26616c0c8eeSKirk McKusick "snapblk");
26716c0c8eeSKirk McKusick else
268d3009da8SKirk McKusick printf("\tlbn %jd-%jd %s\n",
269d3009da8SKirk McKusick (intmax_t)lbn - seq, (intmax_t)lbn - 1,
27016c0c8eeSKirk McKusick firstblk == 0 ? "hole" :
27116c0c8eeSKirk McKusick firstblk == BLK_NOCOPY ? "nocopy" :
27216c0c8eeSKirk McKusick "snapblk");
27316c0c8eeSKirk McKusick } else if (seq == 1) {
274d3009da8SKirk McKusick if (totfrags == 1)
275d3009da8SKirk McKusick printf("\tlbn %jd blkno %jd%s\n", (intmax_t)(lbn - seq),
2760e3f58b6SKirk McKusick (intmax_t)firstblk, distance(fs, lastblk, firstblk));
27716c0c8eeSKirk McKusick else
278d3009da8SKirk McKusick printf("\tlbn %jd blkno %jd-%jd%s\n",
279d3009da8SKirk McKusick (intmax_t)(lbn - seq), (intmax_t)firstblk,
280d3009da8SKirk McKusick (intmax_t)(firstblk + totfrags - 1),
2810e3f58b6SKirk McKusick distance(fs, lastblk, firstblk));
282d3009da8SKirk McKusick lastblk = firstblk + totfrags - 1;
28316c0c8eeSKirk McKusick } else {
284d3009da8SKirk McKusick printf("\tlbn %jd-%jd blkno %jd-%jd%s\n", (intmax_t)(lbn - seq),
285d3009da8SKirk McKusick (intmax_t)(lbn - 1), (intmax_t)firstblk,
286d3009da8SKirk McKusick (intmax_t)(firstblk + totfrags - 1),
2870e3f58b6SKirk McKusick distance(fs, lastblk, firstblk));
288d3009da8SKirk McKusick lastblk = firstblk + totfrags - 1;
28916c0c8eeSKirk McKusick }
29016c0c8eeSKirk McKusick if (lastlbn > 0 || blkno == 0) {
29116c0c8eeSKirk McKusick seq = 1;
292d3009da8SKirk McKusick totfrags = numfrags;
29316c0c8eeSKirk McKusick firstblk = blkno;
29416c0c8eeSKirk McKusick return;
29516c0c8eeSKirk McKusick }
29616c0c8eeSKirk McKusick prtindir:
2970e3f58b6SKirk McKusick if (seq != 0 && (fs->fs_metaspace == 0 || lastindirblk == 0))
29816c0c8eeSKirk McKusick lastindirblk = lastblk;
29916c0c8eeSKirk McKusick printf("%s-level indirect, blkno %jd-%jd%s\n", indirname[-lastlbn],
300d3009da8SKirk McKusick (intmax_t)blkno, (intmax_t)(blkno + numfrags - 1),
3010e3f58b6SKirk McKusick distance(fs, lastindirblk, blkno));
302d3009da8SKirk McKusick lastindirblk = blkno + numfrags - 1;
3030e3f58b6SKirk McKusick if (fs->fs_metaspace == 0)
30416c0c8eeSKirk McKusick lastblk = lastindirblk;
30516c0c8eeSKirk McKusick seq = 0;
30616c0c8eeSKirk McKusick }
307