ref: 285644aadb1b58735651a5068703372f8fc9adac
dir: /unused.c/
#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 /a/frees as they are free to use. watch -e '6\.unused' 'date; ./6.unused -D 7 <{seq 1 1 3; seq 5 1 6} ' 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 \ `{dd -if /dev/sdF1/fs -bs 512 -iseek 1 -count 1 -quiet 1 | awk '$1 == "nblocks" { print $2 }'} \ <`{disk/used /dev/sdF1/fs} # this crashes the rc window, too much memory? disk/unused 11721040049 `{disk/used /dev/sdF1/fs} disk/used /dev/sdF1/fs > /mnt/term/tmp/used.blocks disk/unused 11721040049 /mnt/term/tmp/used.blocks diff <{ disk/unused -l 32 <{disk/used tests/test.0/disk}} <{ 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; void collect(Stream * s); void *emalloc(u32); static void init(Stream *s); void panic(char *fmt, ...); void show(Stream * s); static void usage(void) { fprint(2, "usage: unused -l [-D ] nblocks list_of_used_blocks_file\n"); exits("usage"); } void printfd(int fd, char *fmt, ...) { va_list va; va_start(va, fmt); vfprint(fd, fmt, va); va_end(va); } void main(int argc, char *argv[]) { Stream u; /* u = used */ struct Extents unused; u64 nblocks; int listblocks = 0; Errenv env = {0}; envpp = privalloc(); *envpp = &env; if(waserror()){ panic(0, "err stack %d: %lux %lux %lux %lux %lux %lux", env.nlabel, env.label[0][JMPBUFPC], env.label[1][JMPBUFPC], env.label[2][JMPBUFPC], env.label[3][JMPBUFPC], env.label[4][JMPBUFPC], env.label[5][JMPBUFPC]); } ARGBEGIN{ default: usage(); case 'D': chatty9p = ++debug; break; case 'l': listblocks++; break; }ARGEND if(argc != 2) usage(); nblocks = atoll(argv[0]); u.file = strdup(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, "unused", 0, 0, 2, nil, fprint, panic, emalloc); holes(u.es, &unused); 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, s->name, 0, 0, 2, nil, fprint, panic, emalloc); 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); ufree(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); }