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