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> 3468d7185bSKirk McKusick #include <string.h> 350e3f58b6SKirk McKusick #include <libufs.h> 3616c0c8eeSKirk McKusick 3768d7185bSKirk McKusick #ifdef PRTBLKNOS 3816c0c8eeSKirk McKusick union dinode { 390e3f58b6SKirk McKusick struct ufs1_dinode dp1; 400e3f58b6SKirk McKusick struct ufs2_dinode dp2; 4116c0c8eeSKirk McKusick }; 4268d7185bSKirk McKusick extern struct uufsd disk; 4368d7185bSKirk McKusick #else /* used by fsdb */ 4468d7185bSKirk McKusick #include <fsck.h> 4568d7185bSKirk McKusick static struct bufarea *bp; 4668d7185bSKirk McKusick #endif 4716c0c8eeSKirk McKusick 4868d7185bSKirk McKusick void prtblknos(struct fs *fs, union dinode *dp); 4916c0c8eeSKirk McKusick 50d3009da8SKirk McKusick static const char *distance(struct fs *, ufs2_daddr_t, ufs2_daddr_t); 51d3009da8SKirk McKusick static void printblk(struct fs *, ufs_lbn_t, ufs2_daddr_t, int, ufs_lbn_t); 5268d7185bSKirk McKusick static void indirprt(struct fs *, int, ufs_lbn_t, ufs_lbn_t, ufs2_daddr_t, 53d3009da8SKirk McKusick ufs_lbn_t); 5416c0c8eeSKirk McKusick 550e3f58b6SKirk McKusick void 56e5d0d1c5SKirk McKusick prtblknos(struct fs *fs, union dinode *dp) 5716c0c8eeSKirk McKusick { 58d3009da8SKirk McKusick int i, mode, frags; 59d3009da8SKirk McKusick ufs_lbn_t lbn, lastlbn, len, blksperindir; 6016c0c8eeSKirk McKusick ufs2_daddr_t blkno; 610e3f58b6SKirk McKusick off_t size; 6216c0c8eeSKirk McKusick 6315e4030eSKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) { 640e3f58b6SKirk McKusick size = dp->dp1.di_size; 6515e4030eSKirk McKusick mode = dp->dp1.di_mode; 6615e4030eSKirk McKusick } else { 670e3f58b6SKirk McKusick size = dp->dp2.di_size; 6815e4030eSKirk McKusick mode = dp->dp2.di_mode; 6915e4030eSKirk McKusick } 7015e4030eSKirk McKusick switch (mode & IFMT) { 71d3009da8SKirk McKusick default: 72d3009da8SKirk McKusick printf("unknown inode type 0%d\n", (mode & IFMT)); 73d3009da8SKirk McKusick return; 74d3009da8SKirk McKusick case 0: 75d3009da8SKirk McKusick printf("unallocated inode\n"); 76d3009da8SKirk McKusick return; 7715e4030eSKirk McKusick case IFIFO: 7815e4030eSKirk McKusick printf("fifo\n"); 7915e4030eSKirk McKusick return; 8015e4030eSKirk McKusick case IFCHR: 8115e4030eSKirk McKusick printf("character device\n"); 8215e4030eSKirk McKusick return; 8315e4030eSKirk McKusick case IFBLK: 8415e4030eSKirk McKusick printf("block device\n"); 8515e4030eSKirk McKusick return; 8615e4030eSKirk McKusick case IFSOCK: 8715e4030eSKirk McKusick printf("socket\n"); 8815e4030eSKirk McKusick return; 8915e4030eSKirk McKusick case IFWHT: 9015e4030eSKirk McKusick printf("whiteout\n"); 9115e4030eSKirk McKusick return; 9215e4030eSKirk McKusick case IFLNK: 9315e4030eSKirk McKusick if (size == 0) { 9415e4030eSKirk McKusick printf("empty symbolic link\n"); 9515e4030eSKirk McKusick return; 9615e4030eSKirk McKusick } 9715e4030eSKirk McKusick if (size < fs->fs_maxsymlinklen) { 9815e4030eSKirk McKusick printf("symbolic link referencing %s\n", 9915e4030eSKirk McKusick (fs->fs_magic == FS_UFS1_MAGIC) ? 1005b13fa79SJessica Clarke dp->dp1.di_shortlink : 1015b13fa79SJessica Clarke dp->dp2.di_shortlink); 10215e4030eSKirk McKusick return; 10315e4030eSKirk McKusick } 10415e4030eSKirk McKusick printf("symbolic link\n"); 10515e4030eSKirk McKusick break; 10615e4030eSKirk McKusick case IFREG: 10715e4030eSKirk McKusick if (size == 0) { 10816c0c8eeSKirk McKusick printf("empty file\n"); 1090e3f58b6SKirk McKusick return; 11016c0c8eeSKirk McKusick } 111d3009da8SKirk McKusick printf("regular file, size %jd\n", (intmax_t)size); 11215e4030eSKirk McKusick break; 11315e4030eSKirk McKusick case IFDIR: 11415e4030eSKirk McKusick if (size == 0) { 11515e4030eSKirk McKusick printf("empty directory\n"); 11615e4030eSKirk McKusick return; 11715e4030eSKirk McKusick } 118d3009da8SKirk McKusick printf("directory, size %jd\n", (intmax_t)size); 11915e4030eSKirk McKusick break; 12015e4030eSKirk McKusick } 121d3009da8SKirk McKusick lastlbn = howmany(size, fs->fs_bsize); 122d3009da8SKirk McKusick len = lastlbn < UFS_NDADDR ? lastlbn : UFS_NDADDR; 12316c0c8eeSKirk McKusick for (i = 0; i < len; i++) { 124d3009da8SKirk McKusick if (i < lastlbn - 1) 1250e3f58b6SKirk McKusick frags = fs->fs_frag; 12616c0c8eeSKirk McKusick else 12728ac2238SKirk McKusick frags = howmany(size - (lastlbn - 1) * fs->fs_bsize, 1280e3f58b6SKirk McKusick fs->fs_fsize); 1290e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 1300e3f58b6SKirk McKusick blkno = dp->dp1.di_db[i]; 13116c0c8eeSKirk McKusick else 1320e3f58b6SKirk McKusick blkno = dp->dp2.di_db[i]; 133d3009da8SKirk McKusick printblk(fs, i, blkno, frags, lastlbn); 13416c0c8eeSKirk McKusick } 13516c0c8eeSKirk McKusick 13616c0c8eeSKirk McKusick blksperindir = 1; 137d3009da8SKirk McKusick len = lastlbn - UFS_NDADDR; 13816c0c8eeSKirk McKusick lbn = UFS_NDADDR; 13916c0c8eeSKirk McKusick for (i = 0; len > 0 && i < UFS_NIADDR; i++) { 1400e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 1410e3f58b6SKirk McKusick blkno = dp->dp1.di_ib[i]; 14216c0c8eeSKirk McKusick else 1430e3f58b6SKirk McKusick blkno = dp->dp2.di_ib[i]; 14468d7185bSKirk McKusick indirprt(fs, i, blksperindir, lbn, blkno, lastlbn); 1450e3f58b6SKirk McKusick blksperindir *= NINDIR(fs); 14616c0c8eeSKirk McKusick lbn += blksperindir; 14716c0c8eeSKirk McKusick len -= blksperindir; 14816c0c8eeSKirk McKusick } 14916c0c8eeSKirk McKusick 15016c0c8eeSKirk McKusick /* dummy print to flush out last extent */ 151d3009da8SKirk McKusick printblk(fs, lastlbn, 0, frags, 0); 15216c0c8eeSKirk McKusick } 15316c0c8eeSKirk McKusick 1540e3f58b6SKirk McKusick static void 155e5d0d1c5SKirk McKusick indirprt(struct fs *fs, int level, ufs_lbn_t blksperindir, ufs_lbn_t lbn, 156e5d0d1c5SKirk McKusick ufs2_daddr_t blkno, ufs_lbn_t lastlbn) 15716c0c8eeSKirk McKusick { 15816c0c8eeSKirk McKusick char indir[MAXBSIZE]; 159d3009da8SKirk McKusick ufs_lbn_t i, last; 16016c0c8eeSKirk McKusick 16115e4030eSKirk McKusick if (blkno == 0) { 16215e4030eSKirk McKusick printblk(fs, lbn, blkno, 16315e4030eSKirk McKusick blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn); 16415e4030eSKirk McKusick return; 16515e4030eSKirk McKusick } 1660e3f58b6SKirk McKusick printblk(fs, lbn, blkno, fs->fs_frag, -level); 16716c0c8eeSKirk McKusick /* read in the indirect block. */ 16868d7185bSKirk McKusick #ifdef PRTBLKNOS 16968d7185bSKirk McKusick if (bread(&disk, fsbtodb(fs, blkno), indir, fs->fs_bsize) == -1) { 17068d7185bSKirk McKusick #else /* used by fsdb */ 17168d7185bSKirk McKusick bp = getdatablk(blkno, fs->fs_bsize, BT_LEVEL1 + level); 17268d7185bSKirk McKusick if (bp->b_errs == 0) { 17368d7185bSKirk McKusick memcpy(indir, bp->b_un.b_buf, fs->fs_bsize); 17468d7185bSKirk McKusick } else { 17568d7185bSKirk McKusick #endif 176c343fa81SKirk McKusick warn("Read of indirect block %jd failed", (intmax_t)blkno); 177c343fa81SKirk McKusick /* List the unreadable part as a hole */ 178c343fa81SKirk McKusick printblk(fs, lbn, 0, 179c343fa81SKirk McKusick blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn); 180c343fa81SKirk McKusick return; 181c343fa81SKirk McKusick } 1820e3f58b6SKirk McKusick last = howmany(lastlbn - lbn, blksperindir) < NINDIR(fs) ? 1830e3f58b6SKirk McKusick howmany(lastlbn - lbn, blksperindir) : NINDIR(fs); 18416c0c8eeSKirk McKusick if (blksperindir == 1) { 18516c0c8eeSKirk McKusick for (i = 0; i < last; i++) { 1860e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 18716c0c8eeSKirk McKusick blkno = ((ufs1_daddr_t *)indir)[i]; 18816c0c8eeSKirk McKusick else 18916c0c8eeSKirk McKusick blkno = ((ufs2_daddr_t *)indir)[i]; 1900e3f58b6SKirk McKusick printblk(fs, lbn + i, blkno, fs->fs_frag, lastlbn); 19116c0c8eeSKirk McKusick } 19216c0c8eeSKirk McKusick return; 19316c0c8eeSKirk McKusick } 19416c0c8eeSKirk McKusick for (i = 0; i < last; i++) { 1950e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 19616c0c8eeSKirk McKusick blkno = ((ufs1_daddr_t *)indir)[i]; 19716c0c8eeSKirk McKusick else 19816c0c8eeSKirk McKusick blkno = ((ufs2_daddr_t *)indir)[i]; 19968d7185bSKirk McKusick indirprt(fs, level - 1, blksperindir / NINDIR(fs), 20016c0c8eeSKirk McKusick lbn + blksperindir * i, blkno, lastlbn); 20116c0c8eeSKirk McKusick } 20216c0c8eeSKirk McKusick } 20316c0c8eeSKirk McKusick 204d3009da8SKirk McKusick static const char * 205e5d0d1c5SKirk McKusick distance(struct fs *fs, ufs2_daddr_t lastblk, 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 230e5d0d1c5SKirk McKusick printblk(struct fs *fs, ufs_lbn_t lbn, ufs2_daddr_t blkno, int numfrags, 231e5d0d1c5SKirk McKusick ufs_lbn_t lastlbn) 23216c0c8eeSKirk McKusick { 23316c0c8eeSKirk McKusick static int seq; 234d3009da8SKirk McKusick static ufs2_daddr_t totfrags, lastindirblk, lastblk, firstblk; 23516c0c8eeSKirk McKusick 23616c0c8eeSKirk McKusick if (lastlbn <= 0) 23716c0c8eeSKirk McKusick goto flush; 23816c0c8eeSKirk McKusick if (seq == 0) { 239d3009da8SKirk McKusick seq = howmany(numfrags, fs->fs_frag); 240d3009da8SKirk McKusick totfrags = numfrags; 24116c0c8eeSKirk McKusick firstblk = blkno; 24216c0c8eeSKirk McKusick return; 24316c0c8eeSKirk McKusick } 24416c0c8eeSKirk McKusick if (lbn == 0) { 245d3009da8SKirk McKusick seq = howmany(numfrags, fs->fs_frag); 246d3009da8SKirk McKusick totfrags = numfrags; 24716c0c8eeSKirk McKusick lastblk = 0; 24816c0c8eeSKirk McKusick firstblk = blkno; 24916c0c8eeSKirk McKusick lastindirblk = 0; 25016c0c8eeSKirk McKusick return; 25116c0c8eeSKirk McKusick } 25216c0c8eeSKirk McKusick if (lbn < lastlbn && ((firstblk == 0 && blkno == 0) || 25316c0c8eeSKirk McKusick (firstblk == BLK_NOCOPY && blkno == BLK_NOCOPY) || 25416c0c8eeSKirk McKusick (firstblk == BLK_SNAP && blkno == BLK_SNAP) || 25515e4030eSKirk McKusick blkno == firstblk + seq * fs->fs_frag)) { 256d3009da8SKirk McKusick seq += howmany(numfrags, fs->fs_frag); 257d3009da8SKirk McKusick totfrags += numfrags; 25816c0c8eeSKirk McKusick return; 25916c0c8eeSKirk McKusick } 26016c0c8eeSKirk McKusick flush: 26116c0c8eeSKirk McKusick if (seq == 0) 26216c0c8eeSKirk McKusick goto prtindir; 26316c0c8eeSKirk McKusick if (firstblk <= BLK_SNAP) { 26416c0c8eeSKirk McKusick if (seq == 1) 265d3009da8SKirk McKusick printf("\tlbn %jd %s\n", (intmax_t)(lbn - seq), 26616c0c8eeSKirk McKusick firstblk == 0 ? "hole" : 26716c0c8eeSKirk McKusick firstblk == BLK_NOCOPY ? "nocopy" : 26816c0c8eeSKirk McKusick "snapblk"); 26916c0c8eeSKirk McKusick else 270d3009da8SKirk McKusick printf("\tlbn %jd-%jd %s\n", 271d3009da8SKirk McKusick (intmax_t)lbn - seq, (intmax_t)lbn - 1, 27216c0c8eeSKirk McKusick firstblk == 0 ? "hole" : 27316c0c8eeSKirk McKusick firstblk == BLK_NOCOPY ? "nocopy" : 27416c0c8eeSKirk McKusick "snapblk"); 27516c0c8eeSKirk McKusick } else if (seq == 1) { 276d3009da8SKirk McKusick if (totfrags == 1) 277d3009da8SKirk McKusick printf("\tlbn %jd blkno %jd%s\n", (intmax_t)(lbn - seq), 2780e3f58b6SKirk McKusick (intmax_t)firstblk, distance(fs, lastblk, firstblk)); 27916c0c8eeSKirk McKusick else 280d3009da8SKirk McKusick printf("\tlbn %jd blkno %jd-%jd%s\n", 281d3009da8SKirk McKusick (intmax_t)(lbn - seq), (intmax_t)firstblk, 282d3009da8SKirk McKusick (intmax_t)(firstblk + totfrags - 1), 2830e3f58b6SKirk McKusick distance(fs, lastblk, firstblk)); 284d3009da8SKirk McKusick lastblk = firstblk + totfrags - 1; 28516c0c8eeSKirk McKusick } else { 286d3009da8SKirk McKusick printf("\tlbn %jd-%jd blkno %jd-%jd%s\n", (intmax_t)(lbn - seq), 287d3009da8SKirk McKusick (intmax_t)(lbn - 1), (intmax_t)firstblk, 288d3009da8SKirk McKusick (intmax_t)(firstblk + totfrags - 1), 2890e3f58b6SKirk McKusick distance(fs, lastblk, firstblk)); 290d3009da8SKirk McKusick lastblk = firstblk + totfrags - 1; 29116c0c8eeSKirk McKusick } 29216c0c8eeSKirk McKusick if (lastlbn > 0 || blkno == 0) { 29316c0c8eeSKirk McKusick seq = 1; 294d3009da8SKirk McKusick totfrags = numfrags; 29516c0c8eeSKirk McKusick firstblk = blkno; 29616c0c8eeSKirk McKusick return; 29716c0c8eeSKirk McKusick } 29816c0c8eeSKirk McKusick prtindir: 2990e3f58b6SKirk McKusick if (seq != 0 && (fs->fs_metaspace == 0 || lastindirblk == 0)) 30016c0c8eeSKirk McKusick lastindirblk = lastblk; 30116c0c8eeSKirk McKusick printf("%s-level indirect, blkno %jd-%jd%s\n", indirname[-lastlbn], 302d3009da8SKirk McKusick (intmax_t)blkno, (intmax_t)(blkno + numfrags - 1), 3030e3f58b6SKirk McKusick distance(fs, lastindirblk, blkno)); 304d3009da8SKirk McKusick lastindirblk = blkno + numfrags - 1; 3050e3f58b6SKirk McKusick if (fs->fs_metaspace == 0) 30616c0c8eeSKirk McKusick lastblk = lastindirblk; 30716c0c8eeSKirk McKusick seq = 0; 30816c0c8eeSKirk McKusick } 309