du.c revision 1.3 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.12 (Berkeley) 6/20/91";*/
45 static char rcsid[] = "$Id: du.c,v 1.3 1993/08/06 01:36:45 deraadt 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 main(argc, argv)
58 int argc;
59 char **argv;
60 {
61 extern int optind;
62 register FTS *fts;
63 register FTSENT *p;
64 register int kvalue, listdirs, listfiles;
65 int aflag, ch, ftsoptions, sflag;
66 char **save;
67
68 ftsoptions = FTS_PHYSICAL;
69 kvalue = 0;
70 save = argv;
71 aflag = sflag = 0;
72 while ((ch = getopt(argc, argv, "aksx")) != EOF)
73 switch(ch) {
74 case 'a':
75 aflag = 1;
76 break;
77 case 'k':
78 kvalue = 1;
79 break;
80 case 's':
81 sflag = 1;
82 break;
83 case 'x':
84 ftsoptions |= FTS_XDEV;
85 break;
86 case '?':
87 default:
88 usage();
89 }
90 argv += optind;
91
92 if (aflag) {
93 if (sflag)
94 usage();
95 listdirs = listfiles = 1;
96 } else if (sflag)
97 listdirs = listfiles = 0;
98 else {
99 listfiles = 0;
100 listdirs = 1;
101 }
102
103 if (!*argv) {
104 argv = save;
105 argv[0] = ".";
106 argv[1] = NULL;
107 }
108
109 if (!(fts = fts_open(argv, ftsoptions, (int (*)())NULL))) {
110 (void)fprintf(stderr, "du: %s.\n", strerror(errno));
111 exit(1);
112 }
113
114 while (p = fts_read(fts))
115 switch(p->fts_info) {
116 case FTS_D:
117 break;
118 case FTS_DP:
119 p->fts_parent->fts_number +=
120 p->fts_number += p->fts_statp->st_blocks;
121 /*
122 * If listing each directory, or not listing files
123 * or directories and this is post-order of the
124 * root of a traversal, display the total.
125 */
126 if (listdirs || !listfiles && !p->fts_level)
127 (void)printf("%ld\t%s\n", kvalue ?
128 howmany(p->fts_number, 2) :
129 p->fts_number, p->fts_path);
130 break;
131 case FTS_DNR:
132 case FTS_ERR:
133 case FTS_NS:
134 (void)fprintf(stderr,
135 "du: %s: %s.\n", p->fts_path, strerror(errno));
136 break;
137 case FTS_SL:
138 if (p->fts_level == FTS_ROOTLEVEL) {
139 (void)fts_set(fts, p, FTS_FOLLOW);
140 break;
141 }
142 /* FALLTHROUGH */
143 default:
144 if (p->fts_statp->st_nlink > 1 && linkchk(p))
145 break;
146 /*
147 * If listing each file, or a non-directory file was
148 * the root of a traversal, display the total.
149 */
150 if (listfiles || !p->fts_level)
151 (void)printf("%ld\t%s\n", kvalue ?
152 howmany(p->fts_statp->st_blocks, 2) :
153 p->fts_statp->st_blocks, p->fts_path);
154 p->fts_parent->fts_number += p->fts_statp->st_blocks;
155 }
156 exit(0);
157 }
158
159 typedef struct _ID {
160 dev_t dev;
161 ino_t inode;
162 } ID;
163
164 linkchk(p)
165 register FTSENT *p;
166 {
167 static ID *files;
168 static int maxfiles, nfiles;
169 register ID *fp, *start;
170 register ino_t ino;
171 register dev_t dev;
172
173 ino = p->fts_statp->st_ino;
174 dev = p->fts_statp->st_dev;
175 if (start = files)
176 for (fp = start + nfiles - 1; fp >= start; --fp)
177 if (ino == fp->inode && dev == fp->dev)
178 return(1);
179
180 if (nfiles == maxfiles && !(files = (ID *)realloc((char *)files,
181 (u_int)(sizeof(ID) * (maxfiles += 128))))) {
182 (void)fprintf(stderr, "du: %s\n", strerror(errno));
183 exit(1);
184 }
185 files[nfiles].inode = ino;
186 files[nfiles].dev = dev;
187 ++nfiles;
188 return(0);
189 }
190
191 usage()
192 {
193 (void)fprintf(stderr, "usage: du [-a | -s] [-kx] [file ...]\n");
194 exit(1);
195 }
196