Mercurial > hg > toybox
annotate toys/posix/du.c @ 674:7e846e281e38
New build infrastructure to generate FLAG_ macros and TT alias, #define FOR_commandname before #including toys.h to trigger it. Rename DEFINE_GLOBALS() to just GLOBALS() (because I could never remember if it was DECLARE_GLOBALS). Convert existing commands to use new infrastructure, and replace optflag constants with FLAG_ macros where appropriate.
author | Rob Landley <rob@landley.net> |
---|---|
date | Mon, 08 Oct 2012 00:02:30 -0500 |
parents | 2b957eaa00c7 |
children | 786841fdb1e0 |
rev | line source |
---|---|
658 | 1 /* vi: set sw=4 ts=4: |
2 * | |
3 * du.c - disk usage program. | |
4 * | |
5 * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com> | |
6 * | |
7 * See http://opengroup.org/onlinepubs/9699919799/utilities/du.html | |
8 | |
9 USE_DU(NEWTOY(du, "d#<0hmlcaHkLsx", TOYFLAG_USR|TOYFLAG_BIN)) | |
10 | |
11 config DU | |
12 bool "du" | |
13 default y | |
14 help | |
15 usage: du [-d N] [-askxHLlmc] [file...] | |
16 | |
17 Estimate file space usage (default in unit of 512 blocks). | |
18 -a Show all file sizes | |
19 -H Follow symlinks on cmdline | |
20 -L Follow all symlinks | |
21 -k Show size in units of 1024. | |
22 -s Show only the total Size for each file specified | |
23 -x Estimate size only on the same device | |
24 -c Print total size of all arguments | |
25 -d N Limit output to directories (and files with -a) of depth < N | |
26 -l Count sizes many times if hard linked | |
27 -h Sizes in human readable format (e.g., 1K 243M 2G ) | |
28 -m Sizes in megabytes | |
29 */ | |
30 | |
674
7e846e281e38
New build infrastructure to generate FLAG_ macros and TT alias, #define FOR_commandname before #including toys.h to trigger it. Rename DEFINE_GLOBALS() to just GLOBALS() (because I could never remember if it was DECLARE_GLOBALS). Convert existing commands to use new infrastructure, and replace optflag constants with FLAG_ macros where appropriate.
Rob Landley <rob@landley.net>
parents:
658
diff
changeset
|
31 #define FOR_du |
658 | 32 #include "toys.h" |
33 | |
674
7e846e281e38
New build infrastructure to generate FLAG_ macros and TT alias, #define FOR_commandname before #including toys.h to trigger it. Rename DEFINE_GLOBALS() to just GLOBALS() (because I could never remember if it was DECLARE_GLOBALS). Convert existing commands to use new infrastructure, and replace optflag constants with FLAG_ macros where appropriate.
Rob Landley <rob@landley.net>
parents:
658
diff
changeset
|
34 GLOBALS( |
658 | 35 long maxdepth; |
36 long depth; | |
37 long *dirsum; | |
38 long total; | |
39 dev_t st_dev; | |
40 struct arg_list *inodes; | |
41 ) | |
42 | |
43 typedef struct node_size { | |
44 struct dirtree *node; | |
45 long size; | |
46 }node_size; | |
47 | |
48 typedef struct inode_ent { | |
49 ino_t ino; | |
50 dev_t dev; | |
51 }inode_ent_t; | |
52 | |
53 /* | |
54 * Adding '/' to the name if name is '.' or '..' | |
55 */ | |
56 | |
57 char *make_pathproper(char *str) | |
58 { | |
59 char *path = str; | |
60 switch(strlen(str)) { | |
61 case 1: | |
62 if(str[0] == '.') path = xstrdup("./"); | |
63 break; | |
64 case 2: | |
65 if(str[0] == '.' && str[1] == '.') path = xstrdup("../"); | |
66 break; | |
67 default: | |
68 break; | |
69 } | |
70 return path; | |
71 } | |
72 | |
73 /* | |
74 * Print the size of the given entry in specified format, default in blocks of 512 bytes | |
75 */ | |
76 void print(long size, char* name) | |
77 { | |
78 unsigned long long tempsize = (unsigned long long)size * 512; | |
79 unsigned long unit = 512; | |
80 char *sizestr = NULL; | |
81 if(TT.depth > TT.maxdepth) return; | |
82 if(toys.optflags & FLAG_h) unit = 0; | |
83 if(toys.optflags & FLAG_k) unit = 1024; | |
84 if(toys.optflags & FLAG_m) unit = 1024*1024; | |
85 sizestr = make_human_readable(tempsize, unit); //make human readable string, depending upon unit size. | |
86 xprintf("%s\t%s\n",sizestr, name); | |
87 free(sizestr); | |
88 } | |
89 | |
90 /* | |
91 * free the inodes which are stored for hard link reference | |
92 */ | |
93 void free_inodes(void *data) | |
94 { | |
95 void *arg = ((struct arg_list*)data)->arg; | |
96 if(arg) free(arg); | |
97 free(data); | |
98 } | |
99 | |
100 /* | |
101 * allocate and add a node to the list | |
102 */ | |
103 static void llist_add_inode(struct arg_list **old, void *data) | |
104 { | |
105 struct arg_list *new = xmalloc(sizeof(struct arg_list)); | |
106 | |
107 new->arg = (char*)data; | |
108 new->next = *old; | |
109 *old = new; | |
110 } | |
111 | |
112 /* | |
113 * check if the given stat entry is already there in list or not | |
114 */ | |
115 int is_inode_present(struct stat *st) | |
116 { | |
117 struct arg_list *temparg = NULL; | |
118 inode_ent_t *ent = NULL; | |
119 if(!TT.inodes) return 0; | |
120 for(temparg = TT.inodes; temparg; temparg = (struct arg_list *)temparg->next) { | |
121 ent = (inode_ent_t*)temparg->arg; | |
122 if(ent && ent->ino == st->st_ino && ent->dev == st->st_dev) return 1; | |
123 } | |
124 return 0; | |
125 } | |
126 | |
127 /* | |
128 * Compute the size of the node | |
129 */ | |
130 int do_du(struct dirtree *node) | |
131 { | |
132 inode_ent_t *ino_details = NULL; | |
133 node_size *nd = NULL; | |
134 if(!dirtree_notdotdot(node)) return 0; | |
135 if((toys.optflags & FLAG_x) && (TT.st_dev != node->st.st_dev)) //if file not on same device, don't count size | |
136 return DIRTREE_RECURSE; | |
137 | |
138 if(!(toys.optflags & FLAG_l) && node->st.st_nlink > 1 && !node->extra) { //keeping reference for hard links | |
139 if(is_inode_present(&node->st)) return DIRTREE_RECURSE; | |
140 ino_details = xzalloc(sizeof(inode_ent_t)); | |
141 ino_details->ino = node->st.st_ino; | |
142 ino_details->dev = node->st.st_dev; | |
143 llist_add_inode(&TT.inodes, (void*)ino_details); | |
144 } | |
145 | |
146 if(S_ISDIR(node->st.st_mode)) { | |
147 if(!(node->extra && (long)((node_size*)(node->extra))->node == (long)node)) { | |
148 nd = xzalloc(sizeof(node_size)); | |
149 nd->node = node; | |
150 nd->size = 0; | |
151 TT.dirsum = (long*)&(nd->size); | |
152 node->extra = (long)nd; | |
153 *TT.dirsum = 0; | |
154 TT.depth++; | |
155 return (DIRTREE_RECURSE|DIRTREE_COMEAGAIN | ((toys.optflags & FLAG_L) ? DIRTREE_SYMFOLLOW : 0)); //DIRTREE_COMEAGAIN to comeback and print the entry. | |
156 } | |
157 else if(node->extra) { //extra is set for a returning DIR entry. | |
158 long offset = 0; | |
159 nd = (node_size*)node->extra; | |
160 offset = nd->size; | |
161 nd->size += node->st.st_blocks; | |
162 TT.depth--; | |
163 if(!(toys.optflags & FLAG_s)) | |
164 print(*TT.dirsum, dirtree_path(node, NULL)); | |
165 if((node->parent) && (node->parent->extra)) { | |
166 /* when returning from internal directory, get the saved size of the parent and continue from there */ | |
167 nd = (node_size*)node->parent->extra; | |
168 TT.dirsum = (long*)&(nd->size); | |
169 *TT.dirsum += offset; | |
170 *TT.dirsum += node->st.st_blocks; | |
171 return DIRTREE_RECURSE; | |
172 } | |
173 else if(!node->parent) { | |
174 /*if node has no parent, it means it is the top in the tree, stop recursing here */ | |
175 TT.total += *TT.dirsum; | |
176 if((toys.optflags & FLAG_s)) | |
177 print(*TT.dirsum, dirtree_path(node, NULL)); | |
178 return 0; | |
179 } | |
180 } | |
181 } | |
182 else if(!(node->parent)) { | |
183 /* this is the file specified on cmdline */ | |
184 TT.total += node->st.st_blocks; | |
185 print(node->st.st_blocks, dirtree_path(node, NULL)); | |
186 return 0; | |
187 } | |
188 if(TT.dirsum) *TT.dirsum += node->st.st_blocks; | |
189 if(toys.optflags & FLAG_a && !(toys.optflags & FLAG_s)) | |
190 print(node->st.st_blocks, dirtree_path(node, NULL)); | |
191 return DIRTREE_RECURSE; | |
192 } | |
193 | |
194 /* | |
195 * DU utility main function | |
196 */ | |
197 void du_main(void) | |
198 { | |
199 int symfollow = toys.optflags & (FLAG_H | FLAG_L); | |
200 TT.total = 0; | |
201 TT.inodes = NULL; | |
202 | |
203 if(!(toys.optflags & FLAG_d)) TT.maxdepth = INT_MAX; | |
204 if(toys.optc == 0) toys.optargs[0] = "./"; | |
205 while(*toys.optargs) { | |
206 TT.depth = 0; | |
207 char *path = make_pathproper(*toys.optargs); | |
208 struct dirtree *root = dirtree_add_node(AT_FDCWD, path, symfollow); //create a node | |
209 if(root) { | |
210 TT.st_dev = root->st.st_dev; | |
211 handle_callback(root, do_du); //this will recurse thru the DIR children. | |
212 } | |
213 toys.optargs++; | |
214 } | |
215 if(TT.inodes) llist_traverse(TT.inodes, free_inodes); //free the stored nodes | |
216 if(toys.optflags & FLAG_c) print(TT.total, "total"); | |
217 } |