1*cf5a6c84SAndroid Build Coastguard Worker /* du.c - disk usage program.
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2012 Ashwini Kumar <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * See http://opengroup.org/onlinepubs/9699919799/utilities/du.html
6*cf5a6c84SAndroid Build Coastguard Worker *
7*cf5a6c84SAndroid Build Coastguard Worker * TODO: cleanup (should seen_inode be lib?)
8*cf5a6c84SAndroid Build Coastguard Worker * 32 bit du -b maxes out at 4 gigs (instead of 2 terabytes via *512 trick)
9*cf5a6c84SAndroid Build Coastguard Worker * because dirtree->extra is a long.
10*cf5a6c84SAndroid Build Coastguard Worker
11*cf5a6c84SAndroid Build Coastguard Worker USE_DU(NEWTOY(du, "d#<0=-1hmlcaHkKLsxb[-HL][-kKmh]", TOYFLAG_USR|TOYFLAG_BIN))
12*cf5a6c84SAndroid Build Coastguard Worker
13*cf5a6c84SAndroid Build Coastguard Worker config DU
14*cf5a6c84SAndroid Build Coastguard Worker bool "du"
15*cf5a6c84SAndroid Build Coastguard Worker default y
16*cf5a6c84SAndroid Build Coastguard Worker help
17*cf5a6c84SAndroid Build Coastguard Worker usage: du [-d N] [-abcHKkLlmsx] [FILE...]
18*cf5a6c84SAndroid Build Coastguard Worker
19*cf5a6c84SAndroid Build Coastguard Worker Show disk usage, space consumed by files and directories.
20*cf5a6c84SAndroid Build Coastguard Worker
21*cf5a6c84SAndroid Build Coastguard Worker Size in:
22*cf5a6c84SAndroid Build Coastguard Worker -b Apparent bytes (directory listing size, not space used)
23*cf5a6c84SAndroid Build Coastguard Worker -h Human readable (e.g., 1K 243M 2G)
24*cf5a6c84SAndroid Build Coastguard Worker -k 1024 byte blocks (default)
25*cf5a6c84SAndroid Build Coastguard Worker -K 512 byte blocks (posix)
26*cf5a6c84SAndroid Build Coastguard Worker -m Megabytes
27*cf5a6c84SAndroid Build Coastguard Worker
28*cf5a6c84SAndroid Build Coastguard Worker What to show:
29*cf5a6c84SAndroid Build Coastguard Worker -a All files, not just directories
30*cf5a6c84SAndroid Build Coastguard Worker -c Cumulative total
31*cf5a6c84SAndroid Build Coastguard Worker -d N Only depth < N
32*cf5a6c84SAndroid Build Coastguard Worker -H Follow symlinks on cmdline
33*cf5a6c84SAndroid Build Coastguard Worker -L Follow all symlinks
34*cf5a6c84SAndroid Build Coastguard Worker -l Disable hardlink filter
35*cf5a6c84SAndroid Build Coastguard Worker -s Only total size of each argument
36*cf5a6c84SAndroid Build Coastguard Worker -x Don't leave this filesystem
37*cf5a6c84SAndroid Build Coastguard Worker */
38*cf5a6c84SAndroid Build Coastguard Worker
39*cf5a6c84SAndroid Build Coastguard Worker #define FOR_du
40*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
41*cf5a6c84SAndroid Build Coastguard Worker
42*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
43*cf5a6c84SAndroid Build Coastguard Worker long d;
44*cf5a6c84SAndroid Build Coastguard Worker
45*cf5a6c84SAndroid Build Coastguard Worker unsigned long depth, total;
46*cf5a6c84SAndroid Build Coastguard Worker dev_t st_dev;
47*cf5a6c84SAndroid Build Coastguard Worker void *inodes;
48*cf5a6c84SAndroid Build Coastguard Worker )
49*cf5a6c84SAndroid Build Coastguard Worker
50*cf5a6c84SAndroid Build Coastguard Worker typedef struct node_size {
51*cf5a6c84SAndroid Build Coastguard Worker struct dirtree *node;
52*cf5a6c84SAndroid Build Coastguard Worker long size;
53*cf5a6c84SAndroid Build Coastguard Worker } node_size;
54*cf5a6c84SAndroid Build Coastguard Worker
55*cf5a6c84SAndroid Build Coastguard Worker // Print the size and name, given size in bytes
print(long long size,struct dirtree * node)56*cf5a6c84SAndroid Build Coastguard Worker static void print(long long size, struct dirtree *node)
57*cf5a6c84SAndroid Build Coastguard Worker {
58*cf5a6c84SAndroid Build Coastguard Worker char *name = "total";
59*cf5a6c84SAndroid Build Coastguard Worker
60*cf5a6c84SAndroid Build Coastguard Worker if (TT.depth > TT.d) return;
61*cf5a6c84SAndroid Build Coastguard Worker
62*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(h)) {
63*cf5a6c84SAndroid Build Coastguard Worker human_readable(toybuf, size, 0);
64*cf5a6c84SAndroid Build Coastguard Worker printf("%s", toybuf);
65*cf5a6c84SAndroid Build Coastguard Worker } else {
66*cf5a6c84SAndroid Build Coastguard Worker int bits = 10;
67*cf5a6c84SAndroid Build Coastguard Worker
68*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(K)) bits = 9;
69*cf5a6c84SAndroid Build Coastguard Worker else if (FLAG(m)) bits = 20;
70*cf5a6c84SAndroid Build Coastguard Worker
71*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(b) && bits == 10 && !FLAG(k)) printf("%llu", size);
72*cf5a6c84SAndroid Build Coastguard Worker else printf("%llu", (size>>bits)+!!(size&((1<<bits)-1)));
73*cf5a6c84SAndroid Build Coastguard Worker }
74*cf5a6c84SAndroid Build Coastguard Worker if (node) name = dirtree_path(node, NULL);
75*cf5a6c84SAndroid Build Coastguard Worker xprintf("\t%s\n", name);
76*cf5a6c84SAndroid Build Coastguard Worker if (node) free(name);
77*cf5a6c84SAndroid Build Coastguard Worker }
78*cf5a6c84SAndroid Build Coastguard Worker
79*cf5a6c84SAndroid Build Coastguard Worker // Return whether or not we've seen this inode+dev, adding it to the list if
80*cf5a6c84SAndroid Build Coastguard Worker // we haven't.
seen_inode(void ** list,struct stat * st)81*cf5a6c84SAndroid Build Coastguard Worker static int seen_inode(void **list, struct stat *st)
82*cf5a6c84SAndroid Build Coastguard Worker {
83*cf5a6c84SAndroid Build Coastguard Worker if (!st) llist_traverse(st, free);
84*cf5a6c84SAndroid Build Coastguard Worker
85*cf5a6c84SAndroid Build Coastguard Worker // Skipping dir nodes isn't _quite_ right. They're not hardlinked, but could
86*cf5a6c84SAndroid Build Coastguard Worker // be bind mounted. Still, it's more efficient and the archivers can't use
87*cf5a6c84SAndroid Build Coastguard Worker // hardlinked directory info anyway. (Note that we don't catch bind mounted
88*cf5a6c84SAndroid Build Coastguard Worker // _files_ because it doesn't change st_nlink.)
89*cf5a6c84SAndroid Build Coastguard Worker else if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
90*cf5a6c84SAndroid Build Coastguard Worker struct inode_list {
91*cf5a6c84SAndroid Build Coastguard Worker struct inode_list *next;
92*cf5a6c84SAndroid Build Coastguard Worker struct dev_ino di;
93*cf5a6c84SAndroid Build Coastguard Worker } *new;
94*cf5a6c84SAndroid Build Coastguard Worker
95*cf5a6c84SAndroid Build Coastguard Worker for (new = *list; new; new = new->next)
96*cf5a6c84SAndroid Build Coastguard Worker if(same_dev_ino(st, &new->di)) return 1;
97*cf5a6c84SAndroid Build Coastguard Worker
98*cf5a6c84SAndroid Build Coastguard Worker new = xzalloc(sizeof(*new));
99*cf5a6c84SAndroid Build Coastguard Worker new->di.ino = st->st_ino;
100*cf5a6c84SAndroid Build Coastguard Worker new->di.dev = st->st_dev;
101*cf5a6c84SAndroid Build Coastguard Worker new->next = *list;
102*cf5a6c84SAndroid Build Coastguard Worker *list = new;
103*cf5a6c84SAndroid Build Coastguard Worker }
104*cf5a6c84SAndroid Build Coastguard Worker
105*cf5a6c84SAndroid Build Coastguard Worker return 0;
106*cf5a6c84SAndroid Build Coastguard Worker }
107*cf5a6c84SAndroid Build Coastguard Worker
108*cf5a6c84SAndroid Build Coastguard Worker // dirtree callback, compute/display size of node
do_du(struct dirtree * node)109*cf5a6c84SAndroid Build Coastguard Worker static int do_du(struct dirtree *node)
110*cf5a6c84SAndroid Build Coastguard Worker {
111*cf5a6c84SAndroid Build Coastguard Worker unsigned long blocks, again = node->again&DIRTREE_COMEAGAIN;
112*cf5a6c84SAndroid Build Coastguard Worker
113*cf5a6c84SAndroid Build Coastguard Worker if (!node->parent) TT.st_dev = node->st.st_dev;
114*cf5a6c84SAndroid Build Coastguard Worker else if (!dirtree_notdotdot(node)) return 0;
115*cf5a6c84SAndroid Build Coastguard Worker
116*cf5a6c84SAndroid Build Coastguard Worker // detect swiching filesystems
117*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(x) && TT.st_dev != node->st.st_dev) return 0;
118*cf5a6c84SAndroid Build Coastguard Worker
119*cf5a6c84SAndroid Build Coastguard Worker // Don't loop endlessly on recursive directory symlink
120*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(L)) {
121*cf5a6c84SAndroid Build Coastguard Worker struct dirtree *try = node;
122*cf5a6c84SAndroid Build Coastguard Worker
123*cf5a6c84SAndroid Build Coastguard Worker while ((try = try->parent)) if (same_file(&node->st, &try->st)) return 0;
124*cf5a6c84SAndroid Build Coastguard Worker }
125*cf5a6c84SAndroid Build Coastguard Worker
126*cf5a6c84SAndroid Build Coastguard Worker // Don't count hard links twice
127*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(l) && !again)
128*cf5a6c84SAndroid Build Coastguard Worker if (seen_inode(&TT.inodes, &node->st)) return 0;
129*cf5a6c84SAndroid Build Coastguard Worker
130*cf5a6c84SAndroid Build Coastguard Worker // Collect child info before printing directory size
131*cf5a6c84SAndroid Build Coastguard Worker if (S_ISDIR(node->st.st_mode)) {
132*cf5a6c84SAndroid Build Coastguard Worker if (!again) {
133*cf5a6c84SAndroid Build Coastguard Worker TT.depth++;
134*cf5a6c84SAndroid Build Coastguard Worker return DIRTREE_COMEAGAIN|DIRTREE_SYMFOLLOW*FLAG(L);
135*cf5a6c84SAndroid Build Coastguard Worker } else TT.depth--;
136*cf5a6c84SAndroid Build Coastguard Worker }
137*cf5a6c84SAndroid Build Coastguard Worker
138*cf5a6c84SAndroid Build Coastguard Worker // Modern compilers' optimizers are insane and think signed overflow
139*cf5a6c84SAndroid Build Coastguard Worker // behaves differently than unsigned overflow. Sigh. Big hammer.
140*cf5a6c84SAndroid Build Coastguard Worker blocks = FLAG(b) ? node->st.st_size : node->st.st_blocks;
141*cf5a6c84SAndroid Build Coastguard Worker blocks += (unsigned long)node->extra;
142*cf5a6c84SAndroid Build Coastguard Worker node->extra = blocks;
143*cf5a6c84SAndroid Build Coastguard Worker if (node->parent)
144*cf5a6c84SAndroid Build Coastguard Worker node->parent->extra = (unsigned long)node->parent->extra+blocks;
145*cf5a6c84SAndroid Build Coastguard Worker else TT.total += node->extra;
146*cf5a6c84SAndroid Build Coastguard Worker
147*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(a) || !node->parent || (S_ISDIR(node->st.st_mode) && !FLAG(s))) {
148*cf5a6c84SAndroid Build Coastguard Worker blocks = node->extra;
149*cf5a6c84SAndroid Build Coastguard Worker print(FLAG(b) ? blocks : blocks*512LL, node);
150*cf5a6c84SAndroid Build Coastguard Worker }
151*cf5a6c84SAndroid Build Coastguard Worker
152*cf5a6c84SAndroid Build Coastguard Worker return 0;
153*cf5a6c84SAndroid Build Coastguard Worker }
154*cf5a6c84SAndroid Build Coastguard Worker
du_main(void)155*cf5a6c84SAndroid Build Coastguard Worker void du_main(void)
156*cf5a6c84SAndroid Build Coastguard Worker {
157*cf5a6c84SAndroid Build Coastguard Worker char *noargs[] = {".", 0}, **args;
158*cf5a6c84SAndroid Build Coastguard Worker
159*cf5a6c84SAndroid Build Coastguard Worker // Loop over command line arguments, recursing through children
160*cf5a6c84SAndroid Build Coastguard Worker for (args = toys.optc ? toys.optargs : noargs; *args; args++)
161*cf5a6c84SAndroid Build Coastguard Worker dirtree_flagread(*args, DIRTREE_SYMFOLLOW*(FLAG(H)|FLAG(L)), do_du);
162*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(c)) print(FLAG(b) ? TT.total : TT.total*512, 0);
163*cf5a6c84SAndroid Build Coastguard Worker
164*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FREE) seen_inode(TT.inodes, 0);
165*cf5a6c84SAndroid Build Coastguard Worker }
166