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