Accounts for hardlinks more accurately than the original version that came
[util-vserver.git] / src / vdu.c
1 // $Id: vdu.c,v 1.1 2003/09/29 22:01:57 ensc Exp $
2
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on vdu.cc by Jacques Gelinas
5 //  
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
9 // any later version.
10 //  
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //  
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 #ifdef HAVE_CONFIG_H
21 #  include <config.h>
22 #endif
23 #include "compat.h"
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <errno.h>
33 #include <string.h>
34
35 #include <sys/ioctl.h>
36 #include "ext2fs.h"
37
38 // Patch to help compile this utility on unpatched kernel source
39 #ifndef EXT2_IMMUTABLE_FILE_FL
40         #define EXT2_IMMUTABLE_FILE_FL  0x00000010
41         #define EXT2_IMMUTABLE_LINK_FL  0x00008000
42 #endif
43
44
45 //__extension__ typedef long long               longlong;
46 __extension__ typedef long              longlong;
47
48 static longlong inodes;
49 static longlong blocks;
50 static longlong size;
51
52 static short verbose = 0;
53
54 static inline void warning(char *s) {
55     fprintf(stderr,"%s (%s)\n",s,strerror(errno));    
56 }
57
58 void panic(char *s) {
59     warning(s);
60     exit(2);
61 }
62
63 static void vdu_onedir (char const *path)
64 {
65     struct stat dirst, st;
66     struct dirent *ent;
67     char *name;
68     DIR *dir;
69     int dirfd;
70     longlong dirsize, dirinodes, dirblocks;
71
72     dirsize = dirinodes = dirblocks = 0;
73
74     // A handle to speed up chdir
75     if ((dirfd = open (path,O_RDONLY)) == -1) {
76         fprintf (stderr,"Can't open directory %s\n",path);
77         panic("open failed");
78     }
79
80     if (fchdir (dirfd) == -1) {
81         fprintf (stderr,"Can't fchdir directory %s\n",path);
82         panic("fchdir failed");
83     }
84
85     if (fstat (dirfd,&dirst) != 0) {
86         fprintf (stderr,"Can't lstat directory %s\n",path);
87         panic("lstat failed");
88     }
89
90     if ((dir = opendir (".")) == NULL) {
91         fprintf (stderr,"Can't open (opendir) directory %s\n",path);
92         panic("opendir failed");
93     }
94
95
96     /* Walk the directory entries and compute the sum of inodes,
97        blocks, and disk space used. This code will recursively descend
98        down the directory structure. */
99
100     while ((ent=readdir(dir))!=NULL){
101         if (lstat(ent->d_name,&st)==-1){
102             fprintf (stderr,"Can't stat %s/%s\n",path,ent->d_name);
103             warning("lstat failed");
104             continue;
105         }
106         
107         dirinodes ++;
108
109         if (S_ISREG(st.st_mode)){
110             if (st.st_nlink > 1){
111                 long flags;
112                 int fd, res;
113
114                 if ((fd = open(ent->d_name,O_RDONLY))==-1) {
115                     fprintf (stderr,"Can't open file %s/%s\n",path,ent->d_name);                    
116                     warning ("open failed");
117                     continue;
118                 }
119
120                 flags = 0;
121                 res = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
122                 close(fd);
123
124                 if ((res == 0) && (flags & EXT2_IMMUTABLE_LINK_FL)){
125                     if (verbose)
126                         printf ("Skipping %s\n",ent->d_name);               
127                     continue;
128                 }
129             }
130             dirsize += st.st_size;
131             dirblocks += st.st_blocks;
132
133         } else if (S_ISDIR(st.st_mode)) {
134             if ((st.st_dev == dirst.st_dev) &&
135                 (strcmp(ent->d_name,".")!=0) &&
136                 (strcmp(ent->d_name,"..")!=0)) {
137
138                 dirsize += st.st_size;
139                 dirblocks += st.st_blocks;
140
141                 name = strdup(ent->d_name);
142                 if (name==0) {
143                     panic("Out of memory\n");
144                 }
145                 vdu_onedir(name);
146                 free(name);
147                 fchdir(dirfd);
148             }
149         } else {
150             dirsize += st.st_size;
151             dirblocks += st.st_blocks;
152         }
153     }
154     closedir (dir);
155     close (dirfd);
156     if (verbose)
157         printf("%8ld %8ld %8ld %s\n",dirinodes, dirblocks, dirsize>>10,path);
158     inodes += dirinodes;
159     blocks += dirblocks;
160     size   += dirsize;
161 }
162
163
164
165 int main (int argc, char *argv[])
166 {
167     int startdir, i;
168
169     if (argc < 2){
170         fprintf (stderr,"vdu version %s\n",VERSION);
171         fprintf (stderr,"vdu directory ...\n\n");
172         fprintf (stderr,"Compute the size of a directory tree.");
173     }else{
174         if ((startdir = open (".",O_RDONLY)) == -1) {
175             fprintf (stderr,"Can't open current working directory\n");
176             panic("open failed");
177         }
178
179         for (i=1; i<argc; i++){
180             inodes = blocks = size = 0;
181             vdu_onedir (argv[i]);
182             printf("%8ld %8ld %8ld %s TOTAL\n",inodes, blocks, size>>10,argv[i]);
183             if (fchdir (startdir) == -1) {
184                 panic("fchdir failed");
185             }
186         }
187         close(startdir);
188     }
189     return 0;
190 }
191
192 /*
193  * Local variables:
194  *  c-basic-offset: 4
195  * End:
196  */