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