]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/resize-fs.c
resize-fs: Use xsprintf instead of snprintf
[thirdparty/systemd.git] / src / shared / resize-fs.c
CommitLineData
28937bcc
LP
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <linux/btrfs.h>
4#include <linux/magic.h>
5#include <sys/ioctl.h>
6#include <sys/vfs.h>
7
8#include "blockdev-util.h"
9#include "fs-util.h"
10#include "missing_fs.h"
11#include "missing_magic.h"
12#include "missing_xfs.h"
13#include "resize-fs.h"
14#include "stat-util.h"
15
d6f1e660 16int resize_fs(int fd, uint64_t sz, uint64_t *ret_size) {
28937bcc 17 struct statfs sfs;
28937bcc
LP
18
19 assert(fd >= 0);
20
21 /* Rounds down to next block size */
22
23 if (sz <= 0 || sz == UINT64_MAX)
24 return -ERANGE;
25
26 if (fstatfs(fd, &sfs) < 0)
27 return -errno;
28
29 if (is_fs_type(&sfs, EXT4_SUPER_MAGIC)) {
30 uint64_t u;
31
32 if (sz < EXT4_MINIMAL_SIZE)
33 return -ERANGE;
34
35 u = sz / sfs.f_bsize;
36
37 if (ioctl(fd, EXT4_IOC_RESIZE_FS, &u) < 0)
38 return -errno;
39
d6f1e660
ZJS
40 if (ret_size)
41 *ret_size = u * sfs.f_bsize;
42
28937bcc
LP
43 } else if (is_fs_type(&sfs, BTRFS_SUPER_MAGIC)) {
44 struct btrfs_ioctl_vol_args args = {};
45
46 /* 256M is the minimize size enforced by the btrfs kernel code when resizing (which is
47 * strange btw, as mkfs.btrfs is fine creating file systems > 109M). It will return EINVAL in
48 * that case, let's catch this error beforehand though, and report a more explanatory
49 * error. */
50
51 if (sz < BTRFS_MINIMAL_SIZE)
52 return -ERANGE;
53
d6f1e660
ZJS
54 sz -= sz % sfs.f_bsize;
55
683d0bc0 56 xsprintf(args.name, "%" PRIu64, sz);
28937bcc
LP
57
58 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
59 return -errno;
60
d6f1e660
ZJS
61 if (ret_size)
62 *ret_size = sz;
63
28937bcc
LP
64 } else if (is_fs_type(&sfs, XFS_SB_MAGIC)) {
65 xfs_fsop_geom_t geo;
66 xfs_growfs_data_t d;
67
68 if (sz < XFS_MINIMAL_SIZE)
69 return -ERANGE;
70
71 if (ioctl(fd, XFS_IOC_FSGEOMETRY, &geo) < 0)
72 return -errno;
73
74 d = (xfs_growfs_data_t) {
75 .imaxpct = geo.imaxpct,
76 .newblocks = sz / geo.blocksize,
77 };
78
79 if (ioctl(fd, XFS_IOC_FSGROWFSDATA, &d) < 0)
80 return -errno;
81
d6f1e660
ZJS
82 if (ret_size)
83 *ret_size = d.newblocks * geo.blocksize;
84
28937bcc
LP
85 } else
86 return -EOPNOTSUPP;
87
88 return 0;
89}
90
91uint64_t minimal_size_by_fs_magic(statfs_f_type_t magic) {
92
93 switch (magic) {
94
95 case (statfs_f_type_t) EXT4_SUPER_MAGIC:
96 return EXT4_MINIMAL_SIZE;
97
98 case (statfs_f_type_t) XFS_SB_MAGIC:
99 return XFS_MINIMAL_SIZE;
100
101 case (statfs_f_type_t) BTRFS_SUPER_MAGIC:
102 return BTRFS_MINIMAL_SIZE;
103
104 default:
105 return UINT64_MAX;
106 }
107}
108
109uint64_t minimal_size_by_fs_name(const char *name) {
110
111 if (streq_ptr(name, "ext4"))
112 return EXT4_MINIMAL_SIZE;
113
114 if (streq_ptr(name, "xfs"))
115 return XFS_MINIMAL_SIZE;
116
117 if (streq_ptr(name, "btrfs"))
118 return BTRFS_MINIMAL_SIZE;
119
120 return UINT64_MAX;
121}