|
|
1.1 root 1: /*
2: * Print a disc usage summary for
3: * some directories.
4: */
5:
6: #include <stdio.h>
7: #include <sys/types.h>
8: #include <sys/dir.h>
9: #include <sys/stat.h>
10: #include <sys/ino.h>
11: #include <errno.h>
12:
13: #define DIOSIZ (BUFSIZ/8) /* Size of directory i/o, until stacks grow */
14: #define NLINK 500 /* Size of link table */
15: #define NFNAME 1000 /* Size of filename */
16: #define NRECUR 12 /* Depth of recursion < NFILE-3-2 */
17:
18: int aflag; /* do files as well */
19: int sflag; /* only give total */
20: int depth; /* recursion depth */
21:
22: struct linktab {
23: ino_t l_ino;
24: dev_t l_dev;
25: } linktab[NLINK];
26: struct linktab *ltp;
27:
28: char fname[NFNAME];
29:
30: char toodeep[] = "directory structure too deep to traverse";
31:
32: struct stat sb;
33:
34: /*
35: * indirect block overhead based upon size of file
36: */
37: long ranges[] = {
38: ND, /* direct blocks */
39: ND + NBN, /* single indirect */
40: ND + NBN*NBN, /* double indirect */
41: ND + NBN*NBN*NBN /* tripple indirect */
42: };
43:
44: long duentry();
45: long dufork();
46: long dusize();
47: char *buildname();
48: void duerr();
49: void dumsg();
50: void usage();
51: void main();
52:
53: void
54: main(argc, argv)
55: char *argv[];
56: {
57: register int i;
58: register char *ap;
59: int estat;
60:
61: while (argc>1 && *argv[1]=='-') {
62: for (ap = &argv[1][1]; *ap != '\0'; ap++)
63: switch (*ap) {
64: case 'a':
65: aflag = 1;
66: break;
67:
68: case 's':
69: sflag = 1;
70: break;
71:
72: default:
73: usage();
74: }
75: argc--;
76: argv++;
77: }
78: if (argc < 2)
79: estat = du(".");
80: else {
81: estat = 0;
82: for (i=1; i<argc; i++)
83: estat |= du(argv[i]);
84: }
85: exit (estat);
86: }
87:
88: /*
89: * Print out disc usage summary
90: */
91: du(name)
92: char *name;
93: {
94: register char *ep, *cp;
95: fsize_t size;
96: int nondir;
97:
98: ltp = linktab;
99: cp = name;
100: ep = fname;
101: while (*cp)
102: *ep++ = *cp++;
103: *ep = '\0';
104: if (stat(name, &sb) < 0)
105: duerr("%s: nonexistent", name);
106: nondir = (sb.st_mode&S_IFMT) != S_IFDIR;
107: size = duentry(ep, &sb);
108: if (sflag || nondir)
109: printf("%ld\t%s\n", size, fname);
110: return (0);
111: }
112:
113: /*
114: * Do a du on a single entry
115: * The pointer is the end pointer
116: * into the fname buffer.
117: */
118: long
119: duentry(ep, sbp)
120: char *ep;
121: struct stat *sbp;
122: {
123: extern int errno;
124: fsize_t total, fsize;
125: char iobuf[DIOSIZ];
126: register char *np;
127: register struct direct *dp;
128: register int nb;
129: int fd;
130: int dirf;
131:
132: switch (sbp->st_mode & S_IFMT) {
133: case S_IFREG:
134: return (dusize(sbp));
135:
136: case S_IFDIR:
137: total = dusize(sbp);
138: if (++depth >= NRECUR) {
139: depth = 0;
140: return (dufork(ep, sbp));
141: }
142: if ((fd = open(fname, 0)) < 0) {
143: dumsg("cannot open `%s'", fname);
144: return (0);
145: }
146: while ((nb = read(fd, iobuf, DIOSIZ)) > 0)
147: for (dp = iobuf; dp < &iobuf[nb]; dp++) {
148: np = dp->d_name;
149: if (*np++=='.'
150: && (*np=='\0' || (*np++=='.' && *np=='\0')))
151: continue;
152: if (dp->d_ino == 0)
153: continue;
154: if ((np = buildname(dp, ep)) == NULL)
155: continue;
156: if (stat(fname, &sb) < 0) {
157: dumsg("stat failed on `%s'", fname);
158: continue;
159: }
160: dirf = (sb.st_mode&S_IFMT)==S_IFDIR;
161: fsize = duentry(np, sbp);
162: if (aflag && !sflag && !dirf)
163: prsize(fsize);
164: total += fsize;
165: }
166: if (nb < 0)
167: dumsg("%s: directory read error", fname);
168: close(fd);
169: *ep = '\0';
170: if (!sflag)
171: prsize(total);
172: --depth;
173: return (total);
174:
175: default:
176: return (0);
177: }
178: }
179:
180: /*
181: * Fork to do a du on recursive directory
182: * structure that is too deep to fit into
183: * user's open files.
184: */
185: long
186: dufork(ep, sbp)
187: char *ep;
188: struct stat *sbp;
189: {
190: register int i;
191: register int pid;
192: int pfd[2] = {0, 0};
193: int status;
194: long sz = 0;
195:
196: fflush(stdout);
197: if (pipe(pfd)<0 || (pid = fork())<0) {
198: if (pfd[0]) {
199: close(pfd[0]);
200: close(pfd[1]);
201: }
202: dumsg(toodeep);
203: return (0);
204: }
205: if (pid) {
206: close(pfd[1]);
207: while (wait(&status) >= 0)
208: ;
209: if (status || read(pfd[0], &sz, sizeof(long)) != sizeof(long))
210: sz = 0;
211: close(pfd[0]);
212: return (sz);
213: }
214: for (i=3; i<_NFILE; i++)
215: if (i != pfd[1])
216: close(i);
217: sz = duentry(ep, sbp);
218: write(pfd[1], &sz, sizeof(long));
219: close(pfd[1]);
220: exit(0);
221: }
222:
223: /*
224: * Do a du on a single file.
225: * Now takes into account indirect blocks.
226: */
227: long
228: dusize(sbp)
229: struct stat *sbp;
230: {
231: register int i;
232: register long blocks;
233:
234: if ((sbp->st_mode & S_IFMT) != S_IFDIR
235: && sbp->st_nlink > 1
236: && addlink(sbp->st_dev, sbp->st_ino))
237: return (0);
238: blocks = (sbp->st_size+BUFSIZ-1) / BUFSIZ;
239: for (i = 0; i < sizeof(ranges)/sizeof(ranges[0]); ++i)
240: if (blocks <= ranges[i])
241: break;
242: return (blocks + i);
243: }
244:
245: /*
246: * Print out a size line.
247: */
248: prsize(blocks)
249: fsize_t blocks;
250: {
251: printf("%ld\t%s\n", blocks, fname);
252: }
253:
254: /*
255: * Build up the next entry
256: * in the name.
257: */
258: char *
259: buildname(dp, ep)
260: struct direct *dp;
261: register char *ep;
262: {
263: register char *cp = dp->d_name;
264: register unsigned n = DIRSIZ;
265:
266: if (ep+DIRSIZ+2 >= &fname[NFNAME]) {
267: dumsg(toodeep);
268: return (NULL);
269: }
270: if (ep[-1] != '/')
271: *ep++ = '/';
272: do {
273: if (*cp == '\0')
274: break;
275: *ep++ = *cp++;
276: } while (--n);
277: *ep = '\0';
278: return (ep);
279: }
280:
281: /*
282: * Add an entry to the table
283: * of i-numbers with multiple links.
284: * If there are too many multi-link files,
285: * they will get counted twice.
286: * Return 1 if already there.
287: */
288: addlink(dev, ino)
289: register dev_t dev;
290: register ino_t ino;
291: {
292: register struct linktab *lp;
293:
294: for (lp = linktab; lp<ltp; lp++)
295: if (lp->l_ino==ino && lp->l_dev==dev)
296: return (1);
297: if (lp-linktab >= NLINK)
298: return (0);
299: lp->l_ino = ino;
300: lp->l_dev = dev;
301: ltp++;
302: return (0);
303: }
304:
305: void
306: usage()
307: {
308: fprintf(stderr, "Usage: du [-s] [name ...]\n");
309: exit(1);
310: }
311:
312: /* VARARGS */
313: void
314: duerr(x)
315: {
316: fprintf(stderr, "du: %r\n", &x);
317: exit (1);
318: }
319:
320: /* VARARGS */
321: void
322: dumsg(x)
323: {
324: fprintf(stderr, "du: %r\n", &x);
325: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.