1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1991, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)dumplfs.c 8.2 (Berkeley) 11/30/94"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/ucred.h> 20 #include <sys/mount.h> 21 #include <sys/time.h> 22 23 #include <ufs/ufs/dinode.h> 24 #include <ufs/lfs/lfs.h> 25 26 #include <fcntl.h> 27 #include <fstab.h> 28 #include <errno.h> 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <stdio.h> 32 #include <string.h> 33 #include "extern.h" 34 35 static void addseg __P((char *)); 36 static void dump_cleaner_info __P((struct lfs *, void *)); 37 static void dump_dinode __P((struct dinode *)); 38 static void dump_ifile __P((int, struct lfs *, int)); 39 static int dump_ipage_ifile __P((int, IFILE *, int)); 40 static int dump_ipage_segusage __P((struct lfs *, int, IFILE *, int)); 41 static void dump_segment __P((int, int, daddr_t, struct lfs *, int)); 42 static int dump_sum __P((int, struct lfs *, SEGSUM *, int, daddr_t)); 43 static void dump_super __P((struct lfs *)); 44 static void usage __P((void)); 45 46 typedef struct seglist SEGLIST; 47 struct seglist { 48 SEGLIST *next; 49 int num; 50 }; 51 SEGLIST *seglist; 52 53 int daddr_shift; 54 char *special; 55 56 /* Segment Usage formats */ 57 #define print_suheader \ 58 (void)printf("segnum\tflags\tnbytes\tninos\tnsums\tlastmod\n") 59 60 #define print_suentry(i, sp) \ 61 (void)printf("%d\t%c%c%c\t%d\t%d\t%d\t%s", i, \ 62 (((sp)->su_flags & SEGUSE_ACTIVE) ? 'A' : ' '), \ 63 (((sp)->su_flags & SEGUSE_DIRTY) ? 'D' : 'C'), \ 64 (((sp)->su_flags & SEGUSE_SUPERBLOCK) ? 'S' : ' '), \ 65 (sp)->su_nbytes, (sp)->su_ninos, (sp)->su_nsums, \ 66 ctime((time_t *)&(sp)->su_lastmod)) 67 68 /* Ifile formats */ 69 #define print_iheader \ 70 (void)printf("inum\tstatus\tversion\tdaddr\t\tfreeptr\n") 71 #define print_ientry(i, ip) \ 72 if (ip->if_daddr == LFS_UNUSED_DADDR) \ 73 (void)printf("%d\tFREE\t%d\t \t\t%d\n", \ 74 i, ip->if_version, ip->if_nextfree); \ 75 else \ 76 (void)printf("%d\tINUSE\t%d\t%8X \n", \ 77 i, ip->if_version, ip->if_daddr) 78 int 79 main(argc, argv) 80 int argc; 81 char *argv[]; 82 { 83 struct lfs lfs_sb1, lfs_sb2, *lfs_master; 84 daddr_t seg_addr; 85 int ch, do_allsb, do_ientries, fd, segnum; 86 87 do_allsb = 0; 88 do_ientries = 0; 89 while ((ch = getopt(argc, argv, "ais:")) != EOF) 90 switch(ch) { 91 case 'a': /* Dump all superblocks */ 92 do_allsb = 1; 93 break; 94 case 'i': /* Dump ifile entries */ 95 do_ientries = 1; 96 break; 97 case 's': /* Dump out these segments */ 98 addseg(optarg); 99 break; 100 default: 101 usage(); 102 } 103 argc -= optind; 104 argv += optind; 105 106 if (argc != 1) 107 usage(); 108 109 special = argv[0]; 110 if ((fd = open(special, O_RDONLY, 0)) < 0) 111 err("%s: %s", special, strerror(errno)); 112 113 /* Read the first superblock */ 114 get(fd, LFS_LABELPAD, &lfs_sb1, sizeof(struct lfs)); 115 daddr_shift = lfs_sb1.lfs_bshift - lfs_sb1.lfs_fsbtodb; 116 117 /* 118 * Read the second superblock and figure out which check point is 119 * most up to date. 120 */ 121 get(fd, 122 lfs_sb1.lfs_sboffs[1] << daddr_shift, &lfs_sb2, sizeof(struct lfs)); 123 124 lfs_master = &lfs_sb1; 125 if (lfs_sb1.lfs_tstamp < lfs_sb2.lfs_tstamp) 126 lfs_master = &lfs_sb2; 127 128 (void)printf("Master Superblock:\n"); 129 dump_super(lfs_master); 130 131 dump_ifile(fd, lfs_master, do_ientries); 132 133 if (seglist != NULL) 134 for (; seglist != NULL; seglist = seglist->next) { 135 seg_addr = lfs_master->lfs_sboffs[0] + seglist->num * 136 (lfs_master->lfs_ssize << lfs_master->lfs_fsbtodb); 137 dump_segment(fd, 138 seglist->num, seg_addr, lfs_master, do_allsb); 139 } 140 else 141 for (segnum = 0, seg_addr = lfs_master->lfs_sboffs[0]; 142 segnum < lfs_master->lfs_nseg; segnum++, seg_addr += 143 lfs_master->lfs_ssize << lfs_master->lfs_fsbtodb) 144 dump_segment(fd, 145 segnum, seg_addr, lfs_master, do_allsb); 146 147 (void)close(fd); 148 exit(0); 149 } 150 151 /* 152 * We are reading all the blocks of an inode and dumping out the ifile table. 153 * This code could be tighter, but this is a first pass at getting the stuff 154 * printed out rather than making this code incredibly efficient. 155 */ 156 static void 157 dump_ifile(fd, lfsp, do_ientries) 158 int fd; 159 struct lfs *lfsp; 160 int do_ientries; 161 { 162 IFILE *ipage; 163 struct dinode *dip, *dpage; 164 daddr_t addr, *addrp, *dindir, *iaddrp, *indir; 165 int block_limit, i, inum, j, nblocks, nsupb, psize; 166 167 psize = lfsp->lfs_bsize; 168 addr = lfsp->lfs_idaddr; 169 170 if (!(dpage = malloc(psize))) 171 err("%s", strerror(errno)); 172 get(fd, addr << daddr_shift, dpage, psize); 173 174 for (dip = dpage + INOPB(lfsp) - 1; dip >= dpage; --dip) 175 if (dip->di_inumber == LFS_IFILE_INUM) 176 break; 177 178 if (dip < dpage) 179 err("unable to locate ifile inode"); 180 181 (void)printf("\nIFILE inode\n"); 182 dump_dinode(dip); 183 184 (void)printf("\nIFILE contents\n"); 185 nblocks = dip->di_size >> lfsp->lfs_bshift; 186 block_limit = MIN(nblocks, NDADDR); 187 188 /* Get the direct block */ 189 if ((ipage = malloc(psize)) == NULL) 190 err("%s", strerror(errno)); 191 for (inum = 0, addrp = dip->di_db, i = 0; i < block_limit; 192 i++, addrp++) { 193 get(fd, *addrp << daddr_shift, ipage, psize); 194 if (i < lfsp->lfs_cleansz) { 195 dump_cleaner_info(lfsp, ipage); 196 print_suheader; 197 continue; 198 } 199 200 if (i < (lfsp->lfs_segtabsz + lfsp->lfs_cleansz)) { 201 inum = dump_ipage_segusage(lfsp, inum, ipage, 202 lfsp->lfs_sepb); 203 if (!inum) 204 if(!do_ientries) 205 goto e0; 206 else 207 print_iheader; 208 } else 209 inum = dump_ipage_ifile(inum, ipage, lfsp->lfs_ifpb); 210 211 } 212 213 if (nblocks <= NDADDR) 214 goto e0; 215 216 /* Dump out blocks off of single indirect block */ 217 if (!(indir = malloc(psize))) 218 err("%s", strerror(errno)); 219 get(fd, dip->di_ib[0] << daddr_shift, indir, psize); 220 block_limit = MIN(i + lfsp->lfs_nindir, nblocks); 221 for (addrp = indir; i < block_limit; i++, addrp++) { 222 if (*addrp == LFS_UNUSED_DADDR) 223 break; 224 get(fd, *addrp << daddr_shift,ipage, psize); 225 if (i < lfsp->lfs_cleansz) { 226 dump_cleaner_info(lfsp, ipage); 227 continue; 228 } else 229 i -= lfsp->lfs_cleansz; 230 231 if (i < lfsp->lfs_segtabsz) { 232 inum = dump_ipage_segusage(lfsp, inum, ipage, 233 lfsp->lfs_sepb); 234 if (!inum) 235 if(!do_ientries) 236 goto e1; 237 else 238 print_iheader; 239 } else 240 inum = dump_ipage_ifile(inum, ipage, lfsp->lfs_ifpb); 241 } 242 243 if (nblocks <= lfsp->lfs_nindir * lfsp->lfs_ifpb) 244 goto e1; 245 246 /* Get the double indirect block */ 247 if (!(dindir = malloc(psize))) 248 err("%s", strerror(errno)); 249 get(fd, dip->di_ib[1] << daddr_shift, dindir, psize); 250 for (iaddrp = dindir, j = 0; j < lfsp->lfs_nindir; j++, iaddrp++) { 251 if (*iaddrp == LFS_UNUSED_DADDR) 252 break; 253 get(fd, *iaddrp << daddr_shift, indir, psize); 254 block_limit = MIN(i + lfsp->lfs_nindir, nblocks); 255 for (addrp = indir; i < block_limit; i++, addrp++) { 256 if (*addrp == LFS_UNUSED_DADDR) 257 break; 258 get(fd, *addrp << daddr_shift, ipage, psize); 259 if (i < lfsp->lfs_cleansz) { 260 dump_cleaner_info(lfsp, ipage); 261 continue; 262 } else 263 i -= lfsp->lfs_cleansz; 264 265 if (i < lfsp->lfs_segtabsz) { 266 inum = dump_ipage_segusage(lfsp, 267 inum, ipage, lfsp->lfs_sepb); 268 if (!inum) 269 if(!do_ientries) 270 goto e2; 271 else 272 print_iheader; 273 } else 274 inum = dump_ipage_ifile(inum, 275 ipage, lfsp->lfs_ifpb); 276 } 277 } 278 e2: free(dindir); 279 e1: free(indir); 280 e0: free(dpage); 281 free(ipage); 282 } 283 284 static int 285 dump_ipage_ifile(i, pp, tot) 286 int i; 287 IFILE *pp; 288 int tot; 289 { 290 IFILE *ip; 291 int cnt, max; 292 293 max = i + tot; 294 295 for (ip = pp, cnt = i; cnt < max; cnt++, ip++) 296 print_ientry(cnt, ip); 297 return (max); 298 } 299 300 static int 301 dump_ipage_segusage(lfsp, i, pp, tot) 302 struct lfs *lfsp; 303 int i; 304 IFILE *pp; 305 int tot; 306 { 307 SEGUSE *sp; 308 int cnt, max; 309 310 max = i + tot; 311 for (sp = (SEGUSE *)pp, cnt = i; 312 cnt < lfsp->lfs_nseg && cnt < max; cnt++, sp++) 313 print_suentry(cnt, sp); 314 if (max >= lfsp->lfs_nseg) 315 return (0); 316 else 317 return (max); 318 } 319 320 static void 321 dump_dinode(dip) 322 struct dinode *dip; 323 { 324 int i; 325 326 (void)printf("%s%d\t%s%d\t%s%d\t%s%d\t%s%d\n", 327 "mode ", dip->di_mode, 328 "nlink ", dip->di_nlink, 329 "uid ", dip->di_uid, 330 "gid ", dip->di_gid, 331 "size ", dip->di_size); 332 (void)printf("%s%s%s%s%s%s", 333 "atime ", ctime(&dip->di_atime.ts_sec), 334 "mtime ", ctime(&dip->di_mtime.ts_sec), 335 "ctime ", ctime(&dip->di_ctime.ts_sec)); 336 (void)printf("inum %d\n", dip->di_inumber); 337 (void)printf("Direct Addresses\n"); 338 for (i = 0; i < NDADDR; i++) { 339 (void)printf("\t0x%X", dip->di_db[i]); 340 if ((i % 6) == 5) 341 (void)printf("\n"); 342 } 343 for (i = 0; i < NIADDR; i++) 344 (void)printf("\t0x%X", dip->di_ib[i]); 345 (void)printf("\n"); 346 } 347 348 static int 349 dump_sum(fd, lfsp, sp, segnum, addr) 350 struct lfs *lfsp; 351 SEGSUM *sp; 352 int fd, segnum; 353 daddr_t addr; 354 { 355 FINFO *fp; 356 daddr_t *dp; 357 int i, j; 358 int ck; 359 int numblocks; 360 struct dinode *inop; 361 362 if (sp->ss_sumsum != (ck = cksum(&sp->ss_datasum, 363 LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum)))) { 364 (void)printf("dumplfs: %s %d address 0x%lx\n", 365 "corrupt summary block; segment", segnum, addr); 366 return(0); 367 } 368 369 (void)printf("Segment Summary Info at 0x%lx\n", addr); 370 (void)printf(" %s0x%X\t%s%d\t%s%d\n %s0x%X\t%s0x%X", 371 "next ", sp->ss_next, 372 "nfinfo ", sp->ss_nfinfo, 373 "ninos ", sp->ss_ninos, 374 "sumsum ", sp->ss_sumsum, 375 "datasum ", sp->ss_datasum ); 376 (void)printf("\tcreate %s", ctime((time_t *)&sp->ss_create)); 377 378 numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp); 379 380 /* Dump out inode disk addresses */ 381 dp = (daddr_t *)sp; 382 dp += LFS_SUMMARY_SIZE / sizeof(daddr_t); 383 inop = malloc(1 << lfsp->lfs_bshift); 384 printf(" Inode addresses:"); 385 for (dp--, i = 0; i < sp->ss_ninos; dp--) { 386 printf("\t0x%X {", *dp); 387 get(fd, *dp << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb), inop, 388 (1 << lfsp->lfs_bshift)); 389 for (j = 0; i < sp->ss_ninos && j < INOPB(lfsp); j++, i++) { 390 if (j > 0) 391 (void)printf(", "); 392 (void)printf("%d", inop[j].di_inumber); 393 } 394 (void)printf("}"); 395 if (((i/INOPB(lfsp)) % 4) == 3) 396 (void)printf("\n"); 397 } 398 free(inop); 399 400 printf("\n"); 401 for (fp = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo; i++) { 402 numblocks += fp->fi_nblocks; 403 (void)printf(" FINFO for inode: %d version %d nblocks %d\n", 404 fp->fi_ino, fp->fi_version, fp->fi_nblocks); 405 dp = &(fp->fi_blocks[0]); 406 for (j = 0; j < fp->fi_nblocks; j++, dp++) { 407 (void)printf("\t%d", *dp); 408 if ((j % 8) == 7) 409 (void)printf("\n"); 410 } 411 if ((j % 8) != 0) 412 (void)printf("\n"); 413 fp = (FINFO *)dp; 414 } 415 return (numblocks); 416 } 417 418 static void 419 dump_segment(fd, segnum, addr, lfsp, dump_sb) 420 int fd, segnum; 421 daddr_t addr; 422 struct lfs *lfsp; 423 int dump_sb; 424 { 425 struct lfs lfs_sb, *sbp; 426 SEGSUM *sump; 427 char sumblock[LFS_SUMMARY_SIZE]; 428 int did_one, nblocks, sb; 429 off_t sum_offset, super_off; 430 431 (void)printf("\nSEGMENT %d (Disk Address 0x%X)\n", 432 addr >> (lfsp->lfs_segshift - daddr_shift), addr); 433 sum_offset = (addr << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb)); 434 435 sb = 0; 436 did_one = 0; 437 do { 438 get(fd, sum_offset, sumblock, LFS_SUMMARY_SIZE); 439 sump = (SEGSUM *)sumblock; 440 if (sump->ss_sumsum != cksum (&sump->ss_datasum, 441 LFS_SUMMARY_SIZE - sizeof(sump->ss_sumsum))) { 442 sbp = (struct lfs *)sump; 443 if (sb = (sbp->lfs_magic == LFS_MAGIC)) { 444 super_off = sum_offset; 445 sum_offset += LFS_SBPAD; 446 } else if (did_one) 447 break; 448 else { 449 printf("Segment at 0x%X corrupt\n", addr); 450 break; 451 } 452 } else { 453 nblocks = dump_sum(fd, lfsp, sump, segnum, sum_offset >> 454 (lfsp->lfs_bshift - lfsp->lfs_fsbtodb)); 455 if (nblocks) 456 sum_offset += LFS_SUMMARY_SIZE + 457 (nblocks << lfsp->lfs_bshift); 458 else 459 sum_offset = 0; 460 did_one = 1; 461 } 462 } while (sum_offset); 463 464 if (dump_sb && sb) { 465 get(fd, super_off, &lfs_sb, sizeof(struct lfs)); 466 dump_super(&lfs_sb); 467 } 468 return; 469 } 470 471 static void 472 dump_super(lfsp) 473 struct lfs *lfsp; 474 { 475 int i; 476 477 (void)printf("%s0x%X\t%s0x%X\t%s%d\t%s%d\n", 478 "magic ", lfsp->lfs_magic, 479 "version ", lfsp->lfs_version, 480 "size ", lfsp->lfs_size, 481 "ssize ", lfsp->lfs_ssize); 482 (void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n", 483 "dsize ", lfsp->lfs_dsize, 484 "bsize ", lfsp->lfs_bsize, 485 "fsize ", lfsp->lfs_fsize, 486 "frag ", lfsp->lfs_frag); 487 488 (void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n", 489 "minfree ", lfsp->lfs_minfree, 490 "inopb ", lfsp->lfs_inopb, 491 "ifpb ", lfsp->lfs_ifpb, 492 "nindir ", lfsp->lfs_nindir); 493 494 (void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n", 495 "nseg ", lfsp->lfs_nseg, 496 "nspf ", lfsp->lfs_nspf, 497 "cleansz ", lfsp->lfs_cleansz, 498 "segtabsz ", lfsp->lfs_segtabsz); 499 500 (void)printf("%s0x%X\t%s%d\t%s0x%X\t%s%d\n", 501 "segmask ", lfsp->lfs_segmask, 502 "segshift ", lfsp->lfs_segshift, 503 "bmask ", lfsp->lfs_bmask, 504 "bshift ", lfsp->lfs_bshift); 505 506 (void)printf("%s0x%X\t\t%s%d\t%s0x%X\t%s%d\n", 507 "ffmask ", lfsp->lfs_ffmask, 508 "ffshift ", lfsp->lfs_ffshift, 509 "fbmask ", lfsp->lfs_fbmask, 510 "fbshift ", lfsp->lfs_fbshift); 511 512 (void)printf("%s%d\t%s%d\t%s0x%X\t%s0x%qx\n", 513 "sushift ", lfsp->lfs_sushift, 514 "fsbtodb ", lfsp->lfs_fsbtodb, 515 "cksum ", lfsp->lfs_cksum, 516 "maxfilesize ", lfsp->lfs_maxfilesize); 517 518 (void)printf("Superblock disk addresses:\t"); 519 for (i = 0; i < LFS_MAXNUMSB; i++) { 520 (void)printf(" 0x%X", lfsp->lfs_sboffs[i]); 521 if ( i == (LFS_MAXNUMSB >> 1)) 522 (void)printf("\n\t\t\t\t"); 523 } 524 (void)printf("\n"); 525 526 (void)printf("Checkpoint Info\n"); 527 (void)printf("%s%d\t%s0x%X\t%s%d\n", 528 "free ", lfsp->lfs_free, 529 "idaddr ", lfsp->lfs_idaddr, 530 "ifile ", lfsp->lfs_ifile); 531 (void)printf("%s%d\t%s%d\t%s%d\n", 532 "bfree ", lfsp->lfs_bfree, 533 "avail ", lfsp->lfs_avail, 534 "uinodes ", lfsp->lfs_uinodes); 535 (void)printf("%s%d\t%s0x%X\t%s0x%X\n%s0x%X\t%s0x%X\t", 536 "nfiles ", lfsp->lfs_nfiles, 537 "lastseg ", lfsp->lfs_lastseg, 538 "nextseg ", lfsp->lfs_nextseg, 539 "curseg ", lfsp->lfs_curseg, 540 "offset ", lfsp->lfs_offset); 541 (void)printf("tstamp %s", ctime((time_t *)&lfsp->lfs_tstamp)); 542 (void)printf("\nIn-Memory Information\n"); 543 (void)printf("%s%d\t%s0x%X\t%s%d%s%d\t%s%d\n", 544 "seglock ", lfsp->lfs_seglock, 545 "iocount ", lfsp->lfs_iocount, 546 "writer ", lfsp->lfs_writer, 547 "dirops ", lfsp->lfs_dirops, 548 "doifile ", lfsp->lfs_doifile); 549 (void)printf("%s%d\t%s%d\t%s0x%X\t%s%d\n", 550 "nactive ", lfsp->lfs_nactive, 551 "fmod ", lfsp->lfs_fmod, 552 "clean ", lfsp->lfs_clean, 553 "ronly ", lfsp->lfs_ronly); 554 } 555 556 static void 557 addseg(arg) 558 char *arg; 559 { 560 SEGLIST *p; 561 562 if ((p = malloc(sizeof(SEGLIST))) == NULL) 563 err("%s", strerror(errno)); 564 p->next = seglist; 565 p->num = atoi(arg); 566 seglist = p; 567 } 568 569 static void 570 dump_cleaner_info(lfsp, ipage) 571 struct lfs *lfsp; 572 void *ipage; 573 { 574 CLEANERINFO *cip; 575 576 cip = (CLEANERINFO *)ipage; 577 (void)printf("segments clean\t%d\tsegments dirty\t%d\n\n", 578 cip->clean, cip->dirty); 579 } 580 581 static void 582 usage() 583 { 584 (void)fprintf(stderr, "usage: dumplfs [-ai] [-s segnum] file\n"); 585 exit(1); 586 } 587