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 }