1 /* $NetBSD: dumplfs.c,v 1.34 2006/09/01 19:57:41 perseant Exp $ */ 2 3 /*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 34 #ifndef lint 35 __COPYRIGHT( 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 42 static char sccsid[] = "@(#)dumplfs.c 8.5 (Berkeley) 5/24/95"; 43 #else 44 __RCSID("$NetBSD: dumplfs.c,v 1.34 2006/09/01 19:57:41 perseant 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 66 static void addseg(char *); 67 static void dump_cleaner_info(struct lfs *, void *); 68 static void dump_dinode(struct ufs1_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 u_long 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 = (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 118 static inline void 119 print_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 132 int datasum_check = 0; 133 134 int 135 main(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 */ 257 static void 258 dump_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 errx(1, "unable to locate ifile inode at disk address 0x%llx", 280 (long long)addr); 281 282 (void)printf("\nIFILE inode\n"); 283 dump_dinode(dip); 284 285 (void)printf("\nIFILE contents\n"); 286 nblocks = dip->di_size >> lfsp->lfs_bshift; 287 block_limit = MIN(nblocks, NDADDR); 288 289 /* Get the direct block */ 290 if ((ipage = malloc(psize)) == NULL) 291 err(1, "malloc"); 292 for (inum = 0, addrp = dip->di_db, i = 0; i < block_limit; 293 i++, addrp++) { 294 get(fd, fsbtobyte(lfsp, *addrp), ipage, psize); 295 if (i < lfsp->lfs_cleansz) { 296 dump_cleaner_info(lfsp, ipage); 297 if (do_segentries) 298 print_suheader; 299 continue; 300 } 301 302 if (i < (lfsp->lfs_segtabsz + lfsp->lfs_cleansz)) { 303 if (do_segentries) 304 inum = dump_ipage_segusage(lfsp, inum, ipage, 305 lfsp->lfs_sepb); 306 else 307 inum = (i < lfsp->lfs_segtabsz + lfsp->lfs_cleansz - 1); 308 if (!inum) { 309 if(!do_ientries) 310 goto e0; 311 else 312 print_iheader; 313 } 314 } else 315 inum = dump_ipage_ifile(lfsp, inum, ipage, lfsp->lfs_ifpb); 316 } 317 318 if (nblocks <= NDADDR) 319 goto e0; 320 321 /* Dump out blocks off of single indirect block */ 322 if (!(indir = malloc(psize))) 323 err(1, "malloc"); 324 get(fd, fsbtobyte(lfsp, dip->di_ib[0]), indir, psize); 325 block_limit = MIN(i + lfsp->lfs_nindir, nblocks); 326 for (addrp = indir; i < block_limit; i++, addrp++) { 327 if (*addrp == LFS_UNUSED_DADDR) 328 break; 329 get(fd, fsbtobyte(lfsp, *addrp), ipage, psize); 330 if (i < lfsp->lfs_cleansz) { 331 dump_cleaner_info(lfsp, ipage); 332 continue; 333 } 334 335 if (i < lfsp->lfs_segtabsz + lfsp->lfs_cleansz) { 336 if (do_segentries) 337 inum = dump_ipage_segusage(lfsp, inum, ipage, 338 lfsp->lfs_sepb); 339 else 340 inum = (i < lfsp->lfs_segtabsz + lfsp->lfs_cleansz - 1); 341 if (!inum) { 342 if(!do_ientries) 343 goto e1; 344 else 345 print_iheader; 346 } 347 } else 348 inum = dump_ipage_ifile(lfsp, inum, ipage, lfsp->lfs_ifpb); 349 } 350 351 if (nblocks <= lfsp->lfs_nindir * lfsp->lfs_ifpb) 352 goto e1; 353 354 /* Get the double indirect block */ 355 if (!(dindir = malloc(psize))) 356 err(1, "malloc"); 357 get(fd, fsbtobyte(lfsp, dip->di_ib[1]), dindir, psize); 358 for (iaddrp = dindir, j = 0; j < lfsp->lfs_nindir; j++, iaddrp++) { 359 if (*iaddrp == LFS_UNUSED_DADDR) 360 break; 361 get(fd, fsbtobyte(lfsp, *iaddrp), indir, psize); 362 block_limit = MIN(i + lfsp->lfs_nindir, nblocks); 363 for (addrp = indir; i < block_limit; i++, addrp++) { 364 if (*addrp == LFS_UNUSED_DADDR) 365 break; 366 get(fd, fsbtobyte(lfsp, *addrp), ipage, psize); 367 if (i < lfsp->lfs_cleansz) { 368 dump_cleaner_info(lfsp, ipage); 369 continue; 370 } 371 372 if (i < lfsp->lfs_segtabsz + lfsp->lfs_cleansz) { 373 if (do_segentries) 374 inum = dump_ipage_segusage(lfsp, 375 inum, ipage, lfsp->lfs_sepb); 376 else 377 inum = (i < lfsp->lfs_segtabsz + 378 lfsp->lfs_cleansz - 1); 379 if (!inum) { 380 if(!do_ientries) 381 goto e2; 382 else 383 print_iheader; 384 } 385 } else 386 inum = dump_ipage_ifile(lfsp, inum, 387 ipage, lfsp->lfs_ifpb); 388 } 389 } 390 e2: free(dindir); 391 e1: free(indir); 392 e0: free(dpage); 393 free(ipage); 394 } 395 396 static int 397 dump_ipage_ifile(struct lfs *lfsp, int i, char *pp, int tot) 398 { 399 char *ip; 400 int cnt, max, entsize; 401 402 if (lfsp->lfs_version == 1) 403 entsize = sizeof(IFILE_V1); 404 else 405 entsize = sizeof(IFILE); 406 max = i + tot; 407 408 for (ip = pp, cnt = i; cnt < max; cnt++, ip += entsize) 409 print_ientry(cnt, (IFILE *)ip); 410 return (max); 411 } 412 413 static int 414 dump_ipage_segusage(struct lfs *lfsp, int i, char *pp, int tot) 415 { 416 SEGUSE *sp; 417 int cnt, max; 418 struct seglist *slp; 419 420 max = i + tot; 421 for (sp = (SEGUSE *)pp, cnt = i; 422 cnt < lfsp->lfs_nseg && cnt < max; cnt++) { 423 if (seglist == NULL) 424 print_suentry(cnt, sp, lfsp); 425 else { 426 for (slp = seglist; slp != NULL; slp = slp->next) 427 if (cnt == slp->num) { 428 print_suentry(cnt, sp, lfsp); 429 break; 430 } 431 } 432 if (lfsp->lfs_version > 1) 433 ++sp; 434 else 435 sp = (SEGUSE *)((SEGUSE_V1 *)sp + 1); 436 } 437 if (max >= lfsp->lfs_nseg) 438 return (0); 439 else 440 return (max); 441 } 442 443 static void 444 dump_dinode(struct ufs1_dinode *dip) 445 { 446 int i; 447 time_t at, mt, ct; 448 449 at = dip->di_atime; 450 mt = dip->di_mtime; 451 ct = dip->di_ctime; 452 453 (void)printf(" %so%o\t%s%d\t%s%d\t%s%d\t%s%llu\n", 454 "mode ", dip->di_mode, 455 "nlink ", dip->di_nlink, 456 "uid ", dip->di_uid, 457 "gid ", dip->di_gid, 458 "size ", (long long)dip->di_size); 459 (void)printf(" %s%s %s%s %s%s", 460 "atime ", ctime(&at), 461 "mtime ", ctime(&mt), 462 "ctime ", ctime(&ct)); 463 (void)printf(" inum %d\n", dip->di_inumber); 464 (void)printf(" Direct Addresses\n"); 465 for (i = 0; i < NDADDR; i++) { 466 (void)printf("\t0x%x", dip->di_db[i]); 467 if ((i % 6) == 5) 468 (void)printf("\n"); 469 } 470 for (i = 0; i < NIADDR; i++) 471 (void)printf("\t0x%x", dip->di_ib[i]); 472 (void)printf("\n"); 473 } 474 475 static int 476 dump_sum(int fd, struct lfs *lfsp, SEGSUM *sp, int segnum, daddr_t addr) 477 { 478 FINFO *fp; 479 int32_t *dp, *idp; 480 int i, j, acc; 481 int ck; 482 int numbytes, numblocks; 483 char *datap; 484 struct ufs1_dinode *inop; 485 size_t el_size; 486 u_int32_t datasum; 487 time_t t; 488 char *buf; 489 490 if (sp->ss_magic != SS_MAGIC || 491 sp->ss_sumsum != (ck = cksum(&sp->ss_datasum, 492 lfsp->lfs_sumsize - sizeof(sp->ss_sumsum)))) { 493 /* Don't print "corrupt" if we're just too close to the edge */ 494 if (dtosn(lfsp, addr + fsbtodb(lfsp, 1)) == 495 dtosn(lfsp, addr)) 496 (void)printf("dumplfs: %s %d address 0x%llx\n", 497 "corrupt summary block; segment", segnum, 498 (long long)addr); 499 return -1; 500 } 501 if (lfsp->lfs_version > 1 && sp->ss_ident != lfsp->lfs_ident) { 502 (void)printf("dumplfs: %s %d address 0x%llx\n", 503 "summary from a former life; segment", segnum, 504 (long long)addr); 505 return -1; 506 } 507 508 (void)printf("Segment Summary Info at 0x%llx\n", (long long)addr); 509 (void)printf(" %s0x%x\t%s%d\t%s%d\t%s%c%c%c%c\n %s0x%x\t%s0x%x", 510 "next ", sp->ss_next, 511 "nfinfo ", sp->ss_nfinfo, 512 "ninos ", sp->ss_ninos, 513 "flags ", (sp->ss_flags & SS_DIROP) ? 'D' : '-', 514 (sp->ss_flags & SS_CONT) ? 'C' : '-', 515 (sp->ss_flags & SS_CLEAN) ? 'L' : '-', 516 (sp->ss_flags & SS_RFW) ? 'R' : '-', 517 "sumsum ", sp->ss_sumsum, 518 "datasum ", sp->ss_datasum ); 519 if (lfsp->lfs_version == 1) { 520 t = sp->ss_ocreate; 521 (void)printf("\tcreate %s\n", ctime(&t)); 522 } else { 523 t = sp->ss_create; 524 (void)printf("\tcreate %s", ctime(&t)); 525 (void)printf(" roll_id %-8x", sp->ss_ident); 526 (void)printf(" serial %lld\n", (long long)sp->ss_serial); 527 } 528 529 /* Dump out inode disk addresses */ 530 dp = (int32_t *)sp; 531 dp += lfsp->lfs_sumsize / sizeof(int32_t); 532 inop = malloc(lfsp->lfs_bsize); 533 printf(" Inode addresses:"); 534 numbytes = 0; 535 numblocks = 0; 536 for (dp--, i = 0; i < sp->ss_ninos; dp--) { 537 ++numblocks; 538 numbytes += lfsp->lfs_ibsize; /* add bytes for inode block */ 539 printf("\t0x%x {", *dp); 540 get(fd, fsbtobyte(lfsp, *dp), inop, lfsp->lfs_ibsize); 541 for (j = 0; i < sp->ss_ninos && j < INOPB(lfsp); j++, i++) { 542 if (j > 0) 543 (void)printf(", "); 544 (void)printf("%dv%d", inop[j].di_inumber, inop[j].di_gen); 545 } 546 (void)printf("}"); 547 if (((i/INOPB(lfsp)) % 4) == 3) 548 (void)printf("\n"); 549 } 550 free(inop); 551 552 printf("\n"); 553 554 if (lfsp->lfs_version == 1) 555 fp = (FINFO *)((SEGSUM_V1 *)sp + 1); 556 else 557 fp = (FINFO *)(sp + 1); 558 for (i = 0; i < sp->ss_nfinfo; i++) { 559 (void)printf(" FINFO for inode: %d version %d nblocks %d lastlength %d\n", 560 fp->fi_ino, fp->fi_version, fp->fi_nblocks, 561 fp->fi_lastlength); 562 dp = &(fp->fi_blocks[0]); 563 numblocks += fp->fi_nblocks; 564 for (j = 0; j < fp->fi_nblocks; j++, dp++) { 565 (void)printf("\t%d", *dp); 566 if ((j % 8) == 7) 567 (void)printf("\n"); 568 if (j == fp->fi_nblocks - 1) 569 numbytes += fp->fi_lastlength; 570 else 571 numbytes += lfsp->lfs_bsize; 572 } 573 if ((j % 8) != 0) 574 (void)printf("\n"); 575 fp = (FINFO *)dp; 576 } 577 578 if (datasum_check == 0) 579 return (numbytes); 580 581 /* 582 * Now that we know the number of blocks, run back through and 583 * compute the data checksum. (A bad data checksum is not enough 584 * to prevent us from continuing, but it odes merit a warning.) 585 */ 586 idp = (int32_t *)sp; 587 idp += lfsp->lfs_sumsize / sizeof(int32_t); 588 --idp; 589 if (lfsp->lfs_version == 1) { 590 fp = (FINFO *)((SEGSUM_V1 *)sp + 1); 591 el_size = sizeof(unsigned long); 592 } else { 593 fp = (FINFO *)(sp + 1); 594 el_size = sizeof(u_int32_t); 595 } 596 datap = (char *)malloc(el_size * numblocks); 597 memset(datap, 0, el_size * numblocks); 598 acc = 0; 599 addr += btofsb(lfsp, lfsp->lfs_sumsize); 600 buf = malloc(lfsp->lfs_bsize); 601 for (i = 0; i < sp->ss_nfinfo; i++) { 602 while (addr == *idp) { 603 get(fd, fsbtobyte(lfsp, addr), buf, lfsp->lfs_ibsize); 604 memcpy(datap + acc * el_size, buf, el_size); 605 addr += btofsb(lfsp, lfsp->lfs_ibsize); 606 --idp; 607 ++acc; 608 } 609 for (j = 0; j < fp->fi_nblocks; j++) { 610 get(fd, fsbtobyte(lfsp, addr), buf, lfsp->lfs_fsize); 611 memcpy(datap + acc * el_size, buf, el_size); 612 if (j == fp->fi_nblocks - 1) 613 addr += btofsb(lfsp, fp->fi_lastlength); 614 else 615 addr += btofsb(lfsp, lfsp->lfs_bsize); 616 ++acc; 617 } 618 fp = (FINFO *)&(fp->fi_blocks[fp->fi_nblocks]); 619 } 620 while (addr == *idp) { 621 get(fd, fsbtobyte(lfsp, addr), buf, lfsp->lfs_ibsize); 622 memcpy(datap + acc * el_size, buf, el_size); 623 addr += btofsb(lfsp, lfsp->lfs_ibsize); 624 --idp; 625 ++acc; 626 } 627 free(buf); 628 if (acc != numblocks) 629 printf("** counted %d blocks but should have been %d\n", 630 acc, numblocks); 631 datasum = cksum(datap, numblocks * el_size); 632 if (datasum != sp->ss_datasum) 633 printf("** computed datasum 0x%lx does not match given datasum 0x%lx\n", (unsigned long)datasum, (unsigned long)sp->ss_datasum); 634 free(datap); 635 636 return (numbytes); 637 } 638 639 static void 640 dump_segment(int fd, int segnum, daddr_t addr, struct lfs *lfsp, int dump_sb) 641 { 642 struct lfs lfs_sb, *sbp; 643 SEGSUM *sump; 644 char *sumblock; 645 int did_one, nbytes, sb; 646 off_t sum_offset; 647 daddr_t new_addr; 648 649 (void)printf("\nSEGMENT %lld (Disk Address 0x%llx)\n", 650 (long long)dtosn(lfsp, addr), (long long)addr); 651 sum_offset = fsbtobyte(lfsp, addr); 652 sumblock = malloc(lfsp->lfs_sumsize); 653 654 if (lfsp->lfs_version > 1 && segnum == 0) { 655 if (fsbtob(lfsp, lfsp->lfs_start) < LFS_LABELPAD) { 656 /* First segment eats the disklabel */ 657 sum_offset += fragroundup(lfsp, LFS_LABELPAD) - 658 fsbtob(lfsp, lfsp->lfs_start); 659 addr += btofsb(lfsp, fragroundup(lfsp, LFS_LABELPAD)) - 660 lfsp->lfs_start; 661 printf("Disklabel at 0x0\n"); 662 } 663 } 664 665 sb = 0; 666 did_one = 0; 667 do { 668 get(fd, sum_offset, sumblock, lfsp->lfs_sumsize); 669 sump = (SEGSUM *)sumblock; 670 if ((lfsp->lfs_version > 1 && 671 sump->ss_ident != lfsp->lfs_ident) || 672 sump->ss_sumsum != cksum (&sump->ss_datasum, 673 lfsp->lfs_sumsize - sizeof(sump->ss_sumsum))) { 674 sbp = (struct lfs *)sump; 675 if ((sb = (sbp->lfs_magic == LFS_MAGIC))) { 676 printf("Superblock at 0x%x\n", 677 (unsigned)btofsb(lfsp, sum_offset)); 678 if (dump_sb) { 679 get(fd, sum_offset, &(lfs_sb.lfs_dlfs), 680 sizeof(struct dlfs)); 681 dump_super(&lfs_sb); 682 } 683 if (lfsp->lfs_version > 1) 684 sum_offset += fragroundup(lfsp, LFS_SBPAD); 685 else 686 sum_offset += LFS_SBPAD; 687 } else if (did_one) 688 break; 689 else { 690 printf("Segment at 0x%llx empty or corrupt\n", 691 (long long)addr); 692 break; 693 } 694 } else { 695 nbytes = dump_sum(fd, lfsp, sump, segnum, 696 btofsb(lfsp, sum_offset)); 697 if (nbytes >= 0) 698 sum_offset += lfsp->lfs_sumsize + nbytes; 699 else 700 sum_offset = 0; 701 did_one = 1; 702 } 703 /* If the segment ends right on a boundary, it still ends */ 704 new_addr = btofsb(lfsp, sum_offset); 705 /* printf("end daddr = 0x%lx\n", (long)new_addr); */ 706 if (dtosn(lfsp, new_addr) != dtosn(lfsp, addr)) 707 break; 708 } while (sum_offset); 709 710 free(sumblock); 711 } 712 713 static void 714 dump_super(struct lfs *lfsp) 715 { 716 int i; 717 718 (void)printf(" %s0x%-8x %s0x%-8x %s%-10d\n", 719 "magic ", lfsp->lfs_magic, 720 "version ", lfsp->lfs_version, 721 "size ", lfsp->lfs_size); 722 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 723 "ssize ", lfsp->lfs_ssize, 724 "dsize ", lfsp->lfs_dsize, 725 "bsize ", lfsp->lfs_bsize); 726 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 727 "fsize ", lfsp->lfs_fsize, 728 "frag ", lfsp->lfs_frag, 729 "minfree ", lfsp->lfs_minfree); 730 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 731 "inopb ", lfsp->lfs_inopb, 732 "ifpb ", lfsp->lfs_ifpb, 733 "nindir ", lfsp->lfs_nindir); 734 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 735 "nseg ", lfsp->lfs_nseg, 736 "sepb ", lfsp->lfs_sepb, 737 "cleansz ", lfsp->lfs_cleansz); 738 (void)printf(" %s%-10d %s0x%-8x %s%-10d\n", 739 "segtabsz ", lfsp->lfs_segtabsz, 740 "segmask ", lfsp->lfs_segmask, 741 "segshift ", lfsp->lfs_segshift); 742 (void)printf(" %s0x%-8qx %s%-10d %s0x%-8qX\n", 743 "bmask ", (long long)lfsp->lfs_bmask, 744 "bshift ", lfsp->lfs_bshift, 745 "ffmask ", (long long)lfsp->lfs_ffmask); 746 (void)printf(" %s%-10d %s0x%-8qx %s%u\n", 747 "ffshift ", lfsp->lfs_ffshift, 748 "fbmask ", (long long)lfsp->lfs_fbmask, 749 "fbshift ", lfsp->lfs_fbshift); 750 751 (void)printf(" %s%-10d %s%-10d %s0x%-8x\n", 752 "sushift ", lfsp->lfs_sushift, 753 "fsbtodb ", lfsp->lfs_fsbtodb, 754 "cksum ", lfsp->lfs_cksum); 755 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 756 "nclean ", lfsp->lfs_nclean, 757 "dmeta ", lfsp->lfs_dmeta, 758 "minfreeseg ", lfsp->lfs_minfreeseg); 759 (void)printf(" %s0x%-8x %s%-9d %s%-10d\n", 760 "roll_id ", lfsp->lfs_ident, 761 "interleave ", lfsp->lfs_interleave, 762 "sumsize ", lfsp->lfs_sumsize); 763 (void)printf(" %s%-10d %s0x%-8qx\n", 764 "seg0addr ", lfsp->lfs_start, 765 "maxfilesize ", (long long)lfsp->lfs_maxfilesize); 766 767 768 (void)printf(" Superblock disk addresses:\n "); 769 for (i = 0; i < LFS_MAXNUMSB; i++) { 770 (void)printf(" 0x%-8x", lfsp->lfs_sboffs[i]); 771 if (i == (LFS_MAXNUMSB >> 1)) 772 (void)printf("\n "); 773 } 774 (void)printf("\n"); 775 776 (void)printf(" Checkpoint Info\n"); 777 (void)printf(" %s%-10d %s0x%-8x %s%-10d\n", 778 "freehd ", lfsp->lfs_freehd, 779 "idaddr ", lfsp->lfs_idaddr, 780 "ifile ", lfsp->lfs_ifile); 781 (void)printf(" %s%-10d %s%-10d %s%-10d\n", 782 "uinodes ", lfsp->lfs_uinodes, 783 "bfree ", lfsp->lfs_bfree, 784 "avail ", lfsp->lfs_avail); 785 (void)printf(" %s%-10d %s0x%-8x %s0x%-8x\n", 786 "nfiles ", lfsp->lfs_nfiles, 787 "lastseg ", lfsp->lfs_lastseg, 788 "nextseg ", lfsp->lfs_nextseg); 789 (void)printf(" %s0x%-8x %s0x%-8x %s%-10lld\n", 790 "curseg ", lfsp->lfs_curseg, 791 "offset ", lfsp->lfs_offset, 792 "serial ", (long long)lfsp->lfs_serial); 793 (void)printf(" tstamp %s", ctime((time_t *)&lfsp->lfs_tstamp)); 794 } 795 796 static void 797 addseg(char *arg) 798 { 799 SEGLIST *p; 800 801 if ((p = malloc(sizeof(SEGLIST))) == NULL) 802 err(1, "malloc"); 803 p->next = seglist; 804 p->num = atoi(arg); 805 seglist = p; 806 } 807 808 static void 809 dump_cleaner_info(struct lfs *lfsp, void *ipage) 810 { 811 CLEANERINFO *cip; 812 813 cip = (CLEANERINFO *)ipage; 814 if (lfsp->lfs_version > 1) { 815 (void)printf("free_head %d\n", cip->free_head); 816 (void)printf("free_tail %d\n", cip->free_tail); 817 } 818 (void)printf("clean\t%d\tdirty\t%d\n", 819 cip->clean, cip->dirty); 820 (void)printf("bfree\t%d\tavail\t%d\n\n", 821 cip->bfree, cip->avail); 822 } 823 824 static void 825 usage(void) 826 { 827 (void)fprintf(stderr, "usage: dumplfs [-adiS] [-b blkno] [-I blkno] [-s segno] filesys|device\n"); 828 exit(1); 829 } 830