Annotation of src/usr.bin/du/du.c, Revision 1.6
1.6 ! ericj 1: /* $OpenBSD: du.c,v 1.5 1998/02/16 09:23:06 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.6 ! ericj 50: static char rcsid[] = "$OpenBSD: du.c,v 1.5 1998/02/16 09:23:06 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>
61: #include <stdio.h>
62: #include <stdlib.h>
63: #include <string.h>
64: #include <unistd.h>
65:
66: int linkchk __P((FTSENT *));
67: void usage __P((void));
68:
69: int
70: main(argc, argv)
71: int argc;
72: char *argv[];
73: {
74: FTS *fts;
75: FTSENT *p;
1.3 millert 76: long blocksize, totalblocks;
1.1 deraadt 77: int ftsoptions, listdirs, listfiles;
1.3 millert 78: int Hflag, Lflag, Pflag, aflag, ch, cflag, kflag, notused, rval, sflag;
1.1 deraadt 79: char **save;
80:
81: save = argv;
1.3 millert 82: Hflag = Lflag = Pflag = aflag = cflag = kflag = sflag = 0;
83: totalblocks = 0;
1.1 deraadt 84: ftsoptions = FTS_PHYSICAL;
1.5 deraadt 85: while ((ch = getopt(argc, argv, "HLPacksxr")) != -1)
1.1 deraadt 86: switch (ch) {
87: case 'H':
88: Hflag = 1;
89: Lflag = Pflag = 0;
90: break;
91: case 'L':
92: Lflag = 1;
93: Hflag = Pflag = 0;
94: break;
95: case 'P':
96: Pflag = 1;
97: Hflag = Lflag = 0;
98: break;
99: case 'a':
100: aflag = 1;
101: break;
1.3 millert 102: case 'c':
103: cflag = 1;
104: break;
1.1 deraadt 105: case 'k':
106: blocksize = 1024;
107: kflag = 1;
108: break;
109: case 's':
110: sflag = 1;
111: break;
1.5 deraadt 112: case 'r':
113: break;
1.1 deraadt 114: case 'x':
115: ftsoptions |= FTS_XDEV;
116: break;
117: case '?':
118: default:
119: usage();
120: }
121: argc -= optind;
122: argv += optind;
123:
124: /*
125: * XXX
126: * Because of the way that fts(3) works, logical walks will not count
127: * the blocks actually used by symbolic links. We rationalize this by
128: * noting that users computing logical sizes are likely to do logical
129: * copies, so not counting the links is correct. The real reason is
130: * that we'd have to re-implement the kernel's symbolic link traversing
131: * algorithm to get this right. If, for example, you have relative
132: * symbolic links referencing other relative symbolic links, it gets
133: * very nasty, very fast. The bottom line is that it's documented in
134: * the man page, so it's a feature.
135: */
136: if (Hflag)
137: ftsoptions |= FTS_COMFOLLOW;
138: if (Lflag) {
139: ftsoptions &= ~FTS_PHYSICAL;
140: ftsoptions |= FTS_LOGICAL;
141: }
142:
143: if (aflag) {
144: if (sflag)
145: usage();
146: listdirs = listfiles = 1;
147: } else if (sflag)
148: listdirs = listfiles = 0;
149: else {
150: listfiles = 0;
151: listdirs = 1;
152: }
153:
154: if (!*argv) {
155: argv = save;
156: argv[0] = ".";
157: argv[1] = NULL;
158: }
159:
160: if (!kflag)
161: (void)getbsize(¬used, &blocksize);
162: blocksize /= 512;
163:
164: if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
1.3 millert 165: err(1, "fts_open");
1.1 deraadt 166:
167: for (rval = 0; (p = fts_read(fts)) != NULL;)
168: switch (p->fts_info) {
169: case FTS_D: /* Ignore. */
170: break;
171: case FTS_DP:
172: p->fts_parent->fts_number +=
173: p->fts_number += p->fts_statp->st_blocks;
1.3 millert 174: if (cflag)
175: totalblocks += p->fts_statp->st_blocks;
1.1 deraadt 176: /*
177: * If listing each directory, or not listing files
178: * or directories and this is post-order of the
179: * root of a traversal, display the total.
180: */
1.3 millert 181: if (listdirs || (!listfiles && !p->fts_level))
1.1 deraadt 182: (void)printf("%ld\t%s\n",
183: howmany(p->fts_number, blocksize),
184: p->fts_path);
185: break;
186: case FTS_DC: /* Ignore. */
187: break;
188: case FTS_DNR: /* Warn, continue. */
189: case FTS_ERR:
190: case FTS_NS:
191: warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
192: rval = 1;
193: break;
194: default:
195: if (p->fts_statp->st_nlink > 1 && linkchk(p))
196: break;
197: /*
198: * If listing each file, or a non-directory file was
199: * the root of a traversal, display the total.
200: */
201: if (listfiles || !p->fts_level)
202: (void)printf("%qd\t%s\n",
203: howmany(p->fts_statp->st_blocks, blocksize),
204: p->fts_path);
205: p->fts_parent->fts_number += p->fts_statp->st_blocks;
1.3 millert 206: if (cflag)
207: totalblocks += p->fts_statp->st_blocks;
1.1 deraadt 208: }
209: if (errno)
210: err(1, "fts_read");
1.3 millert 211: if (cflag)
212: (void)printf("%ld\ttotal\n",
213: howmany(totalblocks, blocksize));
1.6 ! ericj 214: exit(rval);
1.1 deraadt 215: }
216:
217: typedef struct _ID {
218: dev_t dev;
219: ino_t inode;
220: } ID;
221:
222: int
223: linkchk(p)
224: FTSENT *p;
225: {
226: static ID *files;
227: static int maxfiles, nfiles;
228: ID *fp, *start;
229: ino_t ino;
230: dev_t dev;
231:
232: ino = p->fts_statp->st_ino;
233: dev = p->fts_statp->st_dev;
234: if ((start = files) != NULL)
235: for (fp = start + nfiles - 1; fp >= start; --fp)
236: if (ino == fp->inode && dev == fp->dev)
237: return (1);
238:
239: if (nfiles == maxfiles && (files = realloc((char *)files,
240: (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL)
1.3 millert 241: err(1, "can't allocate memory");
1.1 deraadt 242: files[nfiles].inode = ino;
243: files[nfiles].dev = dev;
244: ++nfiles;
245: return (0);
246: }
247:
248: void
249: usage()
250: {
251:
252: (void)fprintf(stderr,
1.5 deraadt 253: "usage: du [-H | -L | -P] [-a | -s] [-ckrx] [file ...]\n");
1.1 deraadt 254: exit(1);
255: }