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