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 * $FreeBSD$ 2716c0c8eeSKirk McKusick */ 2816c0c8eeSKirk McKusick 2916c0c8eeSKirk McKusick #include <sys/param.h> 3016c0c8eeSKirk McKusick #include <ufs/ffs/fs.h> 3116c0c8eeSKirk McKusick 3216c0c8eeSKirk McKusick #include <err.h> 3316c0c8eeSKirk McKusick #include <stdio.h> 340e3f58b6SKirk McKusick #include <libufs.h> 3516c0c8eeSKirk McKusick 3616c0c8eeSKirk McKusick union dinode { 370e3f58b6SKirk McKusick struct ufs1_dinode dp1; 380e3f58b6SKirk McKusick struct ufs2_dinode dp2; 3916c0c8eeSKirk McKusick }; 4016c0c8eeSKirk McKusick 410e3f58b6SKirk McKusick void prtblknos(struct uufsd *disk, union dinode *dp); 4216c0c8eeSKirk McKusick 43d3009da8SKirk McKusick static const char *distance(struct fs *, ufs2_daddr_t, ufs2_daddr_t); 44d3009da8SKirk McKusick static void printblk(struct fs *, ufs_lbn_t, ufs2_daddr_t, int, ufs_lbn_t); 45d3009da8SKirk McKusick static void indirprt(struct uufsd *, int, ufs_lbn_t, ufs_lbn_t, ufs2_daddr_t, 46d3009da8SKirk McKusick ufs_lbn_t); 4716c0c8eeSKirk McKusick 480e3f58b6SKirk McKusick void 490e3f58b6SKirk McKusick prtblknos(disk, dp) 500e3f58b6SKirk McKusick struct uufsd *disk; 510e3f58b6SKirk McKusick union dinode *dp; 5216c0c8eeSKirk McKusick { 53d3009da8SKirk McKusick int i, mode, frags; 54d3009da8SKirk McKusick ufs_lbn_t lbn, lastlbn, len, blksperindir; 5516c0c8eeSKirk McKusick ufs2_daddr_t blkno; 560e3f58b6SKirk McKusick struct fs *fs; 570e3f58b6SKirk McKusick off_t size; 5816c0c8eeSKirk McKusick 590e3f58b6SKirk McKusick fs = (struct fs *)&disk->d_sb; 6015e4030eSKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) { 610e3f58b6SKirk McKusick size = dp->dp1.di_size; 6215e4030eSKirk McKusick mode = dp->dp1.di_mode; 6315e4030eSKirk McKusick } else { 640e3f58b6SKirk McKusick size = dp->dp2.di_size; 6515e4030eSKirk McKusick mode = dp->dp2.di_mode; 6615e4030eSKirk McKusick } 6715e4030eSKirk McKusick switch (mode & IFMT) { 68d3009da8SKirk McKusick default: 69d3009da8SKirk McKusick printf("unknown inode type 0%d\n", (mode & IFMT)); 70d3009da8SKirk McKusick return; 71d3009da8SKirk McKusick case 0: 72d3009da8SKirk McKusick printf("unallocated inode\n"); 73d3009da8SKirk McKusick return; 7415e4030eSKirk McKusick case IFIFO: 7515e4030eSKirk McKusick printf("fifo\n"); 7615e4030eSKirk McKusick return; 7715e4030eSKirk McKusick case IFCHR: 7815e4030eSKirk McKusick printf("character device\n"); 7915e4030eSKirk McKusick return; 8015e4030eSKirk McKusick case IFBLK: 8115e4030eSKirk McKusick printf("block device\n"); 8215e4030eSKirk McKusick return; 8315e4030eSKirk McKusick case IFSOCK: 8415e4030eSKirk McKusick printf("socket\n"); 8515e4030eSKirk McKusick return; 8615e4030eSKirk McKusick case IFWHT: 8715e4030eSKirk McKusick printf("whiteout\n"); 8815e4030eSKirk McKusick return; 8915e4030eSKirk McKusick case IFLNK: 9015e4030eSKirk McKusick if (size == 0) { 9115e4030eSKirk McKusick printf("empty symbolic link\n"); 9215e4030eSKirk McKusick return; 9315e4030eSKirk McKusick } 9415e4030eSKirk McKusick if (size < fs->fs_maxsymlinklen) { 9515e4030eSKirk McKusick printf("symbolic link referencing %s\n", 9615e4030eSKirk McKusick (fs->fs_magic == FS_UFS1_MAGIC) ? 9715e4030eSKirk McKusick (char *)dp->dp1.di_db : 9815e4030eSKirk McKusick (char *)dp->dp2.di_db); 9915e4030eSKirk McKusick return; 10015e4030eSKirk McKusick } 10115e4030eSKirk McKusick printf("symbolic link\n"); 10215e4030eSKirk McKusick break; 10315e4030eSKirk McKusick case IFREG: 10415e4030eSKirk McKusick if (size == 0) { 10516c0c8eeSKirk McKusick printf("empty file\n"); 1060e3f58b6SKirk McKusick return; 10716c0c8eeSKirk McKusick } 108d3009da8SKirk McKusick printf("regular file, size %jd\n", (intmax_t)size); 10915e4030eSKirk McKusick break; 11015e4030eSKirk McKusick case IFDIR: 11115e4030eSKirk McKusick if (size == 0) { 11215e4030eSKirk McKusick printf("empty directory\n"); 11315e4030eSKirk McKusick return; 11415e4030eSKirk McKusick } 115d3009da8SKirk McKusick printf("directory, size %jd\n", (intmax_t)size); 11615e4030eSKirk McKusick break; 11715e4030eSKirk McKusick } 118d3009da8SKirk McKusick lastlbn = howmany(size, fs->fs_bsize); 119d3009da8SKirk McKusick len = lastlbn < UFS_NDADDR ? lastlbn : UFS_NDADDR; 12016c0c8eeSKirk McKusick for (i = 0; i < len; i++) { 121d3009da8SKirk McKusick if (i < lastlbn - 1) 1220e3f58b6SKirk McKusick frags = fs->fs_frag; 12316c0c8eeSKirk McKusick else 12428ac2238SKirk McKusick frags = howmany(size - (lastlbn - 1) * fs->fs_bsize, 1250e3f58b6SKirk McKusick fs->fs_fsize); 1260e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 1270e3f58b6SKirk McKusick blkno = dp->dp1.di_db[i]; 12816c0c8eeSKirk McKusick else 1290e3f58b6SKirk McKusick blkno = dp->dp2.di_db[i]; 130d3009da8SKirk McKusick printblk(fs, i, blkno, frags, lastlbn); 13116c0c8eeSKirk McKusick } 13216c0c8eeSKirk McKusick 13316c0c8eeSKirk McKusick blksperindir = 1; 134d3009da8SKirk McKusick len = lastlbn - UFS_NDADDR; 13516c0c8eeSKirk McKusick lbn = UFS_NDADDR; 13616c0c8eeSKirk McKusick for (i = 0; len > 0 && i < UFS_NIADDR; i++) { 1370e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 1380e3f58b6SKirk McKusick blkno = dp->dp1.di_ib[i]; 13916c0c8eeSKirk McKusick else 1400e3f58b6SKirk McKusick blkno = dp->dp2.di_ib[i]; 141d3009da8SKirk McKusick indirprt(disk, i, blksperindir, lbn, blkno, lastlbn); 1420e3f58b6SKirk McKusick blksperindir *= NINDIR(fs); 14316c0c8eeSKirk McKusick lbn += blksperindir; 14416c0c8eeSKirk McKusick len -= blksperindir; 14516c0c8eeSKirk McKusick } 14616c0c8eeSKirk McKusick 14716c0c8eeSKirk McKusick /* dummy print to flush out last extent */ 148d3009da8SKirk McKusick printblk(fs, lastlbn, 0, frags, 0); 14916c0c8eeSKirk McKusick } 15016c0c8eeSKirk McKusick 1510e3f58b6SKirk McKusick static void 1520e3f58b6SKirk McKusick indirprt(disk, level, blksperindir, lbn, blkno, lastlbn) 1530e3f58b6SKirk McKusick struct uufsd *disk; 15416c0c8eeSKirk McKusick int level; 155d3009da8SKirk McKusick ufs_lbn_t blksperindir; 156d3009da8SKirk McKusick ufs_lbn_t lbn; 15716c0c8eeSKirk McKusick ufs2_daddr_t blkno; 158d3009da8SKirk McKusick ufs_lbn_t lastlbn; 15916c0c8eeSKirk McKusick { 16016c0c8eeSKirk McKusick char indir[MAXBSIZE]; 1610e3f58b6SKirk McKusick struct fs *fs; 162d3009da8SKirk McKusick ufs_lbn_t i, last; 16316c0c8eeSKirk McKusick 1640e3f58b6SKirk McKusick fs = (struct fs *)&disk->d_sb; 16515e4030eSKirk McKusick if (blkno == 0) { 16615e4030eSKirk McKusick printblk(fs, lbn, blkno, 16715e4030eSKirk McKusick blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn); 16815e4030eSKirk McKusick return; 16915e4030eSKirk McKusick } 1700e3f58b6SKirk McKusick printblk(fs, lbn, blkno, fs->fs_frag, -level); 17116c0c8eeSKirk McKusick /* read in the indirect block. */ 172c343fa81SKirk McKusick if (bread(disk, fsbtodb(fs, blkno), indir, fs->fs_bsize) == -1) { 173c343fa81SKirk McKusick warn("Read of indirect block %jd failed", (intmax_t)blkno); 174c343fa81SKirk McKusick /* List the unreadable part as a hole */ 175c343fa81SKirk McKusick printblk(fs, lbn, 0, 176c343fa81SKirk McKusick blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn); 177c343fa81SKirk McKusick return; 178c343fa81SKirk McKusick } 1790e3f58b6SKirk McKusick last = howmany(lastlbn - lbn, blksperindir) < NINDIR(fs) ? 1800e3f58b6SKirk McKusick howmany(lastlbn - lbn, blksperindir) : NINDIR(fs); 18116c0c8eeSKirk McKusick if (blksperindir == 1) { 18216c0c8eeSKirk McKusick for (i = 0; i < last; i++) { 1830e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 18416c0c8eeSKirk McKusick blkno = ((ufs1_daddr_t *)indir)[i]; 18516c0c8eeSKirk McKusick else 18616c0c8eeSKirk McKusick blkno = ((ufs2_daddr_t *)indir)[i]; 1870e3f58b6SKirk McKusick printblk(fs, lbn + i, blkno, fs->fs_frag, lastlbn); 18816c0c8eeSKirk McKusick } 18916c0c8eeSKirk McKusick return; 19016c0c8eeSKirk McKusick } 19116c0c8eeSKirk McKusick for (i = 0; i < last; i++) { 1920e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 19316c0c8eeSKirk McKusick blkno = ((ufs1_daddr_t *)indir)[i]; 19416c0c8eeSKirk McKusick else 19516c0c8eeSKirk McKusick blkno = ((ufs2_daddr_t *)indir)[i]; 1960e3f58b6SKirk McKusick indirprt(disk, level - 1, blksperindir / NINDIR(fs), 19716c0c8eeSKirk McKusick lbn + blksperindir * i, blkno, lastlbn); 19816c0c8eeSKirk McKusick } 19916c0c8eeSKirk McKusick } 20016c0c8eeSKirk McKusick 201d3009da8SKirk McKusick static const char * 2020e3f58b6SKirk McKusick distance(fs, lastblk, firstblk) 2030e3f58b6SKirk McKusick struct fs *fs; 204d3009da8SKirk McKusick ufs2_daddr_t lastblk; 205d3009da8SKirk McKusick ufs2_daddr_t firstblk; 20616c0c8eeSKirk McKusick { 207d3009da8SKirk McKusick ufs2_daddr_t delta; 20816c0c8eeSKirk McKusick int firstcg, lastcg; 20916c0c8eeSKirk McKusick static char buf[100]; 21016c0c8eeSKirk McKusick 21116c0c8eeSKirk McKusick if (lastblk == 0) 21216c0c8eeSKirk McKusick return (""); 21316c0c8eeSKirk McKusick delta = firstblk - lastblk - 1; 2140e3f58b6SKirk McKusick firstcg = dtog(fs, firstblk); 2150e3f58b6SKirk McKusick lastcg = dtog(fs, lastblk); 21616c0c8eeSKirk McKusick if (firstcg == lastcg) { 21716c0c8eeSKirk McKusick snprintf(buf, 100, " distance %jd", (intmax_t)delta); 21816c0c8eeSKirk McKusick return (&buf[0]); 21916c0c8eeSKirk McKusick } 22016c0c8eeSKirk McKusick snprintf(buf, 100, " cg %d blk %jd to cg %d blk %jd", 221f33fbc18SKirk McKusick lastcg, (intmax_t)dtogd(fs, lastblk), firstcg, 222f33fbc18SKirk McKusick (intmax_t)dtogd(fs, firstblk)); 22316c0c8eeSKirk McKusick return (&buf[0]); 22416c0c8eeSKirk McKusick } 22516c0c8eeSKirk McKusick 22616c0c8eeSKirk McKusick 227d3009da8SKirk McKusick static const char *indirname[UFS_NIADDR] = { "First", "Second", "Third" }; 22816c0c8eeSKirk McKusick 2290e3f58b6SKirk McKusick static void 230d3009da8SKirk McKusick printblk(fs, lbn, blkno, numfrags, lastlbn) 2310e3f58b6SKirk McKusick struct fs *fs; 232d3009da8SKirk McKusick ufs_lbn_t lbn; 23316c0c8eeSKirk McKusick ufs2_daddr_t blkno; 234d3009da8SKirk McKusick int numfrags; 235d3009da8SKirk McKusick ufs_lbn_t lastlbn; 23616c0c8eeSKirk McKusick { 23716c0c8eeSKirk McKusick static int seq; 238d3009da8SKirk McKusick static ufs2_daddr_t totfrags, lastindirblk, lastblk, firstblk; 23916c0c8eeSKirk McKusick 24016c0c8eeSKirk McKusick if (lastlbn <= 0) 24116c0c8eeSKirk McKusick goto flush; 24216c0c8eeSKirk McKusick if (seq == 0) { 243d3009da8SKirk McKusick seq = howmany(numfrags, fs->fs_frag); 244d3009da8SKirk McKusick totfrags = numfrags; 24516c0c8eeSKirk McKusick firstblk = blkno; 24616c0c8eeSKirk McKusick return; 24716c0c8eeSKirk McKusick } 24816c0c8eeSKirk McKusick if (lbn == 0) { 249d3009da8SKirk McKusick seq = howmany(numfrags, fs->fs_frag); 250d3009da8SKirk McKusick totfrags = numfrags; 25116c0c8eeSKirk McKusick lastblk = 0; 25216c0c8eeSKirk McKusick firstblk = blkno; 25316c0c8eeSKirk McKusick lastindirblk = 0; 25416c0c8eeSKirk McKusick return; 25516c0c8eeSKirk McKusick } 25616c0c8eeSKirk McKusick if (lbn < lastlbn && ((firstblk == 0 && blkno == 0) || 25716c0c8eeSKirk McKusick (firstblk == BLK_NOCOPY && blkno == BLK_NOCOPY) || 25816c0c8eeSKirk McKusick (firstblk == BLK_SNAP && blkno == BLK_SNAP) || 25915e4030eSKirk McKusick blkno == firstblk + seq * fs->fs_frag)) { 260d3009da8SKirk McKusick seq += howmany(numfrags, fs->fs_frag); 261d3009da8SKirk McKusick totfrags += numfrags; 26216c0c8eeSKirk McKusick return; 26316c0c8eeSKirk McKusick } 26416c0c8eeSKirk McKusick flush: 26516c0c8eeSKirk McKusick if (seq == 0) 26616c0c8eeSKirk McKusick goto prtindir; 26716c0c8eeSKirk McKusick if (firstblk <= BLK_SNAP) { 26816c0c8eeSKirk McKusick if (seq == 1) 269d3009da8SKirk McKusick printf("\tlbn %jd %s\n", (intmax_t)(lbn - seq), 27016c0c8eeSKirk McKusick firstblk == 0 ? "hole" : 27116c0c8eeSKirk McKusick firstblk == BLK_NOCOPY ? "nocopy" : 27216c0c8eeSKirk McKusick "snapblk"); 27316c0c8eeSKirk McKusick else 274d3009da8SKirk McKusick printf("\tlbn %jd-%jd %s\n", 275d3009da8SKirk McKusick (intmax_t)lbn - seq, (intmax_t)lbn - 1, 27616c0c8eeSKirk McKusick firstblk == 0 ? "hole" : 27716c0c8eeSKirk McKusick firstblk == BLK_NOCOPY ? "nocopy" : 27816c0c8eeSKirk McKusick "snapblk"); 27916c0c8eeSKirk McKusick } else if (seq == 1) { 280d3009da8SKirk McKusick if (totfrags == 1) 281d3009da8SKirk McKusick printf("\tlbn %jd blkno %jd%s\n", (intmax_t)(lbn - seq), 2820e3f58b6SKirk McKusick (intmax_t)firstblk, distance(fs, lastblk, firstblk)); 28316c0c8eeSKirk McKusick else 284d3009da8SKirk McKusick printf("\tlbn %jd blkno %jd-%jd%s\n", 285d3009da8SKirk McKusick (intmax_t)(lbn - seq), (intmax_t)firstblk, 286d3009da8SKirk McKusick (intmax_t)(firstblk + totfrags - 1), 2870e3f58b6SKirk McKusick distance(fs, lastblk, firstblk)); 288d3009da8SKirk McKusick lastblk = firstblk + totfrags - 1; 28916c0c8eeSKirk McKusick } else { 290d3009da8SKirk McKusick printf("\tlbn %jd-%jd blkno %jd-%jd%s\n", (intmax_t)(lbn - seq), 291d3009da8SKirk McKusick (intmax_t)(lbn - 1), (intmax_t)firstblk, 292d3009da8SKirk McKusick (intmax_t)(firstblk + totfrags - 1), 2930e3f58b6SKirk McKusick distance(fs, lastblk, firstblk)); 294d3009da8SKirk McKusick lastblk = firstblk + totfrags - 1; 29516c0c8eeSKirk McKusick } 29616c0c8eeSKirk McKusick if (lastlbn > 0 || blkno == 0) { 29716c0c8eeSKirk McKusick seq = 1; 298d3009da8SKirk McKusick totfrags = numfrags; 29916c0c8eeSKirk McKusick firstblk = blkno; 30016c0c8eeSKirk McKusick return; 30116c0c8eeSKirk McKusick } 30216c0c8eeSKirk McKusick prtindir: 3030e3f58b6SKirk McKusick if (seq != 0 && (fs->fs_metaspace == 0 || lastindirblk == 0)) 30416c0c8eeSKirk McKusick lastindirblk = lastblk; 30516c0c8eeSKirk McKusick printf("%s-level indirect, blkno %jd-%jd%s\n", indirname[-lastlbn], 306d3009da8SKirk McKusick (intmax_t)blkno, (intmax_t)(blkno + numfrags - 1), 3070e3f58b6SKirk McKusick distance(fs, lastindirblk, blkno)); 308d3009da8SKirk McKusick lastindirblk = blkno + numfrags - 1; 3090e3f58b6SKirk McKusick if (fs->fs_metaspace == 0) 31016c0c8eeSKirk McKusick lastblk = lastindirblk; 31116c0c8eeSKirk McKusick seq = 0; 31216c0c8eeSKirk McKusick } 313