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