]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/mkfs-util.c
repart: Extend squashfs logic to all read-only filesystems
[thirdparty/systemd.git] / src / shared / mkfs-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
c95f9a23 2
3c9fbb99
ZJS
3#include <unistd.h>
4
c95f9a23
LP
5#include "id128-util.h"
6#include "mkfs-util.h"
eb43379c 7#include "mountpoint-util.h"
c95f9a23
LP
8#include "path-util.h"
9#include "process-util.h"
0f2b2c48 10#include "stdio-util.h"
c95f9a23 11#include "string-util.h"
dc91c971 12#include "utf8.h"
c95f9a23
LP
13
14int mkfs_exists(const char *fstype) {
15 const char *mkfs;
16 int r;
17
18 assert(fstype);
19
20 if (STR_IN_SET(fstype, "auto", "swap")) /* these aren't real file system types, refuse early */
21 return -EINVAL;
22
23 mkfs = strjoina("mkfs.", fstype);
24 if (!filename_is_valid(mkfs)) /* refuse file system types with slashes and similar */
25 return -EINVAL;
26
f7bc0c32 27 r = find_executable(mkfs, NULL);
c95f9a23
LP
28 if (r == -ENOENT)
29 return false;
30 if (r < 0)
31 return r;
32
33 return true;
34}
35
7ffe593b
ZJS
36static int mangle_linux_fs_label(const char *s, size_t max_len, char **ret) {
37 /* Not more than max_len bytes (12 or 16) */
38
39 assert(s);
40 assert(max_len > 0);
41 assert(ret);
42
43 const char *q;
44 char *ans;
45
46 for (q = s; *q;) {
47 int l;
48
49 l = utf8_encoded_valid_unichar(q, SIZE_MAX);
50 if (l < 0)
51 return l;
52
53 if ((size_t) (q - s + l) > max_len)
54 break;
55 q += l;
56 }
57
58 ans = memdup_suffix0(s, q - s);
59 if (!ans)
60 return -ENOMEM;
61
62 *ret = ans;
63 return 0;
64}
65
dc91c971
ZJS
66static int mangle_fat_label(const char *s, char **ret) {
67 assert(s);
68
69 _cleanup_free_ char *q = NULL;
70 int r;
71
72 r = utf8_to_ascii(s, '_', &q);
73 if (r < 0)
74 return r;
75
76 /* Classic FAT only allows 11 character uppercase labels */
77 strshorten(q, 11);
78 ascii_strupper(q);
79
80 /* mkfs.vfat: Labels with characters *?.,;:/\|+=<>[]" are not allowed.
81 * Let's also replace any control chars. */
82 for (char *p = q; *p; p++)
83 if (strchr("*?.,;:/\\|+=<>[]\"", *p) || char_is_cc(*p))
84 *p = '_';
85
86 *ret = TAKE_PTR(q);
87 return 0;
88}
89
c95f9a23
LP
90int make_filesystem(
91 const char *node,
92 const char *fstype,
93 const char *label,
7f55ad77 94 const char *root,
c95f9a23
LP
95 sd_id128_t uuid,
96 bool discard) {
97
dc91c971 98 _cleanup_free_ char *mkfs = NULL, *mangled_label = NULL;
b7416360 99 char vol_id[CONST_MAX(SD_ID128_UUID_STRING_MAX, 8U + 1U)] = {};
c95f9a23
LP
100 int r;
101
102 assert(node);
103 assert(fstype);
104 assert(label);
105
eb43379c
DDM
106 if (fstype_is_ro(fstype) && !root)
107 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
108 "Cannot generate read-only filesystem %s without a source tree.",
109 fstype);
110
c95f9a23 111 if (streq(fstype, "swap")) {
7f55ad77
DDM
112 if (root)
113 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
114 "A swap filesystem can't be populated, refusing");
f7bc0c32 115 r = find_executable("mkswap", &mkfs);
c95f9a23
LP
116 if (r == -ENOENT)
117 return log_error_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "mkswap binary not available.");
118 if (r < 0)
119 return log_error_errno(r, "Failed to determine whether mkswap binary exists: %m");
7f55ad77 120 } else if (streq(fstype, "squashfs")) {
7f55ad77
DDM
121 r = find_executable("mksquashfs", &mkfs);
122 if (r == -ENOENT)
123 return log_error_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "mksquashfs binary not available.");
124 if (r < 0)
125 return log_error_errno(r, "Failed to determine whether mksquashfs binary exists: %m");
c95f9a23 126 } else {
7f55ad77
DDM
127 if (root)
128 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
eb43379c 129 "Populating with source tree is only supported for read-only filesystems");
c95f9a23
LP
130 r = mkfs_exists(fstype);
131 if (r < 0)
132 return log_error_errno(r, "Failed to determine whether mkfs binary for %s exists: %m", fstype);
133 if (r == 0)
134 return log_error_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "mkfs binary for %s is not available.", fstype);
135
136 mkfs = strjoin("mkfs.", fstype);
137 if (!mkfs)
138 return log_oom();
139 }
140
8d433a99
ZJS
141 if (STR_IN_SET(fstype, "ext2", "ext3", "ext4", "xfs", "swap")) {
142 size_t max_len =
143 streq(fstype, "xfs") ? 12 :
144 streq(fstype, "swap") ? 15 :
145 16;
146
147 r = mangle_linux_fs_label(label, max_len, &mangled_label);
7ffe593b 148 if (r < 0)
8d433a99 149 return log_error_errno(r, "Failed to determine volume label from string \"%s\": %m", label);
7ffe593b
ZJS
150 label = mangled_label;
151
152 } else if (streq(fstype, "vfat")) {
dc91c971
ZJS
153 r = mangle_fat_label(label, &mangled_label);
154 if (r < 0)
155 return log_error_errno(r, "Failed to determine FAT label from string \"%s\": %m", label);
4f05a11c
ZJS
156 label = mangled_label;
157
158 xsprintf(vol_id, "%08" PRIx32,
159 ((uint32_t) uuid.bytes[0] << 24) |
160 ((uint32_t) uuid.bytes[1] << 16) |
161 ((uint32_t) uuid.bytes[2] << 8) |
162 ((uint32_t) uuid.bytes[3])); /* Take first 32 bytes of UUID */
163 }
164
165 if (isempty(vol_id))
b7416360 166 assert_se(sd_id128_to_uuid_string(uuid, vol_id));
4f05a11c 167
c95f9a23
LP
168 r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR, NULL);
169 if (r < 0)
170 return r;
171 if (r == 0) {
c95f9a23 172 /* Child */
4f05a11c
ZJS
173
174 /* When changing this conditional, also adjust the log statement below. */
8e93a614
ZJS
175 if (streq(fstype, "ext2"))
176 (void) execlp(mkfs, mkfs,
4f05a11c 177 "-q",
8e93a614 178 "-L", label,
4f05a11c 179 "-U", vol_id,
8e93a614
ZJS
180 "-I", "256",
181 "-m", "0",
182 "-E", discard ? "discard,lazy_itable_init=1" : "nodiscard,lazy_itable_init=1",
183 node, NULL);
184
185 else if (STR_IN_SET(fstype, "ext3", "ext4"))
c95f9a23 186 (void) execlp(mkfs, mkfs,
4f05a11c 187 "-q",
85b55869 188 "-L", label,
4f05a11c 189 "-U", vol_id,
85b55869
LP
190 "-I", "256",
191 "-O", "has_journal",
192 "-m", "0",
44cdeb6e 193 "-E", discard ? "discard,lazy_itable_init=1" : "nodiscard,lazy_itable_init=1",
85b55869 194 node, NULL);
c95f9a23
LP
195
196 else if (streq(fstype, "btrfs")) {
44cdeb6e 197 (void) execlp(mkfs, mkfs,
4f05a11c 198 "-q",
44cdeb6e 199 "-L", label,
4f05a11c 200 "-U", vol_id,
44cdeb6e
ZJS
201 node,
202 discard ? NULL : "--nodiscard",
203 NULL);
c95f9a23 204
2d96440f
ZJS
205 } else if (streq(fstype, "f2fs")) {
206 (void) execlp(mkfs, mkfs,
207 "-q",
208 "-g", /* "default options" */
209 "-f", /* force override, without this it doesn't seem to want to write to an empty partition */
210 "-l", label,
211 "-U", vol_id,
212 "-t", one_zero(discard),
213 node,
214 NULL);
215
c95f9a23
LP
216 } else if (streq(fstype, "xfs")) {
217 const char *j;
218
4f05a11c 219 j = strjoina("uuid=", vol_id);
44cdeb6e
ZJS
220
221 (void) execlp(mkfs, mkfs,
4f05a11c 222 "-q",
44cdeb6e
ZJS
223 "-L", label,
224 "-m", j,
225 "-m", "reflink=1",
226 node,
227 discard ? NULL : "-K",
228 NULL);
c95f9a23 229
4f05a11c 230 } else if (streq(fstype, "vfat"))
0f2b2c48
LP
231
232 (void) execlp(mkfs, mkfs,
233 "-i", vol_id,
4f05a11c 234 "-n", label,
0f2b2c48
LP
235 "-F", "32", /* yes, we force FAT32 here */
236 node, NULL);
237
4f05a11c
ZJS
238 else if (streq(fstype, "swap"))
239 /* TODO: add --quiet here if
240 * https://github.com/util-linux/util-linux/issues/1499 resolved. */
c95f9a23
LP
241
242 (void) execlp(mkfs, mkfs,
85b55869 243 "-L", label,
4f05a11c 244 "-U", vol_id,
85b55869 245 node, NULL);
c95f9a23 246
7f55ad77
DDM
247 else if (streq(fstype, "squashfs"))
248
249 (void) execlp(mkfs, mkfs,
250 root, node,
251 "-quiet",
252 "-noappend",
253 NULL);
4f05a11c 254 else
c95f9a23
LP
255 /* Generic fallback for all other file systems */
256 (void) execlp(mkfs, mkfs, node, NULL);
257
258 log_error_errno(errno, "Failed to execute %s: %m", mkfs);
259
260 _exit(EXIT_FAILURE);
261 }
262
2d96440f 263 if (STR_IN_SET(fstype, "ext2", "ext3", "ext4", "btrfs", "f2fs", "xfs", "vfat", "swap"))
4f05a11c
ZJS
264 log_info("%s successfully formatted as %s (label \"%s\", uuid %s)",
265 node, fstype, label, vol_id);
266 else
267 log_info("%s successfully formatted as %s (no label or uuid specified)",
268 node, fstype);
269
c95f9a23
LP
270 return 0;
271}