du.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * du - print disk usage
  11. */
  12. #include <u.h>
  13. #include <libc.h>
  14. #include <String.h>
  15. extern int64_t du(char*, Dir*);
  16. extern void err(char*);
  17. extern int64_t blkmultiple(int64_t);
  18. extern int seen(Dir*);
  19. extern int warn(char*);
  20. enum {
  21. Vkilo = 1024LL,
  22. };
  23. /* rounding up, how many units does amt occupy? */
  24. #define HOWMANY(amt, unit) (((amt)+(unit)-1) / (unit))
  25. #define ROUNDUP(amt, unit) (HOWMANY(amt, unit) * (unit))
  26. int aflag;
  27. int autoscale;
  28. int fflag;
  29. int fltflag;
  30. int qflag;
  31. int readflg;
  32. int sflag;
  33. int tflag;
  34. int uflag;
  35. char *fmt = "%llu\t%q\n";
  36. char *readbuf;
  37. int64_t blocksize = Vkilo; /* actually more likely to be 4K or 8K */
  38. int64_t unit; /* scale factor for output */
  39. static char *pfxes[] = { /* SI prefixes for units > 1 */
  40. "",
  41. "k", "M", "G",
  42. "T", "P", "E",
  43. "Z", "Y",
  44. nil,
  45. };
  46. void
  47. usage(void)
  48. {
  49. fprint(2, "usage: du [-aefhnqstu] [-b size] [-p si-pfx] [file ...]\n");
  50. exits("usage");
  51. }
  52. void
  53. printamt(int64_t amt, char *name)
  54. {
  55. if (readflg)
  56. return;
  57. if (autoscale) {
  58. int scale = 0;
  59. double val = (double)amt/unit;
  60. while (fabs(val) >= 1024 && scale < nelem(pfxes)-1) {
  61. scale++;
  62. val /= 1024;
  63. }
  64. print("%.6g%s\t%q\n", val, pfxes[scale], name);
  65. } else if (fltflag)
  66. print("%.6g\t%q\n", (double)amt/unit, name);
  67. else
  68. print(fmt, HOWMANY(amt, unit), name);
  69. }
  70. void
  71. main(int argc, char *argv[])
  72. {
  73. int i, scale;
  74. char *s, *ss, *name;
  75. doquote = needsrcquote;
  76. quotefmtinstall();
  77. ARGBEGIN {
  78. case 'a': /* all files */
  79. aflag = 1;
  80. break;
  81. case 'b': /* block size */
  82. s = ARGF();
  83. if(s) {
  84. blocksize = strtoul(s, &ss, 0);
  85. if(s == ss)
  86. blocksize = 1;
  87. while(*ss++ == 'k')
  88. blocksize *= 1024;
  89. }
  90. break;
  91. case 'e': /* print in %g notation */
  92. fltflag = 1;
  93. break;
  94. case 'f': /* don't print warnings */
  95. fflag = 1;
  96. break;
  97. case 'h': /* similar to -h in bsd but more precise */
  98. autoscale = 1;
  99. break;
  100. case 'n': /* all files, number of bytes */
  101. aflag = 1;
  102. blocksize = 1;
  103. unit = 1;
  104. break;
  105. case 'p':
  106. s = ARGF();
  107. if(s) {
  108. for (scale = 0; pfxes[scale] != nil; scale++)
  109. if (cistrcmp(s, pfxes[scale]) == 0)
  110. break;
  111. if (pfxes[scale] == nil)
  112. sysfatal("unknown suffix %s", s);
  113. unit = 1;
  114. while (scale-- > 0)
  115. unit *= Vkilo;
  116. }
  117. break;
  118. case 'q': /* qid */
  119. fmt = "%.16llux\t%q\n";
  120. qflag = 1;
  121. break;
  122. case 'r':
  123. /* undocumented: just read & ignore every block of every file */
  124. readflg = 1;
  125. break;
  126. case 's': /* only top level */
  127. sflag = 1;
  128. break;
  129. case 't': /* return modified/accessed time */
  130. tflag = 1;
  131. break;
  132. case 'u': /* accessed time */
  133. uflag = 1;
  134. break;
  135. default:
  136. usage();
  137. } ARGEND
  138. if (unit == 0) {
  139. if (qflag || tflag || uflag || autoscale)
  140. unit = 1;
  141. else
  142. unit = Vkilo;
  143. }
  144. if (blocksize < 1)
  145. blocksize = 1;
  146. if (readflg) {
  147. readbuf = malloc(blocksize);
  148. if (readbuf == nil)
  149. sysfatal("out of memory");
  150. }
  151. if(argc==0)
  152. printamt(du(".", dirstat(".")), ".");
  153. else
  154. for(i=0; i<argc; i++) {
  155. name = argv[i];
  156. printamt(du(name, dirstat(name)), name);
  157. }
  158. exits(0);
  159. }
  160. int64_t
  161. dirval(Dir *d, int64_t size)
  162. {
  163. if(qflag)
  164. return d->qid.path;
  165. else if(tflag) {
  166. if(uflag)
  167. return d->atime;
  168. return d->mtime;
  169. } else
  170. return size;
  171. }
  172. void
  173. readfile(char *name)
  174. {
  175. int n, fd = open(name, OREAD);
  176. if(fd < 0) {
  177. warn(name);
  178. return;
  179. }
  180. while ((n = read(fd, readbuf, blocksize)) > 0)
  181. continue;
  182. if (n < 0)
  183. warn(name);
  184. close(fd);
  185. }
  186. int64_t
  187. dufile(char *name, Dir *d)
  188. {
  189. int64_t t = blkmultiple(d->length);
  190. if(aflag || readflg) {
  191. String *file = s_copy(name);
  192. s_append(file, "/");
  193. s_append(file, d->name);
  194. if (readflg)
  195. readfile(s_to_c(file));
  196. t = dirval(d, t);
  197. printamt(t, s_to_c(file));
  198. s_free(file);
  199. }
  200. return t;
  201. }
  202. int64_t
  203. du(char *name, Dir *dir)
  204. {
  205. int fd, i, n;
  206. Dir *buf, *d;
  207. String *file;
  208. int64_t nk, t;
  209. if(dir == nil)
  210. return warn(name);
  211. if((dir->qid.type&QTDIR) == 0)
  212. return dirval(dir, blkmultiple(dir->length));
  213. fd = open(name, OREAD);
  214. if(fd < 0)
  215. return warn(name);
  216. nk = 0;
  217. while((n=dirread(fd, &buf)) > 0) {
  218. d = buf;
  219. for(i = n; i > 0; i--, d++) {
  220. if((d->qid.type&QTDIR) == 0) {
  221. nk += dufile(name, d);
  222. continue;
  223. }
  224. if(strcmp(d->name, ".") == 0 ||
  225. strcmp(d->name, "..") == 0 ||
  226. /* !readflg && */ seen(d))
  227. continue; /* don't get stuck */
  228. file = s_copy(name);
  229. s_append(file, "/");
  230. s_append(file, d->name);
  231. t = du(s_to_c(file), d);
  232. nk += t;
  233. t = dirval(d, t);
  234. if(!sflag)
  235. printamt(t, s_to_c(file));
  236. s_free(file);
  237. }
  238. free(buf);
  239. }
  240. if(n < 0)
  241. warn(name);
  242. close(fd);
  243. return dirval(dir, nk);
  244. }
  245. #define NCACHE 256 /* must be power of two */
  246. typedef struct
  247. {
  248. Dir* cache;
  249. int n;
  250. int max;
  251. } Cache;
  252. Cache cache[NCACHE];
  253. int
  254. seen(Dir *dir)
  255. {
  256. Dir *dp;
  257. int i;
  258. Cache *c;
  259. c = &cache[dir->qid.path&(NCACHE-1)];
  260. dp = c->cache;
  261. for(i=0; i<c->n; i++, dp++)
  262. if(dir->qid.path == dp->qid.path &&
  263. dir->type == dp->type &&
  264. dir->dev == dp->dev)
  265. return 1;
  266. if(c->n == c->max){
  267. if (c->max == 0)
  268. c->max = 8;
  269. else
  270. c->max += c->max/2;
  271. c->cache = realloc(c->cache, c->max*sizeof(Dir));
  272. if(c->cache == nil)
  273. err("malloc failure");
  274. }
  275. c->cache[c->n++] = *dir;
  276. return 0;
  277. }
  278. void
  279. err(char *s)
  280. {
  281. fprint(2, "du: %s: %r\n", s);
  282. exits(s);
  283. }
  284. int
  285. warn(char *s)
  286. {
  287. if(fflag == 0)
  288. fprint(2, "du: %s: %r\n", s);
  289. return 0;
  290. }
  291. /* round up n to nearest block */
  292. int64_t
  293. blkmultiple(int64_t n)
  294. {
  295. if(blocksize == 1) /* no quantization */
  296. return n;
  297. return ROUNDUP(n, blocksize);
  298. }