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