1 /* $NetBSD: dumplfs.c,v 1.67 2025/09/14 19:09:11 perseant Exp $ */ 2 3 /*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 34 #ifndef lint 35 __COPYRIGHT("@(#) Copyright (c) 1991, 1993\ 36 The Regents of the University of California. All rights reserved."); 37 #endif /* not lint */ 38 39 #ifndef lint 40 #if 0 41 static char sccsid[] = "@(#)dumplfs.c 8.5 (Berkeley) 5/24/95"; 42 #else 43 __RCSID("$NetBSD: dumplfs.c,v 1.67 2025/09/14 19:09:11 perseant Exp $"); 44 #endif 45 #endif /* not lint */ 46 47 #include <sys/param.h> 48 #include <sys/ucred.h> 49 #include <sys/mount.h> 50 #include <sys/time.h> 51 52 #include <ufs/lfs/lfs.h> 53 #include <ufs/lfs/lfs_accessors.h> 54 55 #include <err.h> 56 #include <errno.h> 57 #include <fcntl.h> 58 #include <fstab.h> 59 #include <stdbool.h> 60 #include <stdlib.h> 61 #include <stdio.h> 62 #include <string.h> 63 #include <unistd.h> 64 #include <util.h> 65 #include "extern.h" 66 67 static void addseg(char *); 68 static void dump_cleaner_info(struct lfs *, void *); 69 static void dump_dinode(struct lfs *, union lfs_dinode *); 70 static void dump_ifile(int, struct lfs *, int, int, daddr_t); 71 static int dump_ipage_ifile(struct lfs *, int, char *, int); 72 static int dump_ipage_segusage(struct lfs *, int, char *, int); 73 static void dump_segment(int, int, daddr_t, struct lfs *, int); 74 static int dump_sum(int, struct lfs *, SEGSUM *, int, daddr_t); 75 static void dump_super(struct lfs *); 76 static void dump_inoblk(int, struct lfs *, daddr_t, ino_t); 77 static void usage(void); 78 79 extern uint32_t cksum(void *, size_t); 80 81 typedef struct seglist SEGLIST; 82 struct seglist { 83 SEGLIST *next; 84 int num; 85 }; 86 SEGLIST *seglist; 87 88 char *special; 89 90 /* Segment Usage formats */ 91 #define print_suheader \ 92 (void)printf("segnum\tflags\tnbytes\tninos\tnsums\tlastmod\n") 93 94 static inline void 95 print_suentry(int i, SEGUSE *sp, struct lfs *fs) 96 { 97 time_t t; 98 char flags[4] = " "; 99 100 if (sp->su_flags & SEGUSE_ACTIVE) 101 flags[0] = 'A'; 102 if (sp->su_flags & SEGUSE_DIRTY) 103 flags[1] = 'D'; 104 else 105 flags[1] = 'C'; 106 if (sp->su_flags & SEGUSE_SUPERBLOCK) 107 flags[2] = 'S'; 108 109 t = (lfs_sb_getversion(fs) == 1 ? sp->su_olastmod : sp->su_lastmod); 110 111 printf("%d\t%s\t%d\t%d\t%d\t%s", i, flags, 112 sp->su_nbytes, sp->su_ninos, sp->su_nsums, 113 ctime(&t)); 114 } 115 116 /* Ifile formats */ 117 #define print_iheader \ 118 (void)printf("inum\tstatus\tversion\tdaddr\t\tfreeptr\n") 119 120 static inline void 121 print_ientry(int i, struct lfs *lfsp, IFILE *ip) 122 { 123 uint32_t version; 124 daddr_t daddr; 125 ino_t nextfree; 126 127 version = lfs_if_getversion(lfsp, ip); 128 daddr = lfs_if_getdaddr(lfsp, ip); 129 nextfree = lfs_if_getnextfree(lfsp, ip); 130 131 if (daddr == LFS_UNUSED_DADDR) 132 printf("%d\tFREE\t%u\t \t\t%ju\n", i, version, 133 (uintmax_t)nextfree); 134 else 135 printf("%d\tINUSE\t%u\t%8jX\t%s\n", 136 i, version, (intmax_t)daddr, 137 nextfree == LFS_ORPHAN_NEXTFREE(lfsp) ? "orphan" : "-"); 138 } 139 140 /* 141 * Set the is64 and dobyteswap fields of struct lfs. Note that the 142 * magic number (and version) fields are necessarily at the same place 143 * in all superblock versions, so we can read it via u_32 without 144 * getting confused. 145 */ 146 static void 147 identify(struct lfs *fs) 148 { 149 unsigned magic; 150 151 magic = fs->lfs_dlfs_u.u_32.dlfs_magic; 152 switch (magic) { 153 case LFS_MAGIC: 154 fs->lfs_is64 = false; 155 fs->lfs_dobyteswap = false; 156 break; 157 case LFS_MAGIC_SWAPPED: 158 fs->lfs_is64 = false; 159 fs->lfs_dobyteswap = true; 160 break; 161 case LFS64_MAGIC: 162 fs->lfs_is64 = true; 163 fs->lfs_dobyteswap = false; 164 break; 165 case LFS64_MAGIC_SWAPPED: 166 fs->lfs_is64 = true; 167 fs->lfs_dobyteswap = true; 168 break; 169 default: 170 warnx("Superblock magic number 0x%x not known; " 171 "assuming 32-bit, native-endian", magic); 172 fs->lfs_is64 = false; 173 fs->lfs_dobyteswap = false; 174 break; 175 } 176 } 177 178 #define fsbtobyte(fs, b) lfs_fsbtob((fs), (off_t)((b))) 179 180 int datasum_check = 0; 181 182 int 183 main(int argc, char **argv) 184 { 185 struct lfs lfs_sb1, lfs_sb2, *lfs_master; 186 daddr_t seg_addr, idaddr, sbdaddr, inoaddr; 187 int ch, do_allsb, do_ientries, do_segentries, fd, segnum; 188 void *sbuf; 189 char *narg, *s; 190 ino_t dumpino; 191 192 do_allsb = 0; 193 do_ientries = 0; 194 do_segentries = 0; 195 dumpino = 0; 196 idaddr = 0x0; 197 sbdaddr = 0x0; 198 inoaddr = 0x0; 199 narg = NULL; 200 while ((ch = getopt(argc, argv, "ab:diI:n:Ss:")) != -1) 201 switch(ch) { 202 case 'a': /* Dump all superblocks */ 203 do_allsb = 1; 204 break; 205 case 'b': /* Use this superblock */ 206 sbdaddr = strtol(optarg, NULL, 0); 207 break; 208 case 'd': 209 datasum_check = 1; 210 break; 211 case 'i': /* Dump ifile entries */ 212 do_ientries = !do_ientries; 213 break; 214 case 'I': /* Use this ifile inode */ 215 idaddr = strtol(optarg, NULL, 0); 216 break; 217 case 'n': 218 narg = optarg; 219 break; 220 case 'S': 221 do_segentries = !do_segentries; 222 break; 223 case 's': /* Dump out these segments */ 224 addseg(optarg); 225 break; 226 default: 227 usage(); 228 } 229 argc -= optind; 230 argv += optind; 231 232 if (argc != 1) 233 usage(); 234 235 special = argv[0]; 236 if ((fd = open(special, O_RDONLY, 0)) < 0) 237 err(1, "%s", special); 238 239 sbuf = emalloc(LFS_SBPAD); 240 if (sbdaddr == 0x0) { 241 /* Read the proto-superblock */ 242 __CTASSERT(sizeof(struct dlfs) == sizeof(struct dlfs64)); 243 get(fd, LFS_LABELPAD, sbuf, LFS_SBPAD); 244 memcpy(&lfs_sb1.lfs_dlfs_u, sbuf, sizeof(struct dlfs)); 245 identify(&lfs_sb1); 246 247 /* If that wasn't the real first sb, get the real first sb */ 248 if (lfs_sb_getversion(&lfs_sb1) > 1 && 249 lfs_sb_getsboff(&lfs_sb1, 0) > lfs_btofsb(&lfs_sb1, LFS_LABELPAD)) { 250 get(fd, lfs_fsbtob(&lfs_sb1, lfs_sb_getsboff(&lfs_sb1, 0)), 251 &lfs_sb1.lfs_dlfs_u, sizeof(struct dlfs)); 252 identify(&lfs_sb1); 253 } 254 255 /* 256 * Read the second superblock and figure out which check point is 257 * most up to date. 258 */ 259 get(fd, 260 fsbtobyte(&lfs_sb1, lfs_sb_getsboff(&lfs_sb1, 1)), 261 sbuf, LFS_SBPAD); 262 memcpy(&lfs_sb2.lfs_dlfs_u, sbuf, sizeof(struct dlfs)); 263 identify(&lfs_sb2); 264 265 lfs_master = &lfs_sb1; 266 if (lfs_sb_getversion(&lfs_sb1) > 1) { 267 if (lfs_sb_getserial(&lfs_sb1) > lfs_sb_getserial(&lfs_sb2)) { 268 lfs_master = &lfs_sb2; 269 sbdaddr = lfs_sb_getsboff(&lfs_sb1, 1); 270 } else 271 sbdaddr = lfs_sb_getsboff(&lfs_sb1, 0); 272 } else { 273 if (lfs_sb_getotstamp(&lfs_sb1) > lfs_sb_getotstamp(&lfs_sb2)) { 274 lfs_master = &lfs_sb2; 275 sbdaddr = lfs_sb_getsboff(&lfs_sb1, 1); 276 } else 277 sbdaddr = lfs_sb_getsboff(&lfs_sb1, 0); 278 } 279 } else { 280 /* Read the first superblock */ 281 get(fd, dbtob((off_t)sbdaddr), sbuf, LFS_SBPAD); 282 memcpy(&lfs_sb1.lfs_dlfs_u, sbuf, sizeof(struct dlfs)); 283 identify(&lfs_sb1); 284 lfs_master = &lfs_sb1; 285 } 286 287 free(sbuf); 288 289 /* 290 * If asked to dump an inode block, do that and exit. 291 */ 292 if (narg != NULL) { 293 s = strchr(narg, '@'); 294 if (s != NULL) { 295 *s = 0; 296 dumpino = strtol(narg, NULL, 0); 297 if (dumpino <= 0) 298 usage(); 299 narg = s + 1; 300 } 301 inoaddr = strtol(narg, NULL, 0); 302 if (inoaddr <= 0) 303 usage(); 304 305 dump_inoblk(fd, lfs_master, inoaddr, dumpino); 306 exit(0); 307 } 308 309 /* Compatibility */ 310 if (lfs_sb_getversion(lfs_master) == 1) { 311 lfs_sb_setsumsize(lfs_master, LFS_V1_SUMMARY_SIZE); 312 lfs_sb_setibsize(lfs_master, lfs_sb_getbsize(lfs_master)); 313 lfs_sb_sets0addr(lfs_master, lfs_sb_getsboff(lfs_master, 0)); 314 lfs_sb_settstamp(lfs_master, lfs_sb_getotstamp(lfs_master)); 315 lfs_sb_setfsbtodb(lfs_master, 0); 316 } 317 318 (void)printf("Master LFS%d superblock at 0x%llx:\n", 319 lfs_master->lfs_is64 ? 64 : 32, (long long)sbdaddr); 320 dump_super(lfs_master); 321 322 dump_ifile(fd, lfs_master, do_ientries, do_segentries, idaddr); 323 324 if (seglist != NULL) 325 for (; seglist != NULL; seglist = seglist->next) { 326 seg_addr = lfs_sntod(lfs_master, seglist->num); 327 dump_segment(fd, seglist->num, seg_addr, lfs_master, 328 do_allsb); 329 } 330 else 331 for (segnum = 0, seg_addr = lfs_sntod(lfs_master, 0); 332 segnum < lfs_sb_getnseg(lfs_master); 333 segnum++, seg_addr = lfs_sntod(lfs_master, segnum)) 334 dump_segment(fd, segnum, seg_addr, lfs_master, 335 do_allsb); 336 337 (void)close(fd); 338 exit(0); 339 } 340 341 /* 342 * We are reading all the blocks of an inode and dumping out the ifile table. 343 * This code could be tighter, but this is a first pass at getting the stuff 344 * printed out rather than making this code incredibly efficient. 345 */ 346 static void 347 dump_ifile(int fd, struct lfs *lfsp, int do_ientries, int do_segentries, daddr_t addr) 348 { 349 char *ipage; 350 char *dpage; 351 union lfs_dinode *dip = NULL; 352 void *dindir, *indir; 353 unsigned offset; 354 daddr_t thisblock; 355 daddr_t pdb; 356 int block_limit, i, inum, j, nblocks, psize; 357 358 psize = lfs_sb_getbsize(lfsp); 359 if (!addr) 360 addr = lfs_sb_getidaddr(lfsp); 361 362 dpage = emalloc(psize); 363 get(fd, fsbtobyte(lfsp, addr), dpage, psize); 364 365 dip = NULL; 366 for (i = LFS_INOPB(lfsp); i-- > 0; ) { 367 dip = DINO_IN_BLOCK(lfsp, dpage, i); 368 if (lfs_dino_getinumber(lfsp, dip) == LFS_IFILE_INUM) 369 break; 370 } 371 372 /* just in case */ 373 if (dip == NULL) { 374 warnx("this volume apparently has zero inodes per block"); 375 return; 376 } 377 378 if (lfs_dino_getinumber(lfsp, dip) != LFS_IFILE_INUM) { 379 warnx("unable to locate ifile inode at disk address 0x%jx", 380 (uintmax_t)addr); 381 return; 382 } 383 384 (void)printf("\nIFILE inode\n"); 385 dump_dinode(lfsp, dip); 386 387 (void)printf("\nIFILE contents\n"); 388 nblocks = lfs_dino_getsize(lfsp, dip) >> lfs_sb_getbshift(lfsp); 389 block_limit = MIN(nblocks, ULFS_NDADDR); 390 391 /* Get the direct block */ 392 ipage = emalloc(psize); 393 for (inum = 0, i = 0; i < block_limit; i++) { 394 pdb = lfs_dino_getdb(lfsp, dip, i); 395 get(fd, fsbtobyte(lfsp, pdb), ipage, psize); 396 if (i < lfs_sb_getcleansz(lfsp)) { 397 dump_cleaner_info(lfsp, ipage); 398 if (do_segentries) 399 print_suheader; 400 continue; 401 } 402 403 if (i < (lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp))) { 404 if (do_segentries) 405 inum = dump_ipage_segusage(lfsp, inum, ipage, 406 lfs_sb_getsepb(lfsp)); 407 else 408 inum = (i < lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp) - 1); 409 if (!inum) { 410 if(!do_ientries) 411 goto e0; 412 else 413 print_iheader; 414 } 415 } else 416 inum = dump_ipage_ifile(lfsp, inum, ipage, lfs_sb_getifpb(lfsp)); 417 } 418 419 if (nblocks <= ULFS_NDADDR) 420 goto e0; 421 422 /* Dump out blocks off of single indirect block */ 423 indir = emalloc(psize); 424 get(fd, fsbtobyte(lfsp, lfs_dino_getib(lfsp, dip, 0)), indir, psize); 425 block_limit = MIN(i + lfs_sb_getnindir(lfsp), nblocks); 426 for (offset = 0; i < block_limit; i++, offset++) { 427 thisblock = lfs_iblock_get(lfsp, indir, offset); 428 if (thisblock == LFS_UNUSED_DADDR) 429 break; 430 get(fd, fsbtobyte(lfsp, thisblock), ipage, psize); 431 if (i < lfs_sb_getcleansz(lfsp)) { 432 dump_cleaner_info(lfsp, ipage); 433 continue; 434 } 435 436 if (i < lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp)) { 437 if (do_segentries) 438 inum = dump_ipage_segusage(lfsp, inum, ipage, 439 lfs_sb_getsepb(lfsp)); 440 else 441 inum = (i < lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp) - 1); 442 if (!inum) { 443 if(!do_ientries) 444 goto e1; 445 else 446 print_iheader; 447 } 448 } else 449 inum = dump_ipage_ifile(lfsp, inum, ipage, lfs_sb_getifpb(lfsp)); 450 } 451 452 if (nblocks <= ULFS_NDADDR + lfs_sb_getnindir(lfsp)) 453 goto e1; 454 455 /* Get the double indirect block */ 456 dindir = emalloc(psize); 457 get(fd, fsbtobyte(lfsp, lfs_dino_getib(lfsp, dip, 1)), dindir, psize); 458 for (j = 0; j < lfs_sb_getnindir(lfsp); j++) { 459 thisblock = lfs_iblock_get(lfsp, dindir, j); 460 if (thisblock == LFS_UNUSED_DADDR) 461 break; 462 get(fd, fsbtobyte(lfsp, thisblock), indir, psize); 463 block_limit = MIN(i + lfs_sb_getnindir(lfsp), nblocks); 464 for (offset = 0; i < block_limit; i++, offset++) { 465 thisblock = lfs_iblock_get(lfsp, indir, offset); 466 if (thisblock == LFS_UNUSED_DADDR) 467 break; 468 get(fd, fsbtobyte(lfsp, thisblock), ipage, psize); 469 if (i < lfs_sb_getcleansz(lfsp)) { 470 dump_cleaner_info(lfsp, ipage); 471 continue; 472 } 473 474 if (i < lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp)) { 475 if (do_segentries) 476 inum = dump_ipage_segusage(lfsp, 477 inum, ipage, lfs_sb_getsepb(lfsp)); 478 else 479 inum = (i < lfs_sb_getsegtabsz(lfsp) + 480 lfs_sb_getcleansz(lfsp) - 1); 481 if (!inum) { 482 if(!do_ientries) 483 goto e2; 484 else 485 print_iheader; 486 } 487 } else 488 inum = dump_ipage_ifile(lfsp, inum, 489 ipage, lfs_sb_getifpb(lfsp)); 490 } 491 } 492 e2: free(dindir); 493 e1: free(indir); 494 e0: free(dpage); 495 free(ipage); 496 } 497 498 static int 499 dump_ipage_ifile(struct lfs *lfsp, int i, char *pp, int tot) 500 { 501 char *ip; 502 int cnt, max, entsize; 503 504 if (lfsp->lfs_is64) 505 entsize = sizeof(IFILE64); 506 if (lfs_sb_getversion(lfsp) > 1) 507 entsize = sizeof(IFILE32); 508 else 509 entsize = sizeof(IFILE_V1); 510 max = i + tot; 511 512 for (ip = pp, cnt = i; cnt < max; cnt++, ip += entsize) 513 print_ientry(cnt, lfsp, (IFILE *)ip); 514 return (max); 515 } 516 517 static int 518 dump_ipage_segusage(struct lfs *lfsp, int i, char *pp, int tot) 519 { 520 SEGUSE *sp; 521 int cnt, max; 522 struct seglist *slp; 523 524 max = i + tot; 525 for (sp = (SEGUSE *)pp, cnt = i; 526 cnt < lfs_sb_getnseg(lfsp) && cnt < max; cnt++) { 527 if (seglist == NULL) 528 print_suentry(cnt, sp, lfsp); 529 else { 530 for (slp = seglist; slp != NULL; slp = slp->next) 531 if (cnt == slp->num) { 532 print_suentry(cnt, sp, lfsp); 533 break; 534 } 535 } 536 if (lfs_sb_getversion(lfsp) > 1) 537 ++sp; 538 else 539 sp = (SEGUSE *)((SEGUSE_V1 *)sp + 1); 540 } 541 if (max >= lfs_sb_getnseg(lfsp)) 542 return (0); 543 else 544 return (max); 545 } 546 547 static void 548 dump_dinode(struct lfs *fs, union lfs_dinode *dip) 549 { 550 int i; 551 time_t at, mt, ct; 552 553 at = lfs_dino_getatime(fs, dip); 554 mt = lfs_dino_getmtime(fs, dip); 555 ct = lfs_dino_getctime(fs, dip); 556 557 (void)printf(" %so%o\t%s%d\t%s%d\t%s%d\t%s%ju\n", 558 "mode ", lfs_dino_getmode(fs, dip), 559 "nlink ", lfs_dino_getnlink(fs, dip), 560 "uid ", lfs_dino_getuid(fs, dip), 561 "gid ", lfs_dino_getgid(fs, dip), 562 "size ", (uintmax_t)lfs_dino_getsize(fs, dip)); 563 (void)printf(" %s%s", "atime ", ctime(&at)); 564 (void)printf(" %s%s", "mtime ", ctime(&mt)); 565 (void)printf(" %s%s", "ctime ", ctime(&ct)); 566 (void)printf(" inum %ju\tnblocks %ju\n", 567 (uintmax_t)lfs_dino_getinumber(fs, dip), 568 (uintmax_t)lfs_dino_getblocks(fs, dip)); 569 (void)printf(" Direct Addresses\n"); 570 for (i = 0; i < ULFS_NDADDR; i++) { 571 (void)printf("\t0x%jx", (intmax_t)lfs_dino_getdb(fs, dip, i)); 572 if ((i % 6) == 5) 573 (void)printf("\n"); 574 } 575 (void)printf(" Indirect Addresses\n"); 576 for (i = 0; i < ULFS_NIADDR; i++) 577 (void)printf("\t0x%jx", (intmax_t)lfs_dino_getib(fs, dip, i)); 578 (void)printf("\n"); 579 } 580 581 static int 582 dump_sum(int fd, struct lfs *lfsp, SEGSUM *sp, int segnum, daddr_t addr) 583 { 584 FINFO *fp; 585 IINFO *iip, *iip2; 586 union lfs_blocks fipblocks; 587 int i, j, acc; 588 int ck; 589 int numbytes, numblocks; 590 char *datap; 591 char *diblock; 592 union lfs_dinode *dip; 593 size_t el_size; 594 u_int32_t datasum; 595 u_int32_t ssflags; 596 time_t t; 597 char *buf; 598 size_t sumstart; 599 600 sumstart = lfs_ss_getsumstart(lfsp); 601 if (lfs_ss_getmagic(lfsp, sp) != SS_MAGIC || 602 lfs_ss_getsumsum(lfsp, sp) != (ck = cksum((char *)sp + sumstart, 603 lfs_sb_getsumsize(lfsp) - sumstart))) { 604 /* Don't print "corrupt" if we're just too close to the edge */ 605 if (lfs_dtosn(lfsp, addr + LFS_FSBTODB(lfsp, 1)) == 606 lfs_dtosn(lfsp, addr)) 607 (void)printf("dumplfs: %s %d address 0x%llx\n", 608 "corrupt summary block; segment", segnum, 609 (long long)addr); 610 return -1; 611 } 612 if (lfs_sb_getversion(lfsp) > 1 && lfs_ss_getident(lfsp, sp) != lfs_sb_getident(lfsp)) { 613 (void)printf("dumplfs: %s %d address 0x%llx\n", 614 "summary from a former life; segment", segnum, 615 (long long)addr); 616 return -1; 617 } 618 619 (void)printf("Segment Summary Info at 0x%llx\n", (long long)addr); 620 ssflags = lfs_ss_getflags(lfsp, sp); 621 (void)printf(" %s0x%jx\t%s%d\t%s%d\t%s%c%c%c%c\n %s0x%x\t%s0x%x", 622 "next ", (intmax_t)lfs_ss_getnext(lfsp, sp), 623 "nfinfo ", lfs_ss_getnfinfo(lfsp, sp), 624 "ninos ", lfs_ss_getninos(lfsp, sp), 625 "flags ", (ssflags & SS_DIROP) ? 'D' : '-', 626 (ssflags & SS_CONT) ? 'C' : '-', 627 (ssflags & SS_CLEAN) ? 'L' : '-', 628 (ssflags & SS_RFW) ? 'R' : '-', 629 "sumsum ", lfs_ss_getsumsum(lfsp, sp), 630 "datasum ", lfs_ss_getdatasum(lfsp, sp)); 631 if (lfs_sb_getversion(lfsp) == 1) { 632 t = lfs_ss_getocreate(lfsp, sp); 633 (void)printf("\tcreate %s\n", ctime(&t)); 634 } else { 635 t = lfs_ss_getcreate(lfsp, sp); 636 (void)printf("\tcreate %s", ctime(&t)); 637 (void)printf(" roll_id %-8x", lfs_ss_getident(lfsp, sp)); 638 (void)printf(" serial %lld\n", 639 (long long)lfs_ss_getserial(lfsp, sp)); 640 } 641 642 /* Dump out inode disk addresses */ 643 iip = SEGSUM_IINFOSTART(lfsp, sp); 644 diblock = emalloc(lfs_sb_getbsize(lfsp)); 645 printf(" Inode addresses:\n"); 646 numbytes = 0; 647 numblocks = 0; 648 for (i = 0; i < lfs_ss_getninos(lfsp, sp); iip = NEXTLOWER_IINFO(lfsp, iip)) { 649 ++numblocks; 650 numbytes += lfs_sb_getibsize(lfsp); /* add bytes for inode block */ 651 printf("\t0x%jx {", (intmax_t)lfs_ii_getblock(lfsp, iip)); 652 get(fd, fsbtobyte(lfsp, lfs_ii_getblock(lfsp, iip)), diblock, lfs_sb_getibsize(lfsp)); 653 for (j = 0; i < lfs_ss_getninos(lfsp, sp) && j < LFS_INOPB(lfsp); j++, i++) { 654 if (j > 0) 655 (void)printf(", "); 656 dip = DINO_IN_BLOCK(lfsp, diblock, j); 657 (void)printf("%juv%d", lfs_dino_getinumber(lfsp, dip), 658 lfs_dino_getgen(lfsp, dip)); 659 } 660 (void)printf("}\n"); 661 } 662 free(diblock); 663 664 fp = SEGSUM_FINFOBASE(lfsp, sp); 665 for (i = 0; i < lfs_ss_getnfinfo(lfsp, sp); i++) { 666 (void)printf(" FINFO for inode: %ju version %u nblocks %u lastlength %u\n", 667 (uintmax_t)lfs_fi_getino(lfsp, fp), 668 lfs_fi_getversion(lfsp, fp), 669 lfs_fi_getnblocks(lfsp, fp), 670 lfs_fi_getlastlength(lfsp, fp)); 671 lfs_blocks_fromfinfo(lfsp, &fipblocks, fp); 672 numblocks += lfs_fi_getnblocks(lfsp, fp); 673 for (j = 0; j < lfs_fi_getnblocks(lfsp, fp); j++) { 674 (void)printf("\t%jd", 675 (intmax_t)lfs_blocks_get(lfsp, &fipblocks, j)); 676 if ((j % 8) == 7) 677 (void)printf("\n"); 678 if (j == lfs_fi_getnblocks(lfsp, fp) - 1) 679 numbytes += lfs_fi_getlastlength(lfsp, fp); 680 else 681 numbytes += lfs_sb_getbsize(lfsp); 682 } 683 if ((j % 8) != 0) 684 (void)printf("\n"); 685 fp = NEXT_FINFO(lfsp, fp); 686 } 687 688 if (datasum_check == 0) 689 return (numbytes); 690 691 /* 692 * Now that we know the number of blocks, run back through and 693 * compute the data checksum. (A bad data checksum is not enough 694 * to prevent us from continuing, but it does merit a warning.) 695 */ 696 iip2 = SEGSUM_IINFOSTART(lfsp, sp); 697 fp = SEGSUM_FINFOBASE(lfsp, sp); 698 if (lfs_sb_getversion(lfsp) == 1) { 699 el_size = sizeof(unsigned long); 700 } else { 701 el_size = sizeof(u_int32_t); 702 } 703 datap = ecalloc(numblocks, el_size); 704 705 acc = 0; 706 addr += lfs_btofsb(lfsp, lfs_sb_getsumsize(lfsp)); 707 buf = emalloc(lfs_sb_getbsize(lfsp)); 708 for (i = 0; i < lfs_ss_getnfinfo(lfsp, sp); i++) { 709 while (addr == lfs_ii_getblock(lfsp, iip2)) { 710 get(fd, fsbtobyte(lfsp, addr), buf, lfs_sb_getibsize(lfsp)); 711 memcpy(datap + acc * el_size, buf, el_size); 712 addr += lfs_btofsb(lfsp, lfs_sb_getibsize(lfsp)); 713 iip2 = NEXTLOWER_IINFO(lfsp, iip2); 714 ++acc; 715 } 716 for (j = 0; j < lfs_fi_getnblocks(lfsp, fp); j++) { 717 get(fd, fsbtobyte(lfsp, addr), buf, lfs_sb_getfsize(lfsp)); 718 memcpy(datap + acc * el_size, buf, el_size); 719 if (j == lfs_fi_getnblocks(lfsp, fp) - 1) 720 addr += lfs_btofsb(lfsp, lfs_fi_getlastlength(lfsp, fp)); 721 else 722 addr += lfs_btofsb(lfsp, lfs_sb_getbsize(lfsp)); 723 ++acc; 724 } 725 fp = NEXT_FINFO(lfsp, fp); 726 } 727 while (addr == lfs_ii_getblock(lfsp, iip2)) { 728 get(fd, fsbtobyte(lfsp, addr), buf, lfs_sb_getibsize(lfsp)); 729 memcpy(datap + acc * el_size, buf, el_size); 730 addr += lfs_btofsb(lfsp, lfs_sb_getibsize(lfsp)); 731 iip2 = NEXTLOWER_IINFO(lfsp, iip2); 732 ++acc; 733 } 734 free(buf); 735 if (acc != numblocks) 736 printf("** counted %d blocks but should have been %d\n", 737 acc, numblocks); 738 datasum = cksum(datap, numblocks * el_size); 739 if (datasum != lfs_ss_getdatasum(lfsp, sp)) 740 printf("** computed datasum 0x%lx does not match given datasum 0x%lx\n", (unsigned long)datasum, (unsigned long)lfs_ss_getdatasum(lfsp, sp)); 741 free(datap); 742 743 return (numbytes); 744 } 745 746 static void 747 dump_segment(int fd, int segnum, daddr_t addr, struct lfs *lfsp, int dump_sb) 748 { 749 struct lfs lfs_sb, *sbp; 750 SEGSUM *sump; 751 size_t sumstart; 752 char *sumblock; 753 int did_one, nbytes, sb; 754 off_t sum_offset; 755 daddr_t new_addr; 756 757 (void)printf("\nSEGMENT %lld (Disk Address 0x%llx)\n", 758 (long long)lfs_dtosn(lfsp, addr), (long long)addr); 759 sum_offset = fsbtobyte(lfsp, addr); 760 sumblock = emalloc(lfs_sb_getsumsize(lfsp)); 761 762 if (lfs_sb_getversion(lfsp) > 1 && segnum == 0) { 763 if (lfs_fsbtob(lfsp, lfs_sb_gets0addr(lfsp)) < LFS_LABELPAD) { 764 /* First segment eats the disklabel */ 765 sum_offset += lfs_fragroundup(lfsp, LFS_LABELPAD) - 766 lfs_fsbtob(lfsp, lfs_sb_gets0addr(lfsp)); 767 addr += lfs_btofsb(lfsp, lfs_fragroundup(lfsp, LFS_LABELPAD)) - 768 lfs_sb_gets0addr(lfsp); 769 printf("Disklabel at 0x0\n"); 770 } 771 } 772 773 sb = 0; 774 did_one = 0; 775 do { 776 get(fd, sum_offset, sumblock, lfs_sb_getsumsize(lfsp)); 777 sump = (SEGSUM *)sumblock; 778 sumstart = lfs_ss_getsumstart(lfsp); 779 if ((lfs_sb_getversion(lfsp) > 1 && 780 lfs_ss_getident(lfsp, sump) != lfs_sb_getident(lfsp)) || 781 lfs_ss_getsumsum(lfsp, sump) != 782 cksum((char *)sump + sumstart, 783 lfs_sb_getsumsize(lfsp) - sumstart)) { 784 sbp = (struct lfs *)sump; 785 if ((sb = (sbp->lfs_dlfs_u.u_32.dlfs_magic == LFS_MAGIC))) { 786 printf("Superblock at 0x%x\n", 787 (unsigned)lfs_btofsb(lfsp, sum_offset)); 788 if (dump_sb) { 789 __CTASSERT(sizeof(struct dlfs) == 790 sizeof(struct dlfs64)); 791 get(fd, sum_offset, &(lfs_sb.lfs_dlfs_u), 792 sizeof(struct dlfs)); 793 dump_super(&lfs_sb); 794 } 795 if (lfs_sb_getversion(lfsp) > 1) 796 sum_offset += lfs_fragroundup(lfsp, LFS_SBPAD); 797 else 798 sum_offset += LFS_SBPAD; 799 } else if (did_one) 800 break; 801 else { 802 printf("Segment at 0x%llx empty or corrupt\n", 803 (long long)addr); 804 break; 805 } 806 } else { 807 nbytes = dump_sum(fd, lfsp, sump, segnum, 808 lfs_btofsb(lfsp, sum_offset)); 809 if (nbytes >= 0) 810 sum_offset += lfs_sb_getsumsize(lfsp) + nbytes; 811 else 812 sum_offset = 0; 813 did_one = 1; 814 } 815 /* If the segment ends right on a boundary, it still ends */ 816 new_addr = lfs_btofsb(lfsp, sum_offset); 817 /* printf("end daddr = 0x%lx\n", (long)new_addr); */ 818 if (lfs_dtosn(lfsp, new_addr) != lfs_dtosn(lfsp, addr)) 819 break; 820 } while (sum_offset); 821 822 free(sumblock); 823 } 824 825 static void 826 dump_super(struct lfs *lfsp) 827 { 828 time_t stamp; 829 int i; 830 831 (void)printf(" %s0x%-8x %s0x%-8x %s%-10ju\n", 832 "magic ", lfsp->lfs_dlfs_u.u_32.dlfs_magic, 833 "version ", lfs_sb_getversion(lfsp), 834 "size ", (uintmax_t)lfs_sb_getsize(lfsp)); 835 (void)printf(" %s%-10d %s%-10ju %s%-10d\n", 836 "ssize ", lfs_sb_getssize(lfsp), 837 "dsize ", (uintmax_t)lfs_sb_getdsize(lfsp), 838 "bsize ", lfs_sb_getbsize(lfsp)); 839 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 840 "fsize ", lfs_sb_getfsize(lfsp), 841 "frag ", lfs_sb_getfrag(lfsp), 842 "minfree ", lfs_sb_getminfree(lfsp)); 843 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 844 "inopb ", lfs_sb_getinopb(lfsp), 845 "ifpb ", lfs_sb_getifpb(lfsp), 846 "nindir ", lfs_sb_getnindir(lfsp)); 847 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 848 "nseg ", lfs_sb_getnseg(lfsp), 849 "sepb ", lfs_sb_getsepb(lfsp), 850 "cleansz ", lfs_sb_getcleansz(lfsp)); 851 (void)printf(" %s%-10d %s0x%-8x %s%-10d\n", 852 "segtabsz ", lfs_sb_getsegtabsz(lfsp), 853 "segmask ", lfs_sb_getsegmask(lfsp), 854 "segshift ", lfs_sb_getsegshift(lfsp)); 855 (void)printf(" %s0x%-8jx %s%-10d %s0x%-8jX\n", 856 "bmask ", (uintmax_t)lfs_sb_getbmask(lfsp), 857 "bshift ", lfs_sb_getbshift(lfsp), 858 "ffmask ", (uintmax_t)lfs_sb_getffmask(lfsp)); 859 (void)printf(" %s%-10d %s0x%-8jx %s%u\n", 860 "ffshift ", lfs_sb_getffshift(lfsp), 861 "fbmask ", (uintmax_t)lfs_sb_getfbmask(lfsp), 862 "fbshift ", lfs_sb_getfbshift(lfsp)); 863 864 (void)printf(" %s%-10d %s%-10d %s0x%-8x\n", 865 "sushift ", lfs_sb_getsushift(lfsp), 866 "fsbtodb ", lfs_sb_getfsbtodb(lfsp), 867 "cksum ", lfs_sb_getcksum(lfsp)); 868 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 869 "nclean ", lfs_sb_getnclean(lfsp), 870 "dmeta ", lfs_sb_getdmeta(lfsp), 871 "minfreeseg ", lfs_sb_getminfreeseg(lfsp)); 872 (void)printf(" %s0x%-8x %s%-9d %s%-10d\n", 873 "roll_id ", lfs_sb_getident(lfsp), 874 "interleave ", lfs_sb_getinterleave(lfsp), 875 "sumsize ", lfs_sb_getsumsize(lfsp)); 876 (void)printf(" %s%-10jd %s0x%-8jx\n", 877 "seg0addr ", (intmax_t)lfs_sb_gets0addr(lfsp), 878 "maxfilesize ", (uintmax_t)lfs_sb_getmaxfilesize(lfsp)); 879 880 881 (void)printf(" Superblock disk addresses:\n "); 882 for (i = 0; i < LFS_MAXNUMSB; i++) { 883 (void)printf(" 0x%-8jx", (intmax_t)lfs_sb_getsboff(lfsp, i)); 884 if (i == (LFS_MAXNUMSB >> 1)) 885 (void)printf("\n "); 886 } 887 (void)printf("\n"); 888 889 (void)printf(" Checkpoint Info\n"); 890 (void)printf(" %s%-10ju %s0x%-8jx\n", 891 "freehd ", (uintmax_t)lfs_sb_getfreehd(lfsp), 892 "idaddr ", (intmax_t)lfs_sb_getidaddr(lfsp)); 893 (void)printf(" %s%-10d %s%-10jd %s%-10jd\n", 894 "uinodes ", lfs_sb_getuinodes(lfsp), 895 "bfree ", (intmax_t)lfs_sb_getbfree(lfsp), 896 "avail ", (intmax_t)lfs_sb_getavail(lfsp)); 897 (void)printf(" %s%-10ju %s0x%-8jx %s0x%-8jx\n", 898 "nfiles ", (uintmax_t)lfs_sb_getnfiles(lfsp), 899 "lastseg ", (uintmax_t)lfs_sb_getlastseg(lfsp), 900 "nextseg ", (uintmax_t)lfs_sb_getnextseg(lfsp)); 901 (void)printf(" %s0x%-8jx %s0x%-8jx %s%-10ju\n", 902 "curseg ", (uintmax_t)lfs_sb_getcurseg(lfsp), 903 "offset ", (uintmax_t)lfs_sb_getoffset(lfsp), 904 "serial ", (uintmax_t)lfs_sb_getserial(lfsp)); 905 stamp = lfs_sb_gettstamp(lfsp); 906 (void)printf(" tstamp %s", ctime(&stamp)); 907 908 if (!lfsp->lfs_is64) { 909 (void)printf(" 32-bit only derived or constant fields\n"); 910 (void)printf(" %s%-10u\n", 911 "ifile ", lfs_sb_getifile(lfsp)); 912 } 913 } 914 915 static void 916 addseg(char *arg) 917 { 918 SEGLIST *p; 919 920 p = emalloc(sizeof(*p)); 921 p->next = seglist; 922 p->num = atoi(arg); 923 seglist = p; 924 } 925 926 static void 927 dump_cleaner_info(struct lfs *lfsp, void *ipage) 928 { 929 CLEANERINFO *cip; 930 931 cip = (CLEANERINFO *)ipage; 932 if (lfs_sb_getversion(lfsp) > 1) { 933 (void)printf("free_head %ju\n", 934 (uintmax_t)lfs_ci_getfree_head(lfsp, cip)); 935 (void)printf("free_tail %ju\n", 936 (uintmax_t)lfs_ci_getfree_tail(lfsp, cip)); 937 } 938 (void)printf("clean\t%u\tdirty\t%u\n", 939 lfs_ci_getclean(lfsp, cip), lfs_ci_getdirty(lfsp, cip)); 940 (void)printf("bfree\t%jd\tavail\t%jd\n\n", 941 (intmax_t)lfs_ci_getbfree(lfsp, cip), 942 (intmax_t)lfs_ci_getavail(lfsp, cip)); 943 } 944 945 static void 946 dump_inoblk(int fd, struct lfs *lfsp, daddr_t daddr, ino_t ino) 947 { 948 char *buf; 949 union lfs_dinode *dip; 950 ino_t dino; 951 int i; 952 953 buf = emalloc(lfs_sb_getfsize(lfsp)); 954 get(fd, lfs_fsbtob(lfsp, daddr), buf, lfs_sb_getfsize(lfsp)); 955 for (i = 0; i < LFS_INOPB(lfsp); ++i) { 956 dip = DINO_IN_BLOCK(lfsp, buf, i); 957 dino = lfs_dino_getinumber(lfsp, dip); 958 if (dino == 0) 959 continue; 960 else if (ino == 0 || ino == dino) { 961 (void)printf("Addr 0x%jx entry %d inode %jd:\n", 962 (intmax_t)daddr, i, (intmax_t)dino); 963 dump_dinode(lfsp, dip); 964 } 965 } 966 } 967 968 969 static void 970 usage(void) 971 { 972 (void)fprintf(stderr, "usage: dumplfs [-adiS] [-b blkno] [-I blkno] [-s segno] filesys|device\n"); 973 exit(1); 974 } 975