Deleted Added
full compact
1/*
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Newcomb.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char copyright[] =
39"@(#) Copyright (c) 1989, 1993, 1994\n\
40 The Regents of the University of California. All rights reserved.\n";
41#endif /* not lint */
42
43#ifndef lint
44static char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95";
45#endif /* not lint */
46
47
48#include <sys/param.h>
49#include <sys/stat.h>
50
51#include <dirent.h>
52#include <err.h>
53#include <errno.h>
54#include <fts.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <unistd.h>
59
60int linkchk __P((FTSENT *));
61static void usage __P((void));
62
63int
64main(argc, argv)
65 int argc;
66 char *argv[];
67{
68 FTS *fts;
69 FTSENT *p;
70 long blocksize, savednumber = 0;
71 int ftsoptions;
72 int listall;
73 int depth;
74 int Hflag, Lflag, Pflag, aflag, sflag, dflag, cflag, ch, notused, rval;
75 char **save;
76
77 Hflag = Lflag = Pflag = aflag = sflag = dflag = cflag = 0;
78
79 save = argv;
80 ftsoptions = 0;
81 depth = INT_MAX;
82
83 while ((ch = getopt(argc, argv, "HLPad:ksxc")) != -1)
84 switch (ch) {
85 case 'H':
86 Hflag = 1;
87 break;
88 case 'L':
89 if (Pflag)
90 usage();
91 Lflag = 1;
92 break;
93 case 'P':
94 if (Lflag)
95 usage();
96 Pflag = 1;
97 break;
98 case 'a':
99 aflag = 1;
100 break;
101 case 'k':
102 putenv("BLOCKSIZE=1024");
103 break;
104 case 's':
105 sflag = 1;
106 break;
107 case 'x':
108 ftsoptions |= FTS_XDEV;
109 break;
110 case 'd':
111 dflag = 1;
112 errno = 0;
113 depth = atoi(optarg);
114 if (errno == ERANGE || depth < 0) {
115 (void) fprintf(stderr, "Invalid argument to option d: %s", optarg);
116 usage();
117 }
118 break;
119 case 'c':
120 cflag = 1;
121 break;
122 case '?':
123 case 'h':
124 default:
125 usage();
126 }
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
144 if (Hflag + Lflag + Pflag > 1)
145 usage();
146
147 if (Hflag + Lflag + Pflag == 0)
148 Pflag = 1; /* -P (physical) is default */
149
150 if (Hflag)
151 ftsoptions |= FTS_COMFOLLOW;
152
153 if (Lflag)
154 ftsoptions |= FTS_LOGICAL;
155
156 if (Pflag)
157 ftsoptions |= FTS_PHYSICAL;
158
159 listall = 0;
160
161 if (aflag) {
162 if (sflag || dflag)
163 usage();
164 listall = 1;
165 } else if (sflag) {
166 if (dflag)
167 usage();
168 depth = 0;
169 }
170
171 if (!*argv) {
172 argv = save;
173 argv[0] = ".";
174 argv[1] = NULL;
175 }
176
177 (void) getbsize(&notused, &blocksize);
178 blocksize /= 512;
179
180 rval = 0;
181
182 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
183 err(1, "fts_open");
184
185 while ((p = fts_read(fts)) != NULL) {
186 switch (p->fts_info) {
187 case FTS_D: /* Ignore. */
188 break;
189 case FTS_DP:
190 p->fts_parent->fts_number +=
191 p->fts_number += p->fts_statp->st_blocks;
192
193 if (p->fts_level <= depth)
194 (void) printf("%ld\t%s\n",
195 howmany(p->fts_number, blocksize),
196 p->fts_path);
197 break;
198 case FTS_DC: /* Ignore. */
199 break;
200 case FTS_DNR: /* Warn, continue. */
201 case FTS_ERR:
202 case FTS_NS:
203 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
204 rval = 1;
205 break;
206 default:
207 if (p->fts_statp->st_nlink > 1 && linkchk(p))
208 break;
209
210 if (listall || p->fts_level == 0)
211 (void) printf("%qd\t%s\n",
212 howmany(p->fts_statp->st_blocks, blocksize),
213 p->fts_path);
214
215 p->fts_parent->fts_number += p->fts_statp->st_blocks;
216 }
217 savednumber = p->fts_number;
217 savednumber = p->fts_parent->fts_number;
218 }
219
220 if (errno)
221 err(1, "fts_read");
222
223 if (cflag)
224 (void) printf("%ld\ttotal\n", howmany(savednumber, blocksize));
225
226 exit(rval);
227}
228
229
230typedef struct _ID {
231 dev_t dev;
232 ino_t inode;
233} ID;
234
235
236int
237linkchk(p)
238 FTSENT *p;
239{
240 static ID *files;
241 static int maxfiles, nfiles;
242 ID *fp, *start;
243 ino_t ino;
244 dev_t dev;
245
246 ino = p->fts_statp->st_ino;
247 dev = p->fts_statp->st_dev;
248 if ((start = files) != NULL)
249 for (fp = start + nfiles - 1; fp >= start; --fp)
250 if (ino == fp->inode && dev == fp->dev)
251 return (1);
252
253 if (nfiles == maxfiles && (files = realloc((char *)files,
254 (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL)
255 err(1, "can't allocate memory");
256 files[nfiles].inode = ino;
257 files[nfiles].dev = dev;
258 ++nfiles;
259 return (0);
260}
261
262static void
263usage()
264{
265 (void)fprintf(stderr,
266 "usage: du [-H | -L | -P] [-a | -s | -d depth] [-k] [-x] [file ...]\n");
267 exit(1);
268}