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