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