Annotation of src/usr.bin/du/du.c, Revision 1.10
1.10 ! deraadt 1: /* $OpenBSD: du.c,v 1.9 2001/07/12 05:17:00 deraadt Exp $ */
1.3 millert 2: /* $NetBSD: du.c,v 1.11 1996/10/18 07:20:35 thorpej Exp $ */
1.1 deraadt 3:
4: /*
5: * Copyright (c) 1989, 1993, 1994
6: * The Regents of the University of California. All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * Chris Newcomb.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the University of
22: * California, Berkeley and its contributors.
23: * 4. Neither the name of the University nor the names of its contributors
24: * may be used to endorse or promote products derived from this software
25: * without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37: * SUCH DAMAGE.
38: */
39:
40: #ifndef lint
41: static char copyright[] =
42: "@(#) Copyright (c) 1989, 1993, 1994\n\
43: The Regents of the University of California. All rights reserved.\n";
44: #endif /* not lint */
45:
46: #ifndef lint
47: #if 0
48: static char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95";
49: #else
1.10 ! deraadt 50: static char rcsid[] = "$OpenBSD: du.c,v 1.9 2001/07/12 05:17:00 deraadt Exp $";
1.1 deraadt 51: #endif
52: #endif /* not lint */
53:
54: #include <sys/types.h>
55: #include <sys/stat.h>
56:
57: #include <dirent.h>
58: #include <err.h>
59: #include <errno.h>
60: #include <fts.h>
1.7 pjanzen 61: #include <math.h>
1.1 deraadt 62: #include <stdio.h>
63: #include <stdlib.h>
64: #include <string.h>
65: #include <unistd.h>
66:
67: int linkchk __P((FTSENT *));
1.7 pjanzen 68: void prtout __P((quad_t, char *, int));
1.1 deraadt 69: void usage __P((void));
70:
71: int
72: main(argc, argv)
73: int argc;
74: char *argv[];
75: {
76: FTS *fts;
77: FTSENT *p;
1.7 pjanzen 78: long blocksize;
79: quad_t totalblocks;
1.1 deraadt 80: int ftsoptions, listdirs, listfiles;
1.7 pjanzen 81: int Hflag, Lflag, Pflag, aflag, cflag, hflag, kflag, sflag;
82: int ch, notused, rval;
1.1 deraadt 83: char **save;
84:
85: save = argv;
1.7 pjanzen 86: Hflag = Lflag = Pflag = aflag = cflag = hflag = kflag = sflag = 0;
1.3 millert 87: totalblocks = 0;
1.1 deraadt 88: ftsoptions = FTS_PHYSICAL;
1.7 pjanzen 89: while ((ch = getopt(argc, argv, "HLPachksxr")) != -1)
1.1 deraadt 90: switch (ch) {
91: case 'H':
92: Hflag = 1;
93: Lflag = Pflag = 0;
94: break;
95: case 'L':
96: Lflag = 1;
97: Hflag = Pflag = 0;
98: break;
99: case 'P':
100: Pflag = 1;
101: Hflag = Lflag = 0;
102: break;
103: case 'a':
104: aflag = 1;
105: break;
1.3 millert 106: case 'c':
107: cflag = 1;
108: break;
1.7 pjanzen 109: case 'h':
110: hflag = 1;
111: break;
1.1 deraadt 112: case 'k':
113: kflag = 1;
114: break;
115: case 's':
116: sflag = 1;
117: break;
1.5 deraadt 118: case 'r':
119: break;
1.1 deraadt 120: case 'x':
121: ftsoptions |= FTS_XDEV;
122: break;
123: case '?':
124: default:
125: usage();
126: }
127: argc -= optind;
128: argv += optind;
129:
130: /*
131: * XXX
132: * Because of the way that fts(3) works, logical walks will not count
133: * the blocks actually used by symbolic links. We rationalize this by
134: * noting that users computing logical sizes are likely to do logical
135: * copies, so not counting the links is correct. The real reason is
136: * that we'd have to re-implement the kernel's symbolic link traversing
137: * algorithm to get this right. If, for example, you have relative
138: * symbolic links referencing other relative symbolic links, it gets
139: * very nasty, very fast. The bottom line is that it's documented in
140: * the man page, so it's a feature.
141: */
142: if (Hflag)
143: ftsoptions |= FTS_COMFOLLOW;
144: if (Lflag) {
145: ftsoptions &= ~FTS_PHYSICAL;
146: ftsoptions |= FTS_LOGICAL;
147: }
148:
149: if (aflag) {
150: if (sflag)
151: usage();
152: listdirs = listfiles = 1;
153: } else if (sflag)
154: listdirs = listfiles = 0;
155: else {
156: listfiles = 0;
157: listdirs = 1;
158: }
159:
160: if (!*argv) {
161: argv = save;
162: argv[0] = ".";
163: argv[1] = NULL;
164: }
165:
1.8 pjanzen 166: if (hflag)
167: blocksize = 512;
168: else if (kflag)
169: blocksize = 1024;
170: else
1.1 deraadt 171: (void)getbsize(¬used, &blocksize);
172: blocksize /= 512;
173:
174: if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
1.3 millert 175: err(1, "fts_open");
1.1 deraadt 176:
177: for (rval = 0; (p = fts_read(fts)) != NULL;)
178: switch (p->fts_info) {
179: case FTS_D: /* Ignore. */
180: break;
181: case FTS_DP:
182: p->fts_parent->fts_number +=
183: p->fts_number += p->fts_statp->st_blocks;
1.3 millert 184: if (cflag)
185: totalblocks += p->fts_statp->st_blocks;
1.1 deraadt 186: /*
187: * If listing each directory, or not listing files
188: * or directories and this is post-order of the
189: * root of a traversal, display the total.
190: */
1.3 millert 191: if (listdirs || (!listfiles && !p->fts_level))
1.7 pjanzen 192: prtout((quad_t)howmany(p->fts_number, blocksize),
193: p->fts_path, hflag);
1.1 deraadt 194: break;
195: case FTS_DC: /* Ignore. */
196: break;
197: case FTS_DNR: /* Warn, continue. */
198: case FTS_ERR:
199: case FTS_NS:
200: warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
201: rval = 1;
202: break;
203: default:
204: if (p->fts_statp->st_nlink > 1 && linkchk(p))
205: break;
206: /*
207: * If listing each file, or a non-directory file was
208: * the root of a traversal, display the total.
209: */
210: if (listfiles || !p->fts_level)
1.7 pjanzen 211: prtout(howmany(p->fts_statp->st_blocks, blocksize),
212: p->fts_path, hflag);
1.1 deraadt 213: p->fts_parent->fts_number += p->fts_statp->st_blocks;
1.3 millert 214: if (cflag)
215: totalblocks += p->fts_statp->st_blocks;
1.1 deraadt 216: }
217: if (errno)
218: err(1, "fts_read");
1.7 pjanzen 219: if (cflag) {
220: prtout((quad_t)howmany(totalblocks, blocksize), "total", hflag);
221: }
1.6 ericj 222: exit(rval);
1.1 deraadt 223: }
224:
225: typedef struct _ID {
226: dev_t dev;
227: ino_t inode;
228: } ID;
229:
230: int
231: linkchk(p)
232: FTSENT *p;
233: {
234: static ID *files;
235: static int maxfiles, nfiles;
236: ID *fp, *start;
237: ino_t ino;
238: dev_t dev;
239:
240: ino = p->fts_statp->st_ino;
241: dev = p->fts_statp->st_dev;
242: if ((start = files) != NULL)
243: for (fp = start + nfiles - 1; fp >= start; --fp)
244: if (ino == fp->inode && dev == fp->dev)
245: return (1);
246:
247: if (nfiles == maxfiles && (files = realloc((char *)files,
248: (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL)
1.3 millert 249: err(1, "can't allocate memory");
1.1 deraadt 250: files[nfiles].inode = ino;
251: files[nfiles].dev = dev;
252: ++nfiles;
253: return (0);
254: }
255:
1.7 pjanzen 256: /*
257: * "human-readable" output: use 3 digits max.--put unit suffixes at
258: * the end. Makes output compact and easy-to-read.
259: */
260:
261: typedef enum { NONE = 0, KILO, MEGA, GIGA, TERA, PETA /* , EXA */ } unit_t;
262:
263: unit_t
264: unit_adjust(val)
265: double *val;
266: {
267: double abval;
268: unit_t unit;
269:
270: abval = fabs(*val);
271: if (abval < 1024)
272: unit = NONE;
273: else if (abval < 1048576ULL) {
274: unit = KILO;
275: *val /= 1024;
276: } else if (abval < 1073741824ULL) {
277: unit = MEGA;
278: *val /= 1048576;
279: } else if (abval < 1099511627776ULL) {
280: unit = GIGA;
281: *val /= 1073741824ULL;
282: } else if (abval < 1125899906842624ULL) {
283: unit = TERA;
284: *val /= 1099511627776ULL;
285: } else /* if (abval < 1152921504606846976ULL) */ {
286: unit = PETA;
287: *val /= 1125899906842624ULL;
288: }
289: return (unit);
290: }
291:
292: void
293: prtout(size, path, hflag)
294: quad_t size;
295: char *path;
296: int hflag;
297: {
298: unit_t unit;
299: double bytes;
300:
301: if (!hflag)
1.9 deraadt 302: (void)printf("%lld\t%s\n", (long long)size, path);
1.7 pjanzen 303: else {
304: bytes = (double)size * 512.0;
305: unit = unit_adjust(&bytes);
306:
307: if (bytes == 0)
1.10 ! deraadt 308: (void)printf("0B\t%s\n", path);
1.7 pjanzen 309: else if (bytes > 10)
310: (void)printf("%.0f%c\t%s\n", bytes, "BKMGTPE"[unit], path);
311: else
312: (void)printf("%.1f%c\t%s\n", bytes, "BKMGTPE"[unit], path);
313: }
314: }
315:
1.1 deraadt 316: void
317: usage()
318: {
319:
320: (void)fprintf(stderr,
1.7 pjanzen 321: "usage: du [-H | -L | -P] [-a | -s] [-chkrx] [file ...]\n");
1.1 deraadt 322: exit(1);
323: }