10f66f451Sopenharmony_ci/* du.c - disk usage program. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com> 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * See http://opengroup.org/onlinepubs/9699919799/utilities/du.html 60f66f451Sopenharmony_ci * 70f66f451Sopenharmony_ci * TODO: cleanup 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ciUSE_DU(NEWTOY(du, "d#<0=-1hmlcaHkKLsx[-HL][-kKmh]", TOYFLAG_USR|TOYFLAG_BIN)) 100f66f451Sopenharmony_ci 110f66f451Sopenharmony_ciconfig DU 120f66f451Sopenharmony_ci bool "du" 130f66f451Sopenharmony_ci default y 140f66f451Sopenharmony_ci help 150f66f451Sopenharmony_ci usage: du [-kKmh] [file...] 160f66f451Sopenharmony_ci 170f66f451Sopenharmony_ci Show disk usage, space consumed by files. 180f66f451Sopenharmony_ci 190f66f451Sopenharmony_ci Size in: 200f66f451Sopenharmony_ci -k 1024 byte blocks (default) 210f66f451Sopenharmony_ci -K 512 byte blocks (posix) 220f66f451Sopenharmony_ci -m Megabytes 230f66f451Sopenharmony_ci -h Human readable (e.g., 1K 243M 2G) 240f66f451Sopenharmony_ci*/ 250f66f451Sopenharmony_ci 260f66f451Sopenharmony_ci#define FOR_du 270f66f451Sopenharmony_ci#include "toys.h" 280f66f451Sopenharmony_ci 290f66f451Sopenharmony_ciGLOBALS( 300f66f451Sopenharmony_ci long d; 310f66f451Sopenharmony_ci 320f66f451Sopenharmony_ci unsigned long depth, total; 330f66f451Sopenharmony_ci dev_t st_dev; 340f66f451Sopenharmony_ci void *inodes; 350f66f451Sopenharmony_ci) 360f66f451Sopenharmony_ci 370f66f451Sopenharmony_citypedef struct node_size { 380f66f451Sopenharmony_ci struct dirtree *node; 390f66f451Sopenharmony_ci long size; 400f66f451Sopenharmony_ci} node_size; 410f66f451Sopenharmony_ci 420f66f451Sopenharmony_ci// Print the size and name, given size in bytes 430f66f451Sopenharmony_cistatic void print(long long size, struct dirtree *node) 440f66f451Sopenharmony_ci{ 450f66f451Sopenharmony_ci char *name = "total"; 460f66f451Sopenharmony_ci 470f66f451Sopenharmony_ci if (TT.depth > TT.d) return; 480f66f451Sopenharmony_ci 490f66f451Sopenharmony_ci if (toys.optflags & FLAG_h) { 500f66f451Sopenharmony_ci human_readable(toybuf, size, 0); 510f66f451Sopenharmony_ci printf("%s", toybuf); 520f66f451Sopenharmony_ci } else { 530f66f451Sopenharmony_ci int bits = 10; 540f66f451Sopenharmony_ci 550f66f451Sopenharmony_ci if (toys.optflags & FLAG_K) bits = 9; 560f66f451Sopenharmony_ci else if (toys.optflags & FLAG_m) bits = 20; 570f66f451Sopenharmony_ci 580f66f451Sopenharmony_ci printf("%llu", (size>>bits)+!!(size&((1<<bits)-1))); 590f66f451Sopenharmony_ci } 600f66f451Sopenharmony_ci if (node) name = dirtree_path(node, NULL); 610f66f451Sopenharmony_ci xprintf("\t%s\n", name); 620f66f451Sopenharmony_ci if (node) free(name); 630f66f451Sopenharmony_ci} 640f66f451Sopenharmony_ci 650f66f451Sopenharmony_ci// Return whether or not we've seen this inode+dev, adding it to the list if 660f66f451Sopenharmony_ci// we haven't. 670f66f451Sopenharmony_cistatic int seen_inode(void **list, struct stat *st) 680f66f451Sopenharmony_ci{ 690f66f451Sopenharmony_ci if (!st) llist_traverse(st, free); 700f66f451Sopenharmony_ci 710f66f451Sopenharmony_ci // Skipping dir nodes isn't _quite_ right. They're not hardlinked, but could 720f66f451Sopenharmony_ci // be bind mounted. Still, it's more efficient and the archivers can't use 730f66f451Sopenharmony_ci // hardlinked directory info anyway. (Note that we don't catch bind mounted 740f66f451Sopenharmony_ci // _files_ because it doesn't change st_nlink.) 750f66f451Sopenharmony_ci else if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) { 760f66f451Sopenharmony_ci struct inode_list { 770f66f451Sopenharmony_ci struct inode_list *next; 780f66f451Sopenharmony_ci ino_t ino; 790f66f451Sopenharmony_ci dev_t dev; 800f66f451Sopenharmony_ci } *new; 810f66f451Sopenharmony_ci 820f66f451Sopenharmony_ci for (new = *list; new; new = new->next) 830f66f451Sopenharmony_ci if(new->ino == st->st_ino && new->dev == st->st_dev) 840f66f451Sopenharmony_ci return 1; 850f66f451Sopenharmony_ci 860f66f451Sopenharmony_ci new = xzalloc(sizeof(*new)); 870f66f451Sopenharmony_ci new->ino = st->st_ino; 880f66f451Sopenharmony_ci new->dev = st->st_dev; 890f66f451Sopenharmony_ci new->next = *list; 900f66f451Sopenharmony_ci *list = new; 910f66f451Sopenharmony_ci } 920f66f451Sopenharmony_ci 930f66f451Sopenharmony_ci return 0; 940f66f451Sopenharmony_ci} 950f66f451Sopenharmony_ci 960f66f451Sopenharmony_ci// dirtree callback, compute/display size of node 970f66f451Sopenharmony_cistatic int do_du(struct dirtree *node) 980f66f451Sopenharmony_ci{ 990f66f451Sopenharmony_ci if (!node->parent) TT.st_dev = node->st.st_dev; 1000f66f451Sopenharmony_ci else if (!dirtree_notdotdot(node)) return 0; 1010f66f451Sopenharmony_ci 1020f66f451Sopenharmony_ci // detect swiching filesystems 1030f66f451Sopenharmony_ci if ((toys.optflags & FLAG_x) && (TT.st_dev != node->st.st_dev)) 1040f66f451Sopenharmony_ci return 0; 1050f66f451Sopenharmony_ci 1060f66f451Sopenharmony_ci // Don't loop endlessly on recursive directory symlink 1070f66f451Sopenharmony_ci if (toys.optflags & FLAG_L) { 1080f66f451Sopenharmony_ci struct dirtree *try = node; 1090f66f451Sopenharmony_ci 1100f66f451Sopenharmony_ci while ((try = try->parent)) 1110f66f451Sopenharmony_ci if (node->st.st_dev==try->st.st_dev && node->st.st_ino==try->st.st_ino) 1120f66f451Sopenharmony_ci return 0; 1130f66f451Sopenharmony_ci } 1140f66f451Sopenharmony_ci 1150f66f451Sopenharmony_ci // Don't count hard links twice 1160f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_l) && !node->again) 1170f66f451Sopenharmony_ci if (seen_inode(&TT.inodes, &node->st)) return 0; 1180f66f451Sopenharmony_ci 1190f66f451Sopenharmony_ci // Collect child info before printing directory size 1200f66f451Sopenharmony_ci if (S_ISDIR(node->st.st_mode)) { 1210f66f451Sopenharmony_ci if (!node->again) { 1220f66f451Sopenharmony_ci TT.depth++; 1230f66f451Sopenharmony_ci return DIRTREE_COMEAGAIN|(DIRTREE_SYMFOLLOW*!!(toys.optflags&FLAG_L)); 1240f66f451Sopenharmony_ci } else TT.depth--; 1250f66f451Sopenharmony_ci } 1260f66f451Sopenharmony_ci 1270f66f451Sopenharmony_ci // Modern compilers' optimizers are insane and think signed overflow 1280f66f451Sopenharmony_ci // behaves differently than unsigned overflow. Sigh. Big hammer. 1290f66f451Sopenharmony_ci 1300f66f451Sopenharmony_ci if ((toys.optflags & FLAG_a) || !node->parent 1310f66f451Sopenharmony_ci || (S_ISDIR(node->st.st_mode) && !(toys.optflags & FLAG_s))) { 1320f66f451Sopenharmony_ci print(node->st.st_size, node); 1330f66f451Sopenharmony_ci } 1340f66f451Sopenharmony_ci return 0; 1350f66f451Sopenharmony_ci} 1360f66f451Sopenharmony_ci 1370f66f451Sopenharmony_civoid du_main(void) 1380f66f451Sopenharmony_ci{ 1390f66f451Sopenharmony_ci char *noargs[] = {".", 0}, **args; 1400f66f451Sopenharmony_ci if (toys.optc < 1) help_exit(0); 1410f66f451Sopenharmony_ci 1420f66f451Sopenharmony_ci if (!strcmp(*toys.optargs, ".") || !strncmp("./" ,*toys.optargs, 2)) 1430f66f451Sopenharmony_ci help_exit("Directory size statistics are not supported"); 1440f66f451Sopenharmony_ci 1450f66f451Sopenharmony_ci 1460f66f451Sopenharmony_ci // Loop over command line arguments, recursing through children 1470f66f451Sopenharmony_ci for (args = toys.optc ? toys.optargs : noargs; *args; args++) 1480f66f451Sopenharmony_ci dirtree_flagread(*args, DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)), 1490f66f451Sopenharmony_ci do_du); 1500f66f451Sopenharmony_ci if (toys.optflags & FLAG_c) print(TT.total*512, 0); 1510f66f451Sopenharmony_ci 1520f66f451Sopenharmony_ci if (CFG_TOYBOX_FREE) seen_inode(TT.inodes, 0); 1530f66f451Sopenharmony_ci} 154