diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/du.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/du.c')
-rwxr-xr-x | sys/src/cmd/du.c | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/sys/src/cmd/du.c b/sys/src/cmd/du.c new file mode 100755 index 000000000..a4521a6ea --- /dev/null +++ b/sys/src/cmd/du.c @@ -0,0 +1,324 @@ +/* + * du - print disk usage + */ +#include <u.h> +#include <libc.h> +#include <String.h> + +extern vlong du(char*, Dir*); +extern void err(char*); +extern vlong blkmultiple(vlong); +extern int seen(Dir*); +extern int warn(char*); + +enum { + Vkilo = 1024LL, +}; + +/* rounding up, how many units does amt occupy? */ +#define HOWMANY(amt, unit) (((amt)+(unit)-1) / (unit)) +#define ROUNDUP(amt, unit) (HOWMANY(amt, unit) * (unit)) + +int aflag; +int autoscale; +int fflag; +int fltflag; +int qflag; +int readflg; +int sflag; +int tflag; +int uflag; + +char *fmt = "%llud\t%q\n"; +char *readbuf; +vlong blocksize = Vkilo; /* actually more likely to be 4K or 8K */ +vlong unit; /* scale factor for output */ + +static char *pfxes[] = { /* SI prefixes for units > 1 */ + "", + "k", "M", "G", + "T", "P", "E", + "Z", "Y", + nil, +}; + +void +usage(void) +{ + fprint(2, "usage: du [-aefhnqstu] [-b size] [-p si-pfx] [file ...]\n"); + exits("usage"); +} + +void +printamt(vlong amt, char *name) +{ + if (readflg) + return; + if (autoscale) { + int scale = 0; + double val = (double)amt/unit; + + while (fabs(val) >= 1024 && scale < nelem(pfxes)-1) { + scale++; + val /= 1024; + } + print("%.6g%s\t%q\n", val, pfxes[scale], name); + } else if (fltflag) + print("%.6g\t%q\n", (double)amt/unit, name); + else + print(fmt, HOWMANY(amt, unit), name); +} + +void +main(int argc, char *argv[]) +{ + int i, scale; + char *s, *ss, *name; + + doquote = needsrcquote; + quotefmtinstall(); + + ARGBEGIN { + case 'a': /* all files */ + aflag = 1; + break; + case 'b': /* block size */ + s = ARGF(); + if(s) { + blocksize = strtoul(s, &ss, 0); + if(s == ss) + blocksize = 1; + while(*ss++ == 'k') + blocksize *= 1024; + } + break; + case 'e': /* print in %g notation */ + fltflag = 1; + break; + case 'f': /* don't print warnings */ + fflag = 1; + break; + case 'h': /* similar to -h in bsd but more precise */ + autoscale = 1; + break; + case 'n': /* all files, number of bytes */ + aflag = 1; + blocksize = 1; + unit = 1; + break; + case 'p': + s = ARGF(); + if(s) { + for (scale = 0; pfxes[scale] != nil; scale++) + if (cistrcmp(s, pfxes[scale]) == 0) + break; + if (pfxes[scale] == nil) + sysfatal("unknown suffix %s", s); + unit = 1; + while (scale-- > 0) + unit *= Vkilo; + } + break; + case 'q': /* qid */ + fmt = "%.16llux\t%q\n"; + qflag = 1; + break; + case 'r': + /* undocumented: just read & ignore every block of every file */ + readflg = 1; + break; + case 's': /* only top level */ + sflag = 1; + break; + case 't': /* return modified/accessed time */ + tflag = 1; + break; + case 'u': /* accessed time */ + uflag = 1; + break; + default: + usage(); + } ARGEND + + if (unit == 0) + if (qflag || tflag || uflag || autoscale) + unit = 1; + else + unit = Vkilo; + if (blocksize < 1) + blocksize = 1; + + if (readflg) { + readbuf = malloc(blocksize); + if (readbuf == nil) + sysfatal("out of memory"); + } + if(argc==0) + printamt(du(".", dirstat(".")), "."); + else + for(i=0; i<argc; i++) { + name = argv[i]; + printamt(du(name, dirstat(name)), name); + } + exits(0); +} + +vlong +dirval(Dir *d, vlong size) +{ + if(qflag) + return d->qid.path; + else if(tflag) { + if(uflag) + return d->atime; + return d->mtime; + } else + return size; +} + +void +readfile(char *name) +{ + int n, fd = open(name, OREAD); + + if(fd < 0) { + warn(name); + return; + } + while ((n = read(fd, readbuf, blocksize)) > 0) + continue; + if (n < 0) + warn(name); + close(fd); +} + +vlong +dufile(char *name, Dir *d) +{ + vlong t = blkmultiple(d->length); + + if(aflag || readflg) { + String *file = s_copy(name); + + s_append(file, "/"); + s_append(file, d->name); + if (readflg) + readfile(s_to_c(file)); + t = dirval(d, t); + printamt(t, s_to_c(file)); + s_free(file); + } + return t; +} + +vlong +du(char *name, Dir *dir) +{ + int fd, i, n; + Dir *buf, *d; + String *file; + vlong nk, t; + + if(dir == nil) + return warn(name); + + if((dir->qid.type&QTDIR) == 0) + return dirval(dir, blkmultiple(dir->length)); + + fd = open(name, OREAD); + if(fd < 0) + return warn(name); + nk = 0; + while((n=dirread(fd, &buf)) > 0) { + d = buf; + for(i = n; i > 0; i--, d++) { + if((d->qid.type&QTDIR) == 0) { + nk += dufile(name, d); + continue; + } + + if(strcmp(d->name, ".") == 0 || + strcmp(d->name, "..") == 0 || + /* !readflg && */ seen(d)) + continue; /* don't get stuck */ + + file = s_copy(name); + s_append(file, "/"); + s_append(file, d->name); + + t = du(s_to_c(file), d); + + nk += t; + t = dirval(d, t); + if(!sflag) + printamt(t, s_to_c(file)); + s_free(file); + } + free(buf); + } + if(n < 0) + warn(name); + close(fd); + return dirval(dir, nk); +} + +#define NCACHE 256 /* must be power of two */ + +typedef struct +{ + Dir* cache; + int n; + int max; +} Cache; +Cache cache[NCACHE]; + +int +seen(Dir *dir) +{ + Dir *dp; + int i; + Cache *c; + + c = &cache[dir->qid.path&(NCACHE-1)]; + dp = c->cache; + for(i=0; i<c->n; i++, dp++) + if(dir->qid.path == dp->qid.path && + dir->type == dp->type && + dir->dev == dp->dev) + return 1; + if(c->n == c->max){ + if (c->max == 0) + c->max = 8; + else + c->max += c->max/2; + c->cache = realloc(c->cache, c->max*sizeof(Dir)); + if(c->cache == nil) + err("malloc failure"); + } + c->cache[c->n++] = *dir; + return 0; +} + +void +err(char *s) +{ + fprint(2, "du: %s: %r\n", s); + exits(s); +} + +int +warn(char *s) +{ + if(fflag == 0) + fprint(2, "du: %s: %r\n", s); + return 0; +} + +/* round up n to nearest block */ +vlong +blkmultiple(vlong n) +{ + if(blocksize == 1) /* no quantization */ + return n; + return ROUNDUP(n, blocksize); +} |