]>
Commit | Line | Data |
---|---|---|
663996b3 MS |
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
2 | ||
3 | /*** | |
4 | This file is part of systemd. | |
5 | ||
6 | Copyright 2012 Lennart Poettering | |
7 | ||
8 | systemd is free software; you can redistribute it and/or modify it | |
9 | under the terms of the GNU Lesser General Public License as published by | |
10 | the Free Software Foundation; either version 2.1 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | systemd is distributed in the hope that it will be useful, but | |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | Lesser General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU Lesser General Public License | |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
20 | ***/ | |
21 | ||
22 | #include <stdio.h> | |
23 | #include <mntent.h> | |
24 | #include <errno.h> | |
25 | #include <string.h> | |
26 | #include <unistd.h> | |
27 | ||
28 | #include "log.h" | |
29 | #include "util.h" | |
30 | #include "unit-name.h" | |
31 | #include "path-util.h" | |
e735f4d4 | 32 | #include "fstab-util.h" |
663996b3 MS |
33 | #include "mount-setup.h" |
34 | #include "special.h" | |
35 | #include "mkdir.h" | |
60f067b4 JS |
36 | #include "generator.h" |
37 | #include "strv.h" | |
38 | #include "virt.h" | |
663996b3 MS |
39 | |
40 | static const char *arg_dest = "/tmp"; | |
60f067b4 JS |
41 | static bool arg_fstab_enabled = true; |
42 | static char *arg_root_what = NULL; | |
43 | static char *arg_root_fstype = NULL; | |
44 | static char *arg_root_options = NULL; | |
45 | static int arg_root_rw = -1; | |
5eef597e MP |
46 | static char *arg_usr_what = NULL; |
47 | static char *arg_usr_fstype = NULL; | |
48 | static char *arg_usr_options = NULL; | |
e842803a | 49 | |
f47781d8 MP |
50 | static int add_swap( |
51 | const char *what, | |
52 | struct mntent *me, | |
53 | bool noauto, | |
54 | bool nofail) { | |
55 | ||
86f210e9 | 56 | _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL; |
663996b3 | 57 | _cleanup_fclose_ FILE *f = NULL; |
86f210e9 | 58 | int r; |
663996b3 MS |
59 | |
60 | assert(what); | |
61 | assert(me); | |
62 | ||
e735f4d4 MP |
63 | if (access("/proc/swaps", F_OK) < 0) { |
64 | log_info("Swap not supported, ignoring fstab swap entry for %s.", what); | |
65 | return 0; | |
66 | } | |
67 | ||
6300502b | 68 | if (detect_container() > 0) { |
60f067b4 JS |
69 | log_info("Running in a container, ignoring fstab swap entry for %s.", what); |
70 | return 0; | |
71 | } | |
72 | ||
e3bff60a MP |
73 | r = unit_name_from_path(what, ".swap", &name); |
74 | if (r < 0) | |
75 | return log_error_errno(r, "Failed to generate unit name: %m"); | |
663996b3 MS |
76 | |
77 | unit = strjoin(arg_dest, "/", name, NULL); | |
78 | if (!unit) | |
79 | return log_oom(); | |
80 | ||
81 | f = fopen(unit, "wxe"); | |
82 | if (!f) { | |
83 | if (errno == EEXIST) | |
84 | log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit); | |
85 | else | |
f47781d8 | 86 | log_error_errno(errno, "Failed to create unit file %s: %m", unit); |
663996b3 MS |
87 | return -errno; |
88 | } | |
89 | ||
663996b3 | 90 | fprintf(f, |
14228c0d MB |
91 | "# Automatically generated by systemd-fstab-generator\n\n" |
92 | "[Unit]\n" | |
60f067b4 JS |
93 | "SourcePath=/etc/fstab\n" |
94 | "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n" | |
663996b3 MS |
95 | "[Swap]\n" |
96 | "What=%s\n", | |
97 | what); | |
98 | ||
86f210e9 MP |
99 | if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults")) |
100 | fprintf(f, "Options=%s\n", me->mnt_opts); | |
5eef597e MP |
101 | |
102 | r = fflush_and_check(f); | |
f47781d8 MP |
103 | if (r < 0) |
104 | return log_error_errno(r, "Failed to write unit file %s: %m", unit); | |
663996b3 | 105 | |
e842803a | 106 | /* use what as where, to have a nicer error message */ |
86f210e9 | 107 | r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL); |
e842803a MB |
108 | if (r < 0) |
109 | return r; | |
110 | ||
663996b3 | 111 | if (!noauto) { |
f47781d8 MP |
112 | lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET, |
113 | nofail ? ".wants/" : ".requires/", name, NULL); | |
663996b3 MS |
114 | if (!lnk) |
115 | return log_oom(); | |
116 | ||
117 | mkdir_parents_label(lnk, 0755); | |
f47781d8 MP |
118 | if (symlink(unit, lnk) < 0) |
119 | return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); | |
663996b3 MS |
120 | } |
121 | ||
122 | return 0; | |
123 | } | |
124 | ||
663996b3 MS |
125 | static bool mount_is_network(struct mntent *me) { |
126 | assert(me); | |
127 | ||
e735f4d4 MP |
128 | return fstab_test_option(me->mnt_opts, "_netdev\0") || |
129 | fstype_is_network(me->mnt_type); | |
663996b3 MS |
130 | } |
131 | ||
132 | static bool mount_in_initrd(struct mntent *me) { | |
133 | assert(me); | |
134 | ||
e735f4d4 MP |
135 | return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") || |
136 | streq(me->mnt_dir, "/usr"); | |
663996b3 MS |
137 | } |
138 | ||
e3bff60a MP |
139 | static int write_idle_timeout(FILE *f, const char *where, const char *opts) { |
140 | _cleanup_free_ char *timeout = NULL; | |
141 | char timespan[FORMAT_TIMESPAN_MAX]; | |
142 | usec_t u; | |
143 | int r; | |
144 | ||
145 | r = fstab_filter_options(opts, "x-systemd.idle-timeout\0", NULL, &timeout, NULL); | |
146 | if (r < 0) | |
147 | return log_warning_errno(r, "Failed to parse options: %m"); | |
148 | if (r == 0) | |
149 | return 0; | |
150 | ||
151 | r = parse_sec(timeout, &u); | |
152 | if (r < 0) { | |
153 | log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout); | |
154 | return 0; | |
155 | } | |
156 | ||
157 | fprintf(f, "TimeoutIdleSec=%s\n", format_timespan(timespan, sizeof(timespan), u, 0)); | |
158 | ||
159 | return 0; | |
160 | } | |
161 | ||
162 | static int write_requires_after(FILE *f, const char *opts) { | |
163 | _cleanup_strv_free_ char **names = NULL, **units = NULL; | |
164 | _cleanup_free_ char *res = NULL; | |
165 | char **s; | |
166 | int r; | |
167 | ||
168 | assert(f); | |
169 | assert(opts); | |
170 | ||
171 | r = fstab_extract_values(opts, "x-systemd.requires", &names); | |
172 | if (r < 0) | |
173 | return log_warning_errno(r, "Failed to parse options: %m"); | |
174 | if (r == 0) | |
175 | return 0; | |
176 | ||
177 | STRV_FOREACH(s, names) { | |
178 | char *x; | |
179 | ||
180 | r = unit_name_mangle_with_suffix(*s, UNIT_NAME_NOGLOB, ".mount", &x); | |
181 | if (r < 0) | |
182 | return log_error_errno(r, "Failed to generate unit name: %m"); | |
183 | r = strv_consume(&units, x); | |
184 | if (r < 0) | |
185 | return log_oom(); | |
186 | } | |
187 | ||
188 | if (units) { | |
189 | res = strv_join(units, " "); | |
190 | if (!res) | |
191 | return log_oom(); | |
192 | fprintf(f, "After=%1$s\nRequires=%1$s\n", res); | |
193 | } | |
194 | ||
195 | return 0; | |
196 | } | |
197 | ||
198 | static int write_requires_mounts_for(FILE *f, const char *opts) { | |
199 | _cleanup_strv_free_ char **paths = NULL; | |
200 | _cleanup_free_ char *res = NULL; | |
201 | int r; | |
202 | ||
203 | assert(f); | |
204 | assert(opts); | |
205 | ||
206 | r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths); | |
207 | if (r < 0) | |
208 | return log_warning_errno(r, "Failed to parse options: %m"); | |
209 | if (r == 0) | |
210 | return 0; | |
211 | ||
212 | res = strv_join(paths, " "); | |
213 | if (!res) | |
214 | return log_oom(); | |
215 | ||
216 | fprintf(f, "RequiresMountsFor=%s\n", res); | |
217 | ||
218 | return 0; | |
219 | } | |
220 | ||
663996b3 MS |
221 | static int add_mount( |
222 | const char *what, | |
223 | const char *where, | |
60f067b4 | 224 | const char *fstype, |
663996b3 MS |
225 | const char *opts, |
226 | int passno, | |
227 | bool noauto, | |
228 | bool nofail, | |
229 | bool automount, | |
663996b3 MS |
230 | const char *post, |
231 | const char *source) { | |
60f067b4 | 232 | |
663996b3 | 233 | _cleanup_free_ char |
14228c0d | 234 | *name = NULL, *unit = NULL, *lnk = NULL, |
e842803a MB |
235 | *automount_name = NULL, *automount_unit = NULL, |
236 | *filtered = NULL; | |
663996b3 | 237 | _cleanup_fclose_ FILE *f = NULL; |
60f067b4 | 238 | int r; |
663996b3 MS |
239 | |
240 | assert(what); | |
241 | assert(where); | |
663996b3 MS |
242 | assert(opts); |
243 | assert(source); | |
244 | ||
60f067b4 | 245 | if (streq_ptr(fstype, "autofs")) |
663996b3 MS |
246 | return 0; |
247 | ||
248 | if (!is_path(where)) { | |
249 | log_warning("Mount point %s is not a valid path, ignoring.", where); | |
250 | return 0; | |
251 | } | |
252 | ||
253 | if (mount_point_is_api(where) || | |
254 | mount_point_ignore(where)) | |
255 | return 0; | |
256 | ||
60f067b4 | 257 | if (path_equal(where, "/")) { |
e3bff60a MP |
258 | if (noauto) |
259 | log_warning("Ignoring \"noauto\" for root device"); | |
260 | if (nofail) | |
261 | log_warning("Ignoring \"nofail\" for root device"); | |
262 | if (automount) | |
263 | log_warning("Ignoring automount option for root device"); | |
264 | ||
265 | noauto = nofail = automount = false; | |
60f067b4 JS |
266 | } |
267 | ||
e3bff60a MP |
268 | r = unit_name_from_path(where, ".mount", &name); |
269 | if (r < 0) | |
270 | return log_error_errno(r, "Failed to generate unit name: %m"); | |
663996b3 MS |
271 | |
272 | unit = strjoin(arg_dest, "/", name, NULL); | |
273 | if (!unit) | |
274 | return log_oom(); | |
275 | ||
276 | f = fopen(unit, "wxe"); | |
277 | if (!f) { | |
278 | if (errno == EEXIST) | |
279 | log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit); | |
280 | else | |
f47781d8 | 281 | log_error_errno(errno, "Failed to create unit file %s: %m", unit); |
663996b3 MS |
282 | return -errno; |
283 | } | |
284 | ||
285 | fprintf(f, | |
60f067b4 JS |
286 | "# Automatically generated by systemd-fstab-generator\n\n" |
287 | "[Unit]\n" | |
288 | "SourcePath=%s\n" | |
289 | "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n", | |
290 | source); | |
663996b3 | 291 | |
663996b3 | 292 | if (post && !noauto && !nofail && !automount) |
60f067b4 JS |
293 | fprintf(f, "Before=%s\n", post); |
294 | ||
e3bff60a MP |
295 | if (!automount && opts) { |
296 | r = write_requires_after(f, opts); | |
297 | if (r < 0) | |
298 | return r; | |
299 | r = write_requires_mounts_for(f, opts); | |
300 | if (r < 0) | |
301 | return r; | |
302 | } | |
303 | ||
60f067b4 JS |
304 | if (passno != 0) { |
305 | r = generator_write_fsck_deps(f, arg_dest, what, where, fstype); | |
306 | if (r < 0) | |
307 | return r; | |
308 | } | |
663996b3 MS |
309 | |
310 | fprintf(f, | |
311 | "\n" | |
312 | "[Mount]\n" | |
313 | "What=%s\n" | |
60f067b4 | 314 | "Where=%s\n", |
663996b3 | 315 | what, |
60f067b4 | 316 | where); |
663996b3 | 317 | |
60f067b4 JS |
318 | if (!isempty(fstype) && !streq(fstype, "auto")) |
319 | fprintf(f, "Type=%s\n", fstype); | |
320 | ||
e842803a MB |
321 | r = generator_write_timeouts(arg_dest, what, where, opts, &filtered); |
322 | if (r < 0) | |
323 | return r; | |
324 | ||
325 | if (!isempty(filtered) && !streq(filtered, "defaults")) | |
326 | fprintf(f, "Options=%s\n", filtered); | |
663996b3 | 327 | |
e3bff60a MP |
328 | r = fflush_and_check(f); |
329 | if (r < 0) | |
330 | return log_error_errno(r, "Failed to write unit file %s: %m", unit); | |
663996b3 | 331 | |
60f067b4 JS |
332 | if (!noauto && post) { |
333 | lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL); | |
334 | if (!lnk) | |
335 | return log_oom(); | |
336 | ||
337 | mkdir_parents_label(lnk, 0755); | |
f47781d8 MP |
338 | if (symlink(unit, lnk) < 0) |
339 | return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); | |
663996b3 MS |
340 | } |
341 | ||
60f067b4 | 342 | if (automount) { |
e3bff60a MP |
343 | r = unit_name_from_path(where, ".automount", &automount_name); |
344 | if (r < 0) | |
345 | return log_error_errno(r, "Failed to generate unit name: %m"); | |
663996b3 MS |
346 | |
347 | automount_unit = strjoin(arg_dest, "/", automount_name, NULL); | |
348 | if (!automount_unit) | |
349 | return log_oom(); | |
350 | ||
351 | fclose(f); | |
352 | f = fopen(automount_unit, "wxe"); | |
f47781d8 MP |
353 | if (!f) |
354 | return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit); | |
663996b3 MS |
355 | |
356 | fprintf(f, | |
357 | "# Automatically generated by systemd-fstab-generator\n\n" | |
358 | "[Unit]\n" | |
60f067b4 JS |
359 | "SourcePath=%s\n" |
360 | "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n", | |
663996b3 MS |
361 | source); |
362 | ||
363 | if (post) | |
364 | fprintf(f, | |
60f067b4 | 365 | "Before=%s\n", |
663996b3 MS |
366 | post); |
367 | ||
e3bff60a MP |
368 | if (opts) { |
369 | r = write_requires_after(f, opts); | |
370 | if (r < 0) | |
371 | return r; | |
372 | r = write_requires_mounts_for(f, opts); | |
373 | if (r < 0) | |
374 | return r; | |
375 | } | |
376 | ||
663996b3 MS |
377 | fprintf(f, |
378 | "[Automount]\n" | |
379 | "Where=%s\n", | |
380 | where); | |
381 | ||
e3bff60a MP |
382 | r = write_idle_timeout(f, where, opts); |
383 | if (r < 0) | |
384 | return r; | |
385 | ||
386 | r = fflush_and_check(f); | |
387 | if (r < 0) | |
388 | return log_error_errno(r, "Failed to write unit file %s: %m", automount_unit); | |
663996b3 MS |
389 | |
390 | free(lnk); | |
391 | lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL); | |
392 | if (!lnk) | |
393 | return log_oom(); | |
394 | ||
395 | mkdir_parents_label(lnk, 0755); | |
f47781d8 MP |
396 | if (symlink(automount_unit, lnk) < 0) |
397 | return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); | |
663996b3 MS |
398 | } |
399 | ||
400 | return 0; | |
401 | } | |
402 | ||
60f067b4 JS |
403 | static int parse_fstab(bool initrd) { |
404 | _cleanup_endmntent_ FILE *f = NULL; | |
405 | const char *fstab_path; | |
663996b3 | 406 | struct mntent *me; |
60f067b4 | 407 | int r = 0; |
663996b3 | 408 | |
60f067b4 JS |
409 | fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab"; |
410 | f = setmntent(fstab_path, "re"); | |
663996b3 MS |
411 | if (!f) { |
412 | if (errno == ENOENT) | |
413 | return 0; | |
414 | ||
f47781d8 | 415 | log_error_errno(errno, "Failed to open %s: %m", fstab_path); |
663996b3 MS |
416 | return -errno; |
417 | } | |
418 | ||
419 | while ((me = getmntent(f))) { | |
420 | _cleanup_free_ char *where = NULL, *what = NULL; | |
f47781d8 | 421 | bool noauto, nofail; |
663996b3 MS |
422 | int k; |
423 | ||
424 | if (initrd && !mount_in_initrd(me)) | |
425 | continue; | |
426 | ||
427 | what = fstab_node_to_udev_node(me->mnt_fsname); | |
60f067b4 JS |
428 | if (!what) |
429 | return log_oom(); | |
430 | ||
e735f4d4 | 431 | if (is_device_path(what) && path_is_read_only_fs("sys") > 0) { |
60f067b4 JS |
432 | log_info("Running in a container, ignoring fstab device entry for %s.", what); |
433 | continue; | |
663996b3 MS |
434 | } |
435 | ||
60f067b4 JS |
436 | where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir); |
437 | if (!where) | |
438 | return log_oom(); | |
439 | ||
663996b3 MS |
440 | if (is_path(where)) |
441 | path_kill_slashes(where); | |
442 | ||
e735f4d4 MP |
443 | noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0"); |
444 | nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0"); | |
f47781d8 MP |
445 | log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s", |
446 | what, where, me->mnt_type, | |
447 | yes_no(noauto), yes_no(nofail)); | |
663996b3 MS |
448 | |
449 | if (streq(me->mnt_type, "swap")) | |
f47781d8 | 450 | k = add_swap(what, me, noauto, nofail); |
663996b3 | 451 | else { |
f47781d8 | 452 | bool automount; |
14228c0d | 453 | const char *post; |
663996b3 | 454 | |
e735f4d4 MP |
455 | automount = fstab_test_option(me->mnt_opts, |
456 | "comment=systemd.automount\0" | |
457 | "x-systemd.automount\0"); | |
60f067b4 | 458 | if (initrd) |
663996b3 | 459 | post = SPECIAL_INITRD_FS_TARGET; |
60f067b4 | 460 | else if (mount_in_initrd(me)) |
663996b3 | 461 | post = SPECIAL_INITRD_ROOT_FS_TARGET; |
60f067b4 | 462 | else if (mount_is_network(me)) |
663996b3 | 463 | post = SPECIAL_REMOTE_FS_TARGET; |
60f067b4 | 464 | else |
663996b3 | 465 | post = SPECIAL_LOCAL_FS_TARGET; |
663996b3 | 466 | |
60f067b4 JS |
467 | k = add_mount(what, |
468 | where, | |
469 | me->mnt_type, | |
470 | me->mnt_opts, | |
471 | me->mnt_passno, | |
472 | noauto, | |
473 | nofail, | |
474 | automount, | |
475 | post, | |
476 | fstab_path); | |
663996b3 MS |
477 | } |
478 | ||
479 | if (k < 0) | |
480 | r = k; | |
481 | } | |
482 | ||
663996b3 MS |
483 | return r; |
484 | } | |
485 | ||
e3bff60a | 486 | static int add_sysroot_mount(void) { |
e842803a MB |
487 | _cleanup_free_ char *what = NULL; |
488 | const char *opts; | |
663996b3 | 489 | |
60f067b4 | 490 | if (isempty(arg_root_what)) { |
f47781d8 | 491 | log_debug("Could not find a root= entry on the kernel command line."); |
663996b3 MS |
492 | return 0; |
493 | } | |
494 | ||
60f067b4 | 495 | what = fstab_node_to_udev_node(arg_root_what); |
e3bff60a MP |
496 | if (!what) |
497 | return log_oom(); | |
663996b3 | 498 | |
60f067b4 | 499 | if (!arg_root_options) |
e842803a MB |
500 | opts = arg_root_rw > 0 ? "rw" : "ro"; |
501 | else if (arg_root_rw >= 0 || | |
e735f4d4 MP |
502 | !fstab_test_option(arg_root_options, "ro\0" "rw\0")) |
503 | opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro"); | |
e842803a MB |
504 | else |
505 | opts = arg_root_options; | |
663996b3 | 506 | |
60f067b4 JS |
507 | log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype)); |
508 | return add_mount(what, | |
509 | "/sysroot", | |
510 | arg_root_fstype, | |
e842803a | 511 | opts, |
e3bff60a | 512 | is_device_path(what) ? 1 : 0, |
60f067b4 JS |
513 | false, |
514 | false, | |
515 | false, | |
516 | SPECIAL_INITRD_ROOT_FS_TARGET, | |
517 | "/proc/cmdline"); | |
663996b3 MS |
518 | } |
519 | ||
e3bff60a | 520 | static int add_sysroot_usr_mount(void) { |
5eef597e MP |
521 | _cleanup_free_ char *what = NULL; |
522 | const char *opts; | |
523 | ||
524 | if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options) | |
525 | return 0; | |
526 | ||
527 | if (arg_root_what && !arg_usr_what) { | |
528 | arg_usr_what = strdup(arg_root_what); | |
529 | ||
530 | if (!arg_usr_what) | |
531 | return log_oom(); | |
532 | } | |
533 | ||
534 | if (arg_root_fstype && !arg_usr_fstype) { | |
535 | arg_usr_fstype = strdup(arg_root_fstype); | |
536 | ||
537 | if (!arg_usr_fstype) | |
538 | return log_oom(); | |
539 | } | |
540 | ||
541 | if (arg_root_options && !arg_usr_options) { | |
542 | arg_usr_options = strdup(arg_root_options); | |
543 | ||
544 | if (!arg_usr_options) | |
545 | return log_oom(); | |
546 | } | |
547 | ||
f47781d8 | 548 | if (!arg_usr_what) |
5eef597e MP |
549 | return 0; |
550 | ||
551 | what = fstab_node_to_udev_node(arg_usr_what); | |
552 | if (!path_is_absolute(what)) { | |
553 | log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype)); | |
554 | return -1; | |
555 | } | |
556 | ||
f47781d8 MP |
557 | if (!arg_usr_options) |
558 | opts = arg_root_rw > 0 ? "rw" : "ro"; | |
e735f4d4 MP |
559 | else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0")) |
560 | opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro"); | |
f47781d8 MP |
561 | else |
562 | opts = arg_usr_options; | |
5eef597e MP |
563 | |
564 | log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype)); | |
565 | return add_mount(what, | |
566 | "/sysroot/usr", | |
567 | arg_usr_fstype, | |
568 | opts, | |
569 | 1, | |
570 | false, | |
571 | false, | |
572 | false, | |
573 | SPECIAL_INITRD_ROOT_FS_TARGET, | |
574 | "/proc/cmdline"); | |
575 | } | |
576 | ||
60f067b4 | 577 | static int parse_proc_cmdline_item(const char *key, const char *value) { |
663996b3 | 578 | int r; |
663996b3 | 579 | |
5eef597e MP |
580 | /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last |
581 | * instance should take precedence. In the case of multiple rootflags= | |
582 | * or usrflags= the arguments should be concatenated */ | |
663996b3 | 583 | |
60f067b4 JS |
584 | if (STR_IN_SET(key, "fstab", "rd.fstab") && value) { |
585 | ||
586 | r = parse_boolean(value); | |
587 | if (r < 0) | |
588 | log_warning("Failed to parse fstab switch %s. Ignoring.", value); | |
589 | else | |
590 | arg_fstab_enabled = r; | |
663996b3 | 591 | |
60f067b4 | 592 | } else if (streq(key, "root") && value) { |
663996b3 | 593 | |
5eef597e | 594 | if (free_and_strdup(&arg_root_what, value) < 0) |
663996b3 MS |
595 | return log_oom(); |
596 | ||
60f067b4 | 597 | } else if (streq(key, "rootfstype") && value) { |
663996b3 | 598 | |
5eef597e | 599 | if (free_and_strdup(&arg_root_fstype, value) < 0) |
60f067b4 | 600 | return log_oom(); |
663996b3 | 601 | |
60f067b4 JS |
602 | } else if (streq(key, "rootflags") && value) { |
603 | char *o; | |
663996b3 | 604 | |
60f067b4 JS |
605 | o = arg_root_options ? |
606 | strjoin(arg_root_options, ",", value, NULL) : | |
607 | strdup(value); | |
608 | if (!o) | |
609 | return log_oom(); | |
663996b3 | 610 | |
60f067b4 JS |
611 | free(arg_root_options); |
612 | arg_root_options = o; | |
613 | ||
5eef597e MP |
614 | } else if (streq(key, "mount.usr") && value) { |
615 | ||
616 | if (free_and_strdup(&arg_usr_what, value) < 0) | |
617 | return log_oom(); | |
618 | ||
619 | } else if (streq(key, "mount.usrfstype") && value) { | |
620 | ||
621 | if (free_and_strdup(&arg_usr_fstype, value) < 0) | |
622 | return log_oom(); | |
623 | ||
624 | } else if (streq(key, "mount.usrflags") && value) { | |
625 | char *o; | |
626 | ||
627 | o = arg_usr_options ? | |
628 | strjoin(arg_usr_options, ",", value, NULL) : | |
629 | strdup(value); | |
630 | if (!o) | |
631 | return log_oom(); | |
632 | ||
633 | free(arg_usr_options); | |
634 | arg_usr_options = o; | |
635 | ||
60f067b4 JS |
636 | } else if (streq(key, "rw") && !value) |
637 | arg_root_rw = true; | |
638 | else if (streq(key, "ro") && !value) | |
639 | arg_root_rw = false; | |
663996b3 MS |
640 | |
641 | return 0; | |
642 | } | |
643 | ||
644 | int main(int argc, char *argv[]) { | |
60f067b4 | 645 | int r = 0; |
663996b3 MS |
646 | |
647 | if (argc > 1 && argc != 4) { | |
648 | log_error("This program takes three or no arguments."); | |
649 | return EXIT_FAILURE; | |
650 | } | |
651 | ||
652 | if (argc > 1) | |
653 | arg_dest = argv[1]; | |
654 | ||
655 | log_set_target(LOG_TARGET_SAFE); | |
656 | log_parse_environment(); | |
657 | log_open(); | |
658 | ||
659 | umask(0022); | |
660 | ||
f47781d8 MP |
661 | r = parse_proc_cmdline(parse_proc_cmdline_item); |
662 | if (r < 0) | |
663 | log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); | |
663996b3 | 664 | |
5eef597e MP |
665 | /* Always honour root= and usr= in the kernel command line if we are in an initrd */ |
666 | if (in_initrd()) { | |
e3bff60a | 667 | r = add_sysroot_mount(); |
5eef597e | 668 | if (r == 0) |
e3bff60a | 669 | r = add_sysroot_usr_mount(); |
5eef597e | 670 | } |
663996b3 | 671 | |
60f067b4 JS |
672 | /* Honour /etc/fstab only when that's enabled */ |
673 | if (arg_fstab_enabled) { | |
674 | int k; | |
663996b3 | 675 | |
e842803a MB |
676 | log_debug("Parsing /etc/fstab"); |
677 | ||
60f067b4 JS |
678 | /* Parse the local /etc/fstab, possibly from the initrd */ |
679 | k = parse_fstab(false); | |
680 | if (k < 0) | |
681 | r = k; | |
663996b3 | 682 | |
60f067b4 JS |
683 | /* If running in the initrd also parse the /etc/fstab from the host */ |
684 | if (in_initrd()) { | |
e842803a MB |
685 | log_debug("Parsing /sysroot/etc/fstab"); |
686 | ||
60f067b4 JS |
687 | k = parse_fstab(true); |
688 | if (k < 0) | |
689 | r = k; | |
690 | } | |
691 | } | |
663996b3 | 692 | |
5eef597e | 693 | free(arg_root_what); |
f47781d8 MP |
694 | free(arg_root_fstype); |
695 | free(arg_root_options); | |
696 | ||
697 | free(arg_usr_what); | |
698 | free(arg_usr_fstype); | |
699 | free(arg_usr_options); | |
5eef597e | 700 | |
60f067b4 | 701 | return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; |
663996b3 | 702 | } |