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