]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - estimate/xfs_estimate.c
xfsprogs: Die dir1 Die!
[thirdparty/xfsprogs-dev.git] / estimate / xfs_estimate.c
1 /*
2 * Copyright (c) 2000-2002 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 /*
20 * Estimate space of an XFS filesystem
21 */
22 #include <xfs/libxfs.h>
23 #include <sys/stat.h>
24 #include <ftw.h>
25
26 unsigned long long
27 cvtnum(char *s)
28 {
29 unsigned long long i;
30 char *sp;
31
32 i = strtoll(s, &sp, 0);
33 if (i == 0 && sp == s)
34 return 0LL;
35 if (*sp == '\0')
36 return i;
37 if (*sp =='k' && sp[1] == '\0')
38 return 1024LL * i;
39 if (*sp =='m' && sp[1] == '\0')
40 return 1024LL * 1024LL * i;
41 if (*sp =='g' && sp[1] == '\0')
42 return 1024LL * 1024LL * 1024LL * i;
43 return 0LL;
44 }
45
46 int ffn(const char *, const struct stat64 *, int, struct FTW *);
47
48 #define BLOCKSIZE 4096
49 #define INODESIZE 256
50 #define PERDIRENTRY \
51 (sizeof(xfs_dir2_leaf_entry_t) + sizeof(xfs_dir2_data_entry_t))
52 #define LOGSIZE 1000
53
54 #define FBLOCKS(n) ((n)/blocksize)
55 #define RFBYTES(n) ((n) - (FBLOCKS(n) * blocksize))
56
57 unsigned long long dirsize=0; /* bytes */
58 unsigned long long logsize=LOGSIZE*BLOCKSIZE; /* bytes */
59 unsigned long long fullblocks=0; /* FS blocks */
60 unsigned long long isize=0; /* inodes bytes */
61 unsigned long long blocksize=BLOCKSIZE;
62 unsigned long long nslinks=0; /* number of symbolic links */
63 unsigned long long nfiles=0; /* number of regular files */
64 unsigned long long ndirs=0; /* number of directories */
65 unsigned long long nspecial=0; /* number of special files */
66 unsigned long long verbose=0; /* verbose mode TRUE/FALSE */
67
68 int __debug = 0;
69 int ilog = 0;
70 int elog = 0;
71
72 void
73 usage(char *progname)
74 {
75 fprintf(stderr,
76 _("Usage: %s [opts] directory [directory ...]\n"
77 "\t-b blocksize (fundamental filesystem blocksize)\n"
78 "\t-i logsize (internal log size)\n"
79 "\t-e logsize (external log size)\n"
80 "\t-v prints more verbose messages\n"
81 "\t-V prints version and exits\n"
82 "\t-h prints this usage message\n\n"
83 "Note:\tblocksize may have 'k' appended to indicate x1024\n"
84 "\tlogsize may also have 'm' appended to indicate (1024 x 1024)\n"),
85 basename(progname));
86 exit(1);
87 }
88
89 int
90 main(int argc, char **argv)
91 {
92 unsigned long long est;
93 extern int optind;
94 extern char *optarg;
95 char dname[40];
96 int c;
97
98 setlocale(LC_ALL, "");
99 bindtextdomain(PACKAGE, LOCALEDIR);
100 textdomain(PACKAGE);
101
102 while ((c = getopt (argc, argv, "b:hdve:i:V")) != EOF) {
103 switch (c) {
104 case 'b':
105 blocksize=cvtnum(optarg);
106 if (blocksize <= 0LL) {
107 fprintf(stderr, _("blocksize %llu too small\n"),
108 blocksize);
109 usage(argv[0]);
110 }
111 else if (blocksize > 64LL * 1024LL) {
112 fprintf(stderr, _("blocksize %llu too large\n"),
113 blocksize);
114 usage(argv[0]);
115 }
116 break;
117 case 'i':
118 if (elog) {
119 fprintf(stderr, _("already have external log "
120 "noted, can't have both\n"));
121 usage(argv[0]);
122 }
123 logsize=cvtnum(optarg);
124 ilog++;
125 break;
126 case 'e':
127 if (ilog) {
128 fprintf(stderr, _("already have internal log "
129 "noted, can't have both\n"));
130 usage(argv[0]);
131 }
132 logsize=cvtnum(optarg);
133 elog++;
134 break;
135 case 'v':
136 verbose = 1;
137 break;
138 case 'd':
139 __debug++;
140 break;
141 case 'V':
142 printf(_("%s version %s\n"), basename(argv[0]), VERSION);
143 exit(0);
144 default:
145 case 'h':
146 usage(argv[0]);
147 }
148 }
149
150 if (optind == argc)
151 usage(argv[0]);
152
153 if (!elog && !ilog) {
154 ilog=1;
155 logsize=LOGSIZE * blocksize;
156 }
157 if (verbose)
158 printf(_("directory bsize blocks megabytes logsize\n"));
159
160 for ( ; optind < argc; optind++) {
161 dirsize=0LL; /* bytes */
162 fullblocks=0LL; /* FS blocks */
163 isize=0LL; /* inodes bytes */
164 nslinks=0LL; /* number of symbolic links */
165 nfiles=0LL; /* number of regular files */
166 ndirs=0LL; /* number of directories */
167 nspecial=0LL; /* number of special files */
168
169 nftw64(argv[optind], ffn, 40, FTW_PHYS | FTW_MOUNT);
170
171 if (__debug) {
172 printf(_("dirsize=%llu\n"), dirsize);
173 printf(_("fullblocks=%llu\n"), fullblocks);
174 printf(_("isize=%llu\n"), isize);
175
176 printf(_("%llu regular files\n"), nfiles);
177 printf(_("%llu symbolic links\n"), nslinks);
178 printf(_("%llu directories\n"), ndirs);
179 printf(_("%llu special files\n"), nspecial);
180 }
181
182 est = FBLOCKS(isize) + 8 /* blocks for inodes */
183 + FBLOCKS(dirsize) + 1 /* blocks for directories */
184 + fullblocks /* blocks for file contents */
185 + (8 * 16) /* fudge for overhead blks (per ag) */
186 + FBLOCKS(isize / INODESIZE); /* 1 byte/inode for map */
187
188 if (ilog)
189 est += (logsize / blocksize);
190
191 if (!verbose) {
192 printf(_("%s will take about %.1f megabytes\n"),
193 argv[optind],
194 (double)est*(double)blocksize/(1024.0*1024.0));
195 } else {
196 /* avoid running over 39 characters in field */
197 strncpy(dname, argv[optind], 40);
198 dname[39] = '\0';
199 printf(_("%-39s %5llu %8llu %10.1fMB %10llu\n"),
200 dname, blocksize, est,
201 (double)est*(double)blocksize/(1024.0*1024.0), logsize);
202 }
203
204 if (!verbose && elog) {
205 printf(_("\twith the external log using %llu blocks "),
206 logsize/blocksize);
207 printf(_("or about %.1f megabytes\n"),
208 (double)logsize/(1024.0*1024.0));
209 }
210 }
211 return 0;
212 }
213
214 int
215 ffn(const char *path, const struct stat64 *stb, int flags, struct FTW *f)
216 {
217 /* cases are in most-encountered to least-encountered order */
218 dirsize+=PERDIRENTRY+strlen(path);
219 isize+=INODESIZE;
220 switch (S_IFMT & stb->st_mode) {
221 case S_IFREG: /* regular files */
222 fullblocks+=FBLOCKS(stb->st_blocks * 512 + blocksize-1);
223 if (stb->st_blocks * 512 < stb->st_size)
224 fullblocks++; /* add one bmap block here */
225 nfiles++;
226 break;
227 case S_IFLNK: /* symbolic links */
228 if (stb->st_size >= (INODESIZE - (sizeof(xfs_dinode_t)+4)))
229 fullblocks+=FBLOCKS(stb->st_size + blocksize-1);
230 nslinks++;
231 break;
232 case S_IFDIR: /* directories */
233 dirsize+=blocksize; /* fudge upwards */
234 if (stb->st_size >= blocksize)
235 dirsize+=blocksize;
236 ndirs++;
237 break;
238 case S_IFIFO: /* named pipes */
239 case S_IFCHR: /* Character Special device */
240 case S_IFBLK: /* Block Special device */
241 case S_IFSOCK: /* socket */
242 nspecial++;
243 break;
244 }
245 return 0;
246 }