dumplfs.c revision 1.36
1/* $NetBSD: dumplfs.c,v 1.36 2008/02/16 07:32:22 matt 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( 36"@(#) Copyright (c) 1991, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"); 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)dumplfs.c 8.5 (Berkeley) 5/24/95"; 43#else 44__RCSID("$NetBSD: dumplfs.c,v 1.36 2008/02/16 07:32:22 matt Exp $"); 45#endif 46#endif /* not lint */ 47 48#include <sys/param.h> 49#include <sys/ucred.h> 50#include <sys/mount.h> 51#include <sys/time.h> 52 53#include <ufs/ufs/dinode.h> 54#include <ufs/lfs/lfs.h> 55 56#include <err.h> 57#include <errno.h> 58#include <fcntl.h> 59#include <fstab.h> 60#include <stdlib.h> 61#include <stdio.h> 62#include <string.h> 63#include <unistd.h> 64#include "extern.h" 65 66static void addseg(char *); 67static void dump_cleaner_info(struct lfs *, void *); 68static void dump_dinode(struct ufs1_dinode *); 69static void dump_ifile(int, struct lfs *, int, int, daddr_t); 70static int dump_ipage_ifile(struct lfs *, int, char *, int); 71static int dump_ipage_segusage(struct lfs *, int, char *, int); 72static void dump_segment(int, int, daddr_t, struct lfs *, int); 73static int dump_sum(int, struct lfs *, SEGSUM *, int, daddr_t); 74static void dump_super(struct lfs *); 75static void usage(void); 76 77extern uint32_t cksum(void *, size_t); 78 79typedef struct seglist SEGLIST; 80struct seglist { 81 SEGLIST *next; 82 int num; 83}; 84SEGLIST *seglist; 85 86char *special; 87 88/* Segment Usage formats */ 89#define print_suheader \ 90 (void)printf("segnum\tflags\tnbytes\tninos\tnsums\tlastmod\n") 91 92static inline void 93print_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 = (fs->lfs_version == 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 118static inline void 119print_ientry(int i, IFILE *ip) 120{ 121 if (ip->if_daddr == LFS_UNUSED_DADDR) 122 printf("%d\tFREE\t%d\t \t\t%llu\n", i, ip->if_version, 123 (unsigned long long)ip->if_nextfree); 124 else 125 printf("%d\tINUSE\t%d\t%8X\t%s\n", 126 i, ip->if_version, ip->if_daddr, 127 (ip->if_nextfree == LFS_ORPHAN_NEXTFREE ? "FFFFFFFF" : "-")); 128} 129 130#define fsbtobyte(fs, b) fsbtob((fs), (off_t)((b))) 131 132int datasum_check = 0; 133 134int 135main(int argc, char **argv) 136{ 137 struct lfs lfs_sb1, lfs_sb2, *lfs_master; 138 daddr_t seg_addr, idaddr, sbdaddr; 139 int ch, do_allsb, do_ientries, do_segentries, fd, segnum; 140 141 do_allsb = 0; 142 do_ientries = 0; 143 do_segentries = 0; 144 idaddr = 0x0; 145 sbdaddr = 0x0; 146 while ((ch = getopt(argc, argv, "ab:diI:Ss:")) != -1) 147 switch(ch) { 148 case 'a': /* Dump all superblocks */ 149 do_allsb = 1; 150 break; 151 case 'b': /* Use this superblock */ 152 sbdaddr = strtol(optarg, NULL, 0); 153 break; 154 case 'd': 155 datasum_check = 1; 156 break; 157 case 'i': /* Dump ifile entries */ 158 do_ientries = !do_ientries; 159 break; 160 case 'I': /* Use this ifile inode */ 161 idaddr = strtol(optarg, NULL, 0); 162 break; 163 case 'S': 164 do_segentries = !do_segentries; 165 break; 166 case 's': /* Dump out these segments */ 167 addseg(optarg); 168 break; 169 default: 170 usage(); 171 } 172 argc -= optind; 173 argv += optind; 174 175 if (argc != 1) 176 usage(); 177 178 special = argv[0]; 179 if ((fd = open(special, O_RDONLY, 0)) < 0) 180 err(1, "%s", special); 181 182 if (sbdaddr == 0x0) { 183 /* Read the proto-superblock */ 184 get(fd, LFS_LABELPAD, &(lfs_sb1.lfs_dlfs), sizeof(struct dlfs)); 185 186 /* If that wasn't the real first sb, get the real first sb */ 187 if (lfs_sb1.lfs_version > 1 && 188 lfs_sb1.lfs_sboffs[0] > btofsb(&lfs_sb1, LFS_LABELPAD)) 189 get(fd, fsbtob(&lfs_sb1, lfs_sb1.lfs_sboffs[0]), 190 &(lfs_sb1.lfs_dlfs), sizeof(struct dlfs)); 191 192 /* 193 * Read the second superblock and figure out which check point is 194 * most up to date. 195 */ 196 get(fd, 197 fsbtobyte(&lfs_sb1, lfs_sb1.lfs_sboffs[1]), 198 &(lfs_sb2.lfs_dlfs), sizeof(struct dlfs)); 199 200 lfs_master = &lfs_sb1; 201 if (lfs_sb1.lfs_version > 1) { 202 if (lfs_sb1.lfs_serial > lfs_sb2.lfs_serial) { 203 lfs_master = &lfs_sb2; 204 sbdaddr = lfs_sb1.lfs_sboffs[1]; 205 } else 206 sbdaddr = lfs_sb1.lfs_sboffs[0]; 207 } else { 208 if (lfs_sb1.lfs_otstamp > lfs_sb2.lfs_otstamp) { 209 lfs_master = &lfs_sb2; 210 sbdaddr = lfs_sb1.lfs_sboffs[1]; 211 } else 212 sbdaddr = lfs_sb1.lfs_sboffs[0]; 213 } 214 } else { 215 /* Read the first superblock */ 216 get(fd, dbtob((off_t)sbdaddr), &(lfs_sb1.lfs_dlfs), 217 sizeof(struct dlfs)); 218 lfs_master = &lfs_sb1; 219 } 220 221 /* Compatibility */ 222 if (lfs_master->lfs_version == 1) { 223 lfs_master->lfs_sumsize = LFS_V1_SUMMARY_SIZE; 224 lfs_master->lfs_ibsize = lfs_master->lfs_bsize; 225 lfs_master->lfs_start = lfs_master->lfs_sboffs[0]; 226 lfs_master->lfs_tstamp = lfs_master->lfs_otstamp; 227 lfs_master->lfs_fsbtodb = 0; 228 } 229 230 (void)printf("Master Superblock at 0x%llx:\n", (long long)sbdaddr); 231 dump_super(lfs_master); 232 233 dump_ifile(fd, lfs_master, do_ientries, do_segentries, idaddr); 234 235 if (seglist != NULL) 236 for (; seglist != NULL; seglist = seglist->next) { 237 seg_addr = sntod(lfs_master, seglist->num); 238 dump_segment(fd, seglist->num, seg_addr, lfs_master, 239 do_allsb); 240 } 241 else 242 for (segnum = 0, seg_addr = sntod(lfs_master, 0); 243 segnum < lfs_master->lfs_nseg; 244 segnum++, seg_addr = sntod(lfs_master, segnum)) 245 dump_segment(fd, segnum, seg_addr, lfs_master, 246 do_allsb); 247 248 (void)close(fd); 249 exit(0); 250} 251 252/* 253 * We are reading all the blocks of an inode and dumping out the ifile table. 254 * This code could be tighter, but this is a first pass at getting the stuff 255 * printed out rather than making this code incredibly efficient. 256 */ 257static void 258dump_ifile(int fd, struct lfs *lfsp, int do_ientries, int do_segentries, daddr_t addr) 259{ 260 char *ipage; 261 struct ufs1_dinode *dip, *dpage; 262 /* XXX ondisk32 */ 263 int32_t *addrp, *dindir, *iaddrp, *indir; 264 int block_limit, i, inum, j, nblocks, psize; 265 266 psize = lfsp->lfs_bsize; 267 if (!addr) 268 addr = lfsp->lfs_idaddr; 269 270 if (!(dpage = malloc(psize))) 271 err(1, "malloc"); 272 get(fd, fsbtobyte(lfsp, addr), dpage, psize); 273 274 for (dip = dpage + INOPB(lfsp) - 1; dip >= dpage; --dip) 275 if (dip->di_inumber == LFS_IFILE_INUM) 276 break; 277 278 if (dip < dpage) { 279 warnx("unable to locate ifile inode at disk address 0x%llx", 280 (long long)addr); 281 return; 282 } 283 284 (void)printf("\nIFILE inode\n"); 285 dump_dinode(dip); 286 287 (void)printf("\nIFILE contents\n"); 288 nblocks = dip->di_size >> lfsp->lfs_bshift; 289 block_limit = MIN(nblocks, NDADDR); 290 291 /* Get the direct block */ 292 if ((ipage = malloc(psize)) == NULL) 293 err(1, "malloc"); 294 for (inum = 0, addrp = dip->di_db, i = 0; i < block_limit; 295 i++, addrp++) { 296 get(fd, fsbtobyte(lfsp, *addrp), ipage, psize); 297 if (i < lfsp->lfs_cleansz) { 298 dump_cleaner_info(lfsp, ipage); 299 if (do_segentries) 300 print_suheader; 301 continue; 302 } 303 304 if (i < (lfsp->lfs_segtabsz + lfsp->lfs_cleansz)) { 305 if (do_segentries) 306 inum = dump_ipage_segusage(lfsp, inum, ipage, 307 lfsp->lfs_sepb); 308 else 309 inum = (i < lfsp->lfs_segtabsz + lfsp->lfs_cleansz - 1); 310 if (!inum) { 311 if(!do_ientries) 312 goto e0; 313 else 314 print_iheader; 315 } 316 } else 317 inum = dump_ipage_ifile(lfsp, inum, ipage, lfsp->lfs_ifpb); 318 } 319 320 if (nblocks <= NDADDR) 321 goto e0; 322 323 /* Dump out blocks off of single indirect block */ 324 if (!(indir = malloc(psize))) 325 err(1, "malloc"); 326 get(fd, fsbtobyte(lfsp, dip->di_ib[0]), indir, psize); 327 block_limit = MIN(i + lfsp->lfs_nindir, nblocks); 328 for (addrp = indir; i < block_limit; i++, addrp++) { 329 if (*addrp == LFS_UNUSED_DADDR) 330 break; 331 get(fd, fsbtobyte(lfsp, *addrp), ipage, psize); 332 if (i < lfsp->lfs_cleansz) { 333 dump_cleaner_info(lfsp, ipage); 334 continue; 335 } 336 337 if (i < lfsp->lfs_segtabsz + lfsp->lfs_cleansz) { 338 if (do_segentries) 339 inum = dump_ipage_segusage(lfsp, inum, ipage, 340 lfsp->lfs_sepb); 341 else 342 inum = (i < lfsp->lfs_segtabsz + lfsp->lfs_cleansz - 1); 343 if (!inum) { 344 if(!do_ientries) 345 goto e1; 346 else 347 print_iheader; 348 } 349 } else 350 inum = dump_ipage_ifile(lfsp, inum, ipage, lfsp->lfs_ifpb); 351 } 352 353 if (nblocks <= lfsp->lfs_nindir * lfsp->lfs_ifpb) 354 goto e1; 355 356 /* Get the double indirect block */ 357 if (!(dindir = malloc(psize))) 358 err(1, "malloc"); 359 get(fd, fsbtobyte(lfsp, dip->di_ib[1]), dindir, psize); 360 for (iaddrp = dindir, j = 0; j < lfsp->lfs_nindir; j++, iaddrp++) { 361 if (*iaddrp == LFS_UNUSED_DADDR) 362 break; 363 get(fd, fsbtobyte(lfsp, *iaddrp), indir, psize); 364 block_limit = MIN(i + lfsp->lfs_nindir, nblocks); 365 for (addrp = indir; i < block_limit; i++, addrp++) { 366 if (*addrp == LFS_UNUSED_DADDR) 367 break; 368 get(fd, fsbtobyte(lfsp, *addrp), ipage, psize); 369 if (i < lfsp->lfs_cleansz) { 370 dump_cleaner_info(lfsp, ipage); 371 continue; 372 } 373 374 if (i < lfsp->lfs_segtabsz + lfsp->lfs_cleansz) { 375 if (do_segentries) 376 inum = dump_ipage_segusage(lfsp, 377 inum, ipage, lfsp->lfs_sepb); 378 else 379 inum = (i < lfsp->lfs_segtabsz + 380 lfsp->lfs_cleansz - 1); 381 if (!inum) { 382 if(!do_ientries) 383 goto e2; 384 else 385 print_iheader; 386 } 387 } else 388 inum = dump_ipage_ifile(lfsp, inum, 389 ipage, lfsp->lfs_ifpb); 390 } 391 } 392e2: free(dindir); 393e1: free(indir); 394e0: free(dpage); 395 free(ipage); 396} 397 398static int 399dump_ipage_ifile(struct lfs *lfsp, int i, char *pp, int tot) 400{ 401 char *ip; 402 int cnt, max, entsize; 403 404 if (lfsp->lfs_version == 1) 405 entsize = sizeof(IFILE_V1); 406 else 407 entsize = sizeof(IFILE); 408 max = i + tot; 409 410 for (ip = pp, cnt = i; cnt < max; cnt++, ip += entsize) 411 print_ientry(cnt, (IFILE *)ip); 412 return (max); 413} 414 415static int 416dump_ipage_segusage(struct lfs *lfsp, int i, char *pp, int tot) 417{ 418 SEGUSE *sp; 419 int cnt, max; 420 struct seglist *slp; 421 422 max = i + tot; 423 for (sp = (SEGUSE *)pp, cnt = i; 424 cnt < lfsp->lfs_nseg && cnt < max; cnt++) { 425 if (seglist == NULL) 426 print_suentry(cnt, sp, lfsp); 427 else { 428 for (slp = seglist; slp != NULL; slp = slp->next) 429 if (cnt == slp->num) { 430 print_suentry(cnt, sp, lfsp); 431 break; 432 } 433 } 434 if (lfsp->lfs_version > 1) 435 ++sp; 436 else 437 sp = (SEGUSE *)((SEGUSE_V1 *)sp + 1); 438 } 439 if (max >= lfsp->lfs_nseg) 440 return (0); 441 else 442 return (max); 443} 444 445static void 446dump_dinode(struct ufs1_dinode *dip) 447{ 448 int i; 449 time_t at, mt, ct; 450 451 at = dip->di_atime; 452 mt = dip->di_mtime; 453 ct = dip->di_ctime; 454 455 (void)printf(" %so%o\t%s%d\t%s%d\t%s%d\t%s%llu\n", 456 "mode ", dip->di_mode, 457 "nlink ", dip->di_nlink, 458 "uid ", dip->di_uid, 459 "gid ", dip->di_gid, 460 "size ", (long long)dip->di_size); 461 (void)printf(" %s%s %s%s %s%s", 462 "atime ", ctime(&at), 463 "mtime ", ctime(&mt), 464 "ctime ", ctime(&ct)); 465 (void)printf(" inum %d\n", dip->di_inumber); 466 (void)printf(" Direct Addresses\n"); 467 for (i = 0; i < NDADDR; i++) { 468 (void)printf("\t0x%x", dip->di_db[i]); 469 if ((i % 6) == 5) 470 (void)printf("\n"); 471 } 472 for (i = 0; i < NIADDR; i++) 473 (void)printf("\t0x%x", dip->di_ib[i]); 474 (void)printf("\n"); 475} 476 477static int 478dump_sum(int fd, struct lfs *lfsp, SEGSUM *sp, int segnum, daddr_t addr) 479{ 480 FINFO *fp; 481 int32_t *dp, *idp; 482 int i, j, acc; 483 int ck; 484 int numbytes, numblocks; 485 char *datap; 486 struct ufs1_dinode *inop; 487 size_t el_size; 488 u_int32_t datasum; 489 time_t t; 490 char *buf; 491 492 if (sp->ss_magic != SS_MAGIC || 493 sp->ss_sumsum != (ck = cksum(&sp->ss_datasum, 494 lfsp->lfs_sumsize - sizeof(sp->ss_sumsum)))) { 495 /* Don't print "corrupt" if we're just too close to the edge */ 496 if (dtosn(lfsp, addr + fsbtodb(lfsp, 1)) == 497 dtosn(lfsp, addr)) 498 (void)printf("dumplfs: %s %d address 0x%llx\n", 499 "corrupt summary block; segment", segnum, 500 (long long)addr); 501 return -1; 502 } 503 if (lfsp->lfs_version > 1 && sp->ss_ident != lfsp->lfs_ident) { 504 (void)printf("dumplfs: %s %d address 0x%llx\n", 505 "summary from a former life; segment", segnum, 506 (long long)addr); 507 return -1; 508 } 509 510 (void)printf("Segment Summary Info at 0x%llx\n", (long long)addr); 511 (void)printf(" %s0x%x\t%s%d\t%s%d\t%s%c%c%c%c\n %s0x%x\t%s0x%x", 512 "next ", sp->ss_next, 513 "nfinfo ", sp->ss_nfinfo, 514 "ninos ", sp->ss_ninos, 515 "flags ", (sp->ss_flags & SS_DIROP) ? 'D' : '-', 516 (sp->ss_flags & SS_CONT) ? 'C' : '-', 517 (sp->ss_flags & SS_CLEAN) ? 'L' : '-', 518 (sp->ss_flags & SS_RFW) ? 'R' : '-', 519 "sumsum ", sp->ss_sumsum, 520 "datasum ", sp->ss_datasum ); 521 if (lfsp->lfs_version == 1) { 522 t = sp->ss_ocreate; 523 (void)printf("\tcreate %s\n", ctime(&t)); 524 } else { 525 t = sp->ss_create; 526 (void)printf("\tcreate %s", ctime(&t)); 527 (void)printf(" roll_id %-8x", sp->ss_ident); 528 (void)printf(" serial %lld\n", (long long)sp->ss_serial); 529 } 530 531 /* Dump out inode disk addresses */ 532 dp = (int32_t *)sp; 533 dp += lfsp->lfs_sumsize / sizeof(int32_t); 534 inop = malloc(lfsp->lfs_bsize); 535 printf(" Inode addresses:"); 536 numbytes = 0; 537 numblocks = 0; 538 for (dp--, i = 0; i < sp->ss_ninos; dp--) { 539 ++numblocks; 540 numbytes += lfsp->lfs_ibsize; /* add bytes for inode block */ 541 printf("\t0x%x {", *dp); 542 get(fd, fsbtobyte(lfsp, *dp), inop, lfsp->lfs_ibsize); 543 for (j = 0; i < sp->ss_ninos && j < INOPB(lfsp); j++, i++) { 544 if (j > 0) 545 (void)printf(", "); 546 (void)printf("%dv%d", inop[j].di_inumber, inop[j].di_gen); 547 } 548 (void)printf("}"); 549 if (((i/INOPB(lfsp)) % 4) == 3) 550 (void)printf("\n"); 551 } 552 free(inop); 553 554 printf("\n"); 555 556 if (lfsp->lfs_version == 1) 557 fp = (FINFO *)((SEGSUM_V1 *)sp + 1); 558 else 559 fp = (FINFO *)(sp + 1); 560 for (i = 0; i < sp->ss_nfinfo; i++) { 561 (void)printf(" FINFO for inode: %d version %d nblocks %d lastlength %d\n", 562 fp->fi_ino, fp->fi_version, fp->fi_nblocks, 563 fp->fi_lastlength); 564 dp = &(fp->fi_blocks[0]); 565 numblocks += fp->fi_nblocks; 566 for (j = 0; j < fp->fi_nblocks; j++, dp++) { 567 (void)printf("\t%d", *dp); 568 if ((j % 8) == 7) 569 (void)printf("\n"); 570 if (j == fp->fi_nblocks - 1) 571 numbytes += fp->fi_lastlength; 572 else 573 numbytes += lfsp->lfs_bsize; 574 } 575 if ((j % 8) != 0) 576 (void)printf("\n"); 577 fp = (FINFO *)dp; 578 } 579 580 if (datasum_check == 0) 581 return (numbytes); 582 583 /* 584 * Now that we know the number of blocks, run back through and 585 * compute the data checksum. (A bad data checksum is not enough 586 * to prevent us from continuing, but it odes merit a warning.) 587 */ 588 idp = (int32_t *)sp; 589 idp += lfsp->lfs_sumsize / sizeof(int32_t); 590 --idp; 591 if (lfsp->lfs_version == 1) { 592 fp = (FINFO *)((SEGSUM_V1 *)sp + 1); 593 el_size = sizeof(unsigned long); 594 } else { 595 fp = (FINFO *)(sp + 1); 596 el_size = sizeof(u_int32_t); 597 } 598 datap = (char *)malloc(el_size * numblocks); 599 memset(datap, 0, el_size * numblocks); 600 acc = 0; 601 addr += btofsb(lfsp, lfsp->lfs_sumsize); 602 buf = malloc(lfsp->lfs_bsize); 603 for (i = 0; i < sp->ss_nfinfo; i++) { 604 while (addr == *idp) { 605 get(fd, fsbtobyte(lfsp, addr), buf, lfsp->lfs_ibsize); 606 memcpy(datap + acc * el_size, buf, el_size); 607 addr += btofsb(lfsp, lfsp->lfs_ibsize); 608 --idp; 609 ++acc; 610 } 611 for (j = 0; j < fp->fi_nblocks; j++) { 612 get(fd, fsbtobyte(lfsp, addr), buf, lfsp->lfs_fsize); 613 memcpy(datap + acc * el_size, buf, el_size); 614 if (j == fp->fi_nblocks - 1) 615 addr += btofsb(lfsp, fp->fi_lastlength); 616 else 617 addr += btofsb(lfsp, lfsp->lfs_bsize); 618 ++acc; 619 } 620 fp = (FINFO *)&(fp->fi_blocks[fp->fi_nblocks]); 621 } 622 while (addr == *idp) { 623 get(fd, fsbtobyte(lfsp, addr), buf, lfsp->lfs_ibsize); 624 memcpy(datap + acc * el_size, buf, el_size); 625 addr += btofsb(lfsp, lfsp->lfs_ibsize); 626 --idp; 627 ++acc; 628 } 629 free(buf); 630 if (acc != numblocks) 631 printf("** counted %d blocks but should have been %d\n", 632 acc, numblocks); 633 datasum = cksum(datap, numblocks * el_size); 634 if (datasum != sp->ss_datasum) 635 printf("** computed datasum 0x%lx does not match given datasum 0x%lx\n", (unsigned long)datasum, (unsigned long)sp->ss_datasum); 636 free(datap); 637 638 return (numbytes); 639} 640 641static void 642dump_segment(int fd, int segnum, daddr_t addr, struct lfs *lfsp, int dump_sb) 643{ 644 struct lfs lfs_sb, *sbp; 645 SEGSUM *sump; 646 char *sumblock; 647 int did_one, nbytes, sb; 648 off_t sum_offset; 649 daddr_t new_addr; 650 651 (void)printf("\nSEGMENT %lld (Disk Address 0x%llx)\n", 652 (long long)dtosn(lfsp, addr), (long long)addr); 653 sum_offset = fsbtobyte(lfsp, addr); 654 sumblock = malloc(lfsp->lfs_sumsize); 655 656 if (lfsp->lfs_version > 1 && segnum == 0) { 657 if (fsbtob(lfsp, lfsp->lfs_start) < LFS_LABELPAD) { 658 /* First segment eats the disklabel */ 659 sum_offset += fragroundup(lfsp, LFS_LABELPAD) - 660 fsbtob(lfsp, lfsp->lfs_start); 661 addr += btofsb(lfsp, fragroundup(lfsp, LFS_LABELPAD)) - 662 lfsp->lfs_start; 663 printf("Disklabel at 0x0\n"); 664 } 665 } 666 667 sb = 0; 668 did_one = 0; 669 do { 670 get(fd, sum_offset, sumblock, lfsp->lfs_sumsize); 671 sump = (SEGSUM *)sumblock; 672 if ((lfsp->lfs_version > 1 && 673 sump->ss_ident != lfsp->lfs_ident) || 674 sump->ss_sumsum != cksum (&sump->ss_datasum, 675 lfsp->lfs_sumsize - sizeof(sump->ss_sumsum))) { 676 sbp = (struct lfs *)sump; 677 if ((sb = (sbp->lfs_magic == LFS_MAGIC))) { 678 printf("Superblock at 0x%x\n", 679 (unsigned)btofsb(lfsp, sum_offset)); 680 if (dump_sb) { 681 get(fd, sum_offset, &(lfs_sb.lfs_dlfs), 682 sizeof(struct dlfs)); 683 dump_super(&lfs_sb); 684 } 685 if (lfsp->lfs_version > 1) 686 sum_offset += fragroundup(lfsp, LFS_SBPAD); 687 else 688 sum_offset += LFS_SBPAD; 689 } else if (did_one) 690 break; 691 else { 692 printf("Segment at 0x%llx empty or corrupt\n", 693 (long long)addr); 694 break; 695 } 696 } else { 697 nbytes = dump_sum(fd, lfsp, sump, segnum, 698 btofsb(lfsp, sum_offset)); 699 if (nbytes >= 0) 700 sum_offset += lfsp->lfs_sumsize + nbytes; 701 else 702 sum_offset = 0; 703 did_one = 1; 704 } 705 /* If the segment ends right on a boundary, it still ends */ 706 new_addr = btofsb(lfsp, sum_offset); 707 /* printf("end daddr = 0x%lx\n", (long)new_addr); */ 708 if (dtosn(lfsp, new_addr) != dtosn(lfsp, addr)) 709 break; 710 } while (sum_offset); 711 712 free(sumblock); 713} 714 715static void 716dump_super(struct lfs *lfsp) 717{ 718 int i; 719 720 (void)printf(" %s0x%-8x %s0x%-8x %s%-10d\n", 721 "magic ", lfsp->lfs_magic, 722 "version ", lfsp->lfs_version, 723 "size ", lfsp->lfs_size); 724 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 725 "ssize ", lfsp->lfs_ssize, 726 "dsize ", lfsp->lfs_dsize, 727 "bsize ", lfsp->lfs_bsize); 728 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 729 "fsize ", lfsp->lfs_fsize, 730 "frag ", lfsp->lfs_frag, 731 "minfree ", lfsp->lfs_minfree); 732 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 733 "inopb ", lfsp->lfs_inopb, 734 "ifpb ", lfsp->lfs_ifpb, 735 "nindir ", lfsp->lfs_nindir); 736 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 737 "nseg ", lfsp->lfs_nseg, 738 "sepb ", lfsp->lfs_sepb, 739 "cleansz ", lfsp->lfs_cleansz); 740 (void)printf(" %s%-10d %s0x%-8x %s%-10d\n", 741 "segtabsz ", lfsp->lfs_segtabsz, 742 "segmask ", lfsp->lfs_segmask, 743 "segshift ", lfsp->lfs_segshift); 744 (void)printf(" %s0x%-8qx %s%-10d %s0x%-8qX\n", 745 "bmask ", (long long)lfsp->lfs_bmask, 746 "bshift ", lfsp->lfs_bshift, 747 "ffmask ", (long long)lfsp->lfs_ffmask); 748 (void)printf(" %s%-10d %s0x%-8qx %s%u\n", 749 "ffshift ", lfsp->lfs_ffshift, 750 "fbmask ", (long long)lfsp->lfs_fbmask, 751 "fbshift ", lfsp->lfs_fbshift); 752 753 (void)printf(" %s%-10d %s%-10d %s0x%-8x\n", 754 "sushift ", lfsp->lfs_sushift, 755 "fsbtodb ", lfsp->lfs_fsbtodb, 756 "cksum ", lfsp->lfs_cksum); 757 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 758 "nclean ", lfsp->lfs_nclean, 759 "dmeta ", lfsp->lfs_dmeta, 760 "minfreeseg ", lfsp->lfs_minfreeseg); 761 (void)printf(" %s0x%-8x %s%-9d %s%-10d\n", 762 "roll_id ", lfsp->lfs_ident, 763 "interleave ", lfsp->lfs_interleave, 764 "sumsize ", lfsp->lfs_sumsize); 765 (void)printf(" %s%-10d %s0x%-8qx\n", 766 "seg0addr ", lfsp->lfs_start, 767 "maxfilesize ", (long long)lfsp->lfs_maxfilesize); 768 769 770 (void)printf(" Superblock disk addresses:\n "); 771 for (i = 0; i < LFS_MAXNUMSB; i++) { 772 (void)printf(" 0x%-8x", lfsp->lfs_sboffs[i]); 773 if (i == (LFS_MAXNUMSB >> 1)) 774 (void)printf("\n "); 775 } 776 (void)printf("\n"); 777 778 (void)printf(" Checkpoint Info\n"); 779 (void)printf(" %s%-10d %s0x%-8x %s%-10d\n", 780 "freehd ", lfsp->lfs_freehd, 781 "idaddr ", lfsp->lfs_idaddr, 782 "ifile ", lfsp->lfs_ifile); 783 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 784 "uinodes ", lfsp->lfs_uinodes, 785 "bfree ", lfsp->lfs_bfree, 786 "avail ", lfsp->lfs_avail); 787 (void)printf(" %s%-10d %s0x%-8x %s0x%-8x\n", 788 "nfiles ", lfsp->lfs_nfiles, 789 "lastseg ", lfsp->lfs_lastseg, 790 "nextseg ", lfsp->lfs_nextseg); 791 (void)printf(" %s0x%-8x %s0x%-8x %s%-10lld\n", 792 "curseg ", lfsp->lfs_curseg, 793 "offset ", lfsp->lfs_offset, 794 "serial ", (long long)lfsp->lfs_serial); 795 (void)printf(" tstamp %s", ctime((time_t *)&lfsp->lfs_tstamp)); 796} 797 798static void 799addseg(char *arg) 800{ 801 SEGLIST *p; 802 803 if ((p = malloc(sizeof(SEGLIST))) == NULL) 804 err(1, "malloc"); 805 p->next = seglist; 806 p->num = atoi(arg); 807 seglist = p; 808} 809 810static void 811dump_cleaner_info(struct lfs *lfsp, void *ipage) 812{ 813 CLEANERINFO *cip; 814 815 cip = (CLEANERINFO *)ipage; 816 if (lfsp->lfs_version > 1) { 817 (void)printf("free_head %d\n", cip->free_head); 818 (void)printf("free_tail %d\n", cip->free_tail); 819 } 820 (void)printf("clean\t%d\tdirty\t%d\n", 821 cip->clean, cip->dirty); 822 (void)printf("bfree\t%d\tavail\t%d\n\n", 823 cip->bfree, cip->avail); 824} 825 826static void 827usage(void) 828{ 829 (void)fprintf(stderr, "usage: dumplfs [-adiS] [-b blkno] [-I blkno] [-s segno] filesys|device\n"); 830 exit(1); 831} 832