xref: /original-bsd/usr.bin/du/du.c (revision 92ab646d)
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  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 char copyright[] =
13 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
14  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)du.c	5.7 (Berkeley) 06/29/90";
19 #endif /* not lint */
20 
21 #include <sys/param.h>
22 #include <sys/stat.h>
23 #include <dirent.h>
24 #include <string.h>
25 #include <stdio.h>
26 
27 typedef struct _ID {
28 	dev_t	dev;
29 	ino_t	inode;
30 } ID;
31 
32 ID *files;
33 dev_t device;
34 int crossmounts, kvalue, listdirs, listfiles, maxfiles, numfiles;
35 char path[MAXPATHLEN + 1];
36 
37 main(argc, argv)
38 	int argc;
39 	char **argv;
40 {
41 	extern int optind, errno;
42 	int ch;
43 	char *malloc(), top[MAXPATHLEN + 1];
44 
45 	listdirs = crossmounts = 1;
46 	while ((ch = getopt(argc, argv, "aksx")) != EOF)
47 		switch(ch) {
48 		case 'a':
49 			listfiles = 1;
50 			break;
51 		case 'k':
52 			kvalue = 1;
53 			break;
54 		case 's':
55 			listfiles = listdirs = 0;
56 			break;
57 		case 'x':
58 			crossmounts = 0;
59 			break;
60 		case '?':
61 		default:
62 			(void)fprintf(stderr,
63 			    "usage: du [-aksx] [name ...]\n");
64 			exit(1);
65 		}
66 	argv += optind;
67 
68 	files = (ID *)malloc((u_int)(sizeof(ID) * (maxfiles = 128)));
69 
70 	if (!*argv)
71 		du(".");
72 	else {
73 		if (argv[1])
74 			(void)getwd(top);
75 		for (;;) {
76 			du(*argv);
77 			if (!*++argv)
78 				break;
79 			if (chdir(top)) {
80 				(void)fprintf(stderr, "du: %s: %s\n",
81 				    top, strerror(errno));
82 				exit(1);
83 			}
84 		}
85 	}
86 	exit(0);
87 }
88 
89 struct stat info;
90 
91 du(arg)
92 	register char *arg;
93 {
94 	extern int errno;
95 	u_long total, descend();
96 
97 	if (lstat(arg, &info)) {
98 		(void)fprintf(stderr, "du: %s: %s\n", arg, strerror(errno));
99 		return;
100 	}
101 	if ((info.st_mode&S_IFMT) != S_IFDIR) {
102 		(void)printf("%ld\t%s\n", kvalue ?
103 		    howmany(info.st_blocks, 2) : info.st_blocks, arg);
104 		return;
105 	}
106 	device = info.st_dev;
107 	(void)strcpy(path, arg);
108 	total = descend(path);
109 	if (!listfiles && !listdirs)
110 		(void)printf("%lu\t%s\n",
111 		    kvalue ? howmany(total, 2) : total, path);
112 }
113 
114 u_long
115 descend(endp)
116 	register char *endp;
117 {
118 	extern int errno;
119 	register DIR *dir;
120 	register ID *fp;
121 	register struct dirent *dp;
122 	u_long total;
123 	char *realloc();
124 
125 	if (info.st_nlink > 1) {
126 		for (fp = files + numfiles - 1; fp >= files; --fp)
127 			if (info.st_ino == fp->inode &&
128 			    info.st_dev == fp->dev)
129 				return(0L);
130 		if (numfiles == maxfiles)
131 			files = (ID *)realloc((char *)files,
132 			    (u_int)(sizeof(ID) * (maxfiles += 128)));
133 		files[numfiles].inode = info.st_ino;
134 		files[numfiles].dev = info.st_dev;
135 		++numfiles;
136 	}
137 	total = info.st_blocks;
138 	if ((info.st_mode&S_IFMT) == S_IFDIR) {
139 		if (info.st_dev != device && !crossmounts)
140 			return(0L);
141 		if (chdir(endp)) {
142 			(void)fprintf(stderr, "du: %s: %s\n",
143 			    path, strerror(errno));
144 			return(total);
145 		}
146 		if (!(dir = opendir("."))) {
147 			(void)fprintf(stderr, "du: %s: %s\n",
148 			    path, strerror(errno));
149 			if (chdir("..")) {
150 				/* very unlikely */
151 				(void)fprintf(stderr, "du: ..: %s\n",
152 				    strerror(errno));
153 				exit(1);
154 			}
155 			return(total);
156 		}
157 		for (; *endp; ++endp);
158 		if (endp[-1] != '/')
159 			*endp++ = '/';
160 		while (dp = readdir(dir)) {
161 			if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
162 			    dp->d_name[1] == '.' && !dp->d_name[2]))
163 				continue;
164 			bcopy(dp->d_name, endp, dp->d_namlen + 1);
165 			if (lstat(dp->d_name, &info)) {
166 				(void)fprintf(stderr, "du: %s: %s\n", path,
167 				    strerror(errno));
168 				continue;
169 			}
170 			total += descend(endp);
171 		}
172 		closedir(dir);
173 		if (chdir("..")) {
174 			(void)fprintf(stderr, "du: ..: %s\n", strerror(errno));
175 			exit(1);
176 		}
177 		*--endp = '\0';
178 		if (listdirs)
179 			(void)printf("%lu\t%s\n",
180 			    kvalue ? howmany(total, 2) : total, path);
181 	}
182 	else if (listfiles)
183 		(void)printf("%lu\t%s\n",
184 		    kvalue ? howmany(total, 2) : total, path);
185 	return(total);
186 }
187