]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/mkfs-util.c
btrfs-util: Remove bogus assert()
[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");
eaec6994
DDM
126 } else if (fstype_is_ro(fstype)) {
127 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
128 "Don't know how to create read-only file system '%s', refusing.",
129 fstype);
c95f9a23 130 } else {
7f55ad77
DDM
131 if (root)
132 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
eb43379c 133 "Populating with source tree is only supported for read-only filesystems");
c95f9a23
LP
134 r = mkfs_exists(fstype);
135 if (r < 0)
136 return log_error_errno(r, "Failed to determine whether mkfs binary for %s exists: %m", fstype);
137 if (r == 0)
138 return log_error_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "mkfs binary for %s is not available.", fstype);
139
140 mkfs = strjoin("mkfs.", fstype);
141 if (!mkfs)
142 return log_oom();
143 }
144
8d433a99
ZJS
145 if (STR_IN_SET(fstype, "ext2", "ext3", "ext4", "xfs", "swap")) {
146 size_t max_len =
147 streq(fstype, "xfs") ? 12 :
148 streq(fstype, "swap") ? 15 :
149 16;
150
151 r = mangle_linux_fs_label(label, max_len, &mangled_label);
7ffe593b 152 if (r < 0)
8d433a99 153 return log_error_errno(r, "Failed to determine volume label from string \"%s\": %m", label);
7ffe593b
ZJS
154 label = mangled_label;
155
156 } else if (streq(fstype, "vfat")) {
dc91c971
ZJS
157 r = mangle_fat_label(label, &mangled_label);
158 if (r < 0)
159 return log_error_errno(r, "Failed to determine FAT label from string \"%s\": %m", label);
4f05a11c
ZJS
160 label = mangled_label;
161
162 xsprintf(vol_id, "%08" PRIx32,
163 ((uint32_t) uuid.bytes[0] << 24) |
164 ((uint32_t) uuid.bytes[1] << 16) |
165 ((uint32_t) uuid.bytes[2] << 8) |
166 ((uint32_t) uuid.bytes[3])); /* Take first 32 bytes of UUID */
167 }
168
169 if (isempty(vol_id))
b7416360 170 assert_se(sd_id128_to_uuid_string(uuid, vol_id));
4f05a11c 171
c95f9a23
LP
172 r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR, NULL);
173 if (r < 0)
174 return r;
175 if (r == 0) {
c95f9a23 176 /* Child */
4f05a11c
ZJS
177
178 /* When changing this conditional, also adjust the log statement below. */
8e93a614
ZJS
179 if (streq(fstype, "ext2"))
180 (void) execlp(mkfs, mkfs,
4f05a11c 181 "-q",
8e93a614 182 "-L", label,
4f05a11c 183 "-U", vol_id,
8e93a614
ZJS
184 "-I", "256",
185 "-m", "0",
186 "-E", discard ? "discard,lazy_itable_init=1" : "nodiscard,lazy_itable_init=1",
187 node, NULL);
188
189 else if (STR_IN_SET(fstype, "ext3", "ext4"))
c95f9a23 190 (void) execlp(mkfs, mkfs,
4f05a11c 191 "-q",
85b55869 192 "-L", label,
4f05a11c 193 "-U", vol_id,
85b55869
LP
194 "-I", "256",
195 "-O", "has_journal",
196 "-m", "0",
44cdeb6e 197 "-E", discard ? "discard,lazy_itable_init=1" : "nodiscard,lazy_itable_init=1",
85b55869 198 node, NULL);
c95f9a23
LP
199
200 else if (streq(fstype, "btrfs")) {
44cdeb6e 201 (void) execlp(mkfs, mkfs,
4f05a11c 202 "-q",
44cdeb6e 203 "-L", label,
4f05a11c 204 "-U", vol_id,
44cdeb6e
ZJS
205 node,
206 discard ? NULL : "--nodiscard",
207 NULL);
c95f9a23 208
2d96440f
ZJS
209 } else if (streq(fstype, "f2fs")) {
210 (void) execlp(mkfs, mkfs,
211 "-q",
212 "-g", /* "default options" */
213 "-f", /* force override, without this it doesn't seem to want to write to an empty partition */
214 "-l", label,
215 "-U", vol_id,
216 "-t", one_zero(discard),
217 node,
218 NULL);
219
c95f9a23
LP
220 } else if (streq(fstype, "xfs")) {
221 const char *j;
222
4f05a11c 223 j = strjoina("uuid=", vol_id);
44cdeb6e
ZJS
224
225 (void) execlp(mkfs, mkfs,
4f05a11c 226 "-q",
44cdeb6e
ZJS
227 "-L", label,
228 "-m", j,
229 "-m", "reflink=1",
230 node,
231 discard ? NULL : "-K",
232 NULL);
c95f9a23 233
4f05a11c 234 } else if (streq(fstype, "vfat"))
0f2b2c48
LP
235
236 (void) execlp(mkfs, mkfs,
237 "-i", vol_id,
4f05a11c 238 "-n", label,
0f2b2c48
LP
239 "-F", "32", /* yes, we force FAT32 here */
240 node, NULL);
241
4f05a11c
ZJS
242 else if (streq(fstype, "swap"))
243 /* TODO: add --quiet here if
244 * https://github.com/util-linux/util-linux/issues/1499 resolved. */
c95f9a23
LP
245
246 (void) execlp(mkfs, mkfs,
85b55869 247 "-L", label,
4f05a11c 248 "-U", vol_id,
85b55869 249 node, NULL);
c95f9a23 250
7f55ad77
DDM
251 else if (streq(fstype, "squashfs"))
252
253 (void) execlp(mkfs, mkfs,
254 root, node,
255 "-quiet",
256 "-noappend",
257 NULL);
4f05a11c 258 else
c95f9a23
LP
259 /* Generic fallback for all other file systems */
260 (void) execlp(mkfs, mkfs, node, NULL);
261
262 log_error_errno(errno, "Failed to execute %s: %m", mkfs);
263
264 _exit(EXIT_FAILURE);
265 }
266
2d96440f 267 if (STR_IN_SET(fstype, "ext2", "ext3", "ext4", "btrfs", "f2fs", "xfs", "vfat", "swap"))
4f05a11c
ZJS
268 log_info("%s successfully formatted as %s (label \"%s\", uuid %s)",
269 node, fstype, label, vol_id);
270 else
271 log_info("%s successfully formatted as %s (no label or uuid specified)",
272 node, fstype);
273
c95f9a23
LP
274 return 0;
275}