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