du.c revision 1.4 1 /*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * 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 char copyright[] =
39 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
40 All rights reserved.\n";
41 #endif /* not lint */
42
43 #ifndef lint
44 /*static char sccsid[] = "from: @(#)du.c 5.17 (Berkeley) 5/20/92";*/
45 static char rcsid[] = "$Id: du.c,v 1.4 1993/08/06 17:10:02 mycroft Exp $";
46 #endif /* not lint */
47
48 #include <sys/param.h>
49 #include <sys/stat.h>
50 #include <sys/errno.h>
51 #include <dirent.h>
52 #include <stdio.h>
53 #include <fts.h>
54 #include <string.h>
55 #include <stdlib.h>
56
57 void err __P((const char *, ...));
58 char *getbsize __P((char *, int *, long *, int));
59 int linkchk __P((FTSENT *));
60 void usage __P((void));
61
62 main(argc, argv)
63 int argc;
64 char *argv[];
65 {
66 register FTS *fts;
67 register FTSENT *p;
68 register int listdirs, listfiles;
69 long blocksize;
70 int aflag, ch, ftsoptions, notused, sflag, kflag;
71 char **save;
72
73 ftsoptions = FTS_PHYSICAL;
74 save = argv;
75 aflag = kflag = sflag = 0;
76 while ((ch = getopt(argc, argv, "aksx")) != EOF)
77 switch(ch) {
78 case 'a':
79 aflag = 1;
80 break;
81 case 'k':
82 blocksize = 1024;
83 kflag = 1;
84 break;
85 case 's':
86 sflag = 1;
87 break;
88 case 'x':
89 ftsoptions |= FTS_XDEV;
90 break;
91 case '?':
92 default:
93 usage();
94 }
95 argv += optind;
96
97 if (aflag) {
98 if (sflag)
99 usage();
100 listdirs = listfiles = 1;
101 } else if (sflag)
102 listdirs = listfiles = 0;
103 else {
104 listfiles = 0;
105 listdirs = 1;
106 }
107
108 if (!*argv) {
109 argv = save;
110 argv[0] = ".";
111 argv[1] = NULL;
112 }
113
114 (void)getbsize("du", ¬used, &blocksize, kflag);
115 blocksize /= 512;
116
117 if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
118 err("%s", strerror(errno));
119
120 while (p = fts_read(fts))
121 switch(p->fts_info) {
122 case FTS_D:
123 break;
124 case FTS_DP:
125 p->fts_parent->fts_number +=
126 p->fts_number += p->fts_statp->st_blocks;
127 /*
128 * If listing each directory, or not listing files
129 * or directories and this is post-order of the
130 * root of a traversal, display the total.
131 */
132 if (listdirs || !listfiles && !p->fts_level)
133 (void)printf("%ld\t%s\n",
134 howmany(p->fts_number, blocksize),
135 p->fts_path);
136 break;
137 case FTS_DNR:
138 case FTS_ERR:
139 case FTS_NS:
140 (void)fprintf(stderr,
141 "du: %s: %s\n", p->fts_path, strerror(errno));
142 break;
143 case FTS_SL:
144 if (p->fts_level == FTS_ROOTLEVEL) {
145 (void)fts_set(fts, p, FTS_FOLLOW);
146 break;
147 }
148 /* FALLTHROUGH */
149 default:
150 if (p->fts_statp->st_nlink > 1 && linkchk(p))
151 break;
152 /*
153 * If listing each file, or a non-directory file was
154 * the root of a traversal, display the total.
155 */
156 if (listfiles || !p->fts_level)
157 (void)printf("%ld\t%s\n",
158 howmany(p->fts_statp->st_blocks, blocksize),
159 p->fts_path);
160 p->fts_parent->fts_number += p->fts_statp->st_blocks;
161 }
162 if (errno)
163 err("%s", strerror(errno));
164 exit(0);
165 }
166
167 typedef struct _ID {
168 dev_t dev;
169 ino_t inode;
170 } ID;
171
172 int
173 linkchk(p)
174 register FTSENT *p;
175 {
176 static ID *files;
177 static int maxfiles, nfiles;
178 register ID *fp, *start;
179 register ino_t ino;
180 register dev_t dev;
181
182 ino = p->fts_statp->st_ino;
183 dev = p->fts_statp->st_dev;
184 if (start = files)
185 for (fp = start + nfiles - 1; fp >= start; --fp)
186 if (ino == fp->inode && dev == fp->dev)
187 return(1);
188
189 if (nfiles == maxfiles && (files = realloc((char *)files,
190 (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL)
191 err("%s", strerror(errno));
192 files[nfiles].inode = ino;
193 files[nfiles].dev = dev;
194 ++nfiles;
195 return(0);
196 }
197
198 void
199 usage()
200 {
201 (void)fprintf(stderr, "usage: du [-a | -s] [-x] [file ...]\n");
202 exit(1);
203 }
204
205 #if __STDC__
206 #include <stdarg.h>
207 #else
208 #include <varargs.h>
209 #endif
210
211 void
212 #if __STDC__
213 err(const char *fmt, ...)
214 #else
215 err(fmt, va_alist)
216 char *fmt;
217 va_dcl
218 #endif
219 {
220 va_list ap;
221 #if __STDC__
222 va_start(ap, fmt);
223 #else
224 va_start(ap);
225 #endif
226 (void)fprintf(stderr, "du: ");
227 (void)vfprintf(stderr, fmt, ap);
228 va_end(ap);
229 (void)fprintf(stderr, "\n");
230 exit(1);
231 /* NOTREACHED */
232 }
233