ref: 9b76881a8e11c44aae5dfd447e1cd1bc074ec9f3
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 /adm/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 sort -n /mnt/term/tmp/used.blocks -o /mnt/term/tmp/used.blocks.sorted disk/unused 11721040049 /mnt/term/tmp/used.blocks.sorted 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; 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 ] nblocks list_of_used_blocks_file\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(); nblocks = atoll(argv[0]); u.file = estrdup(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", nil); 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, s->name, nil); 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); }