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.10 (Berkeley) 07/19/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 e1; 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("\t%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("\t%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 %lx\n", 364 "corrupt summary block; segment", segnum, addr); 365 366 (void)printf("Segment Summary Info\n"); 367 (void)printf("\t%s%X\t%s%d\t%s%d\t%s%X\t%s%X\n", 368 "next ", sp->ss_next, 369 "nfinfo ", sp->ss_nfinfo, 370 "ninos ", sp->ss_ninos, 371 "sumsum ", sp->ss_sumsum, 372 "datasum ", sp->ss_datasum ); 373 (void)printf("\tcreate %s", ctime((time_t *)&sp->ss_create)); 374 375 numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp); 376 377 /* Dump out inode disk addresses */ 378 dp = (daddr_t *)sp; 379 dp += LFS_SUMMARY_SIZE / sizeof(daddr_t); 380 inop = malloc(1 << lfsp->lfs_bshift); 381 printf("\tInode addresses:"); 382 for (dp--, i = 0; i < sp->ss_ninos; dp--) { 383 printf("\t%X {", *dp); 384 get(fd, *dp << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb), inop, 385 (1 << lfsp->lfs_bshift)); 386 for (j = 0; i < sp->ss_ninos && j < INOPB(lfsp); j++, i++) { 387 if (j > 0) 388 (void)printf(", "); 389 (void)printf("%d", inop[j].di_inum); 390 } 391 (void)printf("}"); 392 if (((i/INOPB(lfsp)) % 4) == 3) 393 (void)printf("\n"); 394 } 395 free(inop); 396 397 printf("\n"); 398 for (fp = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo; i++) { 399 numblocks += fp->fi_nblocks; 400 (void)printf("File Info for file: %d version %d nblocks %d\n", 401 fp->fi_ino, fp->fi_version, fp->fi_nblocks); 402 dp = &(fp->fi_blocks[0]); 403 for (j = 0; j < fp->fi_nblocks; j++, dp++) { 404 (void)printf("\t%d", *dp); 405 if ((j % 8) == 7) 406 (void)printf("\n"); 407 } 408 if ((j % 8) != 0) 409 (void)printf("\n"); 410 fp = (FINFO *)dp; 411 } 412 return (numblocks); 413 } 414 415 static void 416 dump_segment(fd, segnum, addr, lfsp, dump_sb) 417 int fd, segnum; 418 daddr_t addr; 419 struct lfs *lfsp; 420 int dump_sb; 421 { 422 struct lfs lfs_sb, *sbp; 423 SEGSUM *sump; 424 char sumblock[LFS_SUMMARY_SIZE]; 425 int did_one, nblocks, sb; 426 off_t sum_offset, super_off; 427 428 (void)printf("\nSegment Number %d (Disk Address %X)\n", 429 addr >> (lfsp->lfs_segshift - daddr_shift), addr); 430 sum_offset = (addr << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb)); 431 432 sb = 0; 433 did_one = 0; 434 do { 435 get(fd, sum_offset, sumblock, LFS_SUMMARY_SIZE); 436 sump = (SEGSUM *)sumblock; 437 if (sump->ss_sumsum != cksum (&sump->ss_datasum, 438 LFS_SUMMARY_SIZE - sizeof(sump->ss_sumsum))) { 439 sbp = (struct lfs *)sump; 440 if (sb = (sbp->lfs_magic == LFS_MAGIC)) { 441 super_off = sum_offset; 442 sum_offset += LFS_SBPAD; 443 } else if (did_one) 444 break; 445 else { 446 printf("Segment at %X corrupt\n", addr); 447 break; 448 } 449 } else { 450 nblocks = dump_sum(fd, lfsp, sump, segnum, addr); 451 if (nblocks) 452 sum_offset += LFS_SUMMARY_SIZE + 453 (nblocks << lfsp->lfs_bshift); 454 else 455 sum_offset = 0; 456 did_one = 1; 457 } 458 } while (sum_offset); 459 460 if (dump_sb && sb) { 461 get(fd, super_off, &lfs_sb, sizeof(struct lfs)); 462 dump_super(&lfs_sb); 463 } 464 return; 465 } 466 467 static void 468 dump_super(lfsp) 469 struct lfs *lfsp; 470 { 471 int i; 472 473 (void)printf("%s%X\t%s%X\t%s%d\t%s%d\n", 474 "magic ", lfsp->lfs_magic, 475 "version ", lfsp->lfs_version, 476 "size ", lfsp->lfs_size, 477 "ssize ", lfsp->lfs_ssize); 478 (void)printf("%s%d\t%s%d\t%s%d\t%s%d\n", 479 "dsize ", lfsp->lfs_dsize, 480 "bsize ", lfsp->lfs_bsize, 481 "fsize ", lfsp->lfs_fsize, 482 "frag ", lfsp->lfs_frag); 483 484 (void)printf("%s%d\t%s%d\t%s%d\t%s%d\n", 485 "minfree ", lfsp->lfs_minfree, 486 "inopb ", lfsp->lfs_inopb, 487 "ifpb ", lfsp->lfs_ifpb, 488 "nindir ", lfsp->lfs_nindir); 489 490 (void)printf("%s%d\t%s%d\t%s%d\t%s%d\n", 491 "nseg ", lfsp->lfs_nseg, 492 "nspf ", lfsp->lfs_nspf, 493 "cleansz ", lfsp->lfs_cleansz, 494 "segtabsz ", lfsp->lfs_segtabsz); 495 496 (void)printf("%s%X\t%s%d\t%s%X\t%s%d\n", 497 "segmask ", lfsp->lfs_segmask, 498 "segshift ", lfsp->lfs_segshift, 499 "bmask ", lfsp->lfs_bmask, 500 "bshift ", lfsp->lfs_bshift); 501 502 (void)printf("%s%X\t%s%d\t%s%X\t%s%d\n", 503 "ffmask ", lfsp->lfs_ffmask, 504 "ffshift ", lfsp->lfs_ffshift, 505 "fbmask ", lfsp->lfs_fbmask, 506 "fbshift ", lfsp->lfs_fbshift); 507 508 (void)printf("%s%d\t%s%X\t%qd\n", 509 "fsbtodb ", lfsp->lfs_fsbtodb, 510 "cksum ", lfsp->lfs_cksum, 511 "maxfilesize ", lfsp->lfs_maxfilesize); 512 513 (void)printf("Superblock disk addresses:"); 514 for (i = 0; i < LFS_MAXNUMSB; i++) 515 (void)printf(" %X", lfsp->lfs_sboffs[i]); 516 (void)printf("\n"); 517 518 (void)printf("Checkpoint Info\n"); 519 (void)printf("%s%d\t%s%X\t%s%d\n", 520 "free ", lfsp->lfs_free, 521 "idaddr ", lfsp->lfs_idaddr, 522 "ifile ", lfsp->lfs_ifile); 523 (void)printf("%s%X\t%s%d\t%s%X\t%s%X\t%s%X\t%s%X\n", 524 "bfree ", lfsp->lfs_bfree, 525 "nfiles ", lfsp->lfs_nfiles, 526 "lastseg ", lfsp->lfs_lastseg, 527 "nextseg ", lfsp->lfs_nextseg, 528 "curseg ", lfsp->lfs_curseg, 529 "offset ", lfsp->lfs_offset); 530 (void)printf("tstamp %s", ctime((time_t *)&lfsp->lfs_tstamp)); 531 (void)printf("In-Memory Information\n"); 532 (void)printf("%s%d\t%s%X\t%s%d\t%s%d\t%s%d\n", 533 "seglock ", lfsp->lfs_seglock, 534 "iocount ", lfsp->lfs_iocount, 535 "writer ", lfsp->lfs_writer, 536 "dirops ", lfsp->lfs_dirops, 537 "doifile ", lfsp->lfs_doifile ); 538 (void)printf("%s%d\t%s%X\t%s%d\n", 539 "fmod ", lfsp->lfs_fmod, 540 "clean ", lfsp->lfs_clean, 541 "ronly ", lfsp->lfs_ronly); 542 } 543 544 static void 545 addseg(arg) 546 char *arg; 547 { 548 SEGLIST *p; 549 550 if ((p = malloc(sizeof(SEGLIST))) == NULL) 551 err("%s", strerror(errno)); 552 p->next = seglist; 553 p->num = atoi(arg); 554 seglist = p; 555 } 556 557 static void 558 dump_cleaner_info(lfsp, ipage) 559 struct lfs *lfsp; 560 void *ipage; 561 { 562 CLEANERINFO *cip; 563 564 cip = (CLEANERINFO *)ipage; 565 (void)printf("Cleaner Info\nclean\t%d\tdirty\t%d\n", 566 cip->clean, cip->dirty); 567 } 568 569 static void 570 usage() 571 { 572 (void)fprintf(stderr, "usage: dumplfs [-ai] [-s segnum] file\n"); 573 exit(1); 574 } 575