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