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