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