2 * du - print disk usage
8 extern vlong du(char*, Dir*);
9 extern void err(char*);
10 extern vlong blkmultiple(vlong);
11 extern int seen(Dir*);
12 extern int warn(char*);
18 /* rounding up, how many units does amt occupy? */
19 #define HOWMANY(amt, unit) (((amt)+(unit)-1) / (unit))
20 #define ROUNDUP(amt, unit) (HOWMANY(amt, unit) * (unit))
32 char *fmt = "%llud\t%q\n";
34 vlong blocksize = Vkilo; /* actually more likely to be 4K or 8K */
35 vlong unit; /* scale factor for output */
37 static char *pfxes[] = { /* SI prefixes for units > 1 */
48 fprint(2, "usage: du [-aefhnqstu] [-b size] [-p si-pfx] [file ...]\n");
53 printamt(vlong amt, char *name)
59 double val = (double)amt/unit;
61 while (fabs(val) >= 1024 && scale < nelem(pfxes)-1) {
65 print("%.6g%s\t%q\n", val, pfxes[scale], name);
67 print("%.6g\t%q\n", (double)amt/unit, name);
69 print(fmt, HOWMANY(amt, unit), name);
73 main(int argc, char *argv[])
78 doquote = needsrcquote;
82 case 'a': /* all files */
85 case 'b': /* block size */
88 blocksize = strtoul(s, &ss, 0);
95 case 'e': /* print in %g notation */
98 case 'f': /* don't print warnings */
101 case 'h': /* similar to -h in bsd but more precise */
104 case 'n': /* all files, number of bytes */
112 for (scale = 0; pfxes[scale] != nil; scale++)
113 if (cistrcmp(s, pfxes[scale]) == 0)
115 if (pfxes[scale] == nil)
116 sysfatal("unknown suffix %s", s);
123 fmt = "%.16llux\t%q\n";
127 /* undocumented: just read & ignore every block of every file */
130 case 's': /* only top level */
133 case 't': /* return modified/accessed time */
136 case 'u': /* accessed time */
144 if (qflag || tflag || uflag || autoscale)
152 readbuf = malloc(blocksize);
154 sysfatal("out of memory");
157 printamt(du(".", dirstat(".")), ".");
159 for(i=0; i<argc; i++) {
161 printamt(du(name, dirstat(name)), name);
167 dirval(Dir *d, vlong size)
182 int n, fd = open(name, OREAD);
188 while ((n = read(fd, readbuf, blocksize)) > 0)
196 dufile(char *name, Dir *d)
198 vlong t = blkmultiple(d->length);
200 if(aflag || readflg) {
201 String *file = s_copy(name);
204 s_append(file, d->name);
206 readfile(s_to_c(file));
208 printamt(t, s_to_c(file));
215 du(char *name, Dir *dir)
225 if((dir->qid.type&QTDIR) == 0)
226 return dirval(dir, blkmultiple(dir->length));
228 fd = open(name, OREAD);
232 while((n=dirread(fd, &buf)) > 0) {
234 for(i = n; i > 0; i--, d++) {
235 if((d->qid.type&QTDIR) == 0) {
236 nk += dufile(name, d);
240 if(strcmp(d->name, ".") == 0 ||
241 strcmp(d->name, "..") == 0 ||
242 /* !readflg && */ seen(d))
243 continue; /* don't get stuck */
247 s_append(file, d->name);
249 t = du(s_to_c(file), d);
254 printamt(t, s_to_c(file));
262 return dirval(dir, nk);
265 #define NCACHE 256 /* must be power of two */
282 c = &cache[dir->qid.path&(NCACHE-1)];
284 for(i=0; i<c->n; i++, dp++)
285 if(dir->qid.path == dp->qid.path &&
286 dir->type == dp->type &&
294 c->cache = realloc(c->cache, c->max*sizeof(Dir));
296 err("malloc failure");
298 c->cache[c->n++] = *dir;
305 fprint(2, "du: %s: %r\n", s);
313 fprint(2, "du: %s: %r\n", s);
317 /* round up n to nearest block */
321 if(blocksize == 1) /* no quantization */
323 return ROUNDUP(n, blocksize);