summaryrefslogtreecommitdiff
path: root/sys/src/cmd/du.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/du.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/du.c')
-rwxr-xr-xsys/src/cmd/du.c324
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);
+}