1 /* $NetBSD: dumplfs.c,v 1.5 1995/03/18 14:55:21 cgd 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.5 1995/03/18 14:55:21 cgd 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 359 (void)printf("%s%d\t%s%d\t%s%d\t%s%d\t%s%d\n", 360 "mode ", dip->di_mode, 361 "nlink ", dip->di_nlink, 362 "uid ", dip->di_uid, 363 "gid ", dip->di_gid, 364 "size ", dip->di_size); 365 (void)printf("%s%s%s%s%s%s", 366 "atime ", ctime(&dip->di_atime.ts_sec), 367 "mtime ", ctime(&dip->di_mtime.ts_sec), 368 "ctime ", ctime(&dip->di_ctime.ts_sec)); 369 (void)printf("inum %d\n", dip->di_inumber); 370 (void)printf("Direct Addresses\n"); 371 for (i = 0; i < NDADDR; i++) { 372 (void)printf("\t0x%X", dip->di_db[i]); 373 if ((i % 6) == 5) 374 (void)printf("\n"); 375 } 376 for (i = 0; i < NIADDR; i++) 377 (void)printf("\t0x%X", dip->di_ib[i]); 378 (void)printf("\n"); 379 } 380 381 static int 382 dump_sum(fd, lfsp, sp, segnum, addr) 383 struct lfs *lfsp; 384 SEGSUM *sp; 385 int fd, segnum; 386 daddr_t addr; 387 { 388 FINFO *fp; 389 u_int32_t *dp; 390 int i, j; 391 int ck; 392 int numblocks; 393 struct dinode *inop; 394 395 if (sp->ss_sumsum != (ck = cksum(&sp->ss_datasum, 396 LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum)))) { 397 (void)printf("dumplfs: %s %d address 0x%lx\n", 398 "corrupt summary block; segment", segnum, addr); 399 return(0); 400 } 401 402 (void)printf("Segment Summary Info at 0x%lx\n", addr); 403 (void)printf(" %s0x%X\t%s%d\t%s%d\n %s0x%X\t%s0x%X", 404 "next ", sp->ss_next, 405 "nfinfo ", sp->ss_nfinfo, 406 "ninos ", sp->ss_ninos, 407 "sumsum ", sp->ss_sumsum, 408 "datasum ", sp->ss_datasum ); 409 (void)printf("\tcreate %s", ctime((time_t *)&sp->ss_create)); 410 411 numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp); 412 413 /* Dump out inode disk addresses */ 414 dp = (daddr_t *)sp; 415 dp += LFS_SUMMARY_SIZE / sizeof(daddr_t); 416 inop = malloc(1 << lfsp->lfs_bshift); 417 printf(" Inode addresses:"); 418 for (dp--, i = 0; i < sp->ss_ninos; dp--) { 419 printf("\t0x%X {", *dp); 420 get(fd, *dp << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb), inop, 421 (1 << lfsp->lfs_bshift)); 422 for (j = 0; i < sp->ss_ninos && j < INOPB(lfsp); j++, i++) { 423 if (j > 0) 424 (void)printf(", "); 425 (void)printf("%d", inop[j].di_inumber); 426 } 427 (void)printf("}"); 428 if (((i/INOPB(lfsp)) % 4) == 3) 429 (void)printf("\n"); 430 } 431 free(inop); 432 433 printf("\n"); 434 for (fp = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo; i++) { 435 numblocks += fp->fi_nblocks; 436 (void)printf(" FINFO for inode: %d version %d nblocks %d\n", 437 fp->fi_ino, fp->fi_version, fp->fi_nblocks); 438 dp = &(fp->fi_blocks[0]); 439 for (j = 0; j < fp->fi_nblocks; j++, dp++) { 440 (void)printf("\t%d", *dp); 441 if ((j % 8) == 7) 442 (void)printf("\n"); 443 } 444 if ((j % 8) != 0) 445 (void)printf("\n"); 446 fp = (FINFO *)dp; 447 } 448 return (numblocks); 449 } 450 451 static void 452 dump_segment(fd, segnum, addr, lfsp, dump_sb) 453 int fd, segnum; 454 daddr_t addr; 455 struct lfs *lfsp; 456 int dump_sb; 457 { 458 struct lfs lfs_sb, *sbp; 459 SEGSUM *sump; 460 char sumblock[LFS_SUMMARY_SIZE]; 461 int did_one, nblocks, sb; 462 off_t sum_offset, super_off; 463 464 (void)printf("\nSEGMENT %d (Disk Address 0x%X)\n", 465 addr >> (lfsp->lfs_segshift - daddr_shift), addr); 466 sum_offset = (addr << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb)); 467 468 sb = 0; 469 did_one = 0; 470 do { 471 get(fd, sum_offset, sumblock, LFS_SUMMARY_SIZE); 472 sump = (SEGSUM *)sumblock; 473 if (sump->ss_sumsum != cksum (&sump->ss_datasum, 474 LFS_SUMMARY_SIZE - sizeof(sump->ss_sumsum))) { 475 sbp = (struct lfs *)sump; 476 if (sb = (sbp->lfs_magic == LFS_MAGIC)) { 477 super_off = sum_offset; 478 sum_offset += LFS_SBPAD; 479 } else if (did_one) 480 break; 481 else { 482 printf("Segment at 0x%X corrupt\n", addr); 483 break; 484 } 485 } else { 486 nblocks = dump_sum(fd, lfsp, sump, segnum, sum_offset >> 487 (lfsp->lfs_bshift - lfsp->lfs_fsbtodb)); 488 if (nblocks) 489 sum_offset += LFS_SUMMARY_SIZE + 490 (nblocks << lfsp->lfs_bshift); 491 else 492 sum_offset = 0; 493 did_one = 1; 494 } 495 } while (sum_offset); 496 497 if (dump_sb && sb) { 498 get(fd, super_off, &lfs_sb, sizeof(struct lfs)); 499 dump_super(&lfs_sb); 500 } 501 return; 502 } 503 504 static void 505 dump_super(lfsp) 506 struct lfs *lfsp; 507 { 508 int i; 509 510 (void)printf("%s0x%X\t%s0x%X\t%s%d\t%s%d\n", 511 "magic ", lfsp->lfs_magic, 512 "version ", lfsp->lfs_version, 513 "size ", lfsp->lfs_size, 514 "ssize ", lfsp->lfs_ssize); 515 (void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n", 516 "dsize ", lfsp->lfs_dsize, 517 "bsize ", lfsp->lfs_bsize, 518 "fsize ", lfsp->lfs_fsize, 519 "frag ", lfsp->lfs_frag); 520 521 (void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n", 522 "minfree ", lfsp->lfs_minfree, 523 "inopb ", lfsp->lfs_inopb, 524 "ifpb ", lfsp->lfs_ifpb, 525 "nindir ", lfsp->lfs_nindir); 526 527 (void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n", 528 "nseg ", lfsp->lfs_nseg, 529 "nspf ", lfsp->lfs_nspf, 530 "cleansz ", lfsp->lfs_cleansz, 531 "segtabsz ", lfsp->lfs_segtabsz); 532 533 (void)printf("%s0x%X\t%s%d\t%s0x%X\t%s%d\n", 534 "segmask ", lfsp->lfs_segmask, 535 "segshift ", lfsp->lfs_segshift, 536 "bmask ", lfsp->lfs_bmask, 537 "bshift ", lfsp->lfs_bshift); 538 539 (void)printf("%s0x%X\t\t%s%d\t%s0x%X\t%s%d\n", 540 "ffmask ", lfsp->lfs_ffmask, 541 "ffshift ", lfsp->lfs_ffshift, 542 "fbmask ", lfsp->lfs_fbmask, 543 "fbshift ", lfsp->lfs_fbshift); 544 545 (void)printf("%s%d\t%s%d\t%s0x%X\t%s0x%qx\n", 546 "sushift ", lfsp->lfs_sushift, 547 "fsbtodb ", lfsp->lfs_fsbtodb, 548 "cksum ", lfsp->lfs_cksum, 549 "maxfilesize ", lfsp->lfs_maxfilesize); 550 551 (void)printf("Superblock disk addresses:\t"); 552 for (i = 0; i < LFS_MAXNUMSB; i++) { 553 (void)printf(" 0x%X", lfsp->lfs_sboffs[i]); 554 if ( i == (LFS_MAXNUMSB >> 1)) 555 (void)printf("\n\t\t\t\t"); 556 } 557 (void)printf("\n"); 558 559 (void)printf("Checkpoint Info\n"); 560 (void)printf("%s%d\t%s0x%X\t%s%d\n", 561 "free ", lfsp->lfs_free, 562 "idaddr ", lfsp->lfs_idaddr, 563 "ifile ", lfsp->lfs_ifile); 564 (void)printf("%s%d\t%s%d\t%s%d\n", 565 "bfree ", lfsp->lfs_bfree, 566 "avail ", lfsp->lfs_avail, 567 "uinodes ", lfsp->lfs_uinodes); 568 (void)printf("%s%d\t%s0x%X\t%s0x%X\n%s0x%X\t%s0x%X\t", 569 "nfiles ", lfsp->lfs_nfiles, 570 "lastseg ", lfsp->lfs_lastseg, 571 "nextseg ", lfsp->lfs_nextseg, 572 "curseg ", lfsp->lfs_curseg, 573 "offset ", lfsp->lfs_offset); 574 (void)printf("tstamp %s", ctime((time_t *)&lfsp->lfs_tstamp)); 575 (void)printf("\nIn-Memory Information\n"); 576 (void)printf("%s%d\t%s0x%X\t%s%d%s%d\t%s%d\n", 577 "seglock ", lfsp->lfs_seglock, 578 "iocount ", lfsp->lfs_iocount, 579 "writer ", lfsp->lfs_writer, 580 "dirops ", lfsp->lfs_dirops, 581 "doifile ", lfsp->lfs_doifile); 582 (void)printf("%s%d\t%s%d\t%s0x%X\t%s%d\n", 583 "nactive ", lfsp->lfs_nactive, 584 "fmod ", lfsp->lfs_fmod, 585 "clean ", lfsp->lfs_clean, 586 "ronly ", lfsp->lfs_ronly); 587 } 588 589 static void 590 addseg(arg) 591 char *arg; 592 { 593 SEGLIST *p; 594 595 if ((p = malloc(sizeof(SEGLIST))) == NULL) 596 err(1, "malloc"); 597 p->next = seglist; 598 p->num = atoi(arg); 599 seglist = p; 600 } 601 602 static void 603 dump_cleaner_info(lfsp, ipage) 604 struct lfs *lfsp; 605 void *ipage; 606 { 607 CLEANERINFO *cip; 608 609 cip = (CLEANERINFO *)ipage; 610 (void)printf("segments clean\t%d\tsegments dirty\t%d\n\n", 611 cip->clean, cip->dirty); 612 } 613 614 static void 615 usage() 616 { 617 (void)fprintf(stderr, "usage: dumplfs [-ai] [-s segnum] file\n"); 618 exit(1); 619 } 620