blob: fb649aee5e15f6720bec55ee5f4caebc9fbceb41 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
John Beppu0f5e1ab1999-12-09 18:23:54 +00002/*
3 * Mini du implementation for busybox
4 *
5 *
Eric Andersen8ec10a92001-01-27 09:33:39 +00006 * Copyright (C) 1999,2000,2001 by Lineo, inc.
Eric Andersen70e2f0b1999-12-10 06:45:42 +00007 * Written by John Beppu <beppu@lineo.com>
John Beppu0f5e1ab1999-12-09 18:23:54 +00008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
John Beppu0f5e1ab1999-12-09 18:23:54 +000025#include <sys/types.h>
26#include <fcntl.h>
27#include <dirent.h>
28#include <stdio.h>
Eric Andersened3ef502001-01-27 08:24:39 +000029#include <stdlib.h>
30#include <getopt.h>
Eric Anderseneba8ed72001-03-09 14:36:42 +000031#include <string.h>
John Beppu98355411999-12-10 07:40:08 +000032#include <errno.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000033#include "busybox.h"
Eric Andersencbe31da2001-02-20 06:14:08 +000034
John Beppu0f5e1ab1999-12-09 18:23:54 +000035
Richard June6d0921c2001-01-22 22:35:38 +000036#ifdef BB_FEATURE_HUMAN_READABLE
Eric Andersenec9fad92001-03-07 06:04:08 +000037static unsigned long disp_hr = KILOBYTE;
Richard June6d0921c2001-01-22 22:35:38 +000038#endif
39
Erik Andersene49d5ec2000-02-08 19:58:47 +000040typedef void (Display) (long, char *);
John Beppu0f5e1ab1999-12-09 18:23:54 +000041
Erik Andersene49d5ec2000-02-08 19:58:47 +000042static int du_depth = 0;
Erik Andersen27fdd082000-02-19 18:16:49 +000043static int count_hardlinks = 0;
John Beppue1618e41999-12-15 18:52:17 +000044
Erik Andersene49d5ec2000-02-08 19:58:47 +000045static Display *print;
46
47static void print_normal(long size, char *filename)
John Beppu0f5e1ab1999-12-09 18:23:54 +000048{
Richard June6d0921c2001-01-22 22:35:38 +000049#ifdef BB_FEATURE_HUMAN_READABLE
Eric Andersenf429bac2001-06-13 08:02:45 +000050 printf("%s\t%s\n", make_human_readable_str(size<<10, 1, disp_hr), filename);
Richard June6d0921c2001-01-22 22:35:38 +000051#else
Matt Kraai12f417e2001-01-18 02:57:08 +000052 printf("%ld\t%s\n", size, filename);
Richard June6d0921c2001-01-22 22:35:38 +000053#endif
John Beppu0f5e1ab1999-12-09 18:23:54 +000054}
55
Erik Andersene49d5ec2000-02-08 19:58:47 +000056static void print_summary(long size, char *filename)
John Beppue1618e41999-12-15 18:52:17 +000057{
Erik Andersene49d5ec2000-02-08 19:58:47 +000058 if (du_depth == 1) {
59 print_normal(size, filename);
60 }
John Beppue1618e41999-12-15 18:52:17 +000061}
62
Eric Andersen8b113f92001-06-01 21:47:15 +000063#define HASH_SIZE 311 /* Should be prime */
64#define hash_inode(i) ((i) % HASH_SIZE)
65
66typedef struct ino_dev_hash_bucket_struct {
67 struct ino_dev_hash_bucket_struct *next;
68 ino_t ino;
69 dev_t dev;
70 char name[1];
71} ino_dev_hashtable_bucket_t;
72
73static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
74
75/*
76 * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in
77 * `ino_dev_hashtable', else return 0
78 *
79 * If NAME is a non-NULL pointer to a character pointer, and there is
80 * a match, then set *NAME to the value of the name slot in that
81 * bucket.
82 */
83static int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
84{
85 ino_dev_hashtable_bucket_t *bucket;
86
87 bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
88 while (bucket != NULL) {
89 if ((bucket->ino == statbuf->st_ino) &&
90 (bucket->dev == statbuf->st_dev))
91 {
92 if (name) *name = bucket->name;
93 return 1;
94 }
95 bucket = bucket->next;
96 }
97 return 0;
98}
99
100/* Add statbuf to statbuf hash table */
101static void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
102{
103 int i;
104 size_t s;
105 ino_dev_hashtable_bucket_t *bucket;
106
107 i = hash_inode(statbuf->st_ino);
108 s = name ? strlen(name) : 0;
109 bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s);
110 bucket->ino = statbuf->st_ino;
111 bucket->dev = statbuf->st_dev;
112 if (name)
113 strcpy(bucket->name, name);
114 else
115 bucket->name[0] = '\0';
116 bucket->next = ino_dev_hashtable[i];
117 ino_dev_hashtable[i] = bucket;
118}
119
120/* Clear statbuf hash table */
121static void reset_ino_dev_hashtable(void)
122{
123 int i;
124 ino_dev_hashtable_bucket_t *bucket;
125
126 for (i = 0; i < HASH_SIZE; i++) {
127 while (ino_dev_hashtable[i] != NULL) {
128 bucket = ino_dev_hashtable[i]->next;
129 free(ino_dev_hashtable[i]);
130 ino_dev_hashtable[i] = bucket;
131 }
132 }
133}
134
John Beppu0f5e1ab1999-12-09 18:23:54 +0000135/* tiny recursive du */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000136static long du(char *filename)
John Beppu0f5e1ab1999-12-09 18:23:54 +0000137{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000138 struct stat statbuf;
Erik Andersenfac10d72000-02-07 05:29:42 +0000139 long sum;
John Beppu14c82b61999-12-10 06:15:27 +0000140
Erik Andersene49d5ec2000-02-08 19:58:47 +0000141 if ((lstat(filename, &statbuf)) != 0) {
Eric Andersene5dfced2001-04-09 22:48:12 +0000142 perror_msg("%s", filename);
143 return 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000144 }
145
146 du_depth++;
John Beppu08c965a2000-02-13 04:10:57 +0000147 sum = (statbuf.st_blocks >> 1);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000148
Erik Andersen27fdd082000-02-19 18:16:49 +0000149 /* Don't add in stuff pointed to by symbolic links */
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000150 if (S_ISLNK(statbuf.st_mode)) {
Erik Andersen42387e42000-02-21 17:27:17 +0000151 sum = 0L;
Eric Andersen8fa1bf72001-06-30 17:54:20 +0000152 if (du_depth == 1) {
153 }
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000154 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000155 if (S_ISDIR(statbuf.st_mode)) {
156 DIR *dir;
157 struct dirent *entry;
Eric Andersen04b03542001-05-07 22:49:43 +0000158 char *newfile;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000159
160 dir = opendir(filename);
161 if (!dir) {
Erik Andersen42387e42000-02-21 17:27:17 +0000162 du_depth--;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000163 return 0;
164 }
Erik Andersen42387e42000-02-21 17:27:17 +0000165
Eric Andersen04b03542001-05-07 22:49:43 +0000166 newfile = last_char_is(filename, '/');
167 if (newfile)
168 *newfile = '\0';
Erik Andersen42387e42000-02-21 17:27:17 +0000169
Erik Andersene49d5ec2000-02-08 19:58:47 +0000170 while ((entry = readdir(dir))) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000171 char *name = entry->d_name;
172
173 if ((strcmp(name, "..") == 0)
174 || (strcmp(name, ".") == 0)) {
175 continue;
176 }
Eric Andersene5dfced2001-04-09 22:48:12 +0000177 newfile = concat_path_file(filename, name);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000178 sum += du(newfile);
Eric Andersene5dfced2001-04-09 22:48:12 +0000179 free(newfile);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000180 }
181 closedir(dir);
182 print(sum, filename);
183 }
Erik Andersen27fdd082000-02-19 18:16:49 +0000184 else if (statbuf.st_nlink > 1 && !count_hardlinks) {
185 /* Add files with hard links only once */
Erik Andersen029011b2000-03-04 21:19:32 +0000186 if (is_in_ino_dev_hashtable(&statbuf, NULL)) {
Erik Andersen42387e42000-02-21 17:27:17 +0000187 sum = 0L;
188 if (du_depth == 1)
189 print(sum, filename);
190 }
191 else {
Erik Andersen029011b2000-03-04 21:19:32 +0000192 add_to_ino_dev_hashtable(&statbuf, NULL);
Erik Andersen42387e42000-02-21 17:27:17 +0000193 }
Erik Andersen27fdd082000-02-19 18:16:49 +0000194 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000195 du_depth--;
196 return sum;
John Beppu0f5e1ab1999-12-09 18:23:54 +0000197}
198
Erik Andersene49d5ec2000-02-08 19:58:47 +0000199int du_main(int argc, char **argv)
200{
Matt Kraai92ed8a32000-12-06 15:55:23 +0000201 int status = EXIT_SUCCESS;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000202 int i;
Pavel Roskin47d49262000-07-17 16:17:19 +0000203 int c;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000204
205 /* default behaviour */
206 print = print_normal;
207
208 /* parse argv[] */
Richard June6d0921c2001-01-22 22:35:38 +0000209 while ((c = getopt(argc, argv, "sl"
210#ifdef BB_FEATURE_HUMAN_READABLE
211"hm"
212#endif
213"k")) != EOF) {
Eric Andersen17ad45a2000-07-14 18:38:26 +0000214 switch (c) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000215 case 's':
Eric Andersen17ad45a2000-07-14 18:38:26 +0000216 print = print_summary;
217 break;
Erik Andersen27fdd082000-02-19 18:16:49 +0000218 case 'l':
Eric Andersen17ad45a2000-07-14 18:38:26 +0000219 count_hardlinks = 1;
220 break;
Richard June6d0921c2001-01-22 22:35:38 +0000221#ifdef BB_FEATURE_HUMAN_READABLE
Eric Andersenec9fad92001-03-07 06:04:08 +0000222 case 'h': disp_hr = 0; break;
223 case 'm': disp_hr = MEGABYTE; break;
Richard June6d0921c2001-01-22 22:35:38 +0000224#endif
Eric Andersen8b728a22001-03-06 23:14:43 +0000225 case 'k': break;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000226 default:
Eric Andersen67991cf2001-02-14 21:23:06 +0000227 show_usage();
Erik Andersene49d5ec2000-02-08 19:58:47 +0000228 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000229 }
230
231 /* go through remaining args (if any) */
Eric Andersen17ad45a2000-07-14 18:38:26 +0000232 if (optind >= argc) {
Matt Kraai92ed8a32000-12-06 15:55:23 +0000233 if (du(".") == 0)
234 status = EXIT_FAILURE;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000235 } else {
236 long sum;
237
Eric Andersen17ad45a2000-07-14 18:38:26 +0000238 for (i=optind; i < argc; i++) {
Eric Andersen8fa1bf72001-06-30 17:54:20 +0000239 sum = du(argv[i]);
Richard June6d0921c2001-01-22 22:35:38 +0000240 if(is_directory(argv[i], FALSE, NULL)==FALSE) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000241 print_normal(sum, argv[i]);
242 }
Erik Andersen029011b2000-03-04 21:19:32 +0000243 reset_ino_dev_hashtable();
Erik Andersene49d5ec2000-02-08 19:58:47 +0000244 }
245 }
246
Matt Kraai92ed8a32000-12-06 15:55:23 +0000247 return status;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000248}
249
Eric Andersen8fa1bf72001-06-30 17:54:20 +0000250/* $Id: du.c,v 1.50 2001/06/30 17:54:20 andersen Exp $ */
Erik Andersen029011b2000-03-04 21:19:32 +0000251/*
252Local Variables:
253c-file-style: "linux"
254c-basic-offset: 4
255tab-width: 4
256End:
257*/