608 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			608 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014
 | 
						|
 *	The President and Fellows of Harvard College.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 * 3. Neither the name of the University nor the names of its contributors
 | 
						|
 *    may be used to endorse or promote products derived from this software
 | 
						|
 *    without specific prior written permission.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
 | 
						|
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
 | 
						|
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
						|
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
						|
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
						|
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
						|
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
						|
 * SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <stdint.h>
 | 
						|
#include <stdbool.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <assert.h>
 | 
						|
#include <limits.h>
 | 
						|
#include <err.h>
 | 
						|
 | 
						|
#include "support.h"
 | 
						|
#include "kern/sfs.h"
 | 
						|
 | 
						|
 | 
						|
#ifdef HOST
 | 
						|
/*
 | 
						|
 * OS/161 runs natively on a big-endian platform, so we can
 | 
						|
 * conveniently use the byteswapping functions for network byte order.
 | 
						|
 */
 | 
						|
#include <netinet/in.h> // for arpa/inet.h
 | 
						|
#include <arpa/inet.h>  // for ntohl
 | 
						|
#include "hostcompat.h"
 | 
						|
#define SWAP64(x) ntohll(x)
 | 
						|
#define SWAP32(x) ntohl(x)
 | 
						|
#define SWAP16(x) ntohs(x)
 | 
						|
 | 
						|
extern const char *hostcompat_progname;
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
#define SWAP64(x) (x)
 | 
						|
#define SWAP32(x) (x)
 | 
						|
#define SWAP16(x) (x)
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
#include "disk.h"
 | 
						|
 | 
						|
#define ARRAYCOUNT(a) (sizeof(a) / sizeof((a)[0]))
 | 
						|
#define DIVROUNDUP(a, b) (((a) + (b) - 1) / (b))
 | 
						|
 | 
						|
static bool dofiles, dodirs;
 | 
						|
static bool doindirect;
 | 
						|
static bool recurse;
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////
 | 
						|
// printouts
 | 
						|
 | 
						|
static unsigned dumppos;
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
dumpval(const char *desc, const char *val)
 | 
						|
{
 | 
						|
	size_t dlen, vlen, used;
 | 
						|
 | 
						|
	dlen = strlen(desc);
 | 
						|
	vlen = strlen(val);
 | 
						|
 | 
						|
	printf("    ");
 | 
						|
 | 
						|
	printf("%s: %s", desc, val);
 | 
						|
 | 
						|
	used = dlen + 2 + vlen;
 | 
						|
	for (; used < 36; used++) {
 | 
						|
		putchar(' ');
 | 
						|
	}
 | 
						|
 | 
						|
	if (dumppos % 2 == 1) {
 | 
						|
		printf("\n");
 | 
						|
	}
 | 
						|
	dumppos++;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
dumpvalf(const char *desc, const char *valf, ...)
 | 
						|
{
 | 
						|
	va_list ap;
 | 
						|
	char buf[128];
 | 
						|
 | 
						|
	va_start(ap, valf);
 | 
						|
	vsnprintf(buf, sizeof(buf), valf, ap);
 | 
						|
	va_end(ap);
 | 
						|
	dumpval(desc, buf);
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
dumplval(const char *desc, const char *lval)
 | 
						|
{
 | 
						|
	if (dumppos % 2 == 1) {
 | 
						|
		printf("\n");
 | 
						|
		dumppos++;
 | 
						|
	}
 | 
						|
	printf("    %s: %s\n", desc, lval);
 | 
						|
	dumppos += 2;
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////
 | 
						|
// fs structures
 | 
						|
 | 
						|
static void dumpinode(uint32_t ino, const char *name);
 | 
						|
 | 
						|
static
 | 
						|
uint32_t
 | 
						|
readsb(void)
 | 
						|
{
 | 
						|
	struct sfs_superblock sb;
 | 
						|
 | 
						|
	diskread(&sb, SFS_SUPER_BLOCK);
 | 
						|
	if (SWAP32(sb.sb_magic) != SFS_MAGIC) {
 | 
						|
		errx(1, "Not an sfs filesystem");
 | 
						|
	}
 | 
						|
	return SWAP32(sb.sb_nblocks);
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
dumpsb(void)
 | 
						|
{
 | 
						|
	struct sfs_superblock sb;
 | 
						|
	unsigned i;
 | 
						|
 | 
						|
	diskread(&sb, SFS_SUPER_BLOCK);
 | 
						|
	sb.sb_volname[sizeof(sb.sb_volname)-1] = 0;
 | 
						|
 | 
						|
	printf("Superblock\n");
 | 
						|
	printf("----------\n");
 | 
						|
	dumpvalf("Magic", "0x%8x", SWAP32(sb.sb_magic));
 | 
						|
	dumpvalf("Size", "%u blocks", SWAP32(sb.sb_nblocks));
 | 
						|
	dumpvalf("Freemap size", "%u blocks",
 | 
						|
		 SFS_FREEMAPBLOCKS(SWAP32(sb.sb_nblocks)));
 | 
						|
	dumpvalf("Block size", "%u bytes", SFS_BLOCKSIZE);
 | 
						|
	dumplval("Volume name", sb.sb_volname);
 | 
						|
 | 
						|
	for (i=0; i<ARRAYCOUNT(sb.reserved); i++) {
 | 
						|
		if (sb.reserved[i] != 0) {
 | 
						|
			printf("    Word %u in reserved area: 0x%x\n",
 | 
						|
			       i, SWAP32(sb.reserved[i]));
 | 
						|
		}
 | 
						|
	}
 | 
						|
	printf("\n");
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
dumpfreemap(uint32_t fsblocks)
 | 
						|
{
 | 
						|
	uint32_t freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
 | 
						|
	uint32_t i, j, k, bn;
 | 
						|
	uint8_t data[SFS_BLOCKSIZE], mask;
 | 
						|
	char tmp[16];
 | 
						|
 | 
						|
	printf("Free block bitmap\n");
 | 
						|
	printf("-----------------\n");
 | 
						|
	for (i=0; i<freemapblocks; i++) {
 | 
						|
		diskread(data, SFS_FREEMAP_START+i);
 | 
						|
		printf("    Freemap block #%u in disk block %u: blocks %u - %u"
 | 
						|
		       " (0x%x - 0x%x)\n",
 | 
						|
		       i, SFS_FREEMAP_START+i,
 | 
						|
		       i*SFS_BITSPERBLOCK, (i+1)*SFS_BITSPERBLOCK - 1,
 | 
						|
		       i*SFS_BITSPERBLOCK, (i+1)*SFS_BITSPERBLOCK - 1);
 | 
						|
		for (j=0; j<SFS_BLOCKSIZE; j++) {
 | 
						|
			if (j % 8 == 0) {
 | 
						|
				snprintf(tmp, sizeof(tmp), "0x%x",
 | 
						|
					 i*SFS_BITSPERBLOCK + j*8);
 | 
						|
				printf("%-7s ", tmp);
 | 
						|
			}
 | 
						|
			for (k=0; k<8; k++) {
 | 
						|
				bn = i*SFS_BITSPERBLOCK + j*8 + k;
 | 
						|
				mask = 1U << k;
 | 
						|
				if (bn >= fsblocks) {
 | 
						|
					if (data[j] & mask) {
 | 
						|
						putchar('x');
 | 
						|
					}
 | 
						|
					else {
 | 
						|
						putchar('!');
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					if (data[j] & mask) {
 | 
						|
						putchar('*');
 | 
						|
					}
 | 
						|
					else {
 | 
						|
						putchar('.');
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if (j % 8 == 7) {
 | 
						|
				printf("\n");
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				printf(" ");
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	printf("\n");
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
dumpindirect(uint32_t block)
 | 
						|
{
 | 
						|
	uint32_t ib[SFS_BLOCKSIZE/sizeof(uint32_t)];
 | 
						|
	char tmp[128];
 | 
						|
	unsigned i;
 | 
						|
 | 
						|
	if (block == 0) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	printf("Indirect block %u\n", block);
 | 
						|
 | 
						|
	diskread(ib, block);
 | 
						|
	for (i=0; i<ARRAYCOUNT(ib); i++) {
 | 
						|
		if (i % 4 == 0) {
 | 
						|
			printf("@%-3u   ", i);
 | 
						|
		}
 | 
						|
		snprintf(tmp, sizeof(tmp), "%u (0x%x)",
 | 
						|
			 SWAP32(ib[i]), SWAP32(ib[i]));
 | 
						|
		printf("  %-16s", tmp);
 | 
						|
		if (i % 4 == 3) {
 | 
						|
			printf("\n");
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
uint32_t
 | 
						|
traverse_ib(uint32_t fileblock, uint32_t numblocks, uint32_t block,
 | 
						|
	    void (*doblock)(uint32_t, uint32_t))
 | 
						|
{
 | 
						|
	uint32_t ib[SFS_BLOCKSIZE/sizeof(uint32_t)];
 | 
						|
	unsigned i;
 | 
						|
 | 
						|
	if (block == 0) {
 | 
						|
		memset(ib, 0, sizeof(ib));
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		diskread(ib, block);
 | 
						|
	}
 | 
						|
	for (i=0; i<ARRAYCOUNT(ib) && fileblock < numblocks; i++) {
 | 
						|
		doblock(fileblock++, SWAP32(ib[i]));
 | 
						|
	}
 | 
						|
	return fileblock;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
traverse(const struct sfs_dinode *sfi, void (*doblock)(uint32_t, uint32_t))
 | 
						|
{
 | 
						|
	uint32_t fileblock;
 | 
						|
	uint32_t numblocks;
 | 
						|
	unsigned i;
 | 
						|
 | 
						|
	numblocks = DIVROUNDUP(SWAP32(sfi->sfi_size), SFS_BLOCKSIZE);
 | 
						|
 | 
						|
	fileblock = 0;
 | 
						|
	for (i=0; i<SFS_NDIRECT && fileblock < numblocks; i++) {
 | 
						|
		doblock(fileblock++, SWAP32(sfi->sfi_direct[i]));
 | 
						|
	}
 | 
						|
	if (fileblock < numblocks) {
 | 
						|
		fileblock = traverse_ib(fileblock, numblocks,
 | 
						|
					SWAP32(sfi->sfi_indirect), doblock);
 | 
						|
	}
 | 
						|
	assert(fileblock == numblocks);
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
dumpdirblock(uint32_t fileblock, uint32_t diskblock)
 | 
						|
{
 | 
						|
	struct sfs_direntry sds[SFS_BLOCKSIZE/sizeof(struct sfs_direntry)];
 | 
						|
	int nsds = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
 | 
						|
	int i;
 | 
						|
 | 
						|
	(void)fileblock;
 | 
						|
	if (diskblock == 0) {
 | 
						|
		printf("    [block %u - empty]\n", diskblock);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	diskread(&sds, diskblock);
 | 
						|
 | 
						|
	printf("    [block %u]\n", diskblock);
 | 
						|
	for (i=0; i<nsds; i++) {
 | 
						|
		uint32_t ino = SWAP32(sds[i].sfd_ino);
 | 
						|
		if (ino==SFS_NOINO) {
 | 
						|
			printf("        [free entry]\n");
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			sds[i].sfd_name[SFS_NAMELEN-1] = 0; /* just in case */
 | 
						|
			printf("        %u %s\n", ino, sds[i].sfd_name);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
dumpdir(uint32_t ino, const struct sfs_dinode *sfi)
 | 
						|
{
 | 
						|
	int nentries;
 | 
						|
 | 
						|
	nentries = SWAP32(sfi->sfi_size) / sizeof(struct sfs_direntry);
 | 
						|
	if (SWAP32(sfi->sfi_size) % sizeof(struct sfs_direntry) != 0) {
 | 
						|
		warnx("Warning: dir size is not a multiple of dir entry size");
 | 
						|
	}
 | 
						|
	printf("Directory contents for inode %u: %d entries\n", ino, nentries);
 | 
						|
	traverse(sfi, dumpdirblock);
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
recursedirblock(uint32_t fileblock, uint32_t diskblock)
 | 
						|
{
 | 
						|
	struct sfs_direntry sds[SFS_BLOCKSIZE/sizeof(struct sfs_direntry)];
 | 
						|
	int nsds = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
 | 
						|
	int i;
 | 
						|
 | 
						|
	(void)fileblock;
 | 
						|
	if (diskblock == 0) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	diskread(&sds, diskblock);
 | 
						|
 | 
						|
	for (i=0; i<nsds; i++) {
 | 
						|
		uint32_t ino = SWAP32(sds[i].sfd_ino);
 | 
						|
		if (ino==SFS_NOINO) {
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		sds[i].sfd_name[SFS_NAMELEN-1] = 0; /* just in case */
 | 
						|
		dumpinode(ino, sds[i].sfd_name);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
recursedir(uint32_t ino, const struct sfs_dinode *sfi)
 | 
						|
{
 | 
						|
	int nentries;
 | 
						|
 | 
						|
	nentries = SWAP32(sfi->sfi_size) / sizeof(struct sfs_direntry);
 | 
						|
	printf("Reading files in directory %u: %d entries\n", ino, nentries);
 | 
						|
	traverse(sfi, recursedirblock);
 | 
						|
	printf("Done with directory %u\n", ino);
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void dumpfileblock(uint32_t fileblock, uint32_t diskblock)
 | 
						|
{
 | 
						|
	uint8_t data[SFS_BLOCKSIZE];
 | 
						|
	unsigned i, j;
 | 
						|
	char tmp[128];
 | 
						|
 | 
						|
	if (diskblock == 0) {
 | 
						|
		printf("    0x%6x  [sparse]\n", fileblock * SFS_BLOCKSIZE);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	diskread(data, diskblock);
 | 
						|
	for (i=0; i<SFS_BLOCKSIZE; i++) {
 | 
						|
		if (i % 16 == 0) {
 | 
						|
			snprintf(tmp, sizeof(tmp), "0x%x",
 | 
						|
				 fileblock * SFS_BLOCKSIZE + i);
 | 
						|
			printf("%8s", tmp);
 | 
						|
		}
 | 
						|
		if (i % 8 == 0) {
 | 
						|
			printf("  ");
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			printf(" ");
 | 
						|
		}
 | 
						|
		printf("%02x", data[i]);
 | 
						|
		if (i % 16 == 15) {
 | 
						|
			printf("  ");
 | 
						|
			for (j = i-15; j<=i; j++) {
 | 
						|
				if (data[j] < 32 || data[j] > 126) {
 | 
						|
					putchar('.');
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					putchar(data[j]);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			printf("\n");
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
dumpfile(uint32_t ino, const struct sfs_dinode *sfi)
 | 
						|
{
 | 
						|
	printf("File contents for inode %u:\n", ino);
 | 
						|
	traverse(sfi, dumpfileblock);
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
dumpinode(uint32_t ino, const char *name)
 | 
						|
{
 | 
						|
	struct sfs_dinode sfi;
 | 
						|
	const char *typename;
 | 
						|
	char tmp[128];
 | 
						|
	unsigned i;
 | 
						|
 | 
						|
	diskread(&sfi, ino);
 | 
						|
 | 
						|
	printf("Inode %u", ino);
 | 
						|
	if (name != NULL) {
 | 
						|
		printf(" (%s)", name);
 | 
						|
	}
 | 
						|
	printf("\n");
 | 
						|
	printf("--------------\n");
 | 
						|
 | 
						|
	switch (SWAP16(sfi.sfi_type)) {
 | 
						|
	    case SFS_TYPE_FILE: typename = "regular file"; break;
 | 
						|
	    case SFS_TYPE_DIR: typename = "directory"; break;
 | 
						|
	    default: typename = "invalid"; break;
 | 
						|
	}
 | 
						|
	dumpvalf("Type", "%u (%s)", SWAP16(sfi.sfi_type), typename);
 | 
						|
	dumpvalf("Size", "%u", SWAP32(sfi.sfi_size));
 | 
						|
	dumpvalf("Link count", "%u", SWAP16(sfi.sfi_linkcount));
 | 
						|
	printf("\n");
 | 
						|
 | 
						|
        printf("    Direct blocks:\n");
 | 
						|
        for (i=0; i<SFS_NDIRECT; i++) {
 | 
						|
		if (i % 4 == 0) {
 | 
						|
			printf("@%-2u    ", i);
 | 
						|
		}
 | 
						|
		/*
 | 
						|
		 * Assume the disk size might be > 64K sectors (which
 | 
						|
		 * would be 32M) but is < 1024K sectors (512M) so we
 | 
						|
		 * need up to 5 hex digits for a block number. And
 | 
						|
		 * assume it's actually < 1 million sectors so we need
 | 
						|
		 * only up to 6 decimal digits. The complete block
 | 
						|
		 * number print then needs up to 16 digits.
 | 
						|
		 */
 | 
						|
		snprintf(tmp, sizeof(tmp), "%u (0x%x)",
 | 
						|
			 SWAP32(sfi.sfi_direct[i]), SWAP32(sfi.sfi_direct[i]));
 | 
						|
		printf("  %-16s", tmp);
 | 
						|
		if (i % 4 == 3) {
 | 
						|
			printf("\n");
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (i % 4 != 0) {
 | 
						|
		printf("\n");
 | 
						|
	}
 | 
						|
	printf("    Indirect block: %u (0x%x)\n",
 | 
						|
	       SWAP32(sfi.sfi_indirect), SWAP32(sfi.sfi_indirect));
 | 
						|
	for (i=0; i<ARRAYCOUNT(sfi.sfi_waste); i++) {
 | 
						|
		if (sfi.sfi_waste[i] != 0) {
 | 
						|
			printf("    Word %u in waste area: 0x%x\n",
 | 
						|
			       i, SWAP32(sfi.sfi_waste[i]));
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (doindirect) {
 | 
						|
		dumpindirect(SWAP32(sfi.sfi_indirect));
 | 
						|
	}
 | 
						|
 | 
						|
	if (SWAP16(sfi.sfi_type) == SFS_TYPE_DIR && dodirs) {
 | 
						|
		dumpdir(ino, &sfi);
 | 
						|
	}
 | 
						|
	if (SWAP16(sfi.sfi_type) == SFS_TYPE_FILE && dofiles) {
 | 
						|
		dumpfile(ino, &sfi);
 | 
						|
	}
 | 
						|
	if (SWAP16(sfi.sfi_type) == SFS_TYPE_DIR && recurse) {
 | 
						|
		recursedir(ino, &sfi);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////
 | 
						|
// main
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
usage(void)
 | 
						|
{
 | 
						|
	warnx("Usage: dumpsfs [options] device/diskfile");
 | 
						|
	warnx("   -s: dump superblock");
 | 
						|
	warnx("   -b: dump free block bitmap");
 | 
						|
	warnx("   -i ino: dump specified inode");
 | 
						|
	warnx("   -I: dump indirect blocks");
 | 
						|
	warnx("   -f: dump file contents");
 | 
						|
	warnx("   -d: dump directory contents");
 | 
						|
	warnx("   -r: recurse into directory contents");
 | 
						|
	warnx("   -a: equivalent to -sbdfr -i 1");
 | 
						|
	errx(1, "   Default is -i 1");
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
main(int argc, char **argv)
 | 
						|
{
 | 
						|
	bool dosb = false;
 | 
						|
	bool dofreemap = false;
 | 
						|
	uint32_t dumpino = 0;
 | 
						|
	const char *dumpdisk = NULL;
 | 
						|
 | 
						|
	int i, j;
 | 
						|
	uint32_t nblocks;
 | 
						|
 | 
						|
#ifdef HOST
 | 
						|
	/* Don't do this; it frobs the tty and you can't pipe to less */
 | 
						|
	/*hostcompat_init(argc, argv);*/
 | 
						|
	hostcompat_progname = argv[0];
 | 
						|
#endif
 | 
						|
 | 
						|
	for (i=1; i<argc; i++) {
 | 
						|
		if (argv[i][0] == '-') {
 | 
						|
			for (j=1; argv[i][j]; j++) {
 | 
						|
				switch (argv[i][j]) {
 | 
						|
				    case 's': dosb = true; break;
 | 
						|
				    case 'b': dofreemap = true; break;
 | 
						|
				    case 'i':
 | 
						|
					if (argv[i][j+1] == 0) {
 | 
						|
						dumpino = atoi(argv[++i]);
 | 
						|
					}
 | 
						|
					else {
 | 
						|
						dumpino = atoi(argv[i]+j+1);
 | 
						|
						j = strlen(argv[i]);
 | 
						|
					}
 | 
						|
					/* XXX ugly */
 | 
						|
					goto nextarg;
 | 
						|
				    case 'I': doindirect = true; break;
 | 
						|
				    case 'f': dofiles = true; break;
 | 
						|
				    case 'd': dodirs = true; break;
 | 
						|
				    case 'r': recurse = true; break;
 | 
						|
				    case 'a':
 | 
						|
					dosb = true;
 | 
						|
					dofreemap = true;
 | 
						|
					if (dumpino == 0) {
 | 
						|
						dumpino = SFS_ROOTDIR_INO;
 | 
						|
					}
 | 
						|
					doindirect = true;
 | 
						|
					dofiles = true;
 | 
						|
					dodirs = true;
 | 
						|
					recurse = true;
 | 
						|
					break;
 | 
						|
				    default:
 | 
						|
					usage();
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			if (dumpdisk != NULL) {
 | 
						|
				usage();
 | 
						|
			}
 | 
						|
			dumpdisk = argv[i];
 | 
						|
		}
 | 
						|
	 nextarg:
 | 
						|
		;
 | 
						|
	}
 | 
						|
	if (dumpdisk == NULL) {
 | 
						|
		usage();
 | 
						|
	}
 | 
						|
 | 
						|
	if (!dosb && !dofreemap && dumpino == 0) {
 | 
						|
		dumpino = SFS_ROOTDIR_INO;
 | 
						|
	}
 | 
						|
 | 
						|
	opendisk(dumpdisk);
 | 
						|
	nblocks = readsb();
 | 
						|
 | 
						|
	if (dosb) {
 | 
						|
		dumpsb();
 | 
						|
	}
 | 
						|
	if (dofreemap) {
 | 
						|
		dumpfreemap(nblocks);
 | 
						|
	}
 | 
						|
	if (dumpino != 0) {
 | 
						|
		dumpinode(dumpino, NULL);
 | 
						|
	}
 | 
						|
 | 
						|
	closedisk();
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |