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 430e3f58b6SKirk McKusick static void indirprt(struct uufsd *, int, int, int, ufs2_daddr_t, int); 440e3f58b6SKirk McKusick static char *distance(struct fs *, daddr_t, daddr_t); 450e3f58b6SKirk McKusick static void printblk(struct fs *, int, ufs2_daddr_t, int, int); 4616c0c8eeSKirk McKusick 470e3f58b6SKirk McKusick void 480e3f58b6SKirk McKusick prtblknos(disk, dp) 490e3f58b6SKirk McKusick struct uufsd *disk; 500e3f58b6SKirk McKusick union dinode *dp; 5116c0c8eeSKirk McKusick { 5215e4030eSKirk McKusick int i, len, lbn, mode, frags, numblks, blksperindir; 5316c0c8eeSKirk McKusick ufs2_daddr_t blkno; 540e3f58b6SKirk McKusick struct fs *fs; 550e3f58b6SKirk McKusick off_t size; 5616c0c8eeSKirk McKusick 570e3f58b6SKirk McKusick fs = (struct fs *)&disk->d_sb; 5815e4030eSKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) { 590e3f58b6SKirk McKusick size = dp->dp1.di_size; 6015e4030eSKirk McKusick mode = dp->dp1.di_mode; 6115e4030eSKirk McKusick } else { 620e3f58b6SKirk McKusick size = dp->dp2.di_size; 6315e4030eSKirk McKusick mode = dp->dp2.di_mode; 6415e4030eSKirk McKusick } 6515e4030eSKirk McKusick switch (mode & IFMT) { 6615e4030eSKirk McKusick case IFIFO: 6715e4030eSKirk McKusick printf("fifo\n"); 6815e4030eSKirk McKusick return; 6915e4030eSKirk McKusick case IFCHR: 7015e4030eSKirk McKusick printf("character device\n"); 7115e4030eSKirk McKusick return; 7215e4030eSKirk McKusick case IFBLK: 7315e4030eSKirk McKusick printf("block device\n"); 7415e4030eSKirk McKusick return; 7515e4030eSKirk McKusick case IFSOCK: 7615e4030eSKirk McKusick printf("socket\n"); 7715e4030eSKirk McKusick return; 7815e4030eSKirk McKusick case IFWHT: 7915e4030eSKirk McKusick printf("whiteout\n"); 8015e4030eSKirk McKusick return; 8115e4030eSKirk McKusick case IFLNK: 8215e4030eSKirk McKusick if (size == 0) { 8315e4030eSKirk McKusick printf("empty symbolic link\n"); 8415e4030eSKirk McKusick return; 8515e4030eSKirk McKusick } 8615e4030eSKirk McKusick if (size < fs->fs_maxsymlinklen) { 8715e4030eSKirk McKusick printf("symbolic link referencing %s\n", 8815e4030eSKirk McKusick (fs->fs_magic == FS_UFS1_MAGIC) ? 8915e4030eSKirk McKusick (char *)dp->dp1.di_db : 9015e4030eSKirk McKusick (char *)dp->dp2.di_db); 9115e4030eSKirk McKusick return; 9215e4030eSKirk McKusick } 9315e4030eSKirk McKusick printf("symbolic link\n"); 9415e4030eSKirk McKusick break; 9515e4030eSKirk McKusick case IFREG: 9615e4030eSKirk McKusick if (size == 0) { 9716c0c8eeSKirk McKusick printf("empty file\n"); 980e3f58b6SKirk McKusick return; 9916c0c8eeSKirk McKusick } 10015e4030eSKirk McKusick printf("regular file, size %ld\n", size); 10115e4030eSKirk McKusick break; 10215e4030eSKirk McKusick case IFDIR: 10315e4030eSKirk McKusick if (size == 0) { 10415e4030eSKirk McKusick printf("empty directory\n"); 10515e4030eSKirk McKusick return; 10615e4030eSKirk McKusick } 10715e4030eSKirk McKusick printf("directory, size %ld\n", size); 10815e4030eSKirk McKusick break; 10915e4030eSKirk McKusick } 11015e4030eSKirk McKusick numblks = howmany(size, fs->fs_bsize); 11116c0c8eeSKirk McKusick len = numblks < UFS_NDADDR ? numblks : UFS_NDADDR; 11216c0c8eeSKirk McKusick for (i = 0; i < len; i++) { 11316c0c8eeSKirk McKusick if (i < numblks - 1) 1140e3f58b6SKirk McKusick frags = fs->fs_frag; 11516c0c8eeSKirk McKusick else 1160e3f58b6SKirk McKusick frags = howmany(size % fs->fs_bsize, 1170e3f58b6SKirk McKusick fs->fs_fsize); 1180e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 1190e3f58b6SKirk McKusick blkno = dp->dp1.di_db[i]; 12016c0c8eeSKirk McKusick else 1210e3f58b6SKirk McKusick blkno = dp->dp2.di_db[i]; 1220e3f58b6SKirk McKusick printblk(fs, i, blkno, frags, numblks); 12316c0c8eeSKirk McKusick } 12416c0c8eeSKirk McKusick 12516c0c8eeSKirk McKusick blksperindir = 1; 12616c0c8eeSKirk McKusick len = numblks - UFS_NDADDR; 12716c0c8eeSKirk McKusick lbn = UFS_NDADDR; 12816c0c8eeSKirk McKusick for (i = 0; len > 0 && i < UFS_NIADDR; i++) { 1290e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 1300e3f58b6SKirk McKusick blkno = dp->dp1.di_ib[i]; 13116c0c8eeSKirk McKusick else 1320e3f58b6SKirk McKusick blkno = dp->dp2.di_ib[i]; 1330e3f58b6SKirk McKusick indirprt(disk, i, blksperindir, lbn, blkno, numblks); 1340e3f58b6SKirk McKusick blksperindir *= NINDIR(fs); 13516c0c8eeSKirk McKusick lbn += blksperindir; 13616c0c8eeSKirk McKusick len -= blksperindir; 13716c0c8eeSKirk McKusick } 13816c0c8eeSKirk McKusick 13916c0c8eeSKirk McKusick /* dummy print to flush out last extent */ 1400e3f58b6SKirk McKusick printblk(fs, numblks, 0, frags, 0); 14116c0c8eeSKirk McKusick } 14216c0c8eeSKirk McKusick 1430e3f58b6SKirk McKusick static void 1440e3f58b6SKirk McKusick indirprt(disk, level, blksperindir, lbn, blkno, lastlbn) 1450e3f58b6SKirk McKusick struct uufsd *disk; 14616c0c8eeSKirk McKusick int level; 14716c0c8eeSKirk McKusick int blksperindir; 14816c0c8eeSKirk McKusick int lbn; 14916c0c8eeSKirk McKusick ufs2_daddr_t blkno; 15016c0c8eeSKirk McKusick int lastlbn; 15116c0c8eeSKirk McKusick { 15216c0c8eeSKirk McKusick char indir[MAXBSIZE]; 1530e3f58b6SKirk McKusick struct fs *fs; 15416c0c8eeSKirk McKusick int i, last; 15516c0c8eeSKirk McKusick 1560e3f58b6SKirk McKusick fs = (struct fs *)&disk->d_sb; 15715e4030eSKirk McKusick if (blkno == 0) { 15815e4030eSKirk McKusick printblk(fs, lbn, blkno, 15915e4030eSKirk McKusick blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn); 16015e4030eSKirk McKusick return; 16115e4030eSKirk McKusick } 1620e3f58b6SKirk McKusick printblk(fs, lbn, blkno, fs->fs_frag, -level); 16316c0c8eeSKirk McKusick /* read in the indirect block. */ 164c343fa81SKirk McKusick if (bread(disk, fsbtodb(fs, blkno), indir, fs->fs_bsize) == -1) { 165c343fa81SKirk McKusick warn("Read of indirect block %jd failed", (intmax_t)blkno); 166c343fa81SKirk McKusick /* List the unreadable part as a hole */ 167c343fa81SKirk McKusick printblk(fs, lbn, 0, 168c343fa81SKirk McKusick blksperindir * NINDIR(fs) * fs->fs_frag, lastlbn); 169c343fa81SKirk McKusick return; 170c343fa81SKirk McKusick } 1710e3f58b6SKirk McKusick last = howmany(lastlbn - lbn, blksperindir) < NINDIR(fs) ? 1720e3f58b6SKirk McKusick howmany(lastlbn - lbn, blksperindir) : NINDIR(fs); 17316c0c8eeSKirk McKusick if (blksperindir == 1) { 17416c0c8eeSKirk McKusick for (i = 0; i < last; i++) { 1750e3f58b6SKirk McKusick if (fs->fs_magic == FS_UFS1_MAGIC) 17616c0c8eeSKirk McKusick blkno = ((ufs1_daddr_t *)indir)[i]; 17716c0c8eeSKirk McKusick else 17816c0c8eeSKirk McKusick blkno = ((ufs2_daddr_t *)indir)[i]; 1790e3f58b6SKirk McKusick printblk(fs, lbn + i, blkno, fs->fs_frag, lastlbn); 18016c0c8eeSKirk McKusick } 18116c0c8eeSKirk McKusick return; 18216c0c8eeSKirk McKusick } 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 indirprt(disk, level - 1, blksperindir / NINDIR(fs), 18916c0c8eeSKirk McKusick lbn + blksperindir * i, blkno, lastlbn); 19016c0c8eeSKirk McKusick } 19116c0c8eeSKirk McKusick } 19216c0c8eeSKirk McKusick 1930e3f58b6SKirk McKusick static char * 1940e3f58b6SKirk McKusick distance(fs, lastblk, firstblk) 1950e3f58b6SKirk McKusick struct fs *fs; 19616c0c8eeSKirk McKusick daddr_t lastblk; 19716c0c8eeSKirk McKusick daddr_t firstblk; 19816c0c8eeSKirk McKusick { 19916c0c8eeSKirk McKusick daddr_t delta; 20016c0c8eeSKirk McKusick int firstcg, lastcg; 20116c0c8eeSKirk McKusick static char buf[100]; 20216c0c8eeSKirk McKusick 20316c0c8eeSKirk McKusick if (lastblk == 0) 20416c0c8eeSKirk McKusick return (""); 20516c0c8eeSKirk McKusick delta = firstblk - lastblk - 1; 2060e3f58b6SKirk McKusick firstcg = dtog(fs, firstblk); 2070e3f58b6SKirk McKusick lastcg = dtog(fs, lastblk); 20816c0c8eeSKirk McKusick if (firstcg == lastcg) { 20916c0c8eeSKirk McKusick snprintf(buf, 100, " distance %jd", (intmax_t)delta); 21016c0c8eeSKirk McKusick return (&buf[0]); 21116c0c8eeSKirk McKusick } 21216c0c8eeSKirk McKusick snprintf(buf, 100, " cg %d blk %jd to cg %d blk %jd", 213f33fbc18SKirk McKusick lastcg, (intmax_t)dtogd(fs, lastblk), firstcg, 214f33fbc18SKirk McKusick (intmax_t)dtogd(fs, firstblk)); 21516c0c8eeSKirk McKusick return (&buf[0]); 21616c0c8eeSKirk McKusick } 21716c0c8eeSKirk McKusick 21816c0c8eeSKirk McKusick 2190e3f58b6SKirk McKusick static char *indirname[UFS_NIADDR] = { "First", "Second", "Third" }; 22016c0c8eeSKirk McKusick 2210e3f58b6SKirk McKusick static void 2220e3f58b6SKirk McKusick printblk(fs, lbn, blkno, numblks, lastlbn) 2230e3f58b6SKirk McKusick struct fs *fs; 22416c0c8eeSKirk McKusick int lbn; 22516c0c8eeSKirk McKusick ufs2_daddr_t blkno; 22616c0c8eeSKirk McKusick int numblks; 22716c0c8eeSKirk McKusick int lastlbn; 22816c0c8eeSKirk McKusick { 22916c0c8eeSKirk McKusick static int seq; 23016c0c8eeSKirk McKusick static daddr_t lastindirblk, lastblk, firstblk; 23116c0c8eeSKirk McKusick 23216c0c8eeSKirk McKusick if (lastlbn <= 0) 23316c0c8eeSKirk McKusick goto flush; 23416c0c8eeSKirk McKusick if (seq == 0) { 23515e4030eSKirk McKusick seq = howmany(numblks, fs->fs_frag); 23616c0c8eeSKirk McKusick firstblk = blkno; 23716c0c8eeSKirk McKusick return; 23816c0c8eeSKirk McKusick } 23916c0c8eeSKirk McKusick if (lbn == 0) { 24015e4030eSKirk McKusick seq = howmany(numblks, fs->fs_frag); 24116c0c8eeSKirk McKusick lastblk = 0; 24216c0c8eeSKirk McKusick firstblk = blkno; 24316c0c8eeSKirk McKusick lastindirblk = 0; 24416c0c8eeSKirk McKusick return; 24516c0c8eeSKirk McKusick } 24616c0c8eeSKirk McKusick if (lbn < lastlbn && ((firstblk == 0 && blkno == 0) || 24716c0c8eeSKirk McKusick (firstblk == BLK_NOCOPY && blkno == BLK_NOCOPY) || 24816c0c8eeSKirk McKusick (firstblk == BLK_SNAP && blkno == BLK_SNAP) || 24915e4030eSKirk McKusick blkno == firstblk + seq * fs->fs_frag)) { 25015e4030eSKirk McKusick seq += howmany(numblks, fs->fs_frag); 25116c0c8eeSKirk McKusick return; 25216c0c8eeSKirk McKusick } 25316c0c8eeSKirk McKusick flush: 25416c0c8eeSKirk McKusick if (seq == 0) 25516c0c8eeSKirk McKusick goto prtindir; 25616c0c8eeSKirk McKusick if (firstblk <= BLK_SNAP) { 25716c0c8eeSKirk McKusick if (seq == 1) 25816c0c8eeSKirk McKusick printf("\tlbn %d %s\n", lbn - seq, 25916c0c8eeSKirk McKusick firstblk == 0 ? "hole" : 26016c0c8eeSKirk McKusick firstblk == BLK_NOCOPY ? "nocopy" : 26116c0c8eeSKirk McKusick "snapblk"); 26216c0c8eeSKirk McKusick else 26316c0c8eeSKirk McKusick printf("\tlbn %d-%d %s\n", 26416c0c8eeSKirk McKusick lbn - seq, lbn - 1, 26516c0c8eeSKirk McKusick firstblk == 0 ? "hole" : 26616c0c8eeSKirk McKusick firstblk == BLK_NOCOPY ? "nocopy" : 26716c0c8eeSKirk McKusick "snapblk"); 26816c0c8eeSKirk McKusick } else if (seq == 1) { 26916c0c8eeSKirk McKusick if (numblks == 1) 27016c0c8eeSKirk McKusick printf("\tlbn %d blkno %jd%s\n", lbn - seq, 2710e3f58b6SKirk McKusick (intmax_t)firstblk, distance(fs, lastblk, firstblk)); 27216c0c8eeSKirk McKusick else 27316c0c8eeSKirk McKusick printf("\tlbn %d blkno %jd-%jd%s\n", lbn - seq, 27416c0c8eeSKirk McKusick (intmax_t)firstblk, 27516c0c8eeSKirk McKusick (intmax_t)(firstblk + numblks - 1), 2760e3f58b6SKirk McKusick distance(fs, lastblk, firstblk)); 27716c0c8eeSKirk McKusick lastblk = firstblk + numblks - 1; 27816c0c8eeSKirk McKusick } else { 27916c0c8eeSKirk McKusick printf("\tlbn %d-%d blkno %jd-%jd%s\n", lbn - seq, lbn - 1, 28016c0c8eeSKirk McKusick (intmax_t)firstblk, (intmax_t)(firstblk + 2810e3f58b6SKirk McKusick (seq - 1) * fs->fs_frag + numblks - 1), 2820e3f58b6SKirk McKusick distance(fs, lastblk, firstblk)); 2830e3f58b6SKirk McKusick lastblk = firstblk + (seq - 1) * fs->fs_frag + numblks - 1; 28416c0c8eeSKirk McKusick } 28516c0c8eeSKirk McKusick if (lastlbn > 0 || blkno == 0) { 28616c0c8eeSKirk McKusick seq = 1; 28716c0c8eeSKirk McKusick firstblk = blkno; 28816c0c8eeSKirk McKusick return; 28916c0c8eeSKirk McKusick } 29016c0c8eeSKirk McKusick prtindir: 2910e3f58b6SKirk McKusick if (seq != 0 && (fs->fs_metaspace == 0 || lastindirblk == 0)) 29216c0c8eeSKirk McKusick lastindirblk = lastblk; 29316c0c8eeSKirk McKusick printf("%s-level indirect, blkno %jd-%jd%s\n", indirname[-lastlbn], 29416c0c8eeSKirk McKusick (intmax_t)blkno, (intmax_t)(blkno + numblks - 1), 2950e3f58b6SKirk McKusick distance(fs, lastindirblk, blkno)); 29616c0c8eeSKirk McKusick lastindirblk = blkno + numblks - 1; 2970e3f58b6SKirk McKusick if (fs->fs_metaspace == 0) 29816c0c8eeSKirk McKusick lastblk = lastindirblk; 29916c0c8eeSKirk McKusick seq = 0; 30016c0c8eeSKirk McKusick } 301