Annotation of src/usr.bin/du/du.c, Revision 1.7
1.7 ! pjanzen 1: /* $OpenBSD: du.c,v 1.6 2000/04/16 04:21:34 ericj 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.7 ! pjanzen 50: static char rcsid[] = "$OpenBSD: du.c,v 1.6 2000/04/16 04:21:34 ericj 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: blocksize = 1024;
114: kflag = 1;
115: break;
116: case 's':
117: sflag = 1;
118: break;
1.5 deraadt 119: case 'r':
120: break;
1.1 deraadt 121: case 'x':
122: ftsoptions |= FTS_XDEV;
123: break;
124: case '?':
125: default:
126: usage();
127: }
128: argc -= optind;
129: argv += optind;
130:
131: /*
132: * XXX
133: * Because of the way that fts(3) works, logical walks will not count
134: * the blocks actually used by symbolic links. We rationalize this by
135: * noting that users computing logical sizes are likely to do logical
136: * copies, so not counting the links is correct. The real reason is
137: * that we'd have to re-implement the kernel's symbolic link traversing
138: * algorithm to get this right. If, for example, you have relative
139: * symbolic links referencing other relative symbolic links, it gets
140: * very nasty, very fast. The bottom line is that it's documented in
141: * the man page, so it's a feature.
142: */
143: if (Hflag)
144: ftsoptions |= FTS_COMFOLLOW;
145: if (Lflag) {
146: ftsoptions &= ~FTS_PHYSICAL;
147: ftsoptions |= FTS_LOGICAL;
148: }
149:
150: if (aflag) {
151: if (sflag)
152: usage();
153: listdirs = listfiles = 1;
154: } else if (sflag)
155: listdirs = listfiles = 0;
156: else {
157: listfiles = 0;
158: listdirs = 1;
159: }
160:
161: if (!*argv) {
162: argv = save;
163: argv[0] = ".";
164: argv[1] = NULL;
165: }
166:
1.7 ! pjanzen 167: if (!kflag || hflag)
1.1 deraadt 168: (void)getbsize(¬used, &blocksize);
169: blocksize /= 512;
170:
171: if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
1.3 millert 172: err(1, "fts_open");
1.1 deraadt 173:
174: for (rval = 0; (p = fts_read(fts)) != NULL;)
175: switch (p->fts_info) {
176: case FTS_D: /* Ignore. */
177: break;
178: case FTS_DP:
179: p->fts_parent->fts_number +=
180: p->fts_number += p->fts_statp->st_blocks;
1.3 millert 181: if (cflag)
182: totalblocks += p->fts_statp->st_blocks;
1.1 deraadt 183: /*
184: * If listing each directory, or not listing files
185: * or directories and this is post-order of the
186: * root of a traversal, display the total.
187: */
1.3 millert 188: if (listdirs || (!listfiles && !p->fts_level))
1.7 ! pjanzen 189: prtout((quad_t)howmany(p->fts_number, blocksize),
! 190: p->fts_path, hflag);
1.1 deraadt 191: break;
192: case FTS_DC: /* Ignore. */
193: break;
194: case FTS_DNR: /* Warn, continue. */
195: case FTS_ERR:
196: case FTS_NS:
197: warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
198: rval = 1;
199: break;
200: default:
201: if (p->fts_statp->st_nlink > 1 && linkchk(p))
202: break;
203: /*
204: * If listing each file, or a non-directory file was
205: * the root of a traversal, display the total.
206: */
207: if (listfiles || !p->fts_level)
1.7 ! pjanzen 208: prtout(howmany(p->fts_statp->st_blocks, blocksize),
! 209: p->fts_path, hflag);
1.1 deraadt 210: p->fts_parent->fts_number += p->fts_statp->st_blocks;
1.3 millert 211: if (cflag)
212: totalblocks += p->fts_statp->st_blocks;
1.1 deraadt 213: }
214: if (errno)
215: err(1, "fts_read");
1.7 ! pjanzen 216: if (cflag) {
! 217: prtout((quad_t)howmany(totalblocks, blocksize), "total", hflag);
! 218: }
1.6 ericj 219: exit(rval);
1.1 deraadt 220: }
221:
222: typedef struct _ID {
223: dev_t dev;
224: ino_t inode;
225: } ID;
226:
227: int
228: linkchk(p)
229: FTSENT *p;
230: {
231: static ID *files;
232: static int maxfiles, nfiles;
233: ID *fp, *start;
234: ino_t ino;
235: dev_t dev;
236:
237: ino = p->fts_statp->st_ino;
238: dev = p->fts_statp->st_dev;
239: if ((start = files) != NULL)
240: for (fp = start + nfiles - 1; fp >= start; --fp)
241: if (ino == fp->inode && dev == fp->dev)
242: return (1);
243:
244: if (nfiles == maxfiles && (files = realloc((char *)files,
245: (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL)
1.3 millert 246: err(1, "can't allocate memory");
1.1 deraadt 247: files[nfiles].inode = ino;
248: files[nfiles].dev = dev;
249: ++nfiles;
250: return (0);
251: }
252:
1.7 ! pjanzen 253: /*
! 254: * "human-readable" output: use 3 digits max.--put unit suffixes at
! 255: * the end. Makes output compact and easy-to-read.
! 256: */
! 257:
! 258: typedef enum { NONE = 0, KILO, MEGA, GIGA, TERA, PETA /* , EXA */ } unit_t;
! 259:
! 260: unit_t
! 261: unit_adjust(val)
! 262: double *val;
! 263: {
! 264: double abval;
! 265: unit_t unit;
! 266:
! 267: abval = fabs(*val);
! 268: if (abval < 1024)
! 269: unit = NONE;
! 270: else if (abval < 1048576ULL) {
! 271: unit = KILO;
! 272: *val /= 1024;
! 273: } else if (abval < 1073741824ULL) {
! 274: unit = MEGA;
! 275: *val /= 1048576;
! 276: } else if (abval < 1099511627776ULL) {
! 277: unit = GIGA;
! 278: *val /= 1073741824ULL;
! 279: } else if (abval < 1125899906842624ULL) {
! 280: unit = TERA;
! 281: *val /= 1099511627776ULL;
! 282: } else /* if (abval < 1152921504606846976ULL) */ {
! 283: unit = PETA;
! 284: *val /= 1125899906842624ULL;
! 285: }
! 286: return (unit);
! 287: }
! 288:
! 289: void
! 290: prtout(size, path, hflag)
! 291: quad_t size;
! 292: char *path;
! 293: int hflag;
! 294: {
! 295: unit_t unit;
! 296: double bytes;
! 297:
! 298: if (!hflag)
! 299: (void)printf("%qd\t%s\n", size, path);
! 300: else {
! 301: bytes = (double)size * 512.0;
! 302: unit = unit_adjust(&bytes);
! 303:
! 304: if (bytes == 0)
! 305: (void)printf(" 0B\t%s\n", path);
! 306: else if (bytes > 10)
! 307: (void)printf("%.0f%c\t%s\n", bytes, "BKMGTPE"[unit], path);
! 308: else
! 309: (void)printf("%.1f%c\t%s\n", bytes, "BKMGTPE"[unit], path);
! 310: }
! 311: }
! 312:
1.1 deraadt 313: void
314: usage()
315: {
316:
317: (void)fprintf(stderr,
1.7 ! pjanzen 318: "usage: du [-H | -L | -P] [-a | -s] [-chkrx] [file ...]\n");
1.1 deraadt 319: exit(1);
320: }