]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - growfs/xfs_growfs.c
xfsprogs: libxcmd: avoid using strtok()
[thirdparty/xfsprogs-dev.git] / growfs / xfs_growfs.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
2bd0ea18 4 *
da23017d
NS
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
2bd0ea18
NS
7 * published by the Free Software Foundation.
8 *
da23017d
NS
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.
2bd0ea18 13 *
da23017d
NS
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
2bd0ea18
NS
17 */
18
1d7e80ee 19#include <xfs/libxfs.h>
3d93ccb7 20#include <xfs/path.h>
2bd0ea18 21
8e4b2fda
ES
22/*
23 * When growing a filesystem, this is the most significant
24 * bits we'll accept in the resulting inode numbers
25 * without warning the user.
26 */
27
28#define XFS_MAX_INODE_SIG_BITS 32
29
2bd0ea18
NS
30static void
31usage(void)
32{
9440d84d 33 fprintf(stderr, _(
2bd0ea18
NS
34"Usage: %s [options] mountpoint\n\n\
35Options:\n\
dfc130f3
RC
36 -d grow data/metadata section\n\
37 -l grow log section\n\
38 -r grow realtime section\n\
39 -n don't change anything, just show geometry\n\
40 -I allow inode numbers to exceed %d significant bits\n\
41 -i convert log from external to internal format\n\
42 -t alternate location for mount table (/etc/mtab)\n\
43 -x convert log from internal to external format\n\
44 -D size grow data/metadata section to size blks\n\
45 -L size grow/shrink log section to size blks\n\
46 -R size grow realtime section to size blks\n\
47 -e size set realtime extent size to size blks\n\
48 -m imaxpct set inode max percent to imaxpct\n\
49 -V print version information\n"),
8e4b2fda 50 progname, XFS_MAX_INODE_SIG_BITS);
2bd0ea18
NS
51 exit(2);
52}
53
54void
55report_info(
56 xfs_fsop_geom_t geo,
57 char *mntpoint,
8fc372bc
NS
58 int isint,
59 char *logname,
60 char *rtname,
cdded3d8 61 int lazycount,
2bd0ea18 62 int dirversion,
e78b9efb 63 int logversion,
51ca7008
BN
64 int attrversion,
65 int cimode)
2bd0ea18 66{
9440d84d
NS
67 printf(_(
68 "meta-data=%-22s isize=%-6u agcount=%u, agsize=%u blks\n"
e78b9efb 69 " =%-22s sectsz=%-5u attr=%u\n"
9440d84d 70 "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
b5accb81 71 " =%-22s sunit=%-6u swidth=%u blks\n"
1654e351 72 "naming =version %-14u bsize=%-6u ascii-ci=%d\n"
9440d84d 73 "log =%-22s bsize=%-6u blocks=%u, version=%u\n"
cdded3d8 74 " =%-22s sectsz=%-5u sunit=%u blks, lazy-count=%u\n"
9440d84d
NS
75 "realtime =%-22s extsz=%-6u blocks=%llu, rtextents=%llu\n"),
76
77 mntpoint, geo.inodesize, geo.agcount, geo.agblocks,
e78b9efb 78 "", geo.sectsize, attrversion,
9440d84d
NS
79 "", geo.blocksize, (unsigned long long)geo.datablocks,
80 geo.imaxpct,
8d537733 81 "", geo.sunit, geo.swidth,
1654e351 82 dirversion, geo.dirblocksize, cimode,
8fc372bc
NS
83 isint ? _("internal") : logname ? logname : _("external"),
84 geo.blocksize, geo.logblocks, logversion,
cdded3d8 85 "", geo.logsectsize, geo.logsunit / geo.blocksize, lazycount,
8fc372bc 86 !geo.rtblocks ? _("none") : rtname ? rtname : _("external"),
9440d84d
NS
87 geo.rtextsize * geo.blocksize, (unsigned long long)geo.rtblocks,
88 (unsigned long long)geo.rtextents);
2bd0ea18
NS
89}
90
2bd0ea18
NS
91int
92main(int argc, char **argv)
93{
94 int aflag; /* fake flag, do all pieces */
95 int c; /* current option character */
96 long long ddsize; /* device size in 512-byte blocks */
97 int dflag; /* -d flag */
e78b9efb 98 int attrversion;/* attribute version number */
2bd0ea18 99 int dirversion; /* directory version number */
aedf62b9 100 int logversion; /* log version number */
2bd0ea18
NS
101 long long dlsize; /* device size in 512-byte blocks */
102 long long drsize; /* device size in 512-byte blocks */
103 long long dsize; /* new data size in fs blocks */
104 int error; /* we have hit an error */
105 long esize; /* new rt extent size */
106 int ffd; /* mount point file descriptor */
107 xfs_fsop_geom_t geo; /* current fs geometry */
108 int iflag; /* -i flag */
109 int isint; /* log is currently internal */
110 int lflag; /* -l flag */
111 long long lsize; /* new log size in fs blocks */
112 int maxpct; /* -m flag value */
113 int mflag; /* -m flag */
2bd0ea18
NS
114 int nflag; /* -n flag */
115 xfs_fsop_geom_t ngeo; /* new fs geometry */
116 int rflag; /* -r flag */
117 long long rsize; /* new rt size in fs blocks */
51ca7008 118 int ci; /* ASCII case-insensitive fs */
cdded3d8 119 int lazycount; /* lazy superblock counters */
2bd0ea18 120 int xflag; /* -x flag */
3d93ccb7
NS
121 char *fname; /* mount point name */
122 char *datadev; /* data device name */
123 char *logdev; /* log device name */
124 char *rtdev; /* RT device name */
125 fs_path_t *fs; /* mount point information */
2bd0ea18
NS
126 libxfs_init_t xi; /* libxfs structure */
127
2bd0ea18 128 progname = basename(argv[0]);
9440d84d
NS
129 setlocale(LC_ALL, "");
130 bindtextdomain(PACKAGE, LOCALEDIR);
131 textdomain(PACKAGE);
53f8ad6d 132
2bd0ea18
NS
133 maxpct = esize = 0;
134 dsize = lsize = rsize = 0LL;
53f8ad6d 135 aflag = dflag = iflag = lflag = mflag = nflag = rflag = xflag = 0;
51ca7008 136 ci = 0;
53f8ad6d 137
6d1d29a7 138 while ((c = getopt(argc, argv, "dD:e:ilL:m:np:rR:t:xV")) != EOF) {
2bd0ea18
NS
139 switch (c) {
140 case 'D':
53f8ad6d 141 dsize = strtoll(optarg, NULL, 10);
2bd0ea18
NS
142 /* fall through */
143 case 'd':
144 dflag = 1;
145 break;
146 case 'e':
147 esize = atol(optarg);
148 rflag = 1;
149 break;
150 case 'i':
151 lflag = iflag = 1;
152 break;
153 case 'L':
53f8ad6d 154 lsize = strtoll(optarg, NULL, 10);
2bd0ea18
NS
155 /* fall through */
156 case 'l':
157 lflag = 1;
158 break;
159 case 'm':
160 mflag = 1;
161 maxpct = atoi(optarg);
162 break;
163 case 'n':
164 nflag = 1;
165 break;
166 case 'p':
167 progname = optarg;
168 break;
169 case 'R':
53f8ad6d 170 rsize = strtoll(optarg, NULL, 10);
2bd0ea18
NS
171 /* fall through */
172 case 'r':
173 rflag = 1;
174 break;
175 case 't':
3d93ccb7 176 mtab_file = optarg;
2bd0ea18
NS
177 break;
178 case 'x':
179 lflag = xflag = 1;
180 break;
181 case 'V':
9440d84d 182 printf(_("%s version %s\n"), progname, VERSION);
3d98fe63 183 exit(0);
2bd0ea18
NS
184 case '?':
185 default:
186 usage();
187 }
188 }
189 if (argc - optind != 1)
190 usage();
191 if (iflag && xflag)
192 usage();
193 if (dflag + lflag + rflag == 0)
194 aflag = 1;
195
3d93ccb7
NS
196 fs_table_initialise();
197 fs = fs_table_lookup(argv[optind], FS_MOUNT_POINT);
198 if (!fs) {
199 fprintf(stderr, _("%s: %s is not a mounted XFS filesystem\n"),
200 progname, argv[optind]);
201 return 1;
202 }
203
204 fname = fs->fs_dir;
205 datadev = fs->fs_name;
206 logdev = fs->fs_log;
207 rtdev = fs->fs_rt;
2bd0ea18
NS
208
209 ffd = open(fname, O_RDONLY);
210 if (ffd < 0) {
211 perror(fname);
212 return 1;
213 }
214
93d9f139
NS
215 if (!platform_test_xfs_fd(ffd)) {
216 fprintf(stderr, _("%s: specified file "
217 "[\"%s\"] is not on an XFS filesystem\n"),
218 progname, fname);
219 exit(1);
220 }
221
2bd0ea18 222 /* get the current filesystem size & geometry */
93d9f139 223 if (xfsctl(fname, ffd, XFS_IOC_FSGEOMETRY, &geo) < 0) {
9d77aadd 224 /*
93d9f139 225 * OK, new xfsctl barfed - back off and try earlier version
9d77aadd 226 * as we're probably running an older kernel version.
93d9f139 227 * Only field added in the v2 geometry xfsctl is "logsunit"
9d77aadd
NS
228 * so we'll zero that out for later display (as zero).
229 */
9440d84d 230 geo.logsunit = 0;
93d9f139 231 if (xfsctl(fname, ffd, XFS_IOC_FSGEOMETRY_V1, &geo) < 0) {
9440d84d 232 fprintf(stderr, _(
9d77aadd 233 "%s: cannot determine geometry of filesystem"
9440d84d 234 " mounted at %s: %s\n"),
9d77aadd
NS
235 progname, fname, strerror(errno));
236 exit(1);
237 }
2bd0ea18
NS
238 }
239 isint = geo.logstart > 0;
cdded3d8 240 lazycount = geo.flags & XFS_FSOP_GEOM_FLAGS_LAZYSB ? 1 : 0;
2bd0ea18 241 dirversion = geo.flags & XFS_FSOP_GEOM_FLAGS_DIRV2 ? 2 : 1;
aedf62b9 242 logversion = geo.flags & XFS_FSOP_GEOM_FLAGS_LOGV2 ? 2 : 1;
e78b9efb
NS
243 attrversion = geo.flags & XFS_FSOP_GEOM_FLAGS_ATTR2 ? 2 : \
244 (geo.flags & XFS_FSOP_GEOM_FLAGS_ATTR ? 1 : 0);
51ca7008 245 ci = geo.flags & XFS_FSOP_GEOM_FLAGS_DIRV2CI ? 1 : 0;
2bd0ea18 246 if (nflag) {
8fc372bc 247 report_info(geo, datadev, isint, logdev, rtdev,
8d537733 248 lazycount, dirversion, logversion,
51ca7008 249 attrversion, ci);
2bd0ea18
NS
250 exit(0);
251 }
252
253 /*
254 * Need root access from here on (using raw devices)...
255 */
256
dab9b8d6 257 memset(&xi, 0, sizeof(xi));
2bd0ea18
NS
258 xi.dname = datadev;
259 xi.logname = logdev;
260 xi.rtname = rtdev;
2bd0ea18
NS
261 xi.isreadonly = LIBXFS_ISREADONLY;
262
263 if (!libxfs_init(&xi))
264 usage();
265
266 /* check we got the info for all the sections we are trying to modify */
267 if (!xi.ddev) {
9440d84d 268 fprintf(stderr, _("%s: failed to access data device for %s\n"),
2bd0ea18
NS
269 progname, fname);
270 exit(1);
271 }
272 if (lflag && !isint && !xi.logdev) {
9440d84d 273 fprintf(stderr, _("%s: failed to access external log for %s\n"),
2bd0ea18
NS
274 progname, fname);
275 exit(1);
276 }
277 if (rflag && !xi.rtdev) {
9440d84d
NS
278 fprintf(stderr,
279 _("%s: failed to access realtime device for %s\n"),
2bd0ea18
NS
280 progname, fname);
281 exit(1);
282 }
283
8fc372bc 284 report_info(geo, datadev, isint, logdev, rtdev,
8d537733 285 lazycount, dirversion, logversion,
51ca7008 286 attrversion, ci);
2bd0ea18
NS
287
288 ddsize = xi.dsize;
289 dlsize = ( xi.logBBsize? xi.logBBsize :
290 geo.logblocks * (geo.blocksize / BBSIZE) );
291 drsize = xi.rtsize;
292
b7abc846
ES
293 /*
294 * Ok, Linux only has a 1024-byte resolution on device _size_,
295 * and the sizes below are in basic 512-byte blocks,
296 * so if we have (size % 2), on any partition, we can't get
297 * to the last 512 bytes. Just chop it down by a block.
298 */
dfc130f3 299
b7abc846
ES
300 ddsize -= (ddsize % 2);
301 dlsize -= (dlsize % 2);
302 drsize -= (drsize % 2);
303
2bd0ea18
NS
304 error = 0;
305 if (dflag | aflag) {
306 xfs_growfs_data_t in;
8e4b2fda 307
2bd0ea18
NS
308 if (!mflag)
309 maxpct = geo.imaxpct;
310 if (!dsize)
311 dsize = ddsize / (geo.blocksize / BBSIZE);
312 else if (dsize > ddsize / (geo.blocksize / BBSIZE)) {
9440d84d
NS
313 fprintf(stderr, _(
314 "data size %lld too large, maximum is %lld\n"),
5b64e00a
NS
315 (long long)dsize,
316 (long long)(ddsize/(geo.blocksize/BBSIZE)));
2bd0ea18
NS
317 error = 1;
318 }
8e4b2fda 319
2bd0ea18 320 if (!error && dsize < geo.datablocks) {
9440d84d
NS
321 fprintf(stderr, _("data size %lld too small,"
322 " old size is %lld\n"),
5b64e00a 323 (long long)dsize, (long long)geo.datablocks);
2bd0ea18
NS
324 error = 1;
325 } else if (!error &&
326 dsize == geo.datablocks && maxpct == geo.imaxpct) {
327 if (dflag)
9440d84d
NS
328 fprintf(stderr, _(
329 "data size unchanged, skipping\n"));
2bd0ea18 330 if (mflag)
9440d84d
NS
331 fprintf(stderr, _(
332 "inode max pct unchanged, skipping\n"));
2bd0ea18
NS
333 } else if (!error && !nflag) {
334 in.newblocks = (__u64)dsize;
335 in.imaxpct = (__u32)maxpct;
93d9f139 336 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSDATA, &in) < 0) {
2bd0ea18 337 if (errno == EWOULDBLOCK)
9440d84d
NS
338 fprintf(stderr, _(
339 "%s: growfs operation in progress already\n"),
2bd0ea18
NS
340 progname);
341 else
9440d84d 342 fprintf(stderr, _(
93d9f139 343 "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n"),
2bd0ea18
NS
344 progname, strerror(errno));
345 error = 1;
346 }
347 }
348 }
349
350 if (!error && (rflag | aflag)) {
351 xfs_growfs_rt_t in;
352
353 if (!esize)
354 esize = (__u32)geo.rtextsize;
355 if (!rsize)
356 rsize = drsize / (geo.blocksize / BBSIZE);
357 else if (rsize > drsize / (geo.blocksize / BBSIZE)) {
9440d84d
NS
358 fprintf(stderr, _(
359 "realtime size %lld too large, maximum is %lld\n"),
2bd0ea18
NS
360 rsize, drsize / (geo.blocksize / BBSIZE));
361 error = 1;
362 }
363 if (!error && rsize < geo.rtblocks) {
9440d84d
NS
364 fprintf(stderr, _(
365 "realtime size %lld too small, old size is %lld\n"),
5b64e00a 366 (long long)rsize, (long long)geo.rtblocks);
2bd0ea18
NS
367 error = 1;
368 } else if (!error && rsize == geo.rtblocks) {
369 if (rflag)
9440d84d
NS
370 fprintf(stderr, _(
371 "realtime size unchanged, skipping\n"));
2bd0ea18
NS
372 } else if (!error && !nflag) {
373 in.newblocks = (__u64)rsize;
374 in.extsize = (__u32)esize;
93d9f139 375 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSRT, &in) < 0) {
2bd0ea18 376 if (errno == EWOULDBLOCK)
9440d84d
NS
377 fprintf(stderr, _(
378 "%s: growfs operation in progress already\n"),
2bd0ea18
NS
379 progname);
380 else if (errno == ENOSYS)
9440d84d
NS
381 fprintf(stderr, _(
382 "%s: realtime growth not implemented\n"),
2bd0ea18
NS
383 progname);
384 else
9440d84d 385 fprintf(stderr, _(
93d9f139 386 "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n"),
2bd0ea18
NS
387 progname, strerror(errno));
388 error = 1;
389 }
390 }
391 }
392
393 if (!error && (lflag | aflag)) {
394 xfs_growfs_log_t in;
395
396 if (!lsize)
397 lsize = dlsize / (geo.blocksize / BBSIZE);
398 if (iflag)
399 in.isint = 1;
400 else if (xflag)
401 in.isint = 0;
dfc130f3 402 else
2bd0ea18
NS
403 in.isint = xi.logBBsize == 0;
404 if (lsize == geo.logblocks && (in.isint == isint)) {
405 if (lflag)
406 fprintf(stderr,
9440d84d 407 _("log size unchanged, skipping\n"));
2bd0ea18
NS
408 } else if (!nflag) {
409 in.newblocks = (__u32)lsize;
93d9f139 410 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSLOG, &in) < 0) {
2bd0ea18
NS
411 if (errno == EWOULDBLOCK)
412 fprintf(stderr,
9440d84d 413 _("%s: growfs operation in progress already\n"),
2bd0ea18
NS
414 progname);
415 else if (errno == ENOSYS)
416 fprintf(stderr,
9440d84d
NS
417 _("%s: log growth not supported yet\n"),
418 progname);
2bd0ea18
NS
419 else
420 fprintf(stderr,
93d9f139 421 _("%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n"),
2bd0ea18
NS
422 progname, strerror(errno));
423 error = 1;
424 }
425 }
426 }
427
93d9f139
NS
428 if (xfsctl(fname, ffd, XFS_IOC_FSGEOMETRY_V1, &ngeo) < 0) {
429 fprintf(stderr, _("%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n"),
2bd0ea18
NS
430 progname, strerror(errno));
431 exit(1);
432 }
433 if (geo.datablocks != ngeo.datablocks)
9440d84d 434 printf(_("data blocks changed from %lld to %lld\n"),
5b64e00a 435 (long long)geo.datablocks, (long long)ngeo.datablocks);
2bd0ea18 436 if (geo.imaxpct != ngeo.imaxpct)
9440d84d 437 printf(_("inode max percent changed from %d to %d\n"),
2bd0ea18
NS
438 geo.imaxpct, ngeo.imaxpct);
439 if (geo.logblocks != ngeo.logblocks)
9440d84d 440 printf(_("log blocks changed from %d to %d\n"),
2bd0ea18
NS
441 geo.logblocks, ngeo.logblocks);
442 if ((geo.logstart == 0) != (ngeo.logstart == 0))
9440d84d
NS
443 printf(_("log changed from %s to %s\n"),
444 geo.logstart ? _("internal") : _("external"),
445 ngeo.logstart ? _("internal") : _("external"));
2bd0ea18 446 if (geo.rtblocks != ngeo.rtblocks)
9440d84d 447 printf(_("realtime blocks changed from %lld to %lld\n"),
5b64e00a 448 (long long)geo.rtblocks, (long long)ngeo.rtblocks);
2bd0ea18 449 if (geo.rtextsize != ngeo.rtextsize)
9440d84d 450 printf(_("realtime extent size changed from %d to %d\n"),
2bd0ea18 451 geo.rtextsize, ngeo.rtextsize);
9beae830 452 exit(error);
2bd0ea18 453}