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