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.6 (Berkeley) 12/31/91"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/ucred.h> 20 #include <sys/mount.h> 21 #include <sys/file.h> 22 23 #include <ufs/ufs/dinode.h> 24 #include <ufs/lfs/lfs.h> 25 26 #include <time.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((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), 333 "mtime ", ctime(&dip->di_mtime), 334 "ctime ", ctime(&dip->di_ctime)); 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(lfsp, sp, segnum, addr) 349 struct lfs *lfsp; 350 SEGSUM *sp; 351 int segnum; 352 daddr_t addr; 353 { 354 FINFO *fp; 355 long *dp; 356 int i, j; 357 int ck; 358 int numblocks; 359 360 if (sp->ss_sumsum != (ck = cksum(&sp->ss_datasum, 361 LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum)))) 362 (void)printf("dumplfs: %s %d address %lx\n", 363 "corrupt summary block; segment", segnum, addr); 364 365 (void)printf("Segment Summary Info\n"); 366 (void)printf("\t%s%X\t%s%d\t%s%d\t%s%X\t%s%X\n", 367 "next ", sp->ss_next, 368 "nfinfo ", sp->ss_nfinfo, 369 "ninos ", sp->ss_ninos, 370 "sumsum ", sp->ss_sumsum, 371 "datasum ", sp->ss_datasum ); 372 (void)printf("\tcreate %s", ctime((time_t *)&sp->ss_create)); 373 374 numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp); 375 376 /* Dump out inode disk addresses */ 377 dp = (daddr_t *)sp; 378 dp += LFS_SUMMARY_SIZE / sizeof(daddr_t); 379 printf("\tInode addresses:"); 380 for (dp--, i = 0; i < numblocks; i += INOPB(lfsp)) 381 printf("\t%X", *dp--); 382 383 printf("\n"); 384 for (fp = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo; i++) { 385 numblocks += fp->fi_nblocks; 386 (void)printf("File Info for file: %d version %d nblocks %d\n", 387 fp->fi_ino, fp->fi_version, fp->fi_nblocks); 388 dp = &(fp->fi_blocks[0]); 389 for (j = 0; j < fp->fi_nblocks; j++, dp++) { 390 (void)printf("\t%d", *dp); 391 if ((j % 8) == 7) 392 (void)printf("\n"); 393 } 394 if ((j % 8) != 0) 395 (void)printf("\n"); 396 fp = (FINFO *)dp; 397 } 398 return (numblocks); 399 } 400 401 static void 402 dump_segment(fd, segnum, addr, lfsp, dump_sb) 403 int fd, segnum; 404 daddr_t addr; 405 struct lfs *lfsp; 406 int dump_sb; 407 { 408 struct lfs lfs_sb, *sbp; 409 SEGSUM *sump; 410 char sumblock[LFS_SUMMARY_SIZE]; 411 int did_one, nblocks, sb; 412 off_t sum_offset, super_off; 413 414 (void)printf("\nSegment Number %d (Disk Address %X)\n", 415 addr >> (lfsp->lfs_segshift - daddr_shift), addr); 416 sum_offset = (addr << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb)); 417 418 sb = 0; 419 did_one = 0; 420 do { 421 get(fd, sum_offset, sumblock, LFS_SUMMARY_SIZE); 422 sump = (SEGSUM *)sumblock; 423 if (sump->ss_sumsum != cksum (&sump->ss_datasum, 424 LFS_SUMMARY_SIZE - sizeof(sump->ss_sumsum))) { 425 sbp = (struct lfs *)sump; 426 if (sb = (sbp->lfs_magic == LFS_MAGIC)) { 427 super_off = sum_offset; 428 sum_offset += LFS_SBPAD; 429 } else if (did_one) 430 break; 431 else { 432 printf("Segment at %X corrupt\n", addr); 433 break; 434 } 435 } else { 436 nblocks = dump_sum(lfsp, sump, segnum, addr); 437 if (nblocks) 438 sum_offset += (nblocks << lfsp->lfs_bshift); 439 else 440 sum_offset = 0; 441 did_one = 1; 442 } 443 } while (sum_offset); 444 445 if (dump_sb && sb) { 446 get(fd, super_off, &lfs_sb, sizeof(struct lfs)); 447 dump_super(&lfs_sb); 448 } 449 return; 450 } 451 452 static void 453 dump_super(lfsp) 454 struct lfs *lfsp; 455 { 456 int i; 457 458 (void)printf("%s%X\t%s%X\t%s%d\t%s%d\n", 459 "magic ", lfsp->lfs_magic, 460 "version ", lfsp->lfs_version, 461 "size ", lfsp->lfs_size, 462 "ssize ", lfsp->lfs_ssize); 463 (void)printf("%s%d\t%s%d\t%s%d\t%s%d\n", 464 "dsize ", lfsp->lfs_dsize, 465 "bsize ", lfsp->lfs_bsize, 466 "fsize ", lfsp->lfs_fsize, 467 "frag ", lfsp->lfs_frag); 468 469 (void)printf("%s%d\t%s%d\t%s%d\t%s%d\n", 470 "minfree ", lfsp->lfs_minfree, 471 "inopb ", lfsp->lfs_inopb, 472 "ifpb ", lfsp->lfs_ifpb, 473 "nindir ", lfsp->lfs_nindir); 474 475 (void)printf("%s%d\t%s%d\t%s%d\t%s%d\n", 476 "nseg ", lfsp->lfs_nseg, 477 "nspf ", lfsp->lfs_nspf, 478 "cleansz ", lfsp->lfs_cleansz, 479 "segtabsz ", lfsp->lfs_segtabsz); 480 481 (void)printf("%s%X\t%s%d\t%s%X\t%s%d\n", 482 "segmask ", lfsp->lfs_segmask, 483 "segshift ", lfsp->lfs_segshift, 484 "bmask ", lfsp->lfs_bmask, 485 "bshift ", lfsp->lfs_bshift); 486 487 (void)printf("%s%X\t%s%d\t%s%X\t%s%d\n", 488 "ffmask ", lfsp->lfs_ffmask, 489 "ffshift ", lfsp->lfs_ffshift, 490 "fbmask ", lfsp->lfs_fbmask, 491 "fbshift ", lfsp->lfs_fbshift); 492 493 (void)printf("%s%d\t%s%X\n", 494 "fsbtodb ", lfsp->lfs_fsbtodb, 495 "cksum ", lfsp->lfs_cksum); 496 497 (void)printf("Superblock disk addresses:"); 498 for (i = 0; i < LFS_MAXNUMSB; i++) 499 (void)printf(" %X", lfsp->lfs_sboffs[i]); 500 (void)printf("\n"); 501 502 (void)printf("Checkpoint Info\n"); 503 (void)printf("%s%d\t%s%X\t%s%d\n", 504 "free ", lfsp->lfs_free, 505 "idaddr ", lfsp->lfs_idaddr, 506 "ifile ", lfsp->lfs_ifile); 507 (void)printf("%s%X\t%s%d\t%s%X\t%s%X\t%s%X\t%s%X\n", 508 "bfree ", lfsp->lfs_bfree, 509 "nfiles ", lfsp->lfs_nfiles, 510 "lastseg ", lfsp->lfs_lastseg, 511 "nextseg ", lfsp->lfs_nextseg, 512 "curseg ", lfsp->lfs_curseg, 513 "offset ", lfsp->lfs_offset); 514 (void)printf("tstamp %s", ctime((time_t *)&lfsp->lfs_tstamp)); 515 } 516 517 static void 518 addseg(arg) 519 char *arg; 520 { 521 SEGLIST *p; 522 523 if ((p = malloc(sizeof(SEGLIST))) == NULL) 524 err("%s", strerror(errno)); 525 p->next = seglist; 526 p->num = atoi(arg); 527 seglist = p; 528 } 529 530 static void 531 dump_cleaner_info(lfsp, ipage) 532 struct lfs *lfsp; 533 void *ipage; 534 { 535 CLEANERINFO *cip; 536 537 cip = (CLEANERINFO *)ipage; 538 (void)printf("Cleaner Info\nclean\t%d\tdirty\t%d\n", 539 cip->clean, cip->dirty); 540 } 541 542 static void 543 usage() 544 { 545 (void)fprintf(stderr, "usage: dumplfs [-ai] [-s segnum] file\n"); 546 exit(1); 547 } 548