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