du.c revision 1.11 1 /* $NetBSD: du.c,v 1.11 1996/10/18 07:20:35 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Newcomb.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 static char copyright[] =
41 "@(#) Copyright (c) 1989, 1993, 1994\n\
42 The Regents of the University of California. All rights reserved.\n";
43 #endif /* not lint */
44
45 #ifndef lint
46 #if 0
47 static char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95";
48 #else
49 static char rcsid[] = "$NetBSD: du.c,v 1.11 1996/10/18 07:20:35 thorpej Exp $";
50 #endif
51 #endif /* not lint */
52
53 #include <sys/types.h>
54 #include <sys/stat.h>
55
56 #include <dirent.h>
57 #include <err.h>
58 #include <errno.h>
59 #include <fts.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64
65 int linkchk __P((FTSENT *));
66 void usage __P((void));
67
68 int
69 main(argc, argv)
70 int argc;
71 char *argv[];
72 {
73 FTS *fts;
74 FTSENT *p;
75 long blocksize, totalblocks;
76 int ftsoptions, listdirs, listfiles;
77 int Hflag, Lflag, Pflag, aflag, ch, cflag, kflag, notused, rval, sflag;
78 char **save;
79
80 save = argv;
81 Hflag = Lflag = Pflag = aflag = cflag = kflag = sflag = 0;
82 totalblocks = 0;
83 ftsoptions = FTS_PHYSICAL;
84 while ((ch = getopt(argc, argv, "HLPacksx")) != 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 'c':
102 cflag = 1;
103 break;
104 case 'k':
105 blocksize = 1024;
106 kflag = 1;
107 break;
108 case 's':
109 sflag = 1;
110 break;
111 case 'x':
112 ftsoptions |= FTS_XDEV;
113 break;
114 case '?':
115 default:
116 usage();
117 }
118 argc -= optind;
119 argv += optind;
120
121 /*
122 * XXX
123 * Because of the way that fts(3) works, logical walks will not count
124 * the blocks actually used by symbolic links. We rationalize this by
125 * noting that users computing logical sizes are likely to do logical
126 * copies, so not counting the links is correct. The real reason is
127 * that we'd have to re-implement the kernel's symbolic link traversing
128 * algorithm to get this right. If, for example, you have relative
129 * symbolic links referencing other relative symbolic links, it gets
130 * very nasty, very fast. The bottom line is that it's documented in
131 * the man page, so it's a feature.
132 */
133 if (Hflag)
134 ftsoptions |= FTS_COMFOLLOW;
135 if (Lflag) {
136 ftsoptions &= ~FTS_PHYSICAL;
137 ftsoptions |= FTS_LOGICAL;
138 }
139
140 if (aflag) {
141 if (sflag)
142 usage();
143 listdirs = listfiles = 1;
144 } else if (sflag)
145 listdirs = listfiles = 0;
146 else {
147 listfiles = 0;
148 listdirs = 1;
149 }
150
151 if (!*argv) {
152 argv = save;
153 argv[0] = ".";
154 argv[1] = NULL;
155 }
156
157 if (!kflag)
158 (void)getbsize(¬used, &blocksize);
159 blocksize /= 512;
160
161 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
162 err(1, NULL);
163
164 for (rval = 0; (p = fts_read(fts)) != NULL;)
165 switch (p->fts_info) {
166 case FTS_D: /* Ignore. */
167 break;
168 case FTS_DP:
169 p->fts_parent->fts_number +=
170 p->fts_number += p->fts_statp->st_blocks;
171 if (cflag)
172 totalblocks += p->fts_statp->st_blocks;
173 /*
174 * If listing each directory, or not listing files
175 * or directories and this is post-order of the
176 * root of a traversal, display the total.
177 */
178 if (listdirs || !listfiles && !p->fts_level)
179 (void)printf("%ld\t%s\n",
180 howmany(p->fts_number, blocksize),
181 p->fts_path);
182 break;
183 case FTS_DC: /* Ignore. */
184 break;
185 case FTS_DNR: /* Warn, continue. */
186 case FTS_ERR:
187 case FTS_NS:
188 warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
189 rval = 1;
190 break;
191 default:
192 if (p->fts_statp->st_nlink > 1 && linkchk(p))
193 break;
194 /*
195 * If listing each file, or a non-directory file was
196 * the root of a traversal, display the total.
197 */
198 if (listfiles || !p->fts_level)
199 (void)printf("%qd\t%s\n",
200 howmany(p->fts_statp->st_blocks, blocksize),
201 p->fts_path);
202 p->fts_parent->fts_number += p->fts_statp->st_blocks;
203 if (cflag)
204 totalblocks += p->fts_statp->st_blocks;
205 }
206 if (errno)
207 err(1, "fts_read");
208 if (cflag)
209 (void)printf("%ld\ttotal\n",
210 howmany(totalblocks, blocksize));
211 exit(0);
212 }
213
214 typedef struct _ID {
215 dev_t dev;
216 ino_t inode;
217 } ID;
218
219 int
220 linkchk(p)
221 FTSENT *p;
222 {
223 static ID *files;
224 static int maxfiles, nfiles;
225 ID *fp, *start;
226 ino_t ino;
227 dev_t dev;
228
229 ino = p->fts_statp->st_ino;
230 dev = p->fts_statp->st_dev;
231 if ((start = files) != NULL)
232 for (fp = start + nfiles - 1; fp >= start; --fp)
233 if (ino == fp->inode && dev == fp->dev)
234 return (1);
235
236 if (nfiles == maxfiles && (files = realloc((char *)files,
237 (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL)
238 err(1, "");
239 files[nfiles].inode = ino;
240 files[nfiles].dev = dev;
241 ++nfiles;
242 return (0);
243 }
244
245 void
246 usage()
247 {
248
249 (void)fprintf(stderr,
250 "usage: du [-H | -L | -P] [-a | -s] [-ckx] [file ...]\n");
251 exit(1);
252 }
253