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 <sys/disklabel.h> 31 #include <sys/time.h> 32 33 #include <ufs/ufs/dinode.h> 34 #include <ufs/ffs/fs.h> 35 36 #include <err.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <stdio.h> 42 #include <stdint.h> 43 #include <unistd.h> 44 45 union dinode { 46 struct ufs1_dinode *dp1; 47 struct ufs2_dinode *dp2; 48 }; 49 struct fs *sbp; 50 char *fsname; 51 int fd; 52 53 void indirprt(int level, int blksperindir, int lbn, ufs2_daddr_t blkno, 54 int lastlbn); 55 void printblk(int lbn, ufs2_daddr_t blkno, int numblks, int lastlbn); 56 57 /* 58 * Possible superblock locations ordered from most to least likely. 59 */ 60 static int sblock_try[] = SBLOCKSEARCH; 61 62 int 63 main(argc, argv) 64 int argc; 65 char *argv[]; 66 { 67 int i, len, lbn, frags, inonum, numblks, blksperindir; 68 char sblock[SBLOCKSIZE], ibuf[MAXBSIZE]; 69 ufs2_daddr_t blkno; 70 off_t size, offset; 71 union dinode dp; 72 73 if (argc < 3) { 74 (void)fprintf(stderr,"usage: prtblknos filesystem inode ...\n"); 75 exit(1); 76 } 77 78 fsname = *++argv; 79 80 /* get the superblock. */ 81 if ((fd = open(fsname, O_RDONLY, 0)) < 0) 82 err(1, "%s", fsname); 83 for (i = 0; sblock_try[i] != -1; i++) { 84 if (lseek(fd, sblock_try[i], SEEK_SET) < 0) 85 err(1, "lseek: %s", fsname); 86 if (read(fd, sblock, (long)SBLOCKSIZE) != SBLOCKSIZE) 87 err(1, "can't read superblock: %s", fsname); 88 sbp = (struct fs *)sblock; 89 if ((sbp->fs_magic == FS_UFS1_MAGIC || 90 (sbp->fs_magic == FS_UFS2_MAGIC && 91 sbp->fs_sblockloc == sblock_try[i])) && 92 sbp->fs_bsize <= MAXBSIZE && 93 sbp->fs_bsize >= sizeof(struct fs)) 94 break; 95 } 96 if (sblock_try[i] == -1) 97 errx(1, "Cannot find file system superblock\n"); 98 99 /* remaining arguments are inode numbers. */ 100 while (*++argv) { 101 /* get the inode number. */ 102 if ((inonum = atoi(*argv)) <= 0) 103 errx(1, "%s is not a valid inode number", *argv); 104 (void)printf("%d:", inonum); 105 106 /* read in the appropriate block. */ 107 offset = ino_to_fsba(sbp, inonum); /* inode to fs blk */ 108 offset = fsbtodb(sbp, offset); /* fs blk disk blk */ 109 offset *= DEV_BSIZE; /* disk blk to bytes */ 110 111 /* seek and read the block */ 112 if (lseek(fd, offset, SEEK_SET) < 0) 113 err(1, "%s", fsname); 114 if (read(fd, ibuf, sbp->fs_bsize) != sbp->fs_bsize) 115 err(1, "%s", fsname); 116 117 /* get the inode within the block. */ 118 if (sbp->fs_magic == FS_UFS1_MAGIC) { 119 dp.dp1 = &((struct ufs1_dinode *)(ibuf)) 120 [ino_to_fsbo(sbp, inonum)]; 121 size = dp.dp1->di_size; 122 } else { 123 dp.dp2 = &((struct ufs2_dinode *)(ibuf)) 124 [ino_to_fsbo(sbp, inonum)]; 125 size = dp.dp2->di_size; 126 } 127 128 numblks = howmany(size, sbp->fs_bsize); 129 if (numblks == 0) { 130 printf(" empty file\n"); 131 continue; 132 } 133 len = numblks < UFS_NDADDR ? numblks : UFS_NDADDR; 134 for (i = 0; i < len; i++) { 135 if (i < numblks - 1) 136 frags = sbp->fs_frag; 137 else 138 frags = howmany(size % sbp->fs_bsize, 139 sbp->fs_fsize); 140 if (sbp->fs_magic == FS_UFS1_MAGIC) 141 blkno = dp.dp1->di_db[i]; 142 else 143 blkno = dp.dp2->di_db[i]; 144 printblk(i, blkno, frags, numblks); 145 } 146 147 blksperindir = 1; 148 len = numblks - UFS_NDADDR; 149 lbn = UFS_NDADDR; 150 for (i = 0; len > 0 && i < UFS_NIADDR; i++) { 151 if (sbp->fs_magic == FS_UFS1_MAGIC) 152 blkno = dp.dp1->di_ib[i]; 153 else 154 blkno = dp.dp2->di_ib[i]; 155 indirprt(i, blksperindir, lbn, blkno, numblks); 156 blksperindir *= NINDIR(sbp); 157 lbn += blksperindir; 158 len -= blksperindir; 159 } 160 161 /* dummy print to flush out last extent */ 162 printblk(numblks, 0, frags, 0); 163 } 164 (void)close(fd); 165 exit(0); 166 } 167 168 void 169 indirprt(level, blksperindir, lbn, blkno, lastlbn) 170 int level; 171 int blksperindir; 172 int lbn; 173 ufs2_daddr_t blkno; 174 int lastlbn; 175 { 176 char indir[MAXBSIZE]; 177 off_t offset; 178 int i, last; 179 180 printblk(lbn, blkno, sbp->fs_frag, -level); 181 /* read in the indirect block. */ 182 offset = fsbtodb(sbp, blkno); /* fs blk disk blk */ 183 offset *= DEV_BSIZE; /* disk blk to bytes */ 184 if (lseek(fd, offset, SEEK_SET) < 0) 185 err(1, "%s", fsname); 186 if (read(fd, indir, sbp->fs_bsize) != sbp->fs_bsize) 187 err(1, "%s", fsname); 188 last = howmany(lastlbn - lbn, blksperindir) < NINDIR(sbp) ? 189 howmany(lastlbn - lbn, blksperindir) : NINDIR(sbp); 190 if (blksperindir == 1) { 191 for (i = 0; i < last; i++) { 192 if (sbp->fs_magic == FS_UFS1_MAGIC) 193 blkno = ((ufs1_daddr_t *)indir)[i]; 194 else 195 blkno = ((ufs2_daddr_t *)indir)[i]; 196 printblk(lbn + i, blkno, sbp->fs_frag, lastlbn); 197 } 198 return; 199 } 200 for (i = 0; i < last; i++) { 201 if (sbp->fs_magic == FS_UFS1_MAGIC) 202 blkno = ((ufs1_daddr_t *)indir)[i]; 203 else 204 blkno = ((ufs2_daddr_t *)indir)[i]; 205 indirprt(level - 1, blksperindir / NINDIR(sbp), 206 lbn + blksperindir * i, blkno, lastlbn); 207 } 208 } 209 210 char * 211 distance(lastblk, firstblk) 212 daddr_t lastblk; 213 daddr_t firstblk; 214 { 215 daddr_t delta; 216 int firstcg, lastcg; 217 static char buf[100]; 218 219 if (lastblk == 0) 220 return (""); 221 delta = firstblk - lastblk - 1; 222 firstcg = dtog(sbp, firstblk); 223 lastcg = dtog(sbp, lastblk); 224 if (firstcg == lastcg) { 225 snprintf(buf, 100, " distance %jd", (intmax_t)delta); 226 return (&buf[0]); 227 } 228 snprintf(buf, 100, " cg %d blk %jd to cg %d blk %jd", 229 lastcg, dtogd(sbp, lastblk), firstcg, dtogd(sbp, firstblk)); 230 return (&buf[0]); 231 } 232 233 234 char *indirname[UFS_NIADDR] = { "First", "Second", "Third" }; 235 236 void 237 printblk(lbn, blkno, numblks, lastlbn) 238 int lbn; 239 ufs2_daddr_t blkno; 240 int numblks; 241 int lastlbn; 242 { 243 static int seq; 244 static daddr_t lastindirblk, lastblk, firstblk; 245 246 if (lastlbn <= 0) 247 goto flush; 248 if (seq == 0) { 249 seq = 1; 250 firstblk = blkno; 251 return; 252 } 253 if (lbn == 0) { 254 seq = 1; 255 lastblk = 0; 256 firstblk = blkno; 257 lastindirblk = 0; 258 return; 259 } 260 if (lbn < lastlbn && ((firstblk == 0 && blkno == 0) || 261 (firstblk == BLK_NOCOPY && blkno == BLK_NOCOPY) || 262 (firstblk == BLK_SNAP && blkno == BLK_SNAP) || 263 blkno == firstblk + seq * numblks)) { 264 seq++; 265 return; 266 } 267 flush: 268 if (seq == 0) 269 goto prtindir; 270 if (firstblk <= BLK_SNAP) { 271 if (seq == 1) 272 printf("\tlbn %d %s\n", lbn - seq, 273 firstblk == 0 ? "hole" : 274 firstblk == BLK_NOCOPY ? "nocopy" : 275 "snapblk"); 276 else 277 printf("\tlbn %d-%d %s\n", 278 lbn - seq, lbn - 1, 279 firstblk == 0 ? "hole" : 280 firstblk == BLK_NOCOPY ? "nocopy" : 281 "snapblk"); 282 } else if (seq == 1) { 283 if (numblks == 1) 284 printf("\tlbn %d blkno %jd%s\n", lbn - seq, 285 (intmax_t)firstblk, distance(lastblk, firstblk)); 286 else 287 printf("\tlbn %d blkno %jd-%jd%s\n", lbn - seq, 288 (intmax_t)firstblk, 289 (intmax_t)(firstblk + numblks - 1), 290 distance(lastblk, firstblk)); 291 lastblk = firstblk + numblks - 1; 292 } else { 293 printf("\tlbn %d-%d blkno %jd-%jd%s\n", lbn - seq, lbn - 1, 294 (intmax_t)firstblk, (intmax_t)(firstblk + 295 (seq - 1) * sbp->fs_frag + numblks - 1), 296 distance(lastblk, firstblk)); 297 lastblk = firstblk + (seq - 1) * sbp->fs_frag + numblks - 1; 298 } 299 if (lastlbn > 0 || blkno == 0) { 300 seq = 1; 301 firstblk = blkno; 302 return; 303 } 304 prtindir: 305 if (seq != 0 && (sbp->fs_metaspace == 0 || lastindirblk == 0)) 306 lastindirblk = lastblk; 307 printf("%s-level indirect, blkno %jd-%jd%s\n", indirname[-lastlbn], 308 (intmax_t)blkno, (intmax_t)(blkno + numblks - 1), 309 distance(lastindirblk, blkno)); 310 lastindirblk = blkno + numblks - 1; 311 if (sbp->fs_metaspace == 0) 312 lastblk = lastindirblk; 313 seq = 0; 314 } 315