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