xref: /original-bsd/usr.bin/du/du.c (revision d25e1985)
1 static char *sccsid = "@(#)du.c	4.1 (Berkeley) 10/01/80";
2 #include <stdio.h>
3 #include <sys/param.h>
4 #include <sys/stat.h>
5 #include <sys/dir.h>
6 #define EQ(x,y)	(strcmp(x,y)==0)
7 #define ML	1000
8 
9 struct stat Statb;
10 char	path[256], name[256];
11 int	Aflag = 0,
12 	Sflag = 0,
13 	Noarg = 0;
14 struct {
15 	int	dev,
16 		ino;
17 } ml[ML];
18 long	descend();
19 char	*rindex();
20 char	*strcpy();
21 
22 main(argc, argv)
23 char **argv;
24 {
25 	register	i = 1;
26 	long	blocks = 0;
27 	register char	*np;
28 
29 	if (argc>1) {
30 		if(EQ(argv[i], "-s")) {
31 			++i;
32 			++Sflag;
33 		} else if(EQ(argv[i], "-a")) {
34 			++i;
35 			++Aflag;
36 		}
37 	}
38 	if(i == argc)
39 		++Noarg;
40 
41 	do {
42 		strcpy(path, Noarg? ".": argv[i]);
43 		strcpy(name, path);
44 		if(np = rindex(name, '/')) {
45 			*np++ = '\0';
46 			if(chdir(*name? name: "/") == -1) {
47 				fprintf(stderr, "cannot chdir()\n");
48 				exit(1);
49 			}
50 		} else
51 			np = path;
52 		blocks = descend(path, *np? np: ".");
53 		if(Sflag)
54 			printf("%ld	%s\n", blocks, path);
55 	} while(++i < argc);
56 
57 	exit(0);
58 }
59 
60 long
61 descend(np, fname)
62 char *np, *fname;
63 {
64 	int dir = 0, /* open directory */
65 		offset,
66 		dsize,
67 		entries,
68 		dirsize;
69 
70 	struct direct dentry[BUFSIZ / sizeof (struct direct)];
71 	register  struct direct *dp;
72 	register char *c1, *c2;
73 	int i;
74 	char *endofname;
75 	long blocks = 0;
76 
77 	if(stat(fname,&Statb)<0) {
78 		fprintf(stderr, "--bad status < %s >\n", name);
79 		return 0L;
80 	}
81 	if(Statb.st_nlink > 1 && (Statb.st_mode&S_IFMT)!=S_IFDIR) {
82 		static linked = 0;
83 
84 		for(i = 0; i <= linked; ++i) {
85 			if(ml[i].ino==Statb.st_ino && ml[i].dev==Statb.st_dev)
86 				return 0;
87 		}
88 		if (linked < ML) {
89 			ml[linked].dev = Statb.st_dev;
90 			ml[linked].ino = Statb.st_ino;
91 			++linked;
92 		}
93 	}
94 /*
95 	blocks = (Statb.st_size + BSIZE-1) >> BSHIFT;
96 */
97 	blocks = (Statb.st_size + 511) >> 9;
98 
99 	if((Statb.st_mode&S_IFMT)!=S_IFDIR) {
100 		if(Aflag)
101 			printf("%ld	%s\n", blocks, np);
102 		return(blocks);
103 	}
104 
105 	for(c1 = np; *c1; ++c1);
106 	if(*(c1-1) == '/')
107 		--c1;
108 	endofname = c1;
109 	dirsize = Statb.st_size;
110 	if(chdir(fname) == -1)
111 		return 0;
112 	for(offset=0; offset < dirsize; offset += BUFSIZ) { /* each block */
113 		dsize = BUFSIZ<(dirsize-offset)? BUFSIZ: (dirsize-offset);
114 		if(!dir) {
115 			if((dir=open(".",0))<0) {
116 				fprintf(stderr, "--cannot open < %s >\n",
117 					np);
118 				goto ret;
119 			}
120 			if(offset) lseek(dir, (long)offset, 0);
121 			if(read(dir, (char *)dentry, dsize)<0) {
122 				fprintf(stderr, "--cannot read < %s >\n",
123 					np);
124 				goto ret;
125 			}
126 			if(dir > 10) {
127 				close(dir);
128 				dir = 0;
129 			}
130 		} else
131 			if(read(dir, (char *)dentry, dsize)<0) {
132 				fprintf(stderr, "--cannot read < %s >\n",
133 					np);
134 				goto ret;
135 			}
136 		for(dp=dentry, entries=dsize>>4; entries; --entries, ++dp) {
137 			/* each directory entry */
138 			if(dp->d_ino==0
139 			|| EQ(dp->d_name, ".")
140 			|| EQ(dp->d_name, ".."))
141 				continue;
142 			c1 = endofname;
143 			*c1++ = '/';
144 			c2 = dp->d_name;
145 			for(i=0; i<DIRSIZ; ++i)
146 				if(*c2)
147 					*c1++ = *c2++;
148 				else
149 					break;
150 			*c1 = '\0';
151 			if(c1 == endofname) /* ?? */
152 				return 0L;
153 			blocks += descend(np, endofname+1);
154 		}
155 	}
156 	*endofname = '\0';
157 	if(!Sflag)
158 		printf("%ld	%s\n", blocks, np);
159 ret:
160 	if(dir)
161 		close(dir);
162 	if(chdir("..") == -1) {
163 		*endofname = '\0';
164 		fprintf(stderr, "Bad directory <%s>\n", np);
165 		while(*--endofname != '/');
166 		*endofname = '\0';
167 		if(chdir(np) == -1)
168 			exit(1);
169 	}
170 	return(blocks);
171 }
172