]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - growfs/xfs_growfs.c
xfsprogs: fix silently broken option parsing
[thirdparty/xfsprogs-dev.git] / growfs / xfs_growfs.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
2bd0ea18 2/*
da23017d
NS
3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
2bd0ea18
NS
5 */
6
6b803e5a 7#include "libxfs.h"
42b4c8e8 8#include "libfrog/paths.h"
fee68490 9#include "libfrog/fsgeom.h"
2bd0ea18 10
2bd0ea18
NS
11static void
12usage(void)
13{
9440d84d 14 fprintf(stderr, _(
2bd0ea18
NS
15"Usage: %s [options] mountpoint\n\n\
16Options:\n\
dfc130f3
RC
17 -d grow data/metadata section\n\
18 -l grow log section\n\
19 -r grow realtime section\n\
20 -n don't change anything, just show geometry\n\
dfc130f3
RC
21 -i convert log from external to internal format\n\
22 -t alternate location for mount table (/etc/mtab)\n\
23 -x convert log from internal to external format\n\
24 -D size grow data/metadata section to size blks\n\
25 -L size grow/shrink log section to size blks\n\
26 -R size grow realtime section to size blks\n\
27 -e size set realtime extent size to size blks\n\
28 -m imaxpct set inode max percent to imaxpct\n\
29 -V print version information\n"),
30626ef6 30 progname);
2bd0ea18
NS
31 exit(2);
32}
33
2bd0ea18
NS
34int
35main(int argc, char **argv)
36{
37 int aflag; /* fake flag, do all pieces */
38 int c; /* current option character */
39 long long ddsize; /* device size in 512-byte blocks */
40 int dflag; /* -d flag */
2bd0ea18
NS
41 long long dlsize; /* device size in 512-byte blocks */
42 long long drsize; /* device size in 512-byte blocks */
43 long long dsize; /* new data size in fs blocks */
44 int error; /* we have hit an error */
45 long esize; /* new rt extent size */
46 int ffd; /* mount point file descriptor */
2668d323 47 struct xfs_fsop_geom geo; /* current fs geometry */
2bd0ea18
NS
48 int iflag; /* -i flag */
49 int isint; /* log is currently internal */
50 int lflag; /* -l flag */
51 long long lsize; /* new log size in fs blocks */
52 int maxpct; /* -m flag value */
53 int mflag; /* -m flag */
2bd0ea18 54 int nflag; /* -n flag */
2668d323 55 struct xfs_fsop_geom ngeo; /* new fs geometry */
2bd0ea18
NS
56 int rflag; /* -r flag */
57 long long rsize; /* new rt size in fs blocks */
2bd0ea18 58 int xflag; /* -x flag */
3d93ccb7
NS
59 char *fname; /* mount point name */
60 char *datadev; /* data device name */
61 char *logdev; /* log device name */
62 char *rtdev; /* RT device name */
63 fs_path_t *fs; /* mount point information */
2bd0ea18 64 libxfs_init_t xi; /* libxfs structure */
b97815a0 65 char rpath[PATH_MAX];
9612817d 66 int ret;
2bd0ea18 67
2bd0ea18 68 progname = basename(argv[0]);
9440d84d
NS
69 setlocale(LC_ALL, "");
70 bindtextdomain(PACKAGE, LOCALEDIR);
71 textdomain(PACKAGE);
53f8ad6d 72
2bd0ea18
NS
73 maxpct = esize = 0;
74 dsize = lsize = rsize = 0LL;
53f8ad6d
NS
75 aflag = dflag = iflag = lflag = mflag = nflag = rflag = xflag = 0;
76
6d1d29a7 77 while ((c = getopt(argc, argv, "dD:e:ilL:m:np:rR:t:xV")) != EOF) {
2bd0ea18
NS
78 switch (c) {
79 case 'D':
53f8ad6d 80 dsize = strtoll(optarg, NULL, 10);
2bd0ea18
NS
81 /* fall through */
82 case 'd':
83 dflag = 1;
84 break;
85 case 'e':
86 esize = atol(optarg);
87 rflag = 1;
88 break;
89 case 'i':
90 lflag = iflag = 1;
91 break;
92 case 'L':
53f8ad6d 93 lsize = strtoll(optarg, NULL, 10);
2bd0ea18
NS
94 /* fall through */
95 case 'l':
96 lflag = 1;
97 break;
98 case 'm':
99 mflag = 1;
100 maxpct = atoi(optarg);
101 break;
102 case 'n':
103 nflag = 1;
104 break;
105 case 'p':
106 progname = optarg;
107 break;
108 case 'R':
53f8ad6d 109 rsize = strtoll(optarg, NULL, 10);
2bd0ea18
NS
110 /* fall through */
111 case 'r':
112 rflag = 1;
113 break;
114 case 't':
3d93ccb7 115 mtab_file = optarg;
2bd0ea18
NS
116 break;
117 case 'x':
118 lflag = xflag = 1;
119 break;
120 case 'V':
9440d84d 121 printf(_("%s version %s\n"), progname, VERSION);
3d98fe63 122 exit(0);
2bd0ea18
NS
123 default:
124 usage();
125 }
126 }
127 if (argc - optind != 1)
128 usage();
129 if (iflag && xflag)
130 usage();
17d7016e 131 if (dflag + lflag + rflag + mflag == 0)
2bd0ea18
NS
132 aflag = 1;
133
0900efe4 134 fs_table_initialise(0, NULL, 0, NULL);
b97815a0
BD
135
136 if (!realpath(argv[optind], rpath)) {
137 fprintf(stderr, _("%s: path resolution failed for %s: %s\n"),
138 progname, argv[optind], strerror(errno));
139 return 1;
140 }
141
142 fs = fs_table_lookup_mount(rpath);
7e8275f8
ES
143 if (!fs)
144 fs = fs_table_lookup_blkdev(rpath);
145
3d93ccb7
NS
146 if (!fs) {
147 fprintf(stderr, _("%s: %s is not a mounted XFS filesystem\n"),
148 progname, argv[optind]);
149 return 1;
150 }
151
152 fname = fs->fs_dir;
153 datadev = fs->fs_name;
154 logdev = fs->fs_log;
155 rtdev = fs->fs_rt;
2bd0ea18
NS
156
157 ffd = open(fname, O_RDONLY);
158 if (ffd < 0) {
159 perror(fname);
160 return 1;
161 }
162
93d9f139
NS
163 if (!platform_test_xfs_fd(ffd)) {
164 fprintf(stderr, _("%s: specified file "
165 "[\"%s\"] is not on an XFS filesystem\n"),
166 progname, fname);
167 exit(1);
168 }
169
2bd0ea18 170 /* get the current filesystem size & geometry */
03d96c64 171 ret = -xfrog_geometry(ffd, &geo);
9612817d
DW
172 if (ret) {
173 fprintf(stderr,
174 _("%s: cannot determine geometry of filesystem mounted at %s: %s\n"),
175 progname, fname, strerror(ret));
176 exit(1);
2bd0ea18 177 }
9612817d 178
2bd0ea18 179 isint = geo.logstart > 0;
2bd0ea18
NS
180
181 /*
182 * Need root access from here on (using raw devices)...
183 */
184
dab9b8d6 185 memset(&xi, 0, sizeof(xi));
2bd0ea18
NS
186 xi.dname = datadev;
187 xi.logname = logdev;
188 xi.rtname = rtdev;
2bd0ea18
NS
189 xi.isreadonly = LIBXFS_ISREADONLY;
190
191 if (!libxfs_init(&xi))
192 usage();
193
194 /* check we got the info for all the sections we are trying to modify */
195 if (!xi.ddev) {
9440d84d 196 fprintf(stderr, _("%s: failed to access data device for %s\n"),
2bd0ea18
NS
197 progname, fname);
198 exit(1);
199 }
200 if (lflag && !isint && !xi.logdev) {
9440d84d 201 fprintf(stderr, _("%s: failed to access external log for %s\n"),
2bd0ea18
NS
202 progname, fname);
203 exit(1);
204 }
205 if (rflag && !xi.rtdev) {
9440d84d
NS
206 fprintf(stderr,
207 _("%s: failed to access realtime device for %s\n"),
2bd0ea18
NS
208 progname, fname);
209 exit(1);
210 }
211
35f7c5b3 212 xfs_report_geom(&geo, datadev, logdev, rtdev);
2bd0ea18
NS
213
214 ddsize = xi.dsize;
215 dlsize = ( xi.logBBsize? xi.logBBsize :
216 geo.logblocks * (geo.blocksize / BBSIZE) );
217 drsize = xi.rtsize;
218
b7abc846
ES
219 /*
220 * Ok, Linux only has a 1024-byte resolution on device _size_,
221 * and the sizes below are in basic 512-byte blocks,
222 * so if we have (size % 2), on any partition, we can't get
223 * to the last 512 bytes. Just chop it down by a block.
224 */
dfc130f3 225
b7abc846
ES
226 ddsize -= (ddsize % 2);
227 dlsize -= (dlsize % 2);
228 drsize -= (drsize % 2);
229
2bd0ea18 230 error = 0;
17d7016e
ES
231
232 if (dflag | mflag | aflag) {
2bd0ea18 233 xfs_growfs_data_t in;
8e4b2fda 234
2bd0ea18
NS
235 if (!mflag)
236 maxpct = geo.imaxpct;
17d7016e
ES
237 if (!dflag && !aflag) /* Only mflag, no data size change */
238 dsize = geo.datablocks;
239 else if (!dsize)
2bd0ea18
NS
240 dsize = ddsize / (geo.blocksize / BBSIZE);
241 else if (dsize > ddsize / (geo.blocksize / BBSIZE)) {
9440d84d
NS
242 fprintf(stderr, _(
243 "data size %lld too large, maximum is %lld\n"),
5b64e00a
NS
244 (long long)dsize,
245 (long long)(ddsize/(geo.blocksize/BBSIZE)));
2bd0ea18
NS
246 error = 1;
247 }
8e4b2fda 248
2bd0ea18 249 if (!error && dsize < geo.datablocks) {
9440d84d
NS
250 fprintf(stderr, _("data size %lld too small,"
251 " old size is %lld\n"),
5b64e00a 252 (long long)dsize, (long long)geo.datablocks);
2bd0ea18
NS
253 error = 1;
254 } else if (!error &&
255 dsize == geo.datablocks && maxpct == geo.imaxpct) {
256 if (dflag)
9440d84d
NS
257 fprintf(stderr, _(
258 "data size unchanged, skipping\n"));
2bd0ea18 259 if (mflag)
9440d84d
NS
260 fprintf(stderr, _(
261 "inode max pct unchanged, skipping\n"));
2bd0ea18
NS
262 } else if (!error && !nflag) {
263 in.newblocks = (__u64)dsize;
264 in.imaxpct = (__u32)maxpct;
93d9f139 265 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSDATA, &in) < 0) {
2bd0ea18 266 if (errno == EWOULDBLOCK)
9440d84d
NS
267 fprintf(stderr, _(
268 "%s: growfs operation in progress already\n"),
2bd0ea18
NS
269 progname);
270 else
9440d84d 271 fprintf(stderr, _(
93d9f139 272 "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n"),
2bd0ea18
NS
273 progname, strerror(errno));
274 error = 1;
275 }
276 }
277 }
278
279 if (!error && (rflag | aflag)) {
280 xfs_growfs_rt_t in;
281
282 if (!esize)
283 esize = (__u32)geo.rtextsize;
284 if (!rsize)
285 rsize = drsize / (geo.blocksize / BBSIZE);
286 else if (rsize > drsize / (geo.blocksize / BBSIZE)) {
9440d84d
NS
287 fprintf(stderr, _(
288 "realtime size %lld too large, maximum is %lld\n"),
2bd0ea18
NS
289 rsize, drsize / (geo.blocksize / BBSIZE));
290 error = 1;
291 }
292 if (!error && rsize < geo.rtblocks) {
9440d84d
NS
293 fprintf(stderr, _(
294 "realtime size %lld too small, old size is %lld\n"),
5b64e00a 295 (long long)rsize, (long long)geo.rtblocks);
2bd0ea18
NS
296 error = 1;
297 } else if (!error && rsize == geo.rtblocks) {
298 if (rflag)
9440d84d
NS
299 fprintf(stderr, _(
300 "realtime size unchanged, skipping\n"));
2bd0ea18
NS
301 } else if (!error && !nflag) {
302 in.newblocks = (__u64)rsize;
303 in.extsize = (__u32)esize;
93d9f139 304 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSRT, &in) < 0) {
2bd0ea18 305 if (errno == EWOULDBLOCK)
9440d84d
NS
306 fprintf(stderr, _(
307 "%s: growfs operation in progress already\n"),
2bd0ea18
NS
308 progname);
309 else if (errno == ENOSYS)
9440d84d
NS
310 fprintf(stderr, _(
311 "%s: realtime growth not implemented\n"),
2bd0ea18
NS
312 progname);
313 else
9440d84d 314 fprintf(stderr, _(
93d9f139 315 "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n"),
2bd0ea18
NS
316 progname, strerror(errno));
317 error = 1;
318 }
319 }
320 }
321
322 if (!error && (lflag | aflag)) {
323 xfs_growfs_log_t in;
324
325 if (!lsize)
326 lsize = dlsize / (geo.blocksize / BBSIZE);
327 if (iflag)
328 in.isint = 1;
329 else if (xflag)
330 in.isint = 0;
dfc130f3 331 else
2bd0ea18
NS
332 in.isint = xi.logBBsize == 0;
333 if (lsize == geo.logblocks && (in.isint == isint)) {
334 if (lflag)
335 fprintf(stderr,
9440d84d 336 _("log size unchanged, skipping\n"));
2bd0ea18
NS
337 } else if (!nflag) {
338 in.newblocks = (__u32)lsize;
93d9f139 339 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSLOG, &in) < 0) {
2bd0ea18
NS
340 if (errno == EWOULDBLOCK)
341 fprintf(stderr,
9440d84d 342 _("%s: growfs operation in progress already\n"),
2bd0ea18
NS
343 progname);
344 else if (errno == ENOSYS)
345 fprintf(stderr,
9440d84d
NS
346 _("%s: log growth not supported yet\n"),
347 progname);
2bd0ea18
NS
348 else
349 fprintf(stderr,
93d9f139 350 _("%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n"),
2bd0ea18
NS
351 progname, strerror(errno));
352 error = 1;
353 }
354 }
355 }
356
03d96c64 357 ret = -xfrog_geometry(ffd, &ngeo);
9612817d 358 if (ret) {
93d9f139 359 fprintf(stderr, _("%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n"),
9612817d 360 progname, strerror(ret));
2bd0ea18
NS
361 exit(1);
362 }
363 if (geo.datablocks != ngeo.datablocks)
9440d84d 364 printf(_("data blocks changed from %lld to %lld\n"),
5b64e00a 365 (long long)geo.datablocks, (long long)ngeo.datablocks);
2bd0ea18 366 if (geo.imaxpct != ngeo.imaxpct)
9440d84d 367 printf(_("inode max percent changed from %d to %d\n"),
2bd0ea18
NS
368 geo.imaxpct, ngeo.imaxpct);
369 if (geo.logblocks != ngeo.logblocks)
9440d84d 370 printf(_("log blocks changed from %d to %d\n"),
2bd0ea18
NS
371 geo.logblocks, ngeo.logblocks);
372 if ((geo.logstart == 0) != (ngeo.logstart == 0))
9440d84d
NS
373 printf(_("log changed from %s to %s\n"),
374 geo.logstart ? _("internal") : _("external"),
375 ngeo.logstart ? _("internal") : _("external"));
2bd0ea18 376 if (geo.rtblocks != ngeo.rtblocks)
9440d84d 377 printf(_("realtime blocks changed from %lld to %lld\n"),
5b64e00a 378 (long long)geo.rtblocks, (long long)ngeo.rtblocks);
2bd0ea18 379 if (geo.rtextsize != ngeo.rtextsize)
9440d84d 380 printf(_("realtime extent size changed from %d to %d\n"),
2bd0ea18 381 geo.rtextsize, ngeo.rtextsize);
9beae830 382 exit(error);
2bd0ea18 383}