Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/std/du.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1989-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* du -- report number of blocks used by . | file ...
26
*/
27
28
static const char usage[] =
29
"[-?\n@(#)$Id: du (AT&T Research) 2012-01-26 $\n]"
30
USAGE_LICENSE
31
"[+NAME?du - summarize disk usage]"
32
"[+DESCRIPTION?\bdu\b reports the number of blocks contained in all files"
33
" and recursively all directories named by the \apath\a arguments."
34
" The current directory is used if no \apath\a is given. Usage for"
35
" all files and directories is counted, even when the listing is"
36
" omitted. Directories and files are only counted once, even if"
37
" they appear more than once as a hard link, a target of a"
38
" symbolic link, or an operand.]"
39
"[+?The default block size is 512. The block count includes only the actual"
40
" data blocks used by each file and directory, and may not include"
41
" other filesystem data required to represent the file. Blocks are"
42
" counted only for the first link to a file; subsequent links are"
43
" ignored. Partial blocks are rounded up for each file.]"
44
"[+?If more than one of \b-b\b, \b-h\b, \b-k\b, \b-K,\b or \b-m\b are"
45
" specified only the rightmost takes affect.]"
46
47
"[a:all?List usage for each file. If neither \b--all\b nor \b--summary\b"
48
" is specified then only usage for the \apath\a arguments and"
49
" directories is listed.]"
50
"[b:blocksize?Set the block size to \asize\a. If omitted, \asize\a defaults"
51
" to 512.]#?[size:=512]"
52
"[f:silent?Do not report file and directory access errors.]"
53
"[h:binary-scale|human-readable?Scale disk usage to powers of 1024.]"
54
"[K:decimal-scale?Scale disk usage to powers of 1000.]"
55
"[k:kilobytes?List usage in units of 1024 bytes.]"
56
"[m:megabytes?List usage in units of 1024K bytes.]"
57
"[s:summary|summarize?Only display the total for each \apath\a argument.]"
58
"[t|c:total?Display a grand total for all files and directories.]"
59
"[v|r:verbose?Report all file and directory access errors. This is the"
60
" default.]"
61
"[x|X|l:xdev|local|mount|one-file-system?Do not descend into directories in"
62
" different filesystems than their parents.]"
63
"[L:logical|follow?Follow symbolic links. The default is \b--physical\b.]"
64
"[H:metaphysical?Follow command argument symbolic links, otherwise don't"
65
" follow. The default is \b--physical\b.]"
66
"[P:physical?Don't follow symbolic links. The default is \b--physical\b.]"
67
68
"\n"
69
"\n[ path ... ]\n"
70
"\n"
71
72
"[+SEE ALSO?\bfind\b(1), \bls\b(1), \btw\b(1)]"
73
;
74
75
#include <ast.h>
76
#include <ls.h>
77
#include <cdt.h>
78
#include <fts.h>
79
#include <error.h>
80
81
#define BLOCKS(n) (Count_t)((blocksize==LS_BLOCKSIZE)?(n):(((n)*LS_BLOCKSIZE+blocksize-1)/blocksize))
82
83
typedef Sfulong_t Count_t;
84
85
typedef struct Fileid_s /* unique file id */
86
{
87
ino_t ino;
88
dev_t dev;
89
} Fileid_t;
90
91
typedef struct Hit_s /* file already seen */
92
{
93
Dtlink_t link; /* dictionary link */
94
Fileid_t id; /* unique file id */
95
} Hit_t;
96
97
static void
98
mark(Dt_t* dict, Hit_t* key, FTSENT* ent)
99
{
100
Hit_t* hit;
101
102
static int warned;
103
104
if (hit = newof(0, Hit_t, 1, 0))
105
{
106
*hit = *key;
107
dtinsert(dict, hit);
108
}
109
else if (!warned)
110
{
111
warned = 1;
112
error(1, "%s: file id dictionary out of space", ent->fts_path);
113
}
114
}
115
116
int
117
main(int argc, register char** argv)
118
{
119
register FTS* fts;
120
register FTSENT* ent;
121
char* s;
122
char* d;
123
Dt_t* dict;
124
Count_t n;
125
Count_t b;
126
int dirs;
127
int flags;
128
int list;
129
int logical;
130
int multiple;
131
struct stat st;
132
Hit_t hit;
133
Dtdisc_t disc;
134
135
int all = 0;
136
int silent = 0;
137
int summary = 0;
138
int scale = 0;
139
int total = 0;
140
unsigned long blocksize = 0;
141
Count_t count = 0;
142
143
NoP(argc);
144
error_info.id = "du";
145
blocksize = 0;
146
flags = FTS_PHYSICAL|FTS_NOSEEDOTDIR;
147
for (;;)
148
{
149
switch (optget(argv, usage))
150
{
151
case 'a':
152
all = 1;
153
continue;
154
case 'b':
155
blocksize = (opt_info.num <= 0) ? 512 : opt_info.num;
156
continue;
157
case 'f':
158
silent = 1;
159
continue;
160
case 'h':
161
scale = 1024;
162
blocksize = 0;
163
continue;
164
case 'K':
165
scale = 1000;
166
blocksize = 0;
167
continue;
168
case 'k':
169
blocksize = 1024;
170
continue;
171
case 'm':
172
blocksize = 1024 * 1024;
173
continue;
174
case 's':
175
summary = 1;
176
continue;
177
case 't':
178
total = 1;
179
continue;
180
case 'x':
181
flags |= FTS_XDEV;
182
continue;
183
case 'v':
184
silent = 0;
185
continue;
186
case 'H':
187
flags |= FTS_META|FTS_PHYSICAL;
188
continue;
189
case 'L':
190
flags &= ~(FTS_META|FTS_PHYSICAL);
191
continue;
192
case 'P':
193
flags &= ~FTS_META;
194
flags |= FTS_PHYSICAL;
195
continue;
196
case '?':
197
error(ERROR_USAGE|4, "%s", opt_info.arg);
198
break;
199
case ':':
200
error(2, "%s", opt_info.arg);
201
break;
202
}
203
break;
204
}
205
argv += opt_info.index;
206
if (error_info.errors)
207
error(ERROR_USAGE|4, "%s", optusage(NiL));
208
memset(&hit, 0, sizeof(hit));
209
memset(&disc, 0, sizeof(disc));
210
disc.key = offsetof(Hit_t, id);
211
disc.size = sizeof(Fileid_t);
212
if (!(dict = dtopen(&disc, Dtset)))
213
error(3, "not enough space for file id dictionary");
214
if (blocksize)
215
scale = 0;
216
else
217
blocksize = LS_BLOCKSIZE;
218
if (logical = !(flags & (FTS_META|FTS_PHYSICAL)))
219
flags |= FTS_PHYSICAL;
220
multiple = argv[0] && argv[1];
221
dirs = logical || multiple;
222
if (!(fts = fts_open(argv, flags, NiL)))
223
error(ERROR_system(1), "%s: not found", argv[1]);
224
while (ent = fts_read(fts))
225
{
226
if (ent->fts_info != FTS_DP)
227
{
228
if (multiple && !ent->fts_level)
229
{
230
if (s = strrchr(ent->fts_path, '/'))
231
{
232
*s = 0;
233
d = ent->fts_path;
234
}
235
else
236
d = "..";
237
if (stat(d, &st))
238
{
239
error(ERROR_SYSTEM|2, "%s: cannot stat", d);
240
continue;
241
}
242
hit.id.dev = st.st_dev;
243
hit.id.ino = st.st_ino;
244
if (dtsearch(dict, &hit))
245
{
246
fts_set(NiL, ent, FTS_SKIP);
247
continue;
248
}
249
if (s)
250
*s = '/';
251
}
252
hit.id.dev = ent->fts_statp->st_dev;
253
hit.id.ino = ent->fts_statp->st_ino;
254
if (dirs && dtsearch(dict, &hit))
255
{
256
fts_set(NiL, ent, FTS_SKIP);
257
continue;
258
}
259
}
260
list = !summary;
261
n = 0;
262
switch (ent->fts_info)
263
{
264
case FTS_NS:
265
if (!silent)
266
error(ERROR_SYSTEM|2, "%s: not found", ent->fts_path);
267
continue;
268
case FTS_D:
269
if (!(ent->fts_pointer = newof(0, Count_t, 1, 0)))
270
error(ERROR_SYSTEM|3, "out of space");
271
if (dirs)
272
mark(dict, &hit, ent);
273
continue;
274
case FTS_DC:
275
if (!silent)
276
error(2, "%s: directory causes cycle", ent->fts_path);
277
continue;
278
case FTS_DNR:
279
if (!silent)
280
error(ERROR_SYSTEM|2, "%s: cannot read directory", ent->fts_path);
281
break;
282
case FTS_DNX:
283
if (!silent)
284
error(ERROR_SYSTEM|2, "%s: cannot search directory", ent->fts_path);
285
fts_set(NiL, ent, FTS_SKIP);
286
break;
287
case FTS_DP:
288
if (ent->fts_pointer)
289
{
290
n = *(Count_t*)ent->fts_pointer;
291
free(ent->fts_pointer);
292
}
293
break;
294
case FTS_SL:
295
if (logical)
296
{
297
fts_set(NiL, ent, FTS_FOLLOW);
298
continue;
299
}
300
/*FALLTHROUGH*/
301
default:
302
if (ent->fts_statp->st_nlink > 1 || dirs && !ent->fts_level)
303
mark(dict, &hit, ent);
304
if (!all)
305
list = 0;
306
break;
307
}
308
b = iblocks(ent->fts_statp);
309
count += b;
310
n += b;
311
if (ent->fts_parent->fts_pointer)
312
*(Count_t*)ent->fts_parent->fts_pointer += n;
313
if (!total && (list || ent->fts_level <= 0))
314
{
315
if (scale)
316
sfprintf(sfstdout, "%s\t%s\n", fmtscale((Sfulong_t)n * blocksize, scale), ent->fts_path);
317
else
318
sfprintf(sfstdout, "%I*u\t%s\n", sizeof(Count_t), BLOCKS(n), ent->fts_path);
319
}
320
}
321
if (total)
322
{
323
if (scale)
324
sfprintf(sfstdout, "%s\n", fmtscale(count * blocksize, scale));
325
else
326
sfprintf(sfstdout, "%I*u\n", sizeof(Count_t), BLOCKS(count));
327
}
328
return error_info.errors != 0;
329
}
330
331