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