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