source: trunk/minix/commands/simple/du.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 5.9 KB
Line 
1/* du - report on disk usage Author: Alistair G. Crooks */
2
3/*
4 * du.c 1.1 27/5/87 agc Joypace Ltd.
5 * 1.2 24 Mar 89 nick@nswitgould.oz
6 * 1.3 31 Mar 89 nick@nswitgould.oz
7 * 1.4 22 Feb 90 meulenbr@cst.prl.philips.nl
8 * 1.5 09 Jul 91 hp@vmars.tuwien.ac.at
9 * 1.6 01 Oct 92 kjb@cs.vu.nl
10 * 1.7 04 Jan 93 bde
11 * 1.8 19 Sep 94 kjb
12 * 1.9 28 Oct 99 kjb
13 *
14 * Copyright 1987, Joypace Ltd., London UK. All rights reserved.
15 * This code may be freely distributed, provided that this notice
16 * remains attached.
17 *
18 * du - a public domain interpretation of du(1).
19 *
20 * 1.2: Fixed bug involving 14 character long filenames
21 * 1.3: Add [-l levels] option to restrict printing.
22 * 1.4: Added processing of multiple arguments
23 * 1.5: Fixed processing of multiple arguments. General cleanup.
24 * 1.6: Use readdir
25 * 1.7: Merged 1.5 and 1.6.
26 * Print totals even for non-dirs at top level.
27 * Count blocks for each dir before printing total for the dir.
28 * Count blocks for all non-special files.
29 * Don't clutter link buffer with directories.
30 * 1.8: Remember all links.
31 * 1.9: Added -x flag to not cross device boundaries. Type fixes.
32 */
33
34
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <sys/statfs.h>
38#include <fcntl.h>
39#include <errno.h>
40#include <limits.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44#include <stdio.h>
45#include <dirent.h>
46#include <minix/config.h>
47#include <minix/const.h>
48
49extern char *optarg;
50extern int optind;
51
52#define LINELEN 256
53#define NR_ALREADY 512
54
55#ifdef S_IFLNK
56#define LSTAT lstat
57#else
58#define LSTAT stat
59#endif
60
61typedef struct already {
62 struct already *al_next;
63 int al_dev;
64 ino_t al_inum;
65 nlink_t al_nlink;
66} ALREADY;
67
68_PROTOTYPE(int main, (int argc, char **argv));
69_PROTOTYPE(int makedname, (char *d, char *f, char *out, int outlen));
70_PROTOTYPE(int done, (Dev_t dev, Ino_t inum, Nlink_t nlink));
71_PROTOTYPE(long dodir, (char *d, int thislev, Dev_t dev));
72
73char *prog; /* program name */
74char *optstr = "asxdl:"; /* options */
75int silent = 0; /* silent mode */
76int all = 0; /* all directory entries mode */
77int crosschk = 0; /* do not cross device boundaries mode */
78char *startdir = "."; /* starting from here */
79int levels = 20000; /* # of directory levels to print */
80ALREADY *already[NR_ALREADY];
81int alc;
82
83
84/*
85 * makedname - make the pathname from the directory name, and the
86 * directory entry, placing it in out. If this would overflow,
87 * return 0, otherwise 1.
88 */
89int makedname(d, f, out, outlen)
90char *d;
91char *f;
92char *out;
93int outlen;
94{
95 char *cp;
96 int length;
97
98 length = strlen(f);
99 if (strlen(d) + length + 2 > outlen) return(0);
100 for (cp = out; *d; *cp++ = *d++);
101 if (*(cp - 1) != '/') *cp++ = '/';
102 while (length--) *cp++ = *f++;
103 *cp = '\0';
104 return(1);
105}
106
107/*
108 * done - have we encountered (dev, inum) before? Returns 1 for yes,
109 * 0 for no, and remembers (dev, inum, nlink).
110 */
111int done(dev, inum, nlink)
112dev_t dev;
113ino_t inum;
114nlink_t nlink;
115{
116 register ALREADY **pap, *ap;
117
118 pap = &already[(unsigned) inum % NR_ALREADY];
119 while ((ap = *pap) != NULL) {
120 if (ap->al_inum == inum && ap->al_dev == dev) {
121 if (--ap->al_nlink == 0) {
122 *pap = ap->al_next;
123 free(ap);
124 }
125 return(1);
126 }
127 pap = &ap->al_next;
128 }
129 if ((ap = malloc(sizeof(*ap))) == NULL) {
130 fprintf(stderr, "du: Out of memory\n");
131 exit(1);
132 }
133 ap->al_next = NULL;
134 ap->al_inum = inum;
135 ap->al_dev = dev;
136 ap->al_nlink = nlink - 1;
137 *pap = ap;
138 return(0);
139}
140
141int get_block_size(char *dir, struct stat *st)
142{
143 struct statfs stfs;
144 static int fs_block_size = -1, fs_dev = -1;
145 int d;
146
147 if(st->st_dev == fs_dev)
148 return fs_block_size;
149
150 if((d = open(dir, O_RDONLY)) < 0) {
151 perror(dir);
152 return 0;
153 }
154
155 if(fstatfs(d, &stfs) < 0) {
156 perror(dir);
157 return 0;
158 }
159
160 fs_block_size = stfs.f_bsize;
161 fs_dev = st->st_dev;
162
163 return fs_block_size;
164}
165
166
167/*
168 * dodir - process the directory d. Return the long size (in blocks)
169 * of d and its descendants.
170 */
171long dodir(d, thislev, dev)
172char *d;
173int thislev;
174dev_t dev;
175{
176 int maybe_print;
177 struct stat s;
178 long total_kb;
179 char dent[LINELEN];
180 DIR *dp;
181 struct dirent *entry;
182 int block_size;
183
184 if (LSTAT(d, &s) < 0) {
185 fprintf(stderr,
186 "%s: %s: %s\n", prog, d, strerror(errno));
187 return 0L;
188 }
189 if (s.st_dev != dev && dev != 0 && crosschk) return 0;
190 block_size = get_block_size(d, &s);
191 if(block_size < 1) {
192 fprintf(stderr,
193 "%s: %s: funny block size found (%d)\n",
194 prog, d, block_size);
195 return 0L;
196 }
197 total_kb = ((s.st_size + (block_size - 1)) / block_size) * block_size / 1024;
198 switch (s.st_mode & S_IFMT) {
199 case S_IFDIR:
200 /* Directories should not be linked except to "." and "..", so this
201 * directory should not already have been done.
202 */
203 maybe_print = !silent;
204 if ((dp = opendir(d)) == NULL) break;
205 while ((entry = readdir(dp)) != NULL) {
206 if (strcmp(entry->d_name, ".") == 0 ||
207 strcmp(entry->d_name, "..") == 0)
208 continue;
209 if (!makedname(d, entry->d_name, dent, sizeof(dent))) continue;
210 total_kb += dodir(dent, thislev - 1, s.st_dev);
211 }
212 closedir(dp);
213 break;
214 case S_IFBLK:
215 case S_IFCHR:
216 /* st_size for special files is not related to blocks used. */
217 total_kb = 0;
218 /* Fall through. */
219 default:
220 if (s.st_nlink > 1 && done(s.st_dev, s.st_ino, s.st_nlink)) return 0L;
221 maybe_print = all;
222 break;
223 }
224 if (thislev >= levels || (maybe_print && thislev >= 0)) {
225 printf("%ld\t%s\n", total_kb, d);
226 }
227 return(total_kb);
228}
229
230int main(argc, argv)
231int argc;
232char **argv;
233{
234 int c;
235
236 prog = argv[0];
237 while ((c = getopt(argc, argv, optstr)) != EOF) switch (c) {
238 case 'a': all = 1; break;
239 case 's': silent = 1; break;
240 case 'x':
241 case 'd': crosschk = 1; break;
242 case 'l': levels = atoi(optarg); break;
243 default:
244 fprintf(stderr,
245 "Usage: %s [-asx] [-l levels] [startdir]\n", prog);
246 exit(1);
247 }
248 do {
249 if (optind < argc) startdir = argv[optind++];
250 alc = 0;
251 (void) dodir(startdir, levels, 0);
252 } while (optind < argc);
253 return(0);
254}
Note: See TracBrowser for help on using the repository browser.