code: mafs

ref: 5f15f2246d0fdac0fa98a0a910d40827edfaf68f
dir: /unused.c/

View raw version
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "extents.h"
#include <bio.h>

/*
	indentify block numbers that are not used.
	These blocks can be used to update /adm/frees as they are free to use.

	watch -e '6\.unused' 'date; ./6.unused -D <{seq 1 1 3; seq 5 1 6} 7 '

	disk/unused -D <{seq 1 1 3; seq 5 1 6} 7
collect used +1 +2 +3 +5 +6
show used
	1 .. 3
	5 .. 6
show unused
	3 .. 5

	disk/unused `{disk/used /dev/sdF1/fs} \
	`{dd -if /dev/sdF1/fs -bs 512 -iseek 1 -count 1 -quiet 1 | awk '$1 == "nblocks" { print $2 }'}

	# this crashes the rc window, too much memory?
	disk/unused `{disk/used /dev/sdF1/fs} 11721040049

	disk/used /dev/sdF1/fs > /mnt/term/tmp/used.blocks
	sort -n /mnt/term/tmp/used.blocks -o /mnt/term/tmp/used.blocks.sorted
	disk/unused /mnt/term/tmp/used.blocks.sorted 11721040049

	diff <{ disk/unused -l <{disk/used tests/test.0/disk} 32} <{ disk/free tests/test.0/disk }
 */

enum {
	FileNameLen = KiB,
};

int debug = 0;
int chatty9p = 0;

struct Stream {
	struct Extents *es;
	Biobufhdr bp;
	int fd;
	s8 *buf;
	char *file;
	s8 name[32];
};
typedef struct Stream Stream;

static void init(Stream *s);
void collect(Stream * s);
void *emalloc(u32);
s8 *estrdup(s8 *);
void show(Stream * s);
s8 find(Extents *es, u64 bno);
void common(Stream *u, Stream *f);
void missing(u64 nblocks, Stream *u, Stream *f);

static void
usage(void)
{
	fprint(2, "usage: unused -l [-D ] list_of_used_blocks_file nblocks\n");
	exits("usage");
}

void
main(int argc, char *argv[])
{
	Stream u;	/* u = used */
	struct Extents unused;
	u64 nblocks, i;
	int listblocks = 0;

	ARGBEGIN{
	default:	usage();
	case 'D':	chatty9p = ++debug;	break;
	case 'l':	listblocks++;		break;
	}ARGEND

	if(argc != 2)
		usage();

	u.file = estrdup(argv[0]);
	nblocks = atoll(argv[1]);

	if(u.file == nil)
		sysfatal("no used file");
	if(nblocks == 0)
		sysfatal("nblocks == 0");

	strncpy(u.name, "used", 32);
	init(&u);

	collect(&u);
	if(debug)
		show(&u);

	/* identify unused blocks */
	initextents(&unused);
	for(i = 0; i < nblocks; i++){
		if(find(u.es, i) == 0){
			add(&unused, i, 1);
		}
	}
	if(listblocks)
		showblocknos(1, &unused);
	else
		showextents(1, "", &unused);

	/* why bother? just exits(nil) as cinap suggests */
	Bterm(&u.bp);
	free(u.buf);
	close(u.fd);
	exits(nil);
}

static void
init(Stream *s)
{
	s->buf = emalloc(MiB);
	s->fd = open(s->file, OREAD);
	if(Binits(&s->bp, s->fd, OREAD, (u8*)s->buf, MiB) == Beof)
		sysfatal
		    ("%s: Binits on msin failed: status code: Beof, errstr: %r",
		     argv0);
	Blethal(&s->bp, nil);
}

void
collect(Stream * s)
{
	s8 *p, *ep;
	u64 start, end, nblocks;

	if(debug)
		print("collect %s ", s->name);
	s->es = emalloc(sizeof(Extents));
	initextents(s->es);
	while((s->buf = Brdstr(&s->bp, '\n', 1)) != nil) {
		p = s->buf;
		start = strtoull(p, &ep, 10);
		if(p == ep)
			panic("could not read");

		p = ep;
		p += 1; /* skip over the space */
		end = strtoull(p, &ep, 10);
		if(p == ep)
			panic("could not read");

		p = ep;
		p += 1; /* skip over the space */
		nblocks = strtoull(p, &ep, 10);
		if(p == ep)
			panic("could not read");
		if(end-start+1 != nblocks)
			panic("loadextents does not match up: start %llud end %llud nblocks %llud",
					start, end, nblocks);

		add(s->es, start, nblocks);
// show(s);
	}
	if(debug)
		print("\n");
}

void
show(Stream * s)
{
	print("show %s\n", s->name);
	if(s == nil || s->es == nil){
		print("nil\n");
		return;
	}
	showextents(1, "show stream: ", s->es);
}