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