169800Stomsoft/* 269800Stomsoft * Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz 369800Stomsoft * Copyright (c) 1980, 1989, 1993 The Regents of the University of California. 469800Stomsoft * All rights reserved. 569800Stomsoft * 669800Stomsoft * This code is derived from software contributed to Berkeley by 769800Stomsoft * Christoph Herrmann and Thomas-Henning von Kamptz, Munich and Frankfurt. 869800Stomsoft * 969800Stomsoft * Redistribution and use in source and binary forms, with or without 1069800Stomsoft * modification, are permitted provided that the following conditions 1169800Stomsoft * are met: 1269800Stomsoft * 1. Redistributions of source code must retain the above copyright 1369800Stomsoft * notice, this list of conditions and the following disclaimer. 1469800Stomsoft * 2. Redistributions in binary form must reproduce the above copyright 1569800Stomsoft * notice, this list of conditions and the following disclaimer in the 1669800Stomsoft * documentation and/or other materials provided with the distribution. 1769800Stomsoft * 3. All advertising materials mentioning features or use of this software 1869800Stomsoft * must display the following acknowledgment: 1969800Stomsoft * This product includes software developed by the University of 2069800Stomsoft * California, Berkeley and its contributors, as well as Christoph 2169800Stomsoft * Herrmann and Thomas-Henning von Kamptz. 2269800Stomsoft * 4. Neither the name of the University nor the names of its contributors 2369800Stomsoft * may be used to endorse or promote products derived from this software 2469800Stomsoft * without specific prior written permission. 2569800Stomsoft * 2669800Stomsoft * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2769800Stomsoft * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2869800Stomsoft * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2969800Stomsoft * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3069800Stomsoft * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3169800Stomsoft * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3269800Stomsoft * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3369800Stomsoft * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3469800Stomsoft * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3569800Stomsoft * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3669800Stomsoft * SUCH DAMAGE. 3769800Stomsoft * 3869926Stomsoft * $TSHeader: src/sbin/ffsinfo/ffsinfo.c,v 1.4 2000/12/12 19:30:55 tomsoft Exp $ 3969800Stomsoft * 4069800Stomsoft */ 4169800Stomsoft 4269800Stomsoft#ifndef lint 4369800Stomsoftstatic const char copyright[] = 4469800Stomsoft"@(#) Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz\n\ 4569800StomsoftCopyright (c) 1980, 1989, 1993 The Regents of the University of California.\n\ 4669800StomsoftAll rights reserved.\n"; 4769800Stomsoft#endif /* not lint */ 4869800Stomsoft 4969800Stomsoft#ifndef lint 5069800Stomsoftstatic const char rcsid[] = 5169800Stomsoft "$FreeBSD$"; 5269800Stomsoft#endif /* not lint */ 5369800Stomsoft 5469800Stomsoft/* ********************************************************** INCLUDES ***** */ 5569800Stomsoft#include <sys/param.h> 5669800Stomsoft#include <sys/disklabel.h> 57118918Srwatson#include <sys/mount.h> 5869800Stomsoft#include <sys/stat.h> 5969800Stomsoft 60118918Srwatson#include <ufs/ufs/ufsmount.h> 61118918Srwatson#include <ufs/ufs/dinode.h> 62118918Srwatson#include <ufs/ffs/fs.h> 63118918Srwatson 6469800Stomsoft#include <ctype.h> 6569800Stomsoft#include <err.h> 66139647Srwatson#include <errno.h> 6769800Stomsoft#include <fcntl.h> 68118918Srwatson#include <libufs.h> 69118918Srwatson#include <paths.h> 70118918Srwatson#include <stdio.h> 7169800Stomsoft#include <stdlib.h> 7269800Stomsoft#include <string.h> 7369800Stomsoft#include <unistd.h> 7469800Stomsoft 7569800Stomsoft#include "debug.h" 7669800Stomsoft 7769800Stomsoft/* *********************************************************** GLOBALS ***** */ 7869800Stomsoft#ifdef FS_DEBUG 7969800Stomsoftint _dbg_lvl_ = (DL_INFO); /* DL_TRC */ 8069800Stomsoft#endif /* FS_DEBUG */ 8169800Stomsoft 82118918Srwatsonstruct uufsd disk; 8369800Stomsoft 84118918Srwatson#define sblock disk.d_fs 85118918Srwatson#define acg disk.d_cg 86118918Srwatson 8769800Stomsoftstatic union { 88118918Srwatson struct fs fs; 89118918Srwatson char pad[SBLOCKSIZE]; 90118918Srwatson} fsun; 9169800Stomsoft 92118918Srwatson#define osblock fsun.fs 93118918Srwatson 9469800Stomsoftstatic char i1blk[MAXBSIZE]; 9569800Stomsoftstatic char i2blk[MAXBSIZE]; 9669800Stomsoftstatic char i3blk[MAXBSIZE]; 9769800Stomsoft 9869800Stomsoftstatic struct csum *fscs; 9969800Stomsoft 10069800Stomsoft/* ******************************************************** PROTOTYPES ***** */ 10169926Stomsoftstatic void usage(void); 102118918Srwatsonstatic void dump_whole_ufs1_inode(ino_t, int); 103118918Srwatsonstatic void dump_whole_ufs2_inode(ino_t, int); 10469800Stomsoft 105118918Srwatson#define DUMP_WHOLE_INODE(A,B) \ 106118918Srwatson ( disk.d_ufs == 1 \ 107118918Srwatson ? dump_whole_ufs1_inode((A),(B)) : dump_whole_ufs2_inode((A),(B)) ) 10869800Stomsoft 10969800Stomsoft/* ************************************************************** main ***** */ 11069800Stomsoft/* 111102231Strhodes * ffsinfo(8) is a tool to dump all metadata of a file system. It helps to find 112102231Strhodes * errors is the file system much easier. You can run ffsinfo before and after 11369800Stomsoft * an fsck(8), and compare the two ascii dumps easy with diff, and you see 11469800Stomsoft * directly where the problem is. You can control how much detail you want to 11569800Stomsoft * see with some command line arguments. You can also easy check the status 116102231Strhodes * of a file system, like is there is enough space for growing a file system, 11769800Stomsoft * or how many active snapshots do we have. It provides much more detailed 11869800Stomsoft * information then dumpfs. Snapshots, as they are very new, are not really 11969800Stomsoft * supported. They are just mentioned currently, but it is planned to run 12069800Stomsoft * also over active snapshots, to even get that output. 12169800Stomsoft */ 12269800Stomsoftint 12369800Stomsoftmain(int argc, char **argv) 12469800Stomsoft{ 12569800Stomsoft DBG_FUNC("main") 126118918Srwatson char *device, *special; 127132660Sstefanf int ch; 12869800Stomsoft size_t len; 12969800Stomsoft struct stat st; 13069800Stomsoft struct csum *dbg_csp; 13169800Stomsoft int dbg_csc; 13269800Stomsoft char dbg_line[80]; 13369800Stomsoft int cylno,i; 13469800Stomsoft int cfg_cg, cfg_in, cfg_lv; 13569800Stomsoft int cg_start, cg_stop; 13669800Stomsoft ino_t in; 13769800Stomsoft char *out_file; 13869800Stomsoft 13969800Stomsoft DBG_ENTER; 14069800Stomsoft 141166724Sbrian cfg_lv = 0xff; 142166724Sbrian cfg_in = -2; 143166724Sbrian cfg_cg = -2; 144175782Sdelphij out_file = strdup("-"); 14569926Stomsoft 146166724Sbrian while ((ch = getopt(argc, argv, "g:i:l:o:")) != -1) { 147166724Sbrian switch (ch) { 14869800Stomsoft case 'g': 149166724Sbrian cfg_cg = strtol(optarg, NULL, 0); 150166724Sbrian if (errno == EINVAL || errno == ERANGE) 151139647Srwatson err(1, "%s", optarg); 152166724Sbrian if (cfg_cg < -1) 15369926Stomsoft usage(); 15469800Stomsoft break; 15569800Stomsoft case 'i': 156166724Sbrian cfg_in = strtol(optarg, NULL, 0); 157166724Sbrian if (errno == EINVAL || errno == ERANGE) 158139647Srwatson err(1, "%s", optarg); 159166724Sbrian if (cfg_in < 0) 16069926Stomsoft usage(); 16169800Stomsoft break; 16269800Stomsoft case 'l': 163166724Sbrian cfg_lv = strtol(optarg, NULL, 0); 164166724Sbrian if (errno == EINVAL||errno == ERANGE) 165139647Srwatson err(1, "%s", optarg); 166166724Sbrian if (cfg_lv < 0x1 || cfg_lv > 0x3ff) 16769926Stomsoft usage(); 16869800Stomsoft break; 16969800Stomsoft case 'o': 17069800Stomsoft free(out_file); 171166724Sbrian out_file = strdup(optarg); 172166724Sbrian if (out_file == NULL) 17369926Stomsoft errx(1, "strdup failed"); 17469800Stomsoft break; 17569800Stomsoft case '?': 17669800Stomsoft /* FALLTHROUGH */ 17769800Stomsoft default: 17869926Stomsoft usage(); 17969800Stomsoft } 18069800Stomsoft } 18169800Stomsoft argc -= optind; 18269800Stomsoft argv += optind; 18369800Stomsoft 184166724Sbrian if (argc != 1) 18569926Stomsoft usage(); 186166724Sbrian device = *argv; 187166725Sbrian 18869800Stomsoft /* 18969800Stomsoft * Now we try to guess the (raw)device name. 19069800Stomsoft */ 191166724Sbrian if (0 == strrchr(device, '/') && stat(device, &st) == -1) { 192166724Sbrian /*- 193166724Sbrian * No path prefix was given, so try in this order: 19469800Stomsoft * /dev/r%s 19569800Stomsoft * /dev/%s 19669800Stomsoft * /dev/vinum/r%s 19769800Stomsoft * /dev/vinum/%s. 19869800Stomsoft * 19969800Stomsoft * FreeBSD now doesn't distinguish between raw and block 20069800Stomsoft * devices any longer, but it should still work this way. 20169800Stomsoft */ 202166724Sbrian len = strlen(device) + strlen(_PATH_DEV) + 2 + strlen("vinum/"); 203166724Sbrian special = (char *)malloc(len); 204166724Sbrian if (special == NULL) 20569926Stomsoft errx(1, "malloc failed"); 20669800Stomsoft snprintf(special, len, "%sr%s", _PATH_DEV, device); 20769800Stomsoft if (stat(special, &st) == -1) { 20869800Stomsoft snprintf(special, len, "%s%s", _PATH_DEV, device); 20969800Stomsoft if (stat(special, &st) == -1) { 21069800Stomsoft snprintf(special, len, "%svinum/r%s", 21169800Stomsoft _PATH_DEV, device); 212166724Sbrian if (stat(special, &st) == -1) 213166724Sbrian /* For now this is the 'last resort' */ 21469800Stomsoft snprintf(special, len, "%svinum/%s", 21569800Stomsoft _PATH_DEV, device); 21669800Stomsoft } 21769800Stomsoft } 21869800Stomsoft device = special; 21969800Stomsoft } 22069800Stomsoft 221118918Srwatson if (ufs_disk_fillout(&disk, device) == -1) 222118918Srwatson err(1, "ufs_disk_fillout(%s) failed: %s", device, disk.d_error); 22369800Stomsoft 224166724Sbrian DBG_OPEN(out_file); /* already here we need a superblock */ 22569800Stomsoft 226166724Sbrian if (cfg_lv & 0x001) 227166724Sbrian DBG_DUMP_FS(&sblock, "primary sblock"); 22869800Stomsoft 229166724Sbrian /* Determine here what cylinder groups to dump */ 230166724Sbrian if (cfg_cg==-2) { 231166724Sbrian cg_start = 0; 232166724Sbrian cg_stop = sblock.fs_ncg; 233166724Sbrian } else if (cfg_cg == -1) { 234166724Sbrian cg_start = sblock.fs_ncg - 1; 235166724Sbrian cg_stop = sblock.fs_ncg; 236166724Sbrian } else if (cfg_cg < sblock.fs_ncg) { 237166724Sbrian cg_start = cfg_cg; 238166724Sbrian cg_stop = cfg_cg + 1; 23969800Stomsoft } else { 240166724Sbrian cg_start = sblock.fs_ncg; 241166724Sbrian cg_stop = sblock.fs_ncg; 24269800Stomsoft } 24369800Stomsoft 24469800Stomsoft if (cfg_lv & 0x004) { 24577885Stomsoft fscs = (struct csum *)calloc((size_t)1, 24677885Stomsoft (size_t)sblock.fs_cssize); 247166724Sbrian if (fscs == NULL) 24869926Stomsoft errx(1, "calloc failed"); 24969800Stomsoft 250166724Sbrian /* get the cylinder summary into the memory ... */ 25169800Stomsoft for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) { 252166724Sbrian if (bread(&disk, fsbtodb(&sblock, 253166724Sbrian sblock.fs_csaddr + numfrags(&sblock, i)), 254166724Sbrian (void *)(((char *)fscs)+i), 255166724Sbrian (size_t)(sblock.fs_cssize-i < sblock.fs_bsize ? 256166724Sbrian sblock.fs_cssize - i : sblock.fs_bsize)) == -1) 257118918Srwatson err(1, "bread: %s", disk.d_error); 25869800Stomsoft } 25969800Stomsoft 260166724Sbrian dbg_csp = fscs; 261166724Sbrian /* ... and dump it */ 26269800Stomsoft for(dbg_csc=0; dbg_csc<sblock.fs_ncg; dbg_csc++) { 26377885Stomsoft snprintf(dbg_line, sizeof(dbg_line), 26477885Stomsoft "%d. csum in fscs", dbg_csc); 26569926Stomsoft DBG_DUMP_CSUM(&sblock, 26669926Stomsoft dbg_line, 26769926Stomsoft dbg_csp++); 26869800Stomsoft } 26969800Stomsoft } 27069800Stomsoft 271166725Sbrian if (cfg_lv & 0xf8) { 272166725Sbrian /* for each requested cylinder group ... */ 273166725Sbrian for (cylno = cg_start; cylno < cg_stop; cylno++) { 274166725Sbrian snprintf(dbg_line, sizeof(dbg_line), "cgr %d", cylno); 275166725Sbrian if (cfg_lv & 0x002) { 276166725Sbrian /* dump the superblock copies */ 277166725Sbrian if (bread(&disk, fsbtodb(&sblock, 278166725Sbrian cgsblock(&sblock, cylno)), 279166725Sbrian (void *)&osblock, SBLOCKSIZE) == -1) 280166725Sbrian err(1, "bread: %s", disk.d_error); 281166725Sbrian DBG_DUMP_FS(&osblock, dbg_line); 282166725Sbrian } 283166725Sbrian 284166725Sbrian /* 285166725Sbrian * Read the cylinder group and dump whatever was 286166725Sbrian * requested. 287166725Sbrian */ 288166724Sbrian if (bread(&disk, fsbtodb(&sblock, 289166725Sbrian cgtod(&sblock, cylno)), (void *)&acg, 290166725Sbrian (size_t)sblock.fs_cgsize) == -1) 291118918Srwatson err(1, "bread: %s", disk.d_error); 292166724Sbrian 293166725Sbrian if (cfg_lv & 0x008) 294166725Sbrian DBG_DUMP_CG(&sblock, dbg_line, &acg); 295166725Sbrian if (cfg_lv & 0x010) 296166725Sbrian DBG_DUMP_INMAP(&sblock, dbg_line, &acg); 297166725Sbrian if (cfg_lv & 0x020) 298166725Sbrian DBG_DUMP_FRMAP(&sblock, dbg_line, &acg); 299166725Sbrian if (cfg_lv & 0x040) { 300166725Sbrian DBG_DUMP_CLMAP(&sblock, dbg_line, &acg); 301166725Sbrian DBG_DUMP_CLSUM(&sblock, dbg_line, &acg); 302166725Sbrian } 303166725Sbrian #ifdef NOT_CURRENTLY 304166725Sbrian /* 305166725Sbrian * See the comment in sbin/growfs/debug.c for why this 306166725Sbrian * is currently disabled, and what needs to be done to 307166725Sbrian * re-enable it. 308166725Sbrian */ 309166725Sbrian if (disk.d_ufs == 1 && cfg_lv & 0x080) 310166725Sbrian DBG_DUMP_SPTBL(&sblock, dbg_line, &acg); 311166725Sbrian #endif 312118918Srwatson } 31369800Stomsoft } 314166724Sbrian 315166725Sbrian if (cfg_lv & 0x300) { 316166725Sbrian /* Dump the requested inode(s) */ 317166725Sbrian if (cfg_in != -2) 318166725Sbrian DUMP_WHOLE_INODE((ino_t)cfg_in, cfg_lv); 319166725Sbrian else { 320166725Sbrian for (in = cg_start * sblock.fs_ipg; 321166725Sbrian in < (ino_t)cg_stop * sblock.fs_ipg; 322166725Sbrian in++) 323166725Sbrian DUMP_WHOLE_INODE(in, cfg_lv); 324166725Sbrian } 32569800Stomsoft } 32669800Stomsoft 32769800Stomsoft DBG_CLOSE; 328166724Sbrian DBG_LEAVE; 32969800Stomsoft 33069800Stomsoft return 0; 33169800Stomsoft} 33269800Stomsoft 333118918Srwatson/* ********************************************** dump_whole_ufs1_inode ***** */ 33469800Stomsoft/* 33569800Stomsoft * Here we dump a list of all blocks allocated by this inode. We follow 33669800Stomsoft * all indirect blocks. 33769800Stomsoft */ 33869800Stomsoftvoid 339118918Srwatsondump_whole_ufs1_inode(ino_t inode, int level) 34069800Stomsoft{ 341118918Srwatson DBG_FUNC("dump_whole_ufs1_inode") 342118918Srwatson struct ufs1_dinode *ino; 343118918Srwatson int rb, mode; 34469800Stomsoft unsigned int ind2ctr, ind3ctr; 345118918Srwatson ufs1_daddr_t *ind2ptr, *ind3ptr; 34669800Stomsoft char comment[80]; 34769800Stomsoft 34869800Stomsoft DBG_ENTER; 34969800Stomsoft 35069800Stomsoft /* 35169800Stomsoft * Read the inode from disk/cache. 35269800Stomsoft */ 353118918Srwatson if (getino(&disk, (void **)&ino, inode, &mode) == -1) 354118918Srwatson err(1, "getino: %s", disk.d_error); 35569800Stomsoft 35669800Stomsoft if(ino->di_nlink==0) { 35769800Stomsoft DBG_LEAVE; 35869800Stomsoft return; /* inode not in use */ 35969800Stomsoft } 36069800Stomsoft 36169800Stomsoft /* 36269800Stomsoft * Dump the main inode structure. 36369800Stomsoft */ 36477885Stomsoft snprintf(comment, sizeof(comment), "Inode 0x%08x", inode); 36569800Stomsoft if (level & 0x100) { 36669926Stomsoft DBG_DUMP_INO(&sblock, 36769926Stomsoft comment, 36869926Stomsoft ino); 36969800Stomsoft } 37069800Stomsoft 37169800Stomsoft if (!(level & 0x200)) { 37269800Stomsoft DBG_LEAVE; 37369800Stomsoft return; 37469800Stomsoft } 37569800Stomsoft 37669800Stomsoft /* 37769800Stomsoft * Ok, now prepare for dumping all direct and indirect pointers. 37869800Stomsoft */ 37969800Stomsoft rb=howmany(ino->di_size, sblock.fs_bsize)-NDADDR; 38069800Stomsoft if(rb>0) { 38169800Stomsoft /* 38269800Stomsoft * Dump single indirect block. 38369800Stomsoft */ 384118918Srwatson if (bread(&disk, fsbtodb(&sblock, ino->di_ib[0]), (void *)&i1blk, 385118918Srwatson (size_t)sblock.fs_bsize) == -1) { 386118918Srwatson err(1, "bread: %s", disk.d_error); 387118918Srwatson } 38877885Stomsoft snprintf(comment, sizeof(comment), "Inode 0x%08x: indirect 0", 38977885Stomsoft inode); 39069926Stomsoft DBG_DUMP_IBLK(&sblock, 39169926Stomsoft comment, 39269926Stomsoft i1blk, 39369926Stomsoft (size_t)rb); 394118918Srwatson rb-=howmany(sblock.fs_bsize, sizeof(ufs1_daddr_t)); 39569800Stomsoft } 39669800Stomsoft if(rb>0) { 39769800Stomsoft /* 39869800Stomsoft * Dump double indirect blocks. 39969800Stomsoft */ 400118918Srwatson if (bread(&disk, fsbtodb(&sblock, ino->di_ib[1]), (void *)&i2blk, 401118918Srwatson (size_t)sblock.fs_bsize) == -1) { 402118918Srwatson err(1, "bread: %s", disk.d_error); 403118918Srwatson } 40477885Stomsoft snprintf(comment, sizeof(comment), "Inode 0x%08x: indirect 1", 40577885Stomsoft inode); 40669926Stomsoft DBG_DUMP_IBLK(&sblock, 40769926Stomsoft comment, 40869926Stomsoft i2blk, 409118918Srwatson howmany(rb, howmany(sblock.fs_bsize, sizeof(ufs1_daddr_t)))); 41069800Stomsoft for(ind2ctr=0; ((ind2ctr < howmany(sblock.fs_bsize, 411118918Srwatson sizeof(ufs1_daddr_t))) && (rb>0)); ind2ctr++) { 412118918Srwatson ind2ptr=&((ufs1_daddr_t *)(void *)&i2blk)[ind2ctr]; 41369800Stomsoft 414118918Srwatson if (bread(&disk, fsbtodb(&sblock, *ind2ptr), (void *)&i1blk, 415118918Srwatson (size_t)sblock.fs_bsize) == -1) { 416118918Srwatson err(1, "bread: %s", disk.d_error); 417118918Srwatson } 41877885Stomsoft snprintf(comment, sizeof(comment), 41977885Stomsoft "Inode 0x%08x: indirect 1->%d", inode, ind2ctr); 42069926Stomsoft DBG_DUMP_IBLK(&sblock, 42169926Stomsoft comment, 42269926Stomsoft i1blk, 42369926Stomsoft (size_t)rb); 424118918Srwatson rb-=howmany(sblock.fs_bsize, sizeof(ufs1_daddr_t)); 42569800Stomsoft } 42669800Stomsoft } 42769800Stomsoft if(rb>0) { 42869800Stomsoft /* 42969800Stomsoft * Dump triple indirect blocks. 43069800Stomsoft */ 431118918Srwatson if (bread(&disk, fsbtodb(&sblock, ino->di_ib[2]), (void *)&i3blk, 432118918Srwatson (size_t)sblock.fs_bsize) == -1) { 433118918Srwatson err(1, "bread: %s", disk.d_error); 434118918Srwatson } 43577885Stomsoft snprintf(comment, sizeof(comment), "Inode 0x%08x: indirect 2", 43677885Stomsoft inode); 43769800Stomsoft#define SQUARE(a) ((a)*(a)) 43869926Stomsoft DBG_DUMP_IBLK(&sblock, 43969926Stomsoft comment, 44069926Stomsoft i3blk, 44169926Stomsoft howmany(rb, 442118918Srwatson SQUARE(howmany(sblock.fs_bsize, sizeof(ufs1_daddr_t))))); 44369800Stomsoft#undef SQUARE 444118918Srwatson for(ind3ctr=0; ((ind3ctr<howmany(sblock.fs_bsize, 445118918Srwatson sizeof(ufs1_daddr_t)))&&(rb>0)); ind3ctr++) { 446118918Srwatson ind3ptr=&((ufs1_daddr_t *)(void *)&i3blk)[ind3ctr]; 44769800Stomsoft 448118918Srwatson if (bread(&disk, fsbtodb(&sblock, *ind3ptr), (void *)&i2blk, 449118918Srwatson (size_t)sblock.fs_bsize) == -1) { 450118918Srwatson err(1, "bread: %s", disk.d_error); 451118918Srwatson } 45277885Stomsoft snprintf(comment, sizeof(comment), 45377885Stomsoft "Inode 0x%08x: indirect 2->%d", inode, ind3ctr); 45469926Stomsoft DBG_DUMP_IBLK(&sblock, 45569926Stomsoft comment, 45669926Stomsoft i2blk, 45769926Stomsoft howmany(rb, 458118918Srwatson howmany(sblock.fs_bsize, sizeof(ufs1_daddr_t)))); 45969800Stomsoft for(ind2ctr=0; ((ind2ctr < howmany(sblock.fs_bsize, 460118918Srwatson sizeof(ufs1_daddr_t)))&&(rb>0)); ind2ctr++) { 461118918Srwatson ind2ptr=&((ufs1_daddr_t *)(void *)&i2blk) 46277885Stomsoft [ind2ctr]; 463118918Srwatson if (bread(&disk, fsbtodb(&sblock, *ind2ptr), 464118918Srwatson (void *)&i1blk, (size_t)sblock.fs_bsize) 465118918Srwatson == -1) { 466118918Srwatson err(1, "bread: %s", disk.d_error); 467118918Srwatson } 46877885Stomsoft snprintf(comment, sizeof(comment), 46969800Stomsoft "Inode 0x%08x: indirect 2->%d->%d", inode, 47069800Stomsoft ind3ctr, ind3ctr); 47169926Stomsoft DBG_DUMP_IBLK(&sblock, 47269926Stomsoft comment, 47369926Stomsoft i1blk, 47469926Stomsoft (size_t)rb); 47569800Stomsoft rb-=howmany(sblock.fs_bsize, 476118918Srwatson sizeof(ufs1_daddr_t)); 47769800Stomsoft } 47869800Stomsoft } 47969800Stomsoft } 48069800Stomsoft 48169800Stomsoft DBG_LEAVE; 48269800Stomsoft return; 48369800Stomsoft} 48469800Stomsoft 485118918Srwatson/* ********************************************** dump_whole_ufs2_inode ***** */ 48669800Stomsoft/* 487118918Srwatson * Here we dump a list of all blocks allocated by this inode. We follow 488118918Srwatson * all indirect blocks. 48969800Stomsoft */ 490118918Srwatsonvoid 491118918Srwatsondump_whole_ufs2_inode(ino_t inode, int level) 49269800Stomsoft{ 493118918Srwatson DBG_FUNC("dump_whole_ufs2_inode") 494118918Srwatson struct ufs2_dinode *ino; 495118918Srwatson int rb, mode; 496118918Srwatson unsigned int ind2ctr, ind3ctr; 497118918Srwatson ufs2_daddr_t *ind2ptr, *ind3ptr; 498118918Srwatson char comment[80]; 499118918Srwatson 50069800Stomsoft DBG_ENTER; 50169800Stomsoft 502118918Srwatson /* 503118918Srwatson * Read the inode from disk/cache. 504118918Srwatson */ 505118918Srwatson if (getino(&disk, (void **)&ino, inode, &mode) == -1) 506118918Srwatson err(1, "getino: %s", disk.d_error); 507118918Srwatson 508118918Srwatson if (ino->di_nlink == 0) { 509118918Srwatson DBG_LEAVE; 510118918Srwatson return; /* inode not in use */ 51169800Stomsoft } 512118918Srwatson 513118918Srwatson /* 514118918Srwatson * Dump the main inode structure. 515118918Srwatson */ 516118918Srwatson snprintf(comment, sizeof(comment), "Inode 0x%08x", inode); 517118918Srwatson if (level & 0x100) { 518118918Srwatson DBG_DUMP_INO(&sblock, comment, ino); 51969800Stomsoft } 52069800Stomsoft 521118918Srwatson if (!(level & 0x200)) { 522118918Srwatson DBG_LEAVE; 523118918Srwatson return; 524118918Srwatson } 525118918Srwatson 526118918Srwatson /* 527118918Srwatson * Ok, now prepare for dumping all direct and indirect pointers. 528118918Srwatson */ 529118918Srwatson rb = howmany(ino->di_size, sblock.fs_bsize) - NDADDR; 530118918Srwatson if (rb > 0) { 531118918Srwatson /* 532118918Srwatson * Dump single indirect block. 533118918Srwatson */ 534118918Srwatson if (bread(&disk, fsbtodb(&sblock, ino->di_ib[0]), (void *)&i1blk, 535118918Srwatson (size_t)sblock.fs_bsize) == -1) { 536118918Srwatson err(1, "bread: %s", disk.d_error); 537118918Srwatson } 538118918Srwatson snprintf(comment, sizeof(comment), "Inode 0x%08x: indirect 0", inode); 539118918Srwatson DBG_DUMP_IBLK(&sblock, comment, i1blk, (size_t)rb); 540118918Srwatson rb -= howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t)); 541118918Srwatson } 542118918Srwatson if (rb > 0) { 543118918Srwatson /* 544118918Srwatson * Dump double indirect blocks. 545118918Srwatson */ 546118918Srwatson if (bread(&disk, fsbtodb(&sblock, ino->di_ib[1]), (void *)&i2blk, 547118918Srwatson (size_t)sblock.fs_bsize) == -1) { 548118918Srwatson err(1, "bread: %s", disk.d_error); 549118918Srwatson } 550118918Srwatson snprintf(comment, sizeof(comment), "Inode 0x%08x: indirect 1", inode); 551118918Srwatson DBG_DUMP_IBLK(&sblock, 552118918Srwatson comment, 553118918Srwatson i2blk, 554118918Srwatson howmany(rb, howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t)))); 555118918Srwatson for (ind2ctr = 0; ((ind2ctr < howmany(sblock.fs_bsize, 556118918Srwatson sizeof(ufs2_daddr_t))) && (rb>0)); ind2ctr++) { 557118918Srwatson ind2ptr = &((ufs2_daddr_t *)(void *)&i2blk)[ind2ctr]; 558118918Srwatson 559118918Srwatson if (bread(&disk, fsbtodb(&sblock, *ind2ptr), (void *)&i1blk, 560118918Srwatson (size_t)sblock.fs_bsize) == -1) { 561118918Srwatson err(1, "bread: %s", disk.d_error); 562118918Srwatson } 563118918Srwatson snprintf(comment, sizeof(comment), 564118918Srwatson "Inode 0x%08x: indirect 1->%d", inode, ind2ctr); 565118918Srwatson DBG_DUMP_IBLK(&sblock, comment, i1blk, (size_t)rb); 566118918Srwatson rb -= howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t)); 567118918Srwatson } 568118918Srwatson } 569118918Srwatson if (rb > 0) { 570118918Srwatson /* 571118918Srwatson * Dump triple indirect blocks. 572118918Srwatson */ 573118918Srwatson if (bread(&disk, fsbtodb(&sblock, ino->di_ib[2]), (void *)&i3blk, 574118918Srwatson (size_t)sblock.fs_bsize) == -1) { 575118918Srwatson err(1, "bread: %s", disk.d_error); 576118918Srwatson } 577118918Srwatson snprintf(comment, sizeof(comment), "Inode 0x%08x: indirect 2", inode); 578118918Srwatson#define SQUARE(a) ((a)*(a)) 579118918Srwatson DBG_DUMP_IBLK(&sblock, 580118918Srwatson comment, 581118918Srwatson i3blk, 582118918Srwatson howmany(rb, 583118918Srwatson SQUARE(howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t))))); 584118918Srwatson#undef SQUARE 585118918Srwatson for (ind3ctr = 0; ((ind3ctr < howmany(sblock.fs_bsize, 586118918Srwatson sizeof(ufs2_daddr_t))) && (rb > 0)); ind3ctr++) { 587118918Srwatson ind3ptr = &((ufs2_daddr_t *)(void *)&i3blk)[ind3ctr]; 588118918Srwatson 589118918Srwatson if (bread(&disk, fsbtodb(&sblock, *ind3ptr), (void *)&i2blk, 590118918Srwatson (size_t)sblock.fs_bsize) == -1) { 591118918Srwatson err(1, "bread: %s", disk.d_error); 592118918Srwatson } 593118918Srwatson snprintf(comment, sizeof(comment), 594118918Srwatson "Inode 0x%08x: indirect 2->%d", inode, ind3ctr); 595118918Srwatson DBG_DUMP_IBLK(&sblock, 596118918Srwatson comment, 597118918Srwatson i2blk, 598118918Srwatson howmany(rb, 599118918Srwatson howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t)))); 600118918Srwatson for (ind2ctr = 0; ((ind2ctr < howmany(sblock.fs_bsize, 601118918Srwatson sizeof(ufs2_daddr_t))) && (rb > 0)); ind2ctr++) { 602118918Srwatson ind2ptr = &((ufs2_daddr_t *)(void *)&i2blk) [ind2ctr]; 603118918Srwatson if (bread(&disk, fsbtodb(&sblock, *ind2ptr), (void *)&i1blk, 604118918Srwatson (size_t)sblock.fs_bsize) == -1) { 605118918Srwatson err(1, "bread: %s", disk.d_error); 606118918Srwatson } 607118918Srwatson snprintf(comment, sizeof(comment), 608118918Srwatson "Inode 0x%08x: indirect 2->%d->%d", inode, 609118918Srwatson ind3ctr, ind3ctr); 610118918Srwatson DBG_DUMP_IBLK(&sblock, comment, i1blk, (size_t)rb); 611118918Srwatson rb -= howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t)); 612118918Srwatson } 613118918Srwatson } 614118918Srwatson } 615118918Srwatson 61669800Stomsoft DBG_LEAVE; 617118918Srwatson return; 61869800Stomsoft} 61969800Stomsoft 62069800Stomsoft/* ************************************************************* usage ***** */ 62169800Stomsoft/* 62269800Stomsoft * Dump a line of usage. 62369800Stomsoft */ 62469800Stomsoftvoid 62569926Stomsoftusage(void) 62669800Stomsoft{ 62769800Stomsoft DBG_FUNC("usage") 62869800Stomsoft 62969800Stomsoft DBG_ENTER; 63069800Stomsoft 63169800Stomsoft fprintf(stderr, 632141611Sru "usage: ffsinfo [-g cylinder_group] [-i inode] [-l level] " 63369926Stomsoft "[-o outfile]\n" 63469926Stomsoft " special | file\n"); 63569800Stomsoft 63669800Stomsoft DBG_LEAVE; 63769926Stomsoft exit(1); 63869800Stomsoft} 639