xref: /aosp_15_r20/external/toybox/toys/posix/du.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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