Initial Spring 2016 commit.
This commit is contained in:
10
userland/sbin/Makefile
Normal file
10
userland/sbin/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Makefile for src/sbin (sources for programs installed in /sbin)
|
||||
#
|
||||
|
||||
TOP=../..
|
||||
.include "$(TOP)/mk/os161.config.mk"
|
||||
|
||||
SUBDIRS=reboot halt poweroff mksfs dumpsfs sfsck
|
||||
|
||||
.include "$(TOP)/mk/os161.subdir.mk"
|
15
userland/sbin/dumpsfs/Makefile
Normal file
15
userland/sbin/dumpsfs/Makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
# Makefile for dumpsfs
|
||||
|
||||
TOP=../../..
|
||||
.include "$(TOP)/mk/os161.config.mk"
|
||||
|
||||
PROG=dumpsfs
|
||||
SRCS=dumpsfs.c ../mksfs/disk.c ../mksfs/support.c
|
||||
CFLAGS+=-I../mksfs
|
||||
HOST_CFLAGS+=-I../mksfs
|
||||
BINDIR=/sbin
|
||||
HOSTBINDIR=/hostbin
|
||||
|
||||
|
||||
.include "$(TOP)/mk/os161.prog.mk"
|
||||
.include "$(TOP)/mk/os161.hostprog.mk"
|
607
userland/sbin/dumpsfs/dumpsfs.c
Normal file
607
userland/sbin/dumpsfs/dumpsfs.c
Normal file
@@ -0,0 +1,607 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
12
userland/sbin/halt/Makefile
Normal file
12
userland/sbin/halt/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
# Makefile for halt
|
||||
|
||||
TOP=../../..
|
||||
.include "$(TOP)/mk/os161.config.mk"
|
||||
|
||||
PROG=halt
|
||||
SRCS=halt.c
|
||||
BINDIR=/sbin
|
||||
|
||||
|
||||
.include "$(TOP)/mk/os161.prog.mk"
|
||||
|
44
userland/sbin/halt/halt.c
Normal file
44
userland/sbin/halt/halt.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||
* 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 <unistd.h>
|
||||
|
||||
/*
|
||||
* halt - shut down system, do not reboot, do not turn off power.
|
||||
* Usage: halt
|
||||
*
|
||||
* Just calls reboot() with the RB_HALT flag.
|
||||
*/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
reboot(RB_HALT);
|
||||
return 0;
|
||||
}
|
13
userland/sbin/mksfs/Makefile
Normal file
13
userland/sbin/mksfs/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
# Makefile for mksfs
|
||||
|
||||
TOP=../../..
|
||||
.include "$(TOP)/mk/os161.config.mk"
|
||||
|
||||
PROG=mksfs
|
||||
SRCS=mksfs.c disk.c support.c
|
||||
BINDIR=/sbin
|
||||
HOSTBINDIR=/hostbin
|
||||
|
||||
|
||||
.include "$(TOP)/mk/os161.prog.mk"
|
||||
.include "$(TOP)/mk/os161.hostprog.mk"
|
200
userland/sbin/mksfs/disk.c
Normal file
200
userland/sbin/mksfs/disk.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||
* 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 <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "support.h"
|
||||
#include "disk.h"
|
||||
|
||||
#define HOSTSTRING "System/161 Disk Image"
|
||||
#define BLOCKSIZE 512
|
||||
|
||||
#ifndef EINTR
|
||||
#define EINTR 0
|
||||
#endif
|
||||
|
||||
static int fd=-1;
|
||||
static uint32_t nblocks;
|
||||
|
||||
/*
|
||||
* Open a disk. If we're built for the host OS, check that it's a
|
||||
* System/161 disk image, and then ignore the header block.
|
||||
*/
|
||||
void
|
||||
opendisk(const char *path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
assert(fd<0);
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd<0) {
|
||||
err(1, "%s", path);
|
||||
}
|
||||
if (fstat(fd, &statbuf)) {
|
||||
err(1, "%s: fstat", path);
|
||||
}
|
||||
|
||||
nblocks = statbuf.st_size / BLOCKSIZE;
|
||||
|
||||
#ifdef HOST
|
||||
nblocks--;
|
||||
|
||||
{
|
||||
char buf[64];
|
||||
int len;
|
||||
|
||||
do {
|
||||
len = read(fd, buf, sizeof(buf)-1);
|
||||
if (len < 0 && (errno==EINTR || errno==EAGAIN)) {
|
||||
continue;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
buf[len] = 0;
|
||||
buf[strlen(HOSTSTRING)] = 0;
|
||||
|
||||
if (strcmp(buf, HOSTSTRING)) {
|
||||
errx(1, "%s: Not a System/161 disk image", path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the block size. (This is fixed, but still...)
|
||||
*/
|
||||
uint32_t
|
||||
diskblocksize(void)
|
||||
{
|
||||
assert(fd>=0);
|
||||
return BLOCKSIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the device/image size in blocks.
|
||||
*/
|
||||
uint32_t
|
||||
diskblocks(void)
|
||||
{
|
||||
assert(fd>=0);
|
||||
return nblocks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a block.
|
||||
*/
|
||||
void
|
||||
diskwrite(const void *data, uint32_t block)
|
||||
{
|
||||
const char *cdata = data;
|
||||
uint32_t tot=0;
|
||||
int len;
|
||||
|
||||
assert(fd>=0);
|
||||
|
||||
#ifdef HOST
|
||||
// skip over disk file header
|
||||
block++;
|
||||
#endif
|
||||
|
||||
if (lseek(fd, block*BLOCKSIZE, SEEK_SET)<0) {
|
||||
err(1, "lseek");
|
||||
}
|
||||
|
||||
while (tot < BLOCKSIZE) {
|
||||
len = write(fd, cdata + tot, BLOCKSIZE - tot);
|
||||
if (len < 0) {
|
||||
if (errno==EINTR || errno==EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
err(1, "write");
|
||||
}
|
||||
if (len==0) {
|
||||
err(1, "write returned 0?");
|
||||
}
|
||||
tot += len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a block.
|
||||
*/
|
||||
void
|
||||
diskread(void *data, uint32_t block)
|
||||
{
|
||||
char *cdata = data;
|
||||
uint32_t tot=0;
|
||||
int len;
|
||||
|
||||
assert(fd>=0);
|
||||
|
||||
#ifdef HOST
|
||||
// skip over disk file header
|
||||
block++;
|
||||
#endif
|
||||
|
||||
if (lseek(fd, block*BLOCKSIZE, SEEK_SET)<0) {
|
||||
err(1, "lseek");
|
||||
}
|
||||
|
||||
while (tot < BLOCKSIZE) {
|
||||
len = read(fd, cdata + tot, BLOCKSIZE - tot);
|
||||
if (len < 0) {
|
||||
if (errno==EINTR || errno==EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
err(1, "read");
|
||||
}
|
||||
if (len==0) {
|
||||
err(1, "unexpected EOF in mid-sector");
|
||||
}
|
||||
tot += len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the disk.
|
||||
*/
|
||||
void
|
||||
closedisk(void)
|
||||
{
|
||||
assert(fd>=0);
|
||||
if (close(fd)) {
|
||||
err(1, "close");
|
||||
}
|
||||
fd = -1;
|
||||
}
|
38
userland/sbin/mksfs/disk.h
Normal file
38
userland/sbin/mksfs/disk.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||
* 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.
|
||||
*/
|
||||
|
||||
void opendisk(const char *path);
|
||||
|
||||
uint32_t diskblocksize(void);
|
||||
uint32_t diskblocks(void);
|
||||
|
||||
void diskwrite(const void *data, uint32_t block);
|
||||
void diskread(void *data, uint32_t block);
|
||||
|
||||
void closedisk(void);
|
240
userland/sbin/mksfs/mksfs.c
Normal file
240
userland/sbin/mksfs/mksfs.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "support.h"
|
||||
#include "kern/sfs.h"
|
||||
|
||||
|
||||
#ifdef HOST
|
||||
|
||||
#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)
|
||||
|
||||
#else
|
||||
|
||||
#define SWAP64(x) (x)
|
||||
#define SWAP32(x) (x)
|
||||
#define SWAP16(x) (x)
|
||||
|
||||
#endif
|
||||
|
||||
#include "disk.h"
|
||||
|
||||
/* Maximum size of freemap we support */
|
||||
#define MAXFREEMAPBLOCKS 32
|
||||
|
||||
/* Free block bitmap */
|
||||
static char freemapbuf[MAXFREEMAPBLOCKS * SFS_BLOCKSIZE];
|
||||
|
||||
/*
|
||||
* Assert that the on-disk data structures are correctly sized.
|
||||
*/
|
||||
static
|
||||
void
|
||||
check(void)
|
||||
{
|
||||
assert(sizeof(struct sfs_superblock)==SFS_BLOCKSIZE);
|
||||
assert(sizeof(struct sfs_dinode)==SFS_BLOCKSIZE);
|
||||
assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark a block allocated.
|
||||
*/
|
||||
static
|
||||
void
|
||||
allocblock(uint32_t block)
|
||||
{
|
||||
uint32_t mapbyte = block/CHAR_BIT;
|
||||
unsigned char mask = (1<<(block % CHAR_BIT));
|
||||
|
||||
assert((freemapbuf[mapbyte] & mask) == 0);
|
||||
freemapbuf[mapbyte] |= mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the free block bitmap.
|
||||
*/
|
||||
static
|
||||
void
|
||||
initfreemap(uint32_t fsblocks)
|
||||
{
|
||||
uint32_t freemapbits = SFS_FREEMAPBITS(fsblocks);
|
||||
uint32_t freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
|
||||
uint32_t i;
|
||||
|
||||
if (freemapblocks > MAXFREEMAPBLOCKS) {
|
||||
errx(1, "Filesystem too large -- "
|
||||
"increase MAXFREEMAPBLOCKS and recompile");
|
||||
}
|
||||
|
||||
/* mark the superblock and root inode in use */
|
||||
allocblock(SFS_SUPER_BLOCK);
|
||||
allocblock(SFS_ROOTDIR_INO);
|
||||
|
||||
/* the freemap blocks must be in use */
|
||||
for (i=0; i<freemapblocks; i++) {
|
||||
allocblock(SFS_FREEMAP_START + i);
|
||||
}
|
||||
|
||||
/* all blocks in the freemap but past the volume end are "in use" */
|
||||
for (i=fsblocks; i<freemapbits; i++) {
|
||||
allocblock(i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize and write out the superblock.
|
||||
*/
|
||||
static
|
||||
void
|
||||
writesuper(const char *volname, uint32_t nblocks)
|
||||
{
|
||||
struct sfs_superblock sb;
|
||||
|
||||
/* The cast is required on some outdated host systems. */
|
||||
bzero((void *)&sb, sizeof(sb));
|
||||
|
||||
if (strlen(volname) >= SFS_VOLNAME_SIZE) {
|
||||
errx(1, "Volume name %s too long", volname);
|
||||
}
|
||||
|
||||
/* Initialize the superblock structure */
|
||||
sb.sb_magic = SWAP32(SFS_MAGIC);
|
||||
sb.sb_nblocks = SWAP32(nblocks);
|
||||
strcpy(sb.sb_volname, volname);
|
||||
|
||||
/* and write it out. */
|
||||
diskwrite(&sb, SFS_SUPER_BLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out the free block bitmap.
|
||||
*/
|
||||
static
|
||||
void
|
||||
writefreemap(uint32_t fsblocks)
|
||||
{
|
||||
uint32_t freemapblocks;
|
||||
char *ptr;
|
||||
uint32_t i;
|
||||
|
||||
/* Write out each of the blocks in the free block bitmap. */
|
||||
freemapblocks = SFS_FREEMAPBLOCKS(fsblocks);
|
||||
for (i=0; i<freemapblocks; i++) {
|
||||
ptr = freemapbuf + i*SFS_BLOCKSIZE;
|
||||
diskwrite(ptr, SFS_FREEMAP_START+i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out the root directory inode.
|
||||
*/
|
||||
static
|
||||
void
|
||||
writerootdir(void)
|
||||
{
|
||||
struct sfs_dinode sfi;
|
||||
|
||||
/* Initialize the dinode */
|
||||
bzero((void *)&sfi, sizeof(sfi));
|
||||
sfi.sfi_size = SWAP32(0);
|
||||
sfi.sfi_type = SWAP16(SFS_TYPE_DIR);
|
||||
sfi.sfi_linkcount = SWAP16(1);
|
||||
|
||||
/* Write it out */
|
||||
diskwrite(&sfi, SFS_ROOTDIR_INO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main.
|
||||
*/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
uint32_t size, blocksize;
|
||||
char *volname, *s;
|
||||
|
||||
#ifdef HOST
|
||||
hostcompat_init(argc, argv);
|
||||
#endif
|
||||
|
||||
if (argc!=3) {
|
||||
errx(1, "Usage: mksfs device/diskfile volume-name");
|
||||
}
|
||||
|
||||
check();
|
||||
|
||||
volname = argv[2];
|
||||
|
||||
/* Remove one trailing colon from volname, if present */
|
||||
s = strchr(volname, ':');
|
||||
if (s != NULL) {
|
||||
if (strlen(s)!=1) {
|
||||
errx(1, "Illegal volume name %s", volname);
|
||||
}
|
||||
*s = 0;
|
||||
}
|
||||
|
||||
/* Don't allow slashes */
|
||||
s = strchr(volname, '/');
|
||||
if (s != NULL) {
|
||||
errx(1, "Illegal volume name %s", volname);
|
||||
}
|
||||
|
||||
opendisk(argv[1]);
|
||||
blocksize = diskblocksize();
|
||||
|
||||
if (blocksize!=SFS_BLOCKSIZE) {
|
||||
errx(1, "Device has wrong blocksize %u (should be %u)\n",
|
||||
blocksize, SFS_BLOCKSIZE);
|
||||
}
|
||||
size = diskblocks();
|
||||
|
||||
/* Write out the on-disk structures */
|
||||
initfreemap(size);
|
||||
writesuper(volname, size);
|
||||
writefreemap(size);
|
||||
writerootdir();
|
||||
|
||||
closedisk();
|
||||
|
||||
return 0;
|
||||
}
|
34
userland/sbin/mksfs/support.c
Normal file
34
userland/sbin/mksfs/support.c
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file doesn't actually do anything any more, but I'm going to
|
||||
* leave it here for now (and leave the mechanisms in place for building
|
||||
* it) in case it's wanted again later on.
|
||||
*/
|
64
userland/sbin/mksfs/support.h
Normal file
64
userland/sbin/mksfs/support.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __osf__
|
||||
/* Digital Unix (aka Compaq Tru64) */
|
||||
#define HAS_NO_SIZED_TYPES
|
||||
#endif
|
||||
|
||||
#if defined(__sun__) && defined(__svr4__)
|
||||
/* Solaris */
|
||||
#define HAS_NO_SIZED_TYPES
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some systems don't have uint32_t, uint16_t, or uint8_t.
|
||||
* (Sometime this should be changed so it gets probed by the configure script.)
|
||||
*/
|
||||
|
||||
#ifdef HAS_NO_SIZED_TYPES
|
||||
|
||||
#if defined(__alpha__) || defined(__alpha)
|
||||
/* Alpha processor: lp64 */
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
#elif defined(__sparc__)
|
||||
/* Sparc processor: 32-bit or lp64 */
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
#else
|
||||
#error "HAS_NO_SIZED_TYPES defined and I don't know what the sizes should be"
|
||||
#endif
|
||||
|
||||
#endif
|
11
userland/sbin/poweroff/Makefile
Normal file
11
userland/sbin/poweroff/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
# Makefile for poweroff
|
||||
|
||||
TOP=../../..
|
||||
.include "$(TOP)/mk/os161.config.mk"
|
||||
|
||||
PROG=poweroff
|
||||
SRCS=poweroff.c
|
||||
BINDIR=/sbin
|
||||
|
||||
.include "$(TOP)/mk/os161.prog.mk"
|
||||
|
44
userland/sbin/poweroff/poweroff.c
Normal file
44
userland/sbin/poweroff/poweroff.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||
* 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 <unistd.h>
|
||||
|
||||
/*
|
||||
* poweroff - shut down system and turn off power.
|
||||
* Usage: poweroff
|
||||
*
|
||||
* Just calls reboot() with the RB_POWEROFF flag.
|
||||
*/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
reboot(RB_POWEROFF);
|
||||
return 0;
|
||||
}
|
11
userland/sbin/reboot/Makefile
Normal file
11
userland/sbin/reboot/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
# Makefile for reboot
|
||||
|
||||
TOP=../../..
|
||||
.include "$(TOP)/mk/os161.config.mk"
|
||||
|
||||
PROG=reboot
|
||||
SRCS=reboot.c
|
||||
BINDIR=/sbin
|
||||
|
||||
.include "$(TOP)/mk/os161.prog.mk"
|
||||
|
44
userland/sbin/reboot/reboot.c
Normal file
44
userland/sbin/reboot/reboot.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||
* 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 <unistd.h>
|
||||
|
||||
/*
|
||||
* reboot - shut down system and reboot it.
|
||||
* Usage: reboot
|
||||
*
|
||||
* Just calls reboot() with the RB_REBOOT flag.
|
||||
*/
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
reboot(RB_REBOOT);
|
||||
return 0;
|
||||
}
|
18
userland/sbin/sfsck/Makefile
Normal file
18
userland/sbin/sfsck/Makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
# Makefile for sfsck
|
||||
|
||||
TOP=../../..
|
||||
.include "$(TOP)/mk/os161.config.mk"
|
||||
|
||||
PROG=sfsck
|
||||
SRCS=\
|
||||
main.c pass1.c pass2.c \
|
||||
inode.c freemap.c sb.c \
|
||||
sfs.c utils.c \
|
||||
../mksfs/disk.c ../mksfs/support.c
|
||||
CFLAGS+=-I../mksfs
|
||||
HOST_CFLAGS+=-I../mksfs
|
||||
BINDIR=/sbin
|
||||
HOSTBINDIR=/hostbin
|
||||
|
||||
.include "$(TOP)/mk/os161.prog.mk"
|
||||
.include "$(TOP)/mk/os161.hostprog.mk"
|
64
userland/sbin/sfsck/compat.h
Normal file
64
userland/sbin/sfsck/compat.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SFSCK_H
|
||||
#define SFSCK_H
|
||||
|
||||
/*
|
||||
* Compat definitions.
|
||||
*/
|
||||
|
||||
/* get uint32_t and friends */
|
||||
#include <stdint.h>
|
||||
|
||||
/* get the additional compat stuff shared with mksfs */
|
||||
#include "support.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)
|
||||
|
||||
#else
|
||||
|
||||
#define SWAP64(x) (x)
|
||||
#define SWAP32(x) (x)
|
||||
#define SWAP16(x) (x)
|
||||
#define NO_REALLOC
|
||||
|
||||
#endif /* HOST */
|
||||
|
||||
#endif /* SFSCK_H */
|
310
userland/sbin/sfsck/freemap.c
Normal file
310
userland/sbin/sfsck/freemap.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013, 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> /* for CHAR_BIT */
|
||||
#include <limits.h> /* also for CHAR_BIT */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include <kern/sfs.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "sfs.h"
|
||||
#include "sb.h"
|
||||
#include "freemap.h"
|
||||
#include "main.h"
|
||||
|
||||
static unsigned long blocksinuse = 0;
|
||||
static uint8_t *freemapdata;
|
||||
static uint8_t *tofreedata;
|
||||
|
||||
/*
|
||||
* Allocate space to keep track of the free block bitmap. This is
|
||||
* called after the superblock is loaded so we can ask how big the
|
||||
* volume is.
|
||||
*/
|
||||
void
|
||||
freemap_setup(void)
|
||||
{
|
||||
size_t i, mapbytes;
|
||||
uint32_t fsblocks, mapblocks;
|
||||
|
||||
fsblocks = sb_totalblocks();
|
||||
mapblocks = sb_freemapblocks();
|
||||
mapbytes = mapblocks * SFS_BLOCKSIZE;
|
||||
|
||||
freemapdata = domalloc(mapbytes * sizeof(uint8_t));
|
||||
tofreedata = domalloc(mapbytes * sizeof(uint8_t));
|
||||
for (i=0; i<mapbytes; i++) {
|
||||
freemapdata[i] = tofreedata[i] = 0;
|
||||
}
|
||||
|
||||
/* Mark off what's in the freemap but past the volume end. */
|
||||
for (i=fsblocks; i < mapblocks*SFS_BITSPERBLOCK; i++) {
|
||||
freemap_blockinuse(i, B_PASTEND, 0);
|
||||
}
|
||||
|
||||
/* Mark the superblock block and the freemap blocks in use */
|
||||
freemap_blockinuse(SFS_SUPER_BLOCK, B_SUPERBLOCK, 0);
|
||||
for (i=0; i < mapblocks; i++) {
|
||||
freemap_blockinuse(SFS_FREEMAP_START+i, B_FREEMAPBLOCK, i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a string for a blockusage; used for printing errors.
|
||||
*/
|
||||
static
|
||||
const char *
|
||||
blockusagestr(blockusage_t how, uint32_t howdesc)
|
||||
{
|
||||
static char rv[256];
|
||||
switch (how) {
|
||||
case B_SUPERBLOCK:
|
||||
return "superblock";
|
||||
case B_FREEMAPBLOCK:
|
||||
snprintf(rv, sizeof(rv), "freemap block %lu",
|
||||
(unsigned long) howdesc);
|
||||
break;
|
||||
case B_INODE:
|
||||
snprintf(rv, sizeof(rv), "inode %lu",
|
||||
(unsigned long) howdesc);
|
||||
break;
|
||||
case B_IBLOCK:
|
||||
snprintf(rv, sizeof(rv), "indirect block of inode %lu",
|
||||
(unsigned long) howdesc);
|
||||
break;
|
||||
case B_DIRDATA:
|
||||
snprintf(rv, sizeof(rv), "directory data from inode %lu",
|
||||
(unsigned long) howdesc);
|
||||
break;
|
||||
case B_DATA:
|
||||
snprintf(rv, sizeof(rv), "file data from inode %lu",
|
||||
(unsigned long) howdesc);
|
||||
break;
|
||||
case B_PASTEND:
|
||||
return "past the end of the fs";
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark block BLOCK in use. HOW and HOWDESC describe how it was found
|
||||
* to be in use, so we can print a useful message if it's wrong.
|
||||
*
|
||||
* FUTURE: this should not produce unrecoverable errors.
|
||||
*/
|
||||
void
|
||||
freemap_blockinuse(uint32_t block, blockusage_t how, uint32_t howdesc)
|
||||
{
|
||||
unsigned index = block/8;
|
||||
uint8_t mask = ((uint8_t)1)<<(block%8);
|
||||
|
||||
if (tofreedata[index] & mask) {
|
||||
/* really using the block, don't free it */
|
||||
tofreedata[index] &= ~mask;
|
||||
}
|
||||
|
||||
if (freemapdata[index] & mask) {
|
||||
warnx("Block %lu (used as %s) already in use! (NOT FIXED)",
|
||||
(unsigned long) block, blockusagestr(how, howdesc));
|
||||
setbadness(EXIT_UNRECOV);
|
||||
}
|
||||
|
||||
freemapdata[index] |= mask;
|
||||
|
||||
if (how != B_PASTEND) {
|
||||
blocksinuse++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark a block free. This is specifically for blocks that we are
|
||||
* freeing, that might be marked allocated in the on-disk freemap. If
|
||||
* the block has been found in use, assume the reference that's in use
|
||||
* is valid. This can be caused by freeing a block, reallocating it
|
||||
* somewhere else and then dying without erasing all of the original
|
||||
* usage on disk; most such cases will just show the block in use
|
||||
* twice, which is (not) handled above, but it's possible for the
|
||||
* original usage to be something we are dropping, e.g. if a truncate
|
||||
* (to a nonzero length > INOMAX_D) got partially completed.
|
||||
*/
|
||||
void
|
||||
freemap_blockfree(uint32_t block)
|
||||
{
|
||||
unsigned index = block/8;
|
||||
uint8_t mask = ((uint8_t)1)<<(block%8);
|
||||
|
||||
if (tofreedata[index] & mask) {
|
||||
/* already marked to free once, ignore */
|
||||
return;
|
||||
}
|
||||
if (freemapdata[index] & mask) {
|
||||
/* block is used elsewhere, ignore */
|
||||
return;
|
||||
}
|
||||
tofreedata[index] |= mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the number of bits set.
|
||||
*/
|
||||
static
|
||||
int
|
||||
countbits(uint8_t val)
|
||||
{
|
||||
uint8_t x;
|
||||
int ct=0;
|
||||
|
||||
for (x=1; x; x<<=1) {
|
||||
if (val & x) ct++;
|
||||
}
|
||||
return ct;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a complaint about freemap bits being wrong.
|
||||
*
|
||||
* FREEMAPBLOCK is the block number within the freemap; BYTE is the
|
||||
* byte offset within that block; VAL is the byte value; WHAT is a
|
||||
* string indicating what happened.
|
||||
*/
|
||||
static
|
||||
void
|
||||
reportfreemap(uint32_t mapblock, uint32_t byte, uint8_t val, const char *what)
|
||||
{
|
||||
uint8_t x, y;
|
||||
uint32_t blocknum;
|
||||
|
||||
for (x=1, y=0; x; x<<=1, y++) {
|
||||
if (val & x) {
|
||||
blocknum = mapblock*SFS_BITSPERBLOCK +
|
||||
byte*CHAR_BIT + y;
|
||||
warnx("Block %lu erroneously shown %s in freemap",
|
||||
(unsigned long) blocknum, what);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan the freemap.
|
||||
*
|
||||
* This is called after (at the end of) pass 1, when we've recursively
|
||||
* found all the reachable blocks and marked them.
|
||||
*/
|
||||
void
|
||||
freemap_check(void)
|
||||
{
|
||||
uint8_t actual[SFS_BLOCKSIZE], *expected, *tofree, tmp;
|
||||
uint32_t alloccount=0, freecount=0, i, j;
|
||||
int bchanged;
|
||||
uint32_t bitblocks;
|
||||
|
||||
bitblocks = sb_freemapblocks();
|
||||
|
||||
for (i=0; i<bitblocks; i++) {
|
||||
sfs_readfreemapblock(i, actual);
|
||||
expected = freemapdata + i*SFS_BLOCKSIZE;
|
||||
tofree = tofreedata + i*SFS_BLOCKSIZE;
|
||||
bchanged = 0;
|
||||
|
||||
for (j=0; j<SFS_BLOCKSIZE; j++) {
|
||||
/* we shouldn't have blocks marked both ways */
|
||||
assert((expected[j] & tofree[j])==0);
|
||||
|
||||
/* what's there is what should be there */
|
||||
if (actual[j] == expected[j]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* what's there is what should be there modulo frees */
|
||||
if (actual[j] == (expected[j] | tofree[j])) {
|
||||
actual[j] = expected[j];
|
||||
bchanged = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* oops, it doesn't match... */
|
||||
|
||||
/* free the ones we're freeing (don't report these) */
|
||||
actual[j] &= ~tofree[j];
|
||||
|
||||
/* are we short any? */
|
||||
if ((actual[j] & expected[j]) != expected[j]) {
|
||||
tmp = expected[j] & ~actual[j];
|
||||
alloccount += countbits(tmp);
|
||||
if (tmp != 0) {
|
||||
reportfreemap(i, j, tmp, "free");
|
||||
}
|
||||
}
|
||||
|
||||
/* do we have any extra? */
|
||||
if ((actual[j] & expected[j]) != actual[j]) {
|
||||
tmp = actual[j] & ~expected[j];
|
||||
freecount += countbits(tmp);
|
||||
if (tmp != 0) {
|
||||
reportfreemap(i, j, tmp, "allocated");
|
||||
}
|
||||
}
|
||||
|
||||
/* set it to what it should be */
|
||||
actual[j] = expected[j];
|
||||
bchanged = 1;
|
||||
}
|
||||
|
||||
/* write the block back if necessary */
|
||||
if (bchanged) {
|
||||
sfs_writefreemapblock(i, actual);
|
||||
}
|
||||
}
|
||||
|
||||
if (alloccount > 0) {
|
||||
warnx("%lu blocks erroneously shown free in freemap (fixed)",
|
||||
(unsigned long) alloccount);
|
||||
setbadness(EXIT_RECOV);
|
||||
}
|
||||
if (freecount > 0) {
|
||||
warnx("%lu blocks erroneously shown used in freemap (fixed)",
|
||||
(unsigned long) freecount);
|
||||
setbadness(EXIT_RECOV);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the total number of blocks in use, which we count during
|
||||
* pass 1.
|
||||
*/
|
||||
unsigned long
|
||||
freemap_blocksused(void)
|
||||
{
|
||||
return blocksinuse;
|
||||
}
|
67
userland/sbin/sfsck/freemap.h
Normal file
67
userland/sbin/sfsck/freemap.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREEMAP_H
|
||||
#define FREEMAP_H
|
||||
|
||||
/*
|
||||
* The freemap module accumulates information about the free block
|
||||
* bitmap as other checks are made, and then uses that information
|
||||
* to check and correct it.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
B_SUPERBLOCK, /* Block that is the superblock */
|
||||
B_FREEMAPBLOCK, /* Block used by free-block bitmap */
|
||||
B_INODE, /* Block that is an inode */
|
||||
B_IBLOCK, /* Indirect (or doubly-indirect etc.) block */
|
||||
B_DIRDATA, /* Data block of a directory */
|
||||
B_DATA, /* Data block */
|
||||
B_PASTEND, /* Block off the end of the fs */
|
||||
} blockusage_t;
|
||||
|
||||
/* Call this after loading the superblock but before doing any checks. */
|
||||
void freemap_setup(void);
|
||||
|
||||
/* Call this to note that a block has been found in use. */
|
||||
void freemap_blockinuse(uint32_t block, blockusage_t how, uint32_t howdesc);
|
||||
|
||||
/* Note that a block has been found where it should be dropped. */
|
||||
void freemap_blockfree(uint32_t block);
|
||||
|
||||
/* Call this after all checks that call freemap_block{inuse,free}. */
|
||||
void freemap_check(void);
|
||||
|
||||
/* Return the number of blocks in use. Valid after freemap_check(). */
|
||||
unsigned long freemap_blocksused(void);
|
||||
|
||||
|
||||
#endif /* FREEMAP_H */
|
159
userland/sbin/sfsck/ibmacros.h
Normal file
159
userland/sbin/sfsck/ibmacros.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IBMACROS_H
|
||||
#define IBMACROS_H
|
||||
|
||||
/*
|
||||
* Indirect block access macros
|
||||
*
|
||||
* These are macros for working with the direct and indirect block
|
||||
* pointers in the inode. The scheme here supports a range of possible
|
||||
* configurations, because sometimes adding large file support to SFS
|
||||
* is part of an assignment; there is and should be no obligation to
|
||||
* pick any particular layout, and we'd like sfsck to build and run
|
||||
* seamlessly provided that the values declared in kern/sfs.h are
|
||||
* correct.
|
||||
*
|
||||
* SFS_NDIRECT, SFS_NINDIRECT, SFS_NDINDIRECT, and SFS_NTINDIRECT
|
||||
* should always be defined. If zero, no corresponding field is
|
||||
* assumed to exist in the inode. If one, the field is assumed to
|
||||
* be a single value and not an array. If greater than one, the
|
||||
* field is assumed to be an array.
|
||||
*/
|
||||
|
||||
#ifndef SFS_NDIRECT
|
||||
#error "SFS_NDIRECT not defined"
|
||||
#endif
|
||||
#ifndef SFS_NINDIRECT
|
||||
#error "SFS_NINDIRECT not defined"
|
||||
#endif
|
||||
#ifndef SFS_NDINDIRECT
|
||||
#error "SFS_NDINDIRECT not defined"
|
||||
#endif
|
||||
#ifndef SFS_NTINDIRECT
|
||||
#error "SFS_NTINDIRECT not defined"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For x in D, I, II, III (direct, indirect, 2x/3x indirect) we
|
||||
* provide:
|
||||
*
|
||||
* NUM_x the number of blocks of this type
|
||||
* GET_x retrieve the i'th block of this type
|
||||
* SET_x lvalue for the i'th block of this type
|
||||
* RANGE_x size of the block range mapped with one block of this type
|
||||
* INOMAX_x maximum block number mapped by using this type in the inode
|
||||
*
|
||||
* It is important that the accessor macros (SET_x/GET_x) not refer to
|
||||
* a nonexistent field of the inode in the case where there are zero
|
||||
* blocks of that type, as that will lead to compile failure. Hence the
|
||||
* lengthy definitions. So far I haven't thought any useful cpp hackery
|
||||
* to make them more concise.
|
||||
*/
|
||||
|
||||
/* numbers */
|
||||
|
||||
#define NUM_D SFS_NDIRECT
|
||||
#define NUM_I SFS_NINDIRECT
|
||||
#define NUM_II SFS_NDINDIRECT
|
||||
#define NUM_III SFS_NTINDIRECT
|
||||
|
||||
/* blocks */
|
||||
|
||||
#if NUM_D == 0
|
||||
#define GET_D(sfi, i) GET0_x(sfi, sfi_direct, i)
|
||||
#define SET_D(sfi, i) SET0_x(sfi, sfi_direct, i)
|
||||
#elif NUM_D == 1
|
||||
#define GET_D(sfi, i) GET1_x(sfi, sfi_direct, i)
|
||||
#define SET_D(sfi, i) SET1_x(sfi, sfi_direct, i)
|
||||
#else
|
||||
#define GET_D(sfi, i) GETN_x(sfi, sfi_direct, i)
|
||||
#define SET_D(sfi, i) SETN_x(sfi, sfi_direct, i)
|
||||
#endif
|
||||
|
||||
#if NUM_I == 0
|
||||
#define GET_I(sfi, i) GET0_x(sfi, sfi_indirect, i)
|
||||
#define SET_I(sfi, i) SET0_x(sfi, sfi_indirect, i)
|
||||
#elif NUM_I == 1
|
||||
#define GET_I(sfi, i) GET1_x(sfi, sfi_indirect, i)
|
||||
#define SET_I(sfi, i) SET1_x(sfi, sfi_indirect, i)
|
||||
#else
|
||||
#define GET_I(sfi, i) GETN_x(sfi, sfi_indirect, i)
|
||||
#define SET_I(sfi, i) SETN_x(sfi, sfi_indirect, i)
|
||||
#endif
|
||||
|
||||
#if NUM_II == 0
|
||||
#define GET_II(sfi, i) GET0_x(sfi, sfi_dindirect, i)
|
||||
#define SET_II(sfi, i) SET0_x(sfi, sfi_dindirect, i)
|
||||
#elif NUM_II == 1
|
||||
#define GET_II(sfi, i) GET1_x(sfi, sfi_dindirect, i)
|
||||
#define SET_II(sfi, i) SET1_x(sfi, sfi_dindirect, i)
|
||||
#else
|
||||
#define GET_II(sfi, i) GETN_x(sfi, sfi_dindirect, i)
|
||||
#define SET_II(sfi, i) SETN_x(sfi, sfi_dindirect, i)
|
||||
#endif
|
||||
|
||||
#if NUM_III == 0
|
||||
#define GET_III(sfi, i) GET0_x(sfi, sfi_tindirect, i)
|
||||
#define SET_III(sfi, i) SET0_x(sfi, sfi_tindirect, i)
|
||||
#elif NUM_III == 1
|
||||
#define GET_III(sfi, i) GET1_x(sfi, sfi_tindirect, i)
|
||||
#define SET_III(sfi, i) SET1_x(sfi, sfi_tindirect, i)
|
||||
#else
|
||||
#define GET_III(sfi, i) GETN_x(sfi, sfi_tindirect, i)
|
||||
#define SET_III(sfi, i) SETN_x(sfi, sfi_tindirect, i)
|
||||
#endif
|
||||
|
||||
/* the generic forms of the block macros */
|
||||
|
||||
#define GET0_x(sfi, field, i) ((void)(i), (void)(sfi), 0)
|
||||
#define GET1_x(sfi, field, i) ((void)(i), (sfi)->field)
|
||||
#define GETN_x(sfi, field, i) ((sfi)->field[(i)])
|
||||
|
||||
#define SET0_x(sfi, field, i) (*((void)(i), (void)(sfi), (uint32_t *)NULL))
|
||||
#define SET1_x(sfi, field, i) (*((void)(i), &(sfi)->field))
|
||||
#define SETN_x(sfi, field, i) ((sfi)->field[(i)])
|
||||
|
||||
/* region sizes */
|
||||
|
||||
#define RANGE_D 1
|
||||
#define RANGE_I (RANGE_D * SFS_DBPERIDB)
|
||||
#define RANGE_II (RANGE_I * SFS_DBPERIDB)
|
||||
#define RANGE_III (RANGE_II * SFS_DBPERIDB)
|
||||
|
||||
/* max blocks */
|
||||
|
||||
#define INOMAX_D NUM_D
|
||||
#define INOMAX_I (INOMAX_D + SFS_DBPERIDB * NUM_I)
|
||||
#define INOMAX_II (INOMAX_I + SFS_DBPERIDB * NUM_II)
|
||||
#define INOMAX_III (INOMAX_II + SFS_DBPERIDB * NUM_III)
|
||||
|
||||
|
||||
#endif /* IBMACROS_H */
|
266
userland/sbin/sfsck/inode.c
Normal file
266
userland/sbin/sfsck/inode.c
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include <kern/sfs.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "sfs.h"
|
||||
#include "freemap.h"
|
||||
#include "inode.h"
|
||||
#include "main.h"
|
||||
|
||||
/*
|
||||
* Stuff we remember about inodes.
|
||||
* FUTURE: should count the number of blocks allocated to this inode
|
||||
*/
|
||||
struct inodeinfo {
|
||||
uint32_t ino;
|
||||
uint32_t linkcount; /* files only */
|
||||
int visited; /* dirs only */
|
||||
int type;
|
||||
};
|
||||
|
||||
/* Table of inodes found. */
|
||||
static struct inodeinfo *inodes = NULL;
|
||||
static unsigned ninodes = 0, maxinodes = 0;
|
||||
|
||||
/* Whether the table is sorted and can be looked up with binary search. */
|
||||
static int inodes_sorted = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// inode table ops
|
||||
|
||||
/*
|
||||
* Add an entry to the inode table, realloc'ing it if needed.
|
||||
*/
|
||||
static
|
||||
void
|
||||
inode_addtable(uint32_t ino, int type)
|
||||
{
|
||||
unsigned newmax;
|
||||
|
||||
assert(ninodes <= maxinodes);
|
||||
if (ninodes == maxinodes) {
|
||||
newmax = maxinodes ? maxinodes * 2 : 4;
|
||||
inodes = dorealloc(inodes, maxinodes * sizeof(inodes[0]),
|
||||
newmax * sizeof(inodes[0]));
|
||||
maxinodes = newmax;
|
||||
}
|
||||
inodes[ninodes].ino = ino;
|
||||
inodes[ninodes].linkcount = 0;
|
||||
inodes[ninodes].visited = 0;
|
||||
inodes[ninodes].type = type;
|
||||
ninodes++;
|
||||
inodes_sorted = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare function for inodes.
|
||||
*/
|
||||
static
|
||||
int
|
||||
inode_compare(const void *av, const void *bv)
|
||||
{
|
||||
const struct inodeinfo *a = av;
|
||||
const struct inodeinfo *b = bv;
|
||||
|
||||
if (a->ino < b->ino) {
|
||||
return -1;
|
||||
}
|
||||
if (a->ino > b->ino) {
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* There should be no duplicates in the table! But C99 makes
|
||||
* no guarantees about whether the implementation of qsort can
|
||||
* ask us to compare an element to itself. Assert that this is
|
||||
* what happened.
|
||||
*/
|
||||
assert(av == bv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* After pass1, we sort the inode table for faster access.
|
||||
*/
|
||||
void
|
||||
inode_sorttable(void)
|
||||
{
|
||||
qsort(inodes, ninodes, sizeof(inodes[0]), inode_compare);
|
||||
inodes_sorted = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an inode by binary search.
|
||||
*
|
||||
* This will error out if asked for an inode not in the table; that's
|
||||
* not supposed to happen. (This might need to change; if we improve
|
||||
* the handling of crosslinked directories as suggested in comments in
|
||||
* pass2.c, we'll need to be able to ask if an inode number is valid
|
||||
* and names a directory.)
|
||||
*/
|
||||
static
|
||||
struct inodeinfo *
|
||||
inode_find(uint32_t ino)
|
||||
{
|
||||
unsigned min, max, i;
|
||||
|
||||
assert(inodes_sorted);
|
||||
assert(ninodes > 0);
|
||||
|
||||
min = 0;
|
||||
max = ninodes;
|
||||
while (1) {
|
||||
assert(min <= max);
|
||||
if (min == max) {
|
||||
errx(EXIT_UNRECOV, "FATAL: inode %u wasn't found in my inode table", ino);
|
||||
}
|
||||
i = min + (max - min)/2;
|
||||
if (inodes[i].ino < ino) {
|
||||
min = i + 1;
|
||||
}
|
||||
else if (inodes[i].ino > ino) {
|
||||
max = i;
|
||||
}
|
||||
else {
|
||||
assert(inodes[i].ino == ino);
|
||||
return &inodes[i];
|
||||
}
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// inode ops
|
||||
|
||||
/*
|
||||
* Add an inode; returns 1 if we've already seen it.
|
||||
*
|
||||
* Uses linear search because we only sort the table for faster access
|
||||
* after all inodes have been added. In the FUTURE this could be
|
||||
* changed to a better data structure.
|
||||
*/
|
||||
int
|
||||
inode_add(uint32_t ino, int type)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<ninodes; i++) {
|
||||
if (inodes[i].ino==ino) {
|
||||
assert(inodes[i].linkcount == 0);
|
||||
assert(inodes[i].type == type);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
inode_addtable(ino, type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark an inode (directories only, because that's all the caller
|
||||
* does) visited. Returns nonzero if already visited.
|
||||
*
|
||||
* Note that there is no way to clear the visited flag for now because
|
||||
* it's only used once (by pass2).
|
||||
*/
|
||||
int
|
||||
inode_visitdir(uint32_t ino)
|
||||
{
|
||||
struct inodeinfo *inf;
|
||||
|
||||
inf = inode_find(ino);
|
||||
assert(inf->type == SFS_TYPE_DIR);
|
||||
assert(inf->linkcount == 0);
|
||||
if (inf->visited) {
|
||||
return 1;
|
||||
}
|
||||
inf->visited = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count a link. Only for regular files because that's what the caller
|
||||
* does. (And that, in turn, is because the link count of a directory
|
||||
* is a local property.)
|
||||
*/
|
||||
void
|
||||
inode_addlink(uint32_t ino)
|
||||
{
|
||||
struct inodeinfo *inf;
|
||||
|
||||
inf = inode_find(ino);
|
||||
assert(inf->type == SFS_TYPE_FILE);
|
||||
assert(inf->visited == 0);
|
||||
inf->linkcount++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Correct link counts. This is effectively pass3. (FUTURE: change the
|
||||
* name accordingly.)
|
||||
*/
|
||||
void
|
||||
inode_adjust_filelinks(void)
|
||||
{
|
||||
struct sfs_dinode sfi;
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<ninodes; i++) {
|
||||
if (inodes[i].type == SFS_TYPE_DIR) {
|
||||
/* directory */
|
||||
continue;
|
||||
}
|
||||
assert(inodes[i].type == SFS_TYPE_FILE);
|
||||
|
||||
/* because we've seen it, there must be at least one link */
|
||||
assert(inodes[i].linkcount > 0);
|
||||
|
||||
sfs_readinode(inodes[i].ino, &sfi);
|
||||
assert(sfi.sfi_type == SFS_TYPE_FILE);
|
||||
|
||||
if (sfi.sfi_linkcount != inodes[i].linkcount) {
|
||||
warnx("File %lu link count %lu should be %lu (fixed)",
|
||||
(unsigned long) inodes[i].ino,
|
||||
(unsigned long) sfi.sfi_linkcount,
|
||||
(unsigned long) inodes[i].linkcount);
|
||||
sfi.sfi_linkcount = inodes[i].linkcount;
|
||||
setbadness(EXIT_RECOV);
|
||||
sfs_writeinode(inodes[i].ino, &sfi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
65
userland/sbin/sfsck/inode.h
Normal file
65
userland/sbin/sfsck/inode.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef INODE_H
|
||||
#define INODE_H
|
||||
|
||||
/*
|
||||
* The inode module accumulates non-local information about files and
|
||||
* directories as other checks are made, and then updates inodes
|
||||
* accordingly after the other checks are done.
|
||||
*/
|
||||
|
||||
/* Add an inode. Returns 1 if we've seen this inode before. */
|
||||
int inode_add(uint32_t ino, int type);
|
||||
|
||||
/* Sort the inode table for faster lookup once all inode_add() done. */
|
||||
void inode_sorttable(void);
|
||||
|
||||
/*
|
||||
* Remember that we've seen a particular directory. Returns nonzero if
|
||||
* we've seen this directory before, which means the directory is
|
||||
* crosslinked. Requires inode_sorttable() first.
|
||||
*/
|
||||
int inode_visitdir(uint32_t ino);
|
||||
|
||||
/*
|
||||
* Count a link to a regular file. (Not called for directories.)
|
||||
* Requires inode_sorttable() first.
|
||||
*/
|
||||
void inode_addlink(uint32_t ino);
|
||||
|
||||
/*
|
||||
* Correct the link counts of regular files, once all inode_addlink()
|
||||
* done.
|
||||
*/
|
||||
void inode_adjust_filelinks(void);
|
||||
|
||||
|
||||
#endif /* INODE_H */
|
118
userland/sbin/sfsck/main.c
Normal file
118
userland/sbin/sfsck/main.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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 <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include "disk.h"
|
||||
#include "sfs.h"
|
||||
#include "sb.h"
|
||||
#include "freemap.h"
|
||||
#include "inode.h"
|
||||
#include "passes.h"
|
||||
#include "main.h"
|
||||
|
||||
static int badness=0;
|
||||
|
||||
/*
|
||||
* Update the badness state. (codes are in main.h)
|
||||
*
|
||||
* The badness state only gets worse, and is ultimately the process
|
||||
* exit code.
|
||||
*/
|
||||
void
|
||||
setbadness(int code)
|
||||
{
|
||||
if (badness < code) {
|
||||
badness = code;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Main.
|
||||
*/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
#ifdef HOST
|
||||
hostcompat_init(argc, argv);
|
||||
#endif
|
||||
|
||||
/* FUTURE: add -n option */
|
||||
if (argc!=2) {
|
||||
errx(EXIT_USAGE, "Usage: sfsck device/diskfile");
|
||||
}
|
||||
|
||||
opendisk(argv[1]);
|
||||
|
||||
sfs_setup();
|
||||
sb_load();
|
||||
sb_check();
|
||||
freemap_setup();
|
||||
|
||||
printf("Phase 1 -- check blocks and sizes\n");
|
||||
pass1();
|
||||
freemap_check();
|
||||
|
||||
printf("Phase 2 -- check directory tree\n");
|
||||
inode_sorttable();
|
||||
pass2();
|
||||
|
||||
printf("Phase 3 -- check reference counts\n");
|
||||
inode_adjust_filelinks();
|
||||
|
||||
closedisk();
|
||||
|
||||
warnx("%lu blocks used (of %lu); %lu directories; %lu files",
|
||||
freemap_blocksused(), (unsigned long)sb_totalblocks(),
|
||||
pass1_founddirs(), pass1_foundfiles());
|
||||
|
||||
switch (badness) {
|
||||
case EXIT_USAGE:
|
||||
case EXIT_FATAL:
|
||||
default:
|
||||
/* not supposed to happen here */
|
||||
assert(0);
|
||||
break;
|
||||
case EXIT_UNRECOV:
|
||||
warnx("WARNING - unrecoverable errors. Maybe try again?");
|
||||
break;
|
||||
case EXIT_RECOV:
|
||||
warnx("Caution - filesystem modified. Run again for luck.");
|
||||
break;
|
||||
case EXIT_CLEAN:
|
||||
break;
|
||||
}
|
||||
|
||||
return badness;
|
||||
}
|
48
userland/sbin/sfsck/main.h
Normal file
48
userland/sbin/sfsck/main.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
/*
|
||||
* Levels of problems that we can encounter.
|
||||
*
|
||||
* setbadness() records the maximum level seen so far; this is
|
||||
* the ultimate exit code of sfsck.
|
||||
*/
|
||||
|
||||
#define EXIT_USAGE 4
|
||||
#define EXIT_FATAL 3
|
||||
#define EXIT_UNRECOV 2
|
||||
#define EXIT_RECOV 1
|
||||
#define EXIT_CLEAN 0
|
||||
|
||||
void setbadness(int code);
|
||||
|
||||
#endif /* MAIN_H */
|
496
userland/sbin/sfsck/pass1.c
Normal file
496
userland/sbin/sfsck/pass1.c
Normal file
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include <kern/sfs.h>
|
||||
|
||||
#include "disk.h"
|
||||
#include "utils.h"
|
||||
#include "ibmacros.h"
|
||||
#include "sfs.h"
|
||||
#include "sb.h"
|
||||
#include "freemap.h"
|
||||
#include "inode.h"
|
||||
#include "passes.h"
|
||||
#include "main.h"
|
||||
|
||||
static unsigned long count_dirs=0, count_files=0;
|
||||
|
||||
/*
|
||||
* State for checking indirect blocks.
|
||||
*/
|
||||
struct ibstate {
|
||||
uint32_t ino; /* inode we're doing (constant) */
|
||||
uint32_t curfileblock; /* current block offset in the file */
|
||||
uint32_t fileblocks; /* file size in blocks (constant) */
|
||||
uint32_t volblocks; /* volume size in blocks (constant) */
|
||||
unsigned pasteofcount; /* number of blocks found past eof */
|
||||
blockusage_t usagetype; /* how to call freemap_blockinuse() */
|
||||
};
|
||||
|
||||
/*
|
||||
* Traverse an indirect block, recording blocks that are in use,
|
||||
* dropping any entries that are past EOF, and clearing any entries
|
||||
* that point outside the volume.
|
||||
*
|
||||
* XXX: this should be extended to be able to recover from crosslinked
|
||||
* blocks. Currently it just complains in freemap.c and sets
|
||||
* EXIT_UNRECOV.
|
||||
*
|
||||
* The traversal is recursive; the state is maintained in IBS (as
|
||||
* described above). IENTRY is a pointer to the entry in the parent
|
||||
* indirect block (or the inode) that names the block we're currently
|
||||
* scanning. IECHANGEDP should be set to 1 if *IENTRY is changed.
|
||||
* INDIRECTION is the indirection level of this block (1, 2, or 3).
|
||||
*/
|
||||
static
|
||||
void
|
||||
check_indirect_block(struct ibstate *ibs, uint32_t *ientry, int *iechangedp,
|
||||
int indirection)
|
||||
{
|
||||
uint32_t entries[SFS_DBPERIDB];
|
||||
uint32_t i, ct;
|
||||
uint32_t coveredblocks;
|
||||
int localchanged = 0;
|
||||
int j;
|
||||
|
||||
if (*ientry > 0 && *ientry < ibs->volblocks) {
|
||||
sfs_readindirect(*ientry, entries);
|
||||
freemap_blockinuse(*ientry, B_IBLOCK, ibs->ino);
|
||||
}
|
||||
else {
|
||||
if (*ientry >= ibs->volblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Inode %lu: indirect block pointer (level %d) "
|
||||
"for block %lu outside of volume: %lu "
|
||||
"(cleared)\n",
|
||||
(unsigned long)ibs->ino, indirection,
|
||||
(unsigned long)ibs->curfileblock,
|
||||
(unsigned long)*ientry);
|
||||
*ientry = 0;
|
||||
*iechangedp = 1;
|
||||
}
|
||||
coveredblocks = 1;
|
||||
for (j=0; j<indirection; j++) {
|
||||
coveredblocks *= SFS_DBPERIDB;
|
||||
}
|
||||
ibs->curfileblock += coveredblocks;
|
||||
return;
|
||||
}
|
||||
|
||||
if (indirection > 1) {
|
||||
for (i=0; i<SFS_DBPERIDB; i++) {
|
||||
check_indirect_block(ibs, &entries[i], &localchanged,
|
||||
indirection-1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(indirection==1);
|
||||
|
||||
for (i=0; i<SFS_DBPERIDB; i++) {
|
||||
if (entries[i] >= ibs->volblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Inode %lu: direct block pointer for "
|
||||
"block %lu outside of volume: %lu "
|
||||
"(cleared)\n",
|
||||
(unsigned long)ibs->ino,
|
||||
(unsigned long)ibs->curfileblock,
|
||||
(unsigned long)entries[i]);
|
||||
entries[i] = 0;
|
||||
localchanged = 1;
|
||||
}
|
||||
else if (entries[i] != 0) {
|
||||
if (ibs->curfileblock < ibs->fileblocks) {
|
||||
freemap_blockinuse(entries[i],
|
||||
ibs->usagetype,
|
||||
ibs->ino);
|
||||
}
|
||||
else {
|
||||
setbadness(EXIT_RECOV);
|
||||
ibs->pasteofcount++;
|
||||
freemap_blockfree(entries[i]);
|
||||
entries[i] = 0;
|
||||
localchanged = 1;
|
||||
}
|
||||
}
|
||||
ibs->curfileblock++;
|
||||
}
|
||||
}
|
||||
|
||||
ct=0;
|
||||
for (i=ct=0; i<SFS_DBPERIDB; i++) {
|
||||
if (entries[i]!=0) ct++;
|
||||
}
|
||||
if (ct==0) {
|
||||
if (*ientry != 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
/* this is not necessarily correct */
|
||||
/*ibs->pasteofcount++;*/
|
||||
*iechangedp = 1;
|
||||
freemap_blockfree(*ientry);
|
||||
*ientry = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(*ientry != 0);
|
||||
if (localchanged) {
|
||||
sfs_writeindirect(*ientry, entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the blocks belonging to inode INO, whose inode has already
|
||||
* been loaded into SFI. ISDIR is a shortcut telling us if the inode
|
||||
* is a directory.
|
||||
*
|
||||
* Returns nonzero if SFI has been modified and needs to be written
|
||||
* back.
|
||||
*/
|
||||
static
|
||||
int
|
||||
check_inode_blocks(uint32_t ino, struct sfs_dinode *sfi, int isdir)
|
||||
{
|
||||
struct ibstate ibs;
|
||||
uint32_t size, datablock;
|
||||
int changed;
|
||||
int i;
|
||||
|
||||
size = SFS_ROUNDUP(sfi->sfi_size, SFS_BLOCKSIZE);
|
||||
|
||||
ibs.ino = ino;
|
||||
/*ibs.curfileblock = 0;*/
|
||||
ibs.fileblocks = size/SFS_BLOCKSIZE;
|
||||
ibs.volblocks = sb_totalblocks();
|
||||
ibs.pasteofcount = 0;
|
||||
ibs.usagetype = isdir ? B_DIRDATA : B_DATA;
|
||||
|
||||
changed = 0;
|
||||
|
||||
for (ibs.curfileblock=0; ibs.curfileblock<NUM_D; ibs.curfileblock++) {
|
||||
datablock = GET_D(sfi, ibs.curfileblock);
|
||||
if (datablock >= ibs.volblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Inode %lu: direct block pointer for "
|
||||
"block %lu outside of volume: %lu "
|
||||
"(cleared)\n",
|
||||
(unsigned long)ibs.ino,
|
||||
(unsigned long)ibs.curfileblock,
|
||||
(unsigned long)datablock);
|
||||
SET_D(sfi, ibs.curfileblock) = 0;
|
||||
changed = 1;
|
||||
}
|
||||
else if (datablock > 0) {
|
||||
if (ibs.curfileblock < ibs.fileblocks) {
|
||||
freemap_blockinuse(datablock, ibs.usagetype,
|
||||
ibs.ino);
|
||||
}
|
||||
else {
|
||||
setbadness(EXIT_RECOV);
|
||||
ibs.pasteofcount++;
|
||||
changed = 1;
|
||||
freemap_blockfree(datablock);
|
||||
SET_D(sfi, ibs.curfileblock) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<NUM_I; i++) {
|
||||
check_indirect_block(&ibs, &SET_I(sfi, i), &changed, 1);
|
||||
}
|
||||
for (i=0; i<NUM_II; i++) {
|
||||
check_indirect_block(&ibs, &SET_II(sfi, i), &changed, 2);
|
||||
}
|
||||
for (i=0; i<NUM_III; i++) {
|
||||
check_indirect_block(&ibs, &SET_III(sfi, i), &changed, 3);
|
||||
}
|
||||
|
||||
if (ibs.pasteofcount > 0) {
|
||||
warnx("Inode %lu: %u blocks after EOF (freed)",
|
||||
(unsigned long) ibs.ino, ibs.pasteofcount);
|
||||
setbadness(EXIT_RECOV);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the pass1 inode-level checks on inode INO, which has already
|
||||
* been loaded into SFI. Note that sfi_type has already been
|
||||
* validated.
|
||||
*
|
||||
* Returns nonzero if SFI has been modified and needs to be written
|
||||
* back.
|
||||
*/
|
||||
static
|
||||
int
|
||||
pass1_inode(uint32_t ino, struct sfs_dinode *sfi, int alreadychanged)
|
||||
{
|
||||
int changed = alreadychanged;
|
||||
int isdir = sfi->sfi_type == SFS_TYPE_DIR;
|
||||
|
||||
if (inode_add(ino, sfi->sfi_type)) {
|
||||
/* Already been here. */
|
||||
assert(changed == 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
freemap_blockinuse(ino, B_INODE, ino);
|
||||
|
||||
if (checkzeroed(sfi->sfi_waste, sizeof(sfi->sfi_waste))) {
|
||||
warnx("Inode %lu: sfi_waste section not zeroed (fixed)",
|
||||
(unsigned long) ino);
|
||||
setbadness(EXIT_RECOV);
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
if (check_inode_blocks(ino, sfi, isdir)) {
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
sfs_writeinode(ino, sfi);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the directory entry in SFD. INDEX is its offset, and PATH is
|
||||
* its name; these are used for printing messages.
|
||||
*/
|
||||
static
|
||||
int
|
||||
pass1_direntry(const char *path, uint32_t index, struct sfs_direntry *sfd)
|
||||
{
|
||||
int dchanged = 0;
|
||||
uint32_t nblocks;
|
||||
|
||||
nblocks = sb_totalblocks();
|
||||
|
||||
if (sfd->sfd_ino == SFS_NOINO) {
|
||||
if (sfd->sfd_name[0] != 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu has name but no file",
|
||||
path, (unsigned long) index);
|
||||
sfd->sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
}
|
||||
}
|
||||
else if (sfd->sfd_ino >= nblocks) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu has out of range "
|
||||
"inode (cleared)",
|
||||
path, (unsigned long) index);
|
||||
sfd->sfd_ino = SFS_NOINO;
|
||||
sfd->sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
}
|
||||
else {
|
||||
if (sfd->sfd_name[0] == 0) {
|
||||
/* XXX: what happens if FSCK.n.m already exists? */
|
||||
snprintf(sfd->sfd_name, sizeof(sfd->sfd_name),
|
||||
"FSCK.%lu.%lu",
|
||||
(unsigned long) sfd->sfd_ino,
|
||||
(unsigned long) uniqueid());
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu has file but "
|
||||
"no name (fixed: %s)",
|
||||
path, (unsigned long) index,
|
||||
sfd->sfd_name);
|
||||
dchanged = 1;
|
||||
}
|
||||
if (checknullstring(sfd->sfd_name, sizeof(sfd->sfd_name))) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu not "
|
||||
"null-terminated (fixed)",
|
||||
path, (unsigned long) index);
|
||||
dchanged = 1;
|
||||
}
|
||||
if (checkbadstring(sfd->sfd_name)) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s entry %lu contains invalid "
|
||||
"characters (fixed)",
|
||||
path, (unsigned long) index);
|
||||
dchanged = 1;
|
||||
}
|
||||
}
|
||||
return dchanged;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check a directory. INO is the inode number; PATHSOFAR is the path
|
||||
* to this directory. This traverses the volume directory tree
|
||||
* recursively.
|
||||
*/
|
||||
static
|
||||
void
|
||||
pass1_dir(uint32_t ino, const char *pathsofar)
|
||||
{
|
||||
struct sfs_dinode sfi;
|
||||
struct sfs_direntry *direntries;
|
||||
uint32_t ndirentries, i;
|
||||
int ichanged=0, dchanged=0;
|
||||
|
||||
sfs_readinode(ino, &sfi);
|
||||
|
||||
if (sfi.sfi_size % sizeof(struct sfs_direntry) != 0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s has illegal size %lu (fixed)",
|
||||
pathsofar, (unsigned long) sfi.sfi_size);
|
||||
sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size,
|
||||
sizeof(struct sfs_direntry));
|
||||
ichanged = 1;
|
||||
}
|
||||
count_dirs++;
|
||||
|
||||
if (pass1_inode(ino, &sfi, ichanged)) {
|
||||
/* been here before; crosslinked dir, sort it out in pass 2 */
|
||||
return;
|
||||
}
|
||||
|
||||
ndirentries = sfi.sfi_size/sizeof(struct sfs_direntry);
|
||||
direntries = domalloc(sfi.sfi_size);
|
||||
|
||||
sfs_readdir(&sfi, direntries, ndirentries);
|
||||
|
||||
for (i=0; i<ndirentries; i++) {
|
||||
if (pass1_direntry(pathsofar, i, &direntries[i])) {
|
||||
dchanged = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<ndirentries; i++) {
|
||||
if (direntries[i].sfd_ino == SFS_NOINO) {
|
||||
/* nothing */
|
||||
}
|
||||
else if (!strcmp(direntries[i].sfd_name, ".")) {
|
||||
/* nothing */
|
||||
}
|
||||
else if (!strcmp(direntries[i].sfd_name, "..")) {
|
||||
/* nothing */
|
||||
}
|
||||
else {
|
||||
char path[strlen(pathsofar)+SFS_NAMELEN+1];
|
||||
struct sfs_dinode subsfi;
|
||||
uint32_t subino;
|
||||
|
||||
subino = direntries[i].sfd_ino;
|
||||
sfs_readinode(subino, &subsfi);
|
||||
snprintf(path, sizeof(path), "%s/%s",
|
||||
pathsofar, direntries[i].sfd_name);
|
||||
|
||||
switch (subsfi.sfi_type) {
|
||||
case SFS_TYPE_FILE:
|
||||
if (pass1_inode(subino, &subsfi, 0)) {
|
||||
/* been here before */
|
||||
break;
|
||||
}
|
||||
count_files++;
|
||||
break;
|
||||
case SFS_TYPE_DIR:
|
||||
pass1_dir(subino, path);
|
||||
break;
|
||||
default:
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Object %s: Invalid inode type %u "
|
||||
"(removed)", path, subsfi.sfi_type);
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
direntries[i].sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dchanged) {
|
||||
sfs_writedir(&sfi, direntries, ndirentries);
|
||||
}
|
||||
|
||||
free(direntries);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the root directory, and implicitly everything under it.
|
||||
*/
|
||||
static
|
||||
void
|
||||
pass1_rootdir(void)
|
||||
{
|
||||
struct sfs_dinode sfi;
|
||||
char path[SFS_VOLNAME_SIZE + 2];
|
||||
|
||||
sfs_readinode(SFS_ROOTDIR_INO, &sfi);
|
||||
|
||||
switch (sfi.sfi_type) {
|
||||
case SFS_TYPE_DIR:
|
||||
break;
|
||||
case SFS_TYPE_FILE:
|
||||
warnx("Root directory inode is a regular file (fixed)");
|
||||
goto fix;
|
||||
default:
|
||||
warnx("Root directory inode has invalid type %lu (fixed)",
|
||||
(unsigned long) sfi.sfi_type);
|
||||
fix:
|
||||
setbadness(EXIT_RECOV);
|
||||
sfi.sfi_type = SFS_TYPE_DIR;
|
||||
sfs_writeinode(SFS_ROOTDIR_INO, &sfi);
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(path, sizeof(path), "%s:", sb_volname());
|
||||
pass1_dir(SFS_ROOTDIR_INO, path);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// public interface
|
||||
|
||||
void
|
||||
pass1(void)
|
||||
{
|
||||
pass1_rootdir();
|
||||
}
|
||||
|
||||
unsigned long
|
||||
pass1_founddirs(void)
|
||||
{
|
||||
return count_dirs;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
pass1_foundfiles(void)
|
||||
{
|
||||
return count_files;
|
||||
}
|
325
userland/sbin/sfsck/pass2.c
Normal file
325
userland/sbin/sfsck/pass2.c
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include <kern/sfs.h>
|
||||
|
||||
#include "disk.h"
|
||||
#include "utils.h"
|
||||
#include "ibmacros.h"
|
||||
#include "sfs.h"
|
||||
#include "sb.h"
|
||||
#include "freemap.h"
|
||||
#include "inode.h"
|
||||
#include "passes.h"
|
||||
#include "main.h"
|
||||
|
||||
/*
|
||||
* Process a directory. INO is the inode number; PARENTINO is the
|
||||
* parent's inode number; PATHSOFAR is the path to this directory.
|
||||
*
|
||||
* Recursively checks its subdirs.
|
||||
*
|
||||
* In the FUTURE we might want to improve the handling of crosslinked
|
||||
* directories so it picks the parent that the .. entry points to,
|
||||
* instead of the first entry we recursively find. Beware of course
|
||||
* that the .. entry might not point to anywhere valid at all...
|
||||
*/
|
||||
static
|
||||
int
|
||||
pass2_dir(uint32_t ino, uint32_t parentino, const char *pathsofar)
|
||||
{
|
||||
struct sfs_dinode sfi;
|
||||
struct sfs_direntry *direntries;
|
||||
int *sortvector;
|
||||
uint32_t dirsize, ndirentries, maxdirentries, subdircount, i;
|
||||
int ichanged=0, dchanged=0, dotseen=0, dotdotseen=0;
|
||||
|
||||
if (inode_visitdir(ino)) {
|
||||
/* crosslinked dir; tell parent to remove the entry */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Load the inode. */
|
||||
sfs_readinode(ino, &sfi);
|
||||
|
||||
/*
|
||||
* Load the directory. If there is any leftover room in the
|
||||
* last block, allocate space for it in case we want to insert
|
||||
* entries.
|
||||
*/
|
||||
|
||||
ndirentries = sfi.sfi_size/sizeof(struct sfs_direntry);
|
||||
maxdirentries = SFS_ROUNDUP(ndirentries,
|
||||
SFS_BLOCKSIZE/sizeof(struct sfs_direntry));
|
||||
dirsize = maxdirentries * sizeof(struct sfs_direntry);
|
||||
direntries = domalloc(dirsize);
|
||||
|
||||
sortvector = domalloc(ndirentries * sizeof(int));
|
||||
|
||||
sfs_readdir(&sfi, direntries, ndirentries);
|
||||
for (i=ndirentries; i<maxdirentries; i++) {
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
bzero(direntries[i].sfd_name, sizeof(direntries[i].sfd_name));
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort by name and check for duplicate names.
|
||||
*/
|
||||
|
||||
sfsdir_sort(direntries, ndirentries, sortvector);
|
||||
|
||||
/* don't use ndirentries-1 here, in case ndirentries == 0 */
|
||||
for (i=0; i+1<ndirentries; i++) {
|
||||
struct sfs_direntry *d1 = &direntries[sortvector[i]];
|
||||
struct sfs_direntry *d2 = &direntries[sortvector[i+1]];
|
||||
assert(d1 != d2);
|
||||
|
||||
if (d1->sfd_ino == SFS_NOINO || d2->sfd_ino == SFS_NOINO) {
|
||||
/* sfsdir_sort puts these last */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(d1->sfd_name, d2->sfd_name)) {
|
||||
if (d1->sfd_ino == d2->sfd_ino) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Duplicate entries for "
|
||||
"%s (merged)",
|
||||
pathsofar, d1->sfd_name);
|
||||
d1->sfd_ino = SFS_NOINO;
|
||||
d1->sfd_name[0] = 0;
|
||||
}
|
||||
else {
|
||||
/* XXX: what if FSCK.n.m already exists? */
|
||||
snprintf(d1->sfd_name, sizeof(d1->sfd_name),
|
||||
"FSCK.%lu.%lu",
|
||||
(unsigned long) d1->sfd_ino,
|
||||
(unsigned long) uniqueid());
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Duplicate names %s "
|
||||
"(one renamed: %s)",
|
||||
pathsofar, d2->sfd_name, d1->sfd_name);
|
||||
}
|
||||
dchanged = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for the . and .. entries.
|
||||
*/
|
||||
|
||||
for (i=0; i<ndirentries; i++) {
|
||||
if (!strcmp(direntries[i].sfd_name, ".")) {
|
||||
if (direntries[i].sfd_ino != ino) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Incorrect `.' entry "
|
||||
"(fixed)", pathsofar);
|
||||
direntries[i].sfd_ino = ino;
|
||||
dchanged = 1;
|
||||
}
|
||||
/* duplicates are checked above -> only one . here */
|
||||
assert(dotseen==0);
|
||||
dotseen = 1;
|
||||
}
|
||||
else if (!strcmp(direntries[i].sfd_name, "..")) {
|
||||
if (direntries[i].sfd_ino != parentino) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Incorrect `..' entry "
|
||||
"(fixed)", pathsofar);
|
||||
direntries[i].sfd_ino = parentino;
|
||||
dchanged = 1;
|
||||
}
|
||||
/* duplicates are checked above -> only one .. here */
|
||||
assert(dotdotseen==0);
|
||||
dotdotseen = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If no . entry, try to insert one.
|
||||
*/
|
||||
|
||||
if (!dotseen) {
|
||||
if (sfsdir_tryadd(direntries, ndirentries, ".", ino)==0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `.' entry (added)",
|
||||
pathsofar);
|
||||
dchanged = 1;
|
||||
}
|
||||
else if (sfsdir_tryadd(direntries, maxdirentries, ".",
|
||||
ino)==0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `.' entry (added)",
|
||||
pathsofar);
|
||||
ndirentries++;
|
||||
dchanged = 1;
|
||||
sfi.sfi_size += sizeof(struct sfs_direntry);
|
||||
ichanged = 1;
|
||||
}
|
||||
else {
|
||||
setbadness(EXIT_UNRECOV);
|
||||
warnx("Directory %s: No `.' entry (NOT FIXED)",
|
||||
pathsofar);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If no .. entry, try to insert one.
|
||||
*/
|
||||
|
||||
if (!dotdotseen) {
|
||||
if (sfsdir_tryadd(direntries, ndirentries, "..",
|
||||
parentino)==0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `..' entry (added)",
|
||||
pathsofar);
|
||||
dchanged = 1;
|
||||
}
|
||||
else if (sfsdir_tryadd(direntries, maxdirentries, "..",
|
||||
parentino)==0) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: No `..' entry (added)",
|
||||
pathsofar);
|
||||
ndirentries++;
|
||||
dchanged = 1;
|
||||
sfi.sfi_size += sizeof(struct sfs_direntry);
|
||||
ichanged = 1;
|
||||
}
|
||||
else {
|
||||
setbadness(EXIT_UNRECOV);
|
||||
warnx("Directory %s: No `..' entry (NOT FIXED)",
|
||||
pathsofar);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now load each inode in the directory.
|
||||
*
|
||||
* For regular files, count the number of links we see; for
|
||||
* directories, recurse. Count the number of subdirs seen
|
||||
* so we can correct our own link count if necessary.
|
||||
*/
|
||||
|
||||
subdircount=0;
|
||||
for (i=0; i<ndirentries; i++) {
|
||||
if (direntries[i].sfd_ino == SFS_NOINO) {
|
||||
/* nothing */
|
||||
}
|
||||
else if (!strcmp(direntries[i].sfd_name, ".")) {
|
||||
/* nothing */
|
||||
}
|
||||
else if (!strcmp(direntries[i].sfd_name, "..")) {
|
||||
/* nothing */
|
||||
}
|
||||
else {
|
||||
char path[strlen(pathsofar)+SFS_NAMELEN+1];
|
||||
struct sfs_dinode subsfi;
|
||||
|
||||
sfs_readinode(direntries[i].sfd_ino, &subsfi);
|
||||
snprintf(path, sizeof(path), "%s/%s",
|
||||
pathsofar, direntries[i].sfd_name);
|
||||
|
||||
switch (subsfi.sfi_type) {
|
||||
case SFS_TYPE_FILE:
|
||||
inode_addlink(direntries[i].sfd_ino);
|
||||
break;
|
||||
case SFS_TYPE_DIR:
|
||||
if (pass2_dir(direntries[i].sfd_ino,
|
||||
ino,
|
||||
path)) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Crosslink to "
|
||||
"other directory (removed)",
|
||||
path);
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
direntries[i].sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
}
|
||||
else {
|
||||
subdircount++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Object %s: Invalid inode type %u "
|
||||
"(removed)", path, subsfi.sfi_type);
|
||||
direntries[i].sfd_ino = SFS_NOINO;
|
||||
direntries[i].sfd_name[0] = 0;
|
||||
dchanged = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix up the link count if needed.
|
||||
*/
|
||||
|
||||
if (sfi.sfi_linkcount != subdircount+2) {
|
||||
setbadness(EXIT_RECOV);
|
||||
warnx("Directory %s: Link count %lu should be %lu (fixed)",
|
||||
pathsofar, (unsigned long) sfi.sfi_linkcount,
|
||||
(unsigned long) subdircount+2);
|
||||
sfi.sfi_linkcount = subdircount+2;
|
||||
ichanged = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write back anything that changed, clean up, and return.
|
||||
*/
|
||||
|
||||
if (dchanged) {
|
||||
sfs_writedir(&sfi, direntries, ndirentries);
|
||||
}
|
||||
|
||||
if (ichanged) {
|
||||
sfs_writeinode(ino, &sfi);
|
||||
}
|
||||
|
||||
free(direntries);
|
||||
free(sortvector);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
pass2(void)
|
||||
{
|
||||
char path[SFS_VOLNAME_SIZE + 2];
|
||||
|
||||
snprintf(path, sizeof(path), "%s:", sb_volname());
|
||||
pass2_dir(SFS_ROOTDIR_INO, SFS_ROOTDIR_INO, path);
|
||||
}
|
51
userland/sbin/sfsck/passes.h
Normal file
51
userland/sbin/sfsck/passes.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef PASSES_H
|
||||
#define PASSES_H
|
||||
|
||||
/*
|
||||
* Pass 1 scans the filesystem starting at the root directory, finding
|
||||
* all reachable directories, files, and blocks, and correcting gross
|
||||
* local errors. The results are used to fix the free block bitmap.
|
||||
*
|
||||
* Pass 2 scans the filesystem starting at the root directory,
|
||||
* checking for crosslinked and malformed directories and accumulating
|
||||
* link count information. Because it runs after we've fixed the free
|
||||
* block bitmap, we can (cautiously) allocate blocks if we need to.
|
||||
*/
|
||||
|
||||
void pass1(void);
|
||||
void pass2(void);
|
||||
|
||||
/* After pass1 is done, return the number of dirs and files on the volume. */
|
||||
unsigned long pass1_founddirs(void);
|
||||
unsigned long pass1_foundfiles(void);
|
||||
|
||||
#endif /* PASSES_H */
|
124
userland/sbin/sfsck/sb.c
Normal file
124
userland/sbin/sfsck/sb.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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> /* for CHAR_BIT */
|
||||
#include <limits.h> /* also for CHAR_BIT */
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include <kern/sfs.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "sfs.h"
|
||||
#include "sb.h"
|
||||
#include "freemap.h"
|
||||
#include "main.h"
|
||||
|
||||
static struct sfs_superblock sb;
|
||||
|
||||
/*
|
||||
* Load the superblock.
|
||||
*/
|
||||
void
|
||||
sb_load(void)
|
||||
{
|
||||
sfs_readsb(SFS_SUPER_BLOCK, &sb);
|
||||
if (sb.sb_magic != SFS_MAGIC) {
|
||||
errx(EXIT_FATAL, "Not an sfs filesystem");
|
||||
}
|
||||
|
||||
assert(sb.sb_nblocks > 0);
|
||||
assert(SFS_FREEMAPBLOCKS(sb.sb_nblocks) > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the superblock.
|
||||
*/
|
||||
void
|
||||
sb_check(void)
|
||||
{
|
||||
int schanged=0;
|
||||
|
||||
/*
|
||||
* FUTURE: should we check sb.sb_nblocks against diskblocks()?
|
||||
*/
|
||||
|
||||
/* Check the superblock fields */
|
||||
|
||||
if (checknullstring(sb.sb_volname, sizeof(sb.sb_volname))) {
|
||||
warnx("Volume name not null-terminated (fixed)");
|
||||
setbadness(EXIT_RECOV);
|
||||
schanged = 1;
|
||||
}
|
||||
if (checkbadstring(sb.sb_volname)) {
|
||||
warnx("Volume name contains illegal characters (fixed)");
|
||||
setbadness(EXIT_RECOV);
|
||||
schanged = 1;
|
||||
}
|
||||
if (checkzeroed(sb.reserved, sizeof(sb.reserved))) {
|
||||
warnx("Reserved section of superblock not zeroed (fixed)");
|
||||
setbadness(EXIT_RECOV);
|
||||
schanged = 1;
|
||||
}
|
||||
|
||||
/* Write the superblock back if necessary */
|
||||
if (schanged) {
|
||||
sfs_writesb(SFS_SUPER_BLOCK, &sb);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the total number of blocks in the volume.
|
||||
*/
|
||||
uint32_t
|
||||
sb_totalblocks(void)
|
||||
{
|
||||
return sb.sb_nblocks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of freemap blocks.
|
||||
* (this function probably ought to go away)
|
||||
*/
|
||||
uint32_t
|
||||
sb_freemapblocks(void)
|
||||
{
|
||||
return SFS_FREEMAPBLOCKS(sb.sb_nblocks);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the volume name.
|
||||
*/
|
||||
const char *
|
||||
sb_volname(void)
|
||||
{
|
||||
return sb.sb_volname;
|
||||
}
|
55
userland/sbin/sfsck/sb.h
Normal file
55
userland/sbin/sfsck/sb.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SB_H
|
||||
#define SB_H
|
||||
|
||||
/*
|
||||
* The superblock module checks the superblock and provides
|
||||
* information from the superblock to other modules.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Load the superblock. Should be done before virtually anything else. */
|
||||
void sb_load(void);
|
||||
|
||||
/* After the superblock is loaded: return volume size. */
|
||||
uint32_t sb_totalblocks(void);
|
||||
|
||||
/* After the superblock is loaded: return number of freemap blocks. */
|
||||
uint32_t sb_freemapblocks(void);
|
||||
|
||||
/* After the superblock is loaded: return volume name. */
|
||||
const char *sb_volname(void);
|
||||
|
||||
/* Check the superblock. Must load it first. */
|
||||
void sb_check(void);
|
||||
|
||||
#endif /* SB_H */
|
464
userland/sbin/sfsck/sfs.c
Normal file
464
userland/sbin/sfsck/sfs.c
Normal file
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include <kern/sfs.h>
|
||||
|
||||
#include "disk.h"
|
||||
#include "utils.h"
|
||||
#include "ibmacros.h"
|
||||
#include "sfs.h"
|
||||
#include "main.h"
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// global setup
|
||||
|
||||
void
|
||||
sfs_setup(void)
|
||||
{
|
||||
assert(sizeof(struct sfs_superblock)==SFS_BLOCKSIZE);
|
||||
assert(sizeof(struct sfs_dinode)==SFS_BLOCKSIZE);
|
||||
assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// byte-swap functions
|
||||
|
||||
static
|
||||
void
|
||||
swapsb(struct sfs_superblock *sb)
|
||||
{
|
||||
sb->sb_magic = SWAP32(sb->sb_magic);
|
||||
sb->sb_nblocks = SWAP32(sb->sb_nblocks);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
swapbits(uint8_t *bits)
|
||||
{
|
||||
/* nothing to do */
|
||||
(void)bits;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
swapinode(struct sfs_dinode *sfi)
|
||||
{
|
||||
int i;
|
||||
|
||||
sfi->sfi_size = SWAP32(sfi->sfi_size);
|
||||
sfi->sfi_type = SWAP16(sfi->sfi_type);
|
||||
sfi->sfi_linkcount = SWAP16(sfi->sfi_linkcount);
|
||||
|
||||
for (i=0; i<NUM_D; i++) {
|
||||
SET_D(sfi, i) = SWAP32(GET_D(sfi, i));
|
||||
}
|
||||
|
||||
for (i=0; i<NUM_I; i++) {
|
||||
SET_I(sfi, i) = SWAP32(GET_I(sfi, i));
|
||||
}
|
||||
|
||||
for (i=0; i<NUM_II; i++) {
|
||||
SET_II(sfi, i) = SWAP32(GET_II(sfi, i));
|
||||
}
|
||||
|
||||
for (i=0; i<NUM_III; i++) {
|
||||
SET_III(sfi, i) = SWAP32(GET_III(sfi, i));
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
swapdir(struct sfs_direntry *sfd)
|
||||
{
|
||||
sfd->sfd_ino = SWAP32(sfd->sfd_ino);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
swapindir(uint32_t *entries)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<SFS_DBPERIDB; i++) {
|
||||
entries[i] = SWAP32(entries[i]);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// bmap()
|
||||
|
||||
/*
|
||||
* Indirect block bmap: in indirect block IBLOCK, read the entry at
|
||||
* block OFFSET from the first file block mapped by this indirect
|
||||
* block.
|
||||
*
|
||||
* ENTRYSIZE is how many blocks each entry describes; for a
|
||||
* singly-indirect block this is 1. For a multiply-indirect block,
|
||||
* it is more than 1; in this case recurse.
|
||||
*/
|
||||
static
|
||||
uint32_t
|
||||
ibmap(uint32_t iblock, uint32_t offset, uint32_t entrysize)
|
||||
{
|
||||
uint32_t entries[SFS_DBPERIDB];
|
||||
|
||||
if (iblock == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
diskread(entries, iblock);
|
||||
swapindir(entries);
|
||||
|
||||
if (entrysize > 1) {
|
||||
uint32_t index = offset / entrysize;
|
||||
offset %= entrysize;
|
||||
return ibmap(entries[index], offset, entrysize/SFS_DBPERIDB);
|
||||
}
|
||||
else {
|
||||
assert(offset < SFS_DBPERIDB);
|
||||
return entries[offset];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* bmap() for SFS.
|
||||
*
|
||||
* Given an inode and a file block, returns a disk block.
|
||||
*/
|
||||
static
|
||||
uint32_t
|
||||
bmap(const struct sfs_dinode *sfi, uint32_t fileblock)
|
||||
{
|
||||
uint32_t iblock, offset;
|
||||
|
||||
if (fileblock < INOMAX_D) {
|
||||
return GET_D(sfi, fileblock);
|
||||
}
|
||||
else if (fileblock < INOMAX_I) {
|
||||
iblock = (fileblock - INOMAX_D) / RANGE_I;
|
||||
offset = (fileblock - INOMAX_D) % RANGE_I;
|
||||
return ibmap(GET_I(sfi, iblock), offset, RANGE_D);
|
||||
}
|
||||
else if (fileblock < INOMAX_II) {
|
||||
iblock = (fileblock - INOMAX_I) / RANGE_II;
|
||||
offset = (fileblock - INOMAX_I) % RANGE_II;
|
||||
return ibmap(GET_II(sfi, iblock), offset, RANGE_I);
|
||||
}
|
||||
else if (fileblock < INOMAX_III) {
|
||||
iblock = (fileblock - INOMAX_II) / RANGE_III;
|
||||
offset = (fileblock - INOMAX_II) % RANGE_III;
|
||||
return ibmap(GET_III(sfi, iblock), offset, RANGE_II);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// superblock, free block bitmap, and inode I/O
|
||||
|
||||
/*
|
||||
* superblock - blocknum is a disk block number.
|
||||
*/
|
||||
|
||||
void
|
||||
sfs_readsb(uint32_t blocknum, struct sfs_superblock *sb)
|
||||
{
|
||||
diskread(sb, blocknum);
|
||||
swapsb(sb);
|
||||
}
|
||||
|
||||
void
|
||||
sfs_writesb(uint32_t blocknum, struct sfs_superblock *sb)
|
||||
{
|
||||
swapsb(sb);
|
||||
diskwrite(sb, blocknum);
|
||||
swapsb(sb);
|
||||
}
|
||||
|
||||
/*
|
||||
* freemap blocks - whichblock is a block number within the free block
|
||||
* bitmap.
|
||||
*/
|
||||
|
||||
void
|
||||
sfs_readfreemapblock(uint32_t whichblock, uint8_t *bits)
|
||||
{
|
||||
diskread(bits, SFS_FREEMAP_START + whichblock);
|
||||
swapbits(bits);
|
||||
}
|
||||
|
||||
void
|
||||
sfs_writefreemapblock(uint32_t whichblock, uint8_t *bits)
|
||||
{
|
||||
swapbits(bits);
|
||||
diskwrite(bits, SFS_FREEMAP_START + whichblock);
|
||||
swapbits(bits);
|
||||
}
|
||||
|
||||
/*
|
||||
* inodes - ino is an inode number, which is a disk block number.
|
||||
*/
|
||||
|
||||
void
|
||||
sfs_readinode(uint32_t ino, struct sfs_dinode *sfi)
|
||||
{
|
||||
diskread(sfi, ino);
|
||||
swapinode(sfi);
|
||||
}
|
||||
|
||||
void
|
||||
sfs_writeinode(uint32_t ino, struct sfs_dinode *sfi)
|
||||
{
|
||||
swapinode(sfi);
|
||||
diskwrite(sfi, ino);
|
||||
swapinode(sfi);
|
||||
}
|
||||
|
||||
/*
|
||||
* indirect blocks - blocknum is a disk block number.
|
||||
*/
|
||||
|
||||
void
|
||||
sfs_readindirect(uint32_t blocknum, uint32_t *entries)
|
||||
{
|
||||
diskread(entries, blocknum);
|
||||
swapindir(entries);
|
||||
}
|
||||
|
||||
void
|
||||
sfs_writeindirect(uint32_t blocknum, uint32_t *entries)
|
||||
{
|
||||
swapindir(entries);
|
||||
diskwrite(entries, blocknum);
|
||||
swapindir(entries);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// directory I/O
|
||||
|
||||
/*
|
||||
* Read the directory block at DISKBLOCK into D.
|
||||
*/
|
||||
static
|
||||
void
|
||||
sfs_readdirblock(struct sfs_direntry *d, uint32_t diskblock)
|
||||
{
|
||||
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
|
||||
unsigned j;
|
||||
|
||||
if (diskblock != 0) {
|
||||
diskread(d, diskblock);
|
||||
for (j=0; j<atonce; j++) {
|
||||
swapdir(&d[j]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
warnx("Warning: sparse directory found");
|
||||
bzero(d, SFS_BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in a directory, from the inode SFI, into D, which is a buffer
|
||||
* with ND slots. The caller is assumed to have figured out the right
|
||||
* number of slots.
|
||||
*/
|
||||
void
|
||||
sfs_readdir(struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd)
|
||||
{
|
||||
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
|
||||
unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
|
||||
unsigned i, j;
|
||||
unsigned left, thismany;
|
||||
struct sfs_direntry buffer[atonce];
|
||||
uint32_t diskblock;
|
||||
|
||||
left = nd;
|
||||
for (i=0; i<nblocks; i++) {
|
||||
diskblock = bmap(sfi, i);
|
||||
if (left < atonce) {
|
||||
thismany = left;
|
||||
sfs_readdirblock(buffer, diskblock);
|
||||
for (j=0; j<thismany; j++) {
|
||||
d[i*atonce + j] = buffer[j];
|
||||
}
|
||||
}
|
||||
else {
|
||||
thismany = atonce;
|
||||
sfs_readdirblock(d + i*atonce, diskblock);
|
||||
}
|
||||
left -= thismany;
|
||||
}
|
||||
assert(left == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the directory block D to DISKBLOCK.
|
||||
*/
|
||||
static
|
||||
void
|
||||
sfs_writedirblock(struct sfs_direntry *d, uint32_t diskblock)
|
||||
{
|
||||
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
|
||||
unsigned j, bad;
|
||||
|
||||
if (diskblock != 0) {
|
||||
for (j=0; j<atonce; j++) {
|
||||
swapdir(&d[j]);
|
||||
}
|
||||
diskwrite(d, diskblock);
|
||||
}
|
||||
else {
|
||||
for (j=bad=0; j<atonce; j++) {
|
||||
if (d[j].sfd_ino != SFS_NOINO ||
|
||||
d[j].sfd_name[0] != 0) {
|
||||
bad = 1;
|
||||
}
|
||||
}
|
||||
if (bad) {
|
||||
warnx("Cannot write to missing block in "
|
||||
"sparse directory (ERROR)");
|
||||
setbadness(EXIT_UNRECOV);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out a directory, from the inode SFI, using D, which is a
|
||||
* buffer with ND slots. The caller is assumed to have set the inode
|
||||
* size accordingly.
|
||||
*/
|
||||
void
|
||||
sfs_writedir(const struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd)
|
||||
{
|
||||
const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry);
|
||||
unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
|
||||
unsigned i, j;
|
||||
unsigned left, thismany;
|
||||
struct sfs_direntry buffer[atonce];
|
||||
uint32_t diskblock;
|
||||
|
||||
left = nd;
|
||||
for (i=0; i<nblocks; i++) {
|
||||
diskblock = bmap(sfi, i);
|
||||
if (left < atonce) {
|
||||
thismany = left;
|
||||
for (j=0; j<thismany; j++) {
|
||||
buffer[j] = d[i*atonce + j];
|
||||
}
|
||||
for (; j<atonce; j++) {
|
||||
memset(&buffer[j], 0, sizeof(buffer[j]));
|
||||
}
|
||||
sfs_writedirblock(buffer, diskblock);
|
||||
}
|
||||
else {
|
||||
thismany = atonce;
|
||||
sfs_writedirblock(d + i*atonce, diskblock);
|
||||
}
|
||||
left -= thismany;
|
||||
}
|
||||
assert(left == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// directory utilities
|
||||
|
||||
/* this exists because qsort() doesn't pass a context pointer through */
|
||||
static struct sfs_direntry *global_sortdirs;
|
||||
|
||||
/*
|
||||
* Compare function for the permutation vector produced by
|
||||
* sfsdir_sort().
|
||||
*/
|
||||
static
|
||||
int
|
||||
dirsortfunc(const void *aa, const void *bb)
|
||||
{
|
||||
const int *a = (const int *)aa;
|
||||
const int *b = (const int *)bb;
|
||||
const struct sfs_direntry *ad = &global_sortdirs[*a];
|
||||
const struct sfs_direntry *bd = &global_sortdirs[*b];
|
||||
|
||||
/* Sort unallocated entries last */
|
||||
if (ad->sfd_ino == SFS_NOINO && bd->sfd_ino == SFS_NOINO) {
|
||||
return 0;
|
||||
}
|
||||
if (ad->sfd_ino == SFS_NOINO) {
|
||||
return 1;
|
||||
}
|
||||
if (bd->sfd_ino == SFS_NOINO) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return strcmp(ad->sfd_name, bd->sfd_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort the directory contents in D (with ND entries) by producing a
|
||||
* permutation vector into VECTOR, which should be allocated to hold
|
||||
* ND ints.
|
||||
*/
|
||||
void
|
||||
sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<nd; i++) {
|
||||
vector[i] = i;
|
||||
}
|
||||
|
||||
global_sortdirs = d;
|
||||
qsort(vector, nd, sizeof(int), dirsortfunc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to add an entry NAME/INO to D (which has ND entries) by
|
||||
* finding an empty slot. Cannot allocate new space.
|
||||
*
|
||||
* Returns 0 on success and nonzero on failure.
|
||||
*/
|
||||
int
|
||||
sfsdir_tryadd(struct sfs_direntry *d, int nd, const char *name, uint32_t ino)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<nd; i++) {
|
||||
if (d[i].sfd_ino==SFS_NOINO) {
|
||||
d[i].sfd_ino = ino;
|
||||
assert(strlen(name) < sizeof(d[i].sfd_name));
|
||||
strcpy(d[i].sfd_name, name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
81
userland/sbin/sfsck/sfs.h
Normal file
81
userland/sbin/sfsck/sfs.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SFS_H
|
||||
#define SFS_H
|
||||
|
||||
/*
|
||||
* SFS operations. This module provides functions for reading and
|
||||
* writing SFS structures, and knows under the covers how to byte-swap
|
||||
* them. It also provides utility operations on the SFS structures.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct sfs_superblock;
|
||||
struct sfs_dinode;
|
||||
struct sfs_direntry;
|
||||
|
||||
/* Call this before anything else in this module */
|
||||
void sfs_setup(void);
|
||||
|
||||
/*
|
||||
* Read and write ops for SFS structures
|
||||
*/
|
||||
|
||||
/* superblock */
|
||||
void sfs_readsb(uint32_t blocknum, struct sfs_superblock *sb);
|
||||
void sfs_writesb(uint32_t blocknum, struct sfs_superblock *sb);
|
||||
|
||||
/* freemap blocks; whichblock is the freemap block number (starts at 0) */
|
||||
void sfs_readfreemapblock(uint32_t whichblock, uint8_t *bits);
|
||||
void sfs_writefreemapblock(uint32_t whichblock, uint8_t *bits);
|
||||
|
||||
/* inode */
|
||||
void sfs_readinode(uint32_t inum, struct sfs_dinode *sfi);
|
||||
void sfs_writeinode(uint32_t inum, struct sfs_dinode *sfi);
|
||||
|
||||
/* indirect block (any indirection level) */
|
||||
void sfs_readindirect(uint32_t blocknum, uint32_t *entries);
|
||||
void sfs_writeindirect(uint32_t blocknum, uint32_t *entries);
|
||||
|
||||
/* directory - ND should be the number of directory entries D points to */
|
||||
void sfs_readdir(struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd);
|
||||
void sfs_writedir(const struct sfs_dinode *sfi,
|
||||
struct sfs_direntry *d, unsigned nd);
|
||||
|
||||
/* Try to add an entry to a directory. */
|
||||
int sfsdir_tryadd(struct sfs_direntry *d, int nd,
|
||||
const char *name, uint32_t ino);
|
||||
|
||||
/* Sort a directory by creating a permutation vector. */
|
||||
void sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector);
|
||||
|
||||
|
||||
#endif /* SFS_H */
|
144
userland/sbin/sfsck/utils.c
Normal file
144
userland/sbin/sfsck/utils.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "utils.h"
|
||||
#include "main.h"
|
||||
|
||||
/*
|
||||
* Wrapper around malloc.
|
||||
*/
|
||||
void *
|
||||
domalloc(size_t len)
|
||||
{
|
||||
void *x;
|
||||
x = malloc(len);
|
||||
if (x==NULL) {
|
||||
errx(EXIT_FATAL, "Out of memory");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper around realloc. OSZ is the old block size, which we need if
|
||||
* we're going to emulate realloc with malloc.
|
||||
*/
|
||||
void *
|
||||
dorealloc(void *op, size_t osz, size_t nsz)
|
||||
{
|
||||
void *np;
|
||||
#ifdef NO_REALLOC
|
||||
size_t copysz;
|
||||
|
||||
np = domalloc(nsz);
|
||||
if (op != NULL) {
|
||||
copysz = osz < nsz ? osz : nsz;
|
||||
memcpy(np, op, copysz);
|
||||
free(op);
|
||||
}
|
||||
#else
|
||||
(void)osz;
|
||||
np = realloc(op, nsz);
|
||||
if (np == NULL) {
|
||||
errx(EXIT_FATAL, "Out of memory");
|
||||
}
|
||||
#endif
|
||||
return np;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a unique id number. (unique as in for this run of sfsck...)
|
||||
*/
|
||||
uint32_t
|
||||
uniqueid(void)
|
||||
{
|
||||
static uint32_t uniquecounter;
|
||||
|
||||
return uniquecounter++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if BUF, a string field of length MAXLEN, contains a null
|
||||
* terminator. If not, slam one in and return 1.
|
||||
*/
|
||||
int
|
||||
checknullstring(char *buf, size_t maxlen)
|
||||
{
|
||||
size_t i;
|
||||
for (i=0; i<maxlen; i++) {
|
||||
if (buf[i]==0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
buf[maxlen-1] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if BUF contains characters not allowed in file and volume
|
||||
* names. If so, stomp them and return 1.
|
||||
*/
|
||||
int
|
||||
checkbadstring(char *buf)
|
||||
{
|
||||
size_t i;
|
||||
int rv = 0;
|
||||
|
||||
for (i=0; buf[i]; i++) {
|
||||
if (buf[i]==':' || buf[i]=='/') {
|
||||
buf[i] = '_';
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if BUF, of size LEN, is zeroed. If not, zero it and return 1.
|
||||
*/
|
||||
int
|
||||
checkzeroed(void *vbuf, size_t len)
|
||||
{
|
||||
char *buf = vbuf;
|
||||
size_t i;
|
||||
int rv = 0;
|
||||
|
||||
for (i=0; i < len; i++) {
|
||||
if (buf[i] != 0) {
|
||||
buf[i] = 0;
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
52
userland/sbin/sfsck/utils.h
Normal file
52
userland/sbin/sfsck/utils.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include <sys/types.h> /* for size_t */
|
||||
#include <stdint.h> /* for uint32_t */
|
||||
|
||||
/* non-failing wrapper around malloc */
|
||||
void *domalloc(size_t len);
|
||||
void *dorealloc(void *op, size_t osz, size_t nsz);
|
||||
|
||||
/* return a fresh id number */
|
||||
uint32_t uniqueid(void);
|
||||
|
||||
/* ensure that BUF (of size MAXLEN) is terminated; return 1 if changed */
|
||||
int checknullstring(char *buf, size_t maxlen);
|
||||
|
||||
/* check for illegal filename characters; if found, zap them and return 1 */
|
||||
int checkbadstring(char *buf);
|
||||
|
||||
/* check for nonzero bytes in a zeroed area; if found, zap and return 1 */
|
||||
int checkzeroed(void *buf, size_t len);
|
||||
|
||||
#endif /* UTILS_H */
|
Reference in New Issue
Block a user