]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/fstab-generator/fstab-generator.c
sd-event: drop _likely_()
[thirdparty/systemd.git] / src / fstab-generator / fstab-generator.c
CommitLineData
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
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"
32#include "mount-setup.h"
33#include "special.h"
34#include "mkdir.h"
a5c32cff 35#include "fileio.h"
e48fdd84 36#include "generator.h"
059cb385 37#include "strv.h"
689aede8 38#include "virt.h"
6b1dc2bd
LP
39
40static const char *arg_dest = "/tmp";
e48fdd84 41static bool arg_fstab_enabled = true;
6db615c1
LP
42static char *arg_root_what = NULL;
43static char *arg_root_fstype = NULL;
44static char *arg_root_options = NULL;
45static int arg_root_rw = -1;
6b1dc2bd 46
29686440 47
6b1dc2bd
LP
48static int mount_find_pri(struct mntent *me, int *ret) {
49 char *end, *pri;
50 unsigned long r;
51
52 assert(me);
53 assert(ret);
54
55 pri = hasmntopt(me, "pri");
56 if (!pri)
57 return 0;
58
59 pri += 4;
60
61 errno = 0;
62 r = strtoul(pri, &end, 10);
8333c77e 63 if (errno > 0)
6b1dc2bd
LP
64 return -errno;
65
66 if (end == pri || (*end != ',' && *end != 0))
67 return -EINVAL;
68
69 *ret = (int) r;
70 return 1;
71}
72
73static int add_swap(const char *what, struct mntent *me) {
1dc2ced4 74 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
7fd1b19b 75 _cleanup_fclose_ FILE *f = NULL;
4e82fe52 76 bool noauto;
6b1dc2bd
LP
77 int r, pri = -1;
78
79 assert(what);
80 assert(me);
81
689aede8
LP
82 if (detect_container(NULL) > 0) {
83 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
84 return 0;
85 }
86
6b1dc2bd
LP
87 r = mount_find_pri(me, &pri);
88 if (r < 0) {
89 log_error("Failed to parse priority");
90 return pri;
91 }
92
4e82fe52
TG
93 noauto = !!hasmntopt(me, "noauto");
94
6b1dc2bd 95 name = unit_name_from_path(what, ".swap");
d0aa9ce5
ZJS
96 if (!name)
97 return log_oom();
6b1dc2bd 98
b7def684 99 unit = strjoin(arg_dest, "/", name, NULL);
d0aa9ce5
ZJS
100 if (!unit)
101 return log_oom();
6b1dc2bd
LP
102
103 f = fopen(unit, "wxe");
104 if (!f) {
67ab5f76
TG
105 if (errno == EEXIST)
106 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
107 else
108 log_error("Failed to create unit file %s: %m", unit);
d0aa9ce5 109 return -errno;
6b1dc2bd
LP
110 }
111
6b1dc2bd 112 fprintf(f,
64347fc2
TG
113 "# Automatically generated by systemd-fstab-generator\n\n"
114 "[Unit]\n"
c3834f9b
LP
115 "SourcePath=/etc/fstab\n"
116 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
6b1dc2bd
LP
117 "[Swap]\n"
118 "What=%s\n",
119 what);
120
121 if (pri >= 0)
122 fprintf(f,
123 "Priority=%i\n",
124 pri);
125
126 fflush(f);
127 if (ferror(f)) {
40b8acd0 128 log_error("Failed to write unit file %s: %m", unit);
d0aa9ce5 129 return -errno;
6b1dc2bd
LP
130 }
131
b3208b66
ZJS
132 /* use what as where, to have a nicer error message */
133 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
134 if (r < 0)
135 return r;
136
4e82fe52
TG
137 if (!noauto) {
138 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
139 if (!lnk)
140 return log_oom();
141
142 mkdir_parents_label(lnk, 0755);
143 if (symlink(unit, lnk) < 0) {
144 log_error("Failed to create symlink %s: %m", lnk);
145 return -errno;
146 }
147 }
148
d0aa9ce5 149 return 0;
6b1dc2bd
LP
150}
151
6b1dc2bd
LP
152static bool mount_is_network(struct mntent *me) {
153 assert(me);
154
155 return
156 hasmntopt(me, "_netdev") ||
157 fstype_is_network(me->mnt_type);
158}
159
3d22d1ab
TG
160static bool mount_in_initrd(struct mntent *me) {
161 assert(me);
162
163 return
164 hasmntopt(me, "x-initrd.mount") ||
165 streq(me->mnt_dir, "/usr");
166}
167
e8d2f6cd
LP
168static int add_mount(
169 const char *what,
170 const char *where,
6db615c1 171 const char *fstype,
e8d2f6cd
LP
172 const char *opts,
173 int passno,
174 bool noauto,
175 bool nofail,
176 bool automount,
e8d2f6cd 177 const char *post,
e8d2f6cd 178 const char *source) {
e48fdd84 179
7fd1b19b 180 _cleanup_free_ char
1dc2ced4 181 *name = NULL, *unit = NULL, *lnk = NULL,
29686440
ZJS
182 *automount_name = NULL, *automount_unit = NULL,
183 *filtered = NULL;
7fd1b19b 184 _cleanup_fclose_ FILE *f = NULL;
94192cda 185 int r;
6b1dc2bd
LP
186
187 assert(what);
188 assert(where);
5e398e54
TG
189 assert(opts);
190 assert(source);
6b1dc2bd 191
6db615c1 192 if (streq_ptr(fstype, "autofs"))
6b1dc2bd
LP
193 return 0;
194
195 if (!is_path(where)) {
196 log_warning("Mount point %s is not a valid path, ignoring.", where);
197 return 0;
198 }
199
200 if (mount_point_is_api(where) ||
201 mount_point_ignore(where))
202 return 0;
203
e48fdd84 204 if (path_equal(where, "/")) {
5ecdcf41 205 /* The root disk is not an option */
e48fdd84
LP
206 automount = false;
207 noauto = false;
208 nofail = false;
209 }
210
6b1dc2bd 211 name = unit_name_from_path(where, ".mount");
d0aa9ce5
ZJS
212 if (!name)
213 return log_oom();
6b1dc2bd 214
b7def684 215 unit = strjoin(arg_dest, "/", name, NULL);
d0aa9ce5
ZJS
216 if (!unit)
217 return log_oom();
6b1dc2bd
LP
218
219 f = fopen(unit, "wxe");
220 if (!f) {
67ab5f76
TG
221 if (errno == EEXIST)
222 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
223 else
224 log_error("Failed to create unit file %s: %m", unit);
d0aa9ce5 225 return -errno;
6b1dc2bd
LP
226 }
227
5e398e54 228 fprintf(f,
c3834f9b
LP
229 "# Automatically generated by systemd-fstab-generator\n\n"
230 "[Unit]\n"
231 "SourcePath=%s\n"
232 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
233 source);
6b1dc2bd 234
700e07ff 235 if (post && !noauto && !nofail && !automount)
5ecdcf41 236 fprintf(f, "Before=%s\n", post);
6b1dc2bd 237
e48fdd84 238 if (passno != 0) {
6db615c1 239 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
e48fdd84
LP
240 if (r < 0)
241 return r;
242 }
64e70e4b 243
6b1dc2bd
LP
244 fprintf(f,
245 "\n"
246 "[Mount]\n"
247 "What=%s\n"
6db615c1 248 "Where=%s\n",
6b1dc2bd 249 what,
6db615c1
LP
250 where);
251
252 if (!isempty(fstype) && !streq(fstype, "auto"))
253 fprintf(f, "Type=%s\n", fstype);
6b1dc2bd 254
29686440
ZJS
255 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
256 if (r < 0)
257 return r;
258
259 if (!isempty(filtered) && !streq(filtered, "defaults"))
260 fprintf(f, "Options=%s\n", filtered);
5e398e54 261
6b1dc2bd
LP
262 fflush(f);
263 if (ferror(f)) {
40b8acd0 264 log_error("Failed to write unit file %s: %m", unit);
d0aa9ce5 265 return -errno;
6b1dc2bd
LP
266 }
267
5ecdcf41
LP
268 if (!noauto && post) {
269 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
270 if (!lnk)
271 return log_oom();
272
273 mkdir_parents_label(lnk, 0755);
274 if (symlink(unit, lnk) < 0) {
275 log_error("Failed to create symlink %s: %m", lnk);
276 return -errno;
6b1dc2bd 277 }
6b1dc2bd
LP
278 }
279
e48fdd84 280 if (automount) {
6b1dc2bd 281 automount_name = unit_name_from_path(where, ".automount");
01264ad1 282 if (!automount_name)
d0aa9ce5 283 return log_oom();
6b1dc2bd 284
b7def684 285 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
d0aa9ce5
ZJS
286 if (!automount_unit)
287 return log_oom();
6b1dc2bd
LP
288
289 fclose(f);
290 f = fopen(automount_unit, "wxe");
291 if (!f) {
40b8acd0 292 log_error("Failed to create unit file %s: %m", automount_unit);
d0aa9ce5 293 return -errno;
6b1dc2bd
LP
294 }
295
296 fprintf(f,
297 "# Automatically generated by systemd-fstab-generator\n\n"
298 "[Unit]\n"
c3834f9b
LP
299 "SourcePath=%s\n"
300 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
700e07ff
HH
301 source);
302
303 if (post)
304 fprintf(f,
e48fdd84 305 "Before=%s\n",
700e07ff
HH
306 post);
307
308 fprintf(f,
6b1dc2bd
LP
309 "[Automount]\n"
310 "Where=%s\n",
6b1dc2bd
LP
311 where);
312
313 fflush(f);
314 if (ferror(f)) {
40b8acd0 315 log_error("Failed to write unit file %s: %m", automount_unit);
d0aa9ce5 316 return -errno;
6b1dc2bd
LP
317 }
318
319 free(lnk);
b7def684 320 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
d0aa9ce5
ZJS
321 if (!lnk)
322 return log_oom();
6b1dc2bd 323
d2e54fae 324 mkdir_parents_label(lnk, 0755);
6b1dc2bd 325 if (symlink(automount_unit, lnk) < 0) {
40b8acd0 326 log_error("Failed to create symlink %s: %m", lnk);
d0aa9ce5 327 return -errno;
6b1dc2bd
LP
328 }
329 }
330
d0aa9ce5 331 return 0;
6b1dc2bd
LP
332}
333
e48fdd84 334static int parse_fstab(bool initrd) {
6db615c1 335 _cleanup_endmntent_ FILE *f = NULL;
e48fdd84 336 const char *fstab_path;
6b1dc2bd 337 struct mntent *me;
e48fdd84 338 int r = 0;
6b1dc2bd 339
e48fdd84
LP
340 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
341 f = setmntent(fstab_path, "re");
6b1dc2bd
LP
342 if (!f) {
343 if (errno == ENOENT)
344 return 0;
345
e48fdd84 346 log_error("Failed to open %s: %m", fstab_path);
6b1dc2bd
LP
347 return -errno;
348 }
349
350 while ((me = getmntent(f))) {
7fd1b19b 351 _cleanup_free_ char *where = NULL, *what = NULL;
6b1dc2bd
LP
352 int k;
353
3d22d1ab
TG
354 if (initrd && !mount_in_initrd(me))
355 continue;
356
6b1dc2bd 357 what = fstab_node_to_udev_node(me->mnt_fsname);
e48fdd84
LP
358 if (!what)
359 return log_oom();
360
689aede8
LP
361 if (detect_container(NULL) > 0 && is_device_path(what)) {
362 log_info("Running in a container, ignoring fstab device entry for %s.", what);
363 continue;
364 }
365
e48fdd84
LP
366 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
367 if (!where)
5862d652 368 return log_oom();
6b1dc2bd 369
ec6ceb18 370 if (is_path(where))
6b1dc2bd
LP
371 path_kill_slashes(where);
372
373 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
374
375 if (streq(me->mnt_type, "swap"))
376 k = add_swap(what, me);
5e398e54 377 else {
5073f89f 378 bool noauto, nofail, automount;
80c3b720 379 const char *post;
5e398e54
TG
380
381 noauto = !!hasmntopt(me, "noauto");
382 nofail = !!hasmntopt(me, "nofail");
383 automount =
384 hasmntopt(me, "comment=systemd.automount") ||
385 hasmntopt(me, "x-systemd.automount");
700e07ff 386
e48fdd84 387 if (initrd)
700e07ff 388 post = SPECIAL_INITRD_FS_TARGET;
e48fdd84 389 else if (mount_in_initrd(me))
9e5f0f92 390 post = SPECIAL_INITRD_ROOT_FS_TARGET;
e48fdd84 391 else if (mount_is_network(me))
0c17fbce 392 post = SPECIAL_REMOTE_FS_TARGET;
e48fdd84 393 else
0c17fbce 394 post = SPECIAL_LOCAL_FS_TARGET;
5e398e54 395
6db615c1
LP
396 k = add_mount(what,
397 where,
398 me->mnt_type,
399 me->mnt_opts,
400 me->mnt_passno,
401 noauto,
402 nofail,
403 automount,
404 post,
405 fstab_path);
5e398e54 406 }
6b1dc2bd 407
6b1dc2bd
LP
408 if (k < 0)
409 r = k;
410 }
411
6b1dc2bd
LP
412 return r;
413}
414
6db615c1 415static int add_root_mount(void) {
75a59316
ZJS
416 _cleanup_free_ char *what = NULL;
417 const char *opts;
5e398e54 418
6db615c1 419 if (isempty(arg_root_what)) {
4e5ed9b6 420 log_debug("Could not find a root= entry on the kernel commandline.");
135b5212
HH
421 return 0;
422 }
5e398e54 423
6db615c1
LP
424 what = fstab_node_to_udev_node(arg_root_what);
425 if (!path_is_absolute(what)) {
426 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
135b5212
HH
427 return 0;
428 }
5e398e54 429
6db615c1 430 if (!arg_root_options)
75a59316
ZJS
431 opts = arg_root_rw > 0 ? "rw" : "ro";
432 else if (arg_root_rw >= 0 ||
433 (!mount_test_option(arg_root_options, "ro") &&
434 !mount_test_option(arg_root_options, "rw")))
435 opts = strappenda3(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
436 else
437 opts = arg_root_options;
5e398e54 438
6db615c1
LP
439 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
440 return add_mount(what,
441 "/sysroot",
442 arg_root_fstype,
75a59316 443 opts,
6db615c1 444 1,
5ecdcf41
LP
445 false,
446 false,
6db615c1
LP
447 false,
448 SPECIAL_INITRD_ROOT_FS_TARGET,
449 "/proc/cmdline");
5e398e54
TG
450}
451
059cb385 452static int parse_proc_cmdline_item(const char *key, const char *value) {
74df0fca 453 int r;
94734142 454
6db615c1
LP
455 /* root= and roofstype= may occur more than once, the last
456 * instance should take precedence. In the case of multiple
457 * rootflags= the arguments should be concatenated */
458
059cb385 459 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
e48fdd84 460
059cb385 461 r = parse_boolean(value);
141a79f4 462 if (r < 0)
059cb385 463 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
141a79f4 464 else
e48fdd84 465 arg_fstab_enabled = r;
94734142 466
6db615c1
LP
467 } else if (streq(key, "root") && value) {
468
469 free(arg_root_what);
470 arg_root_what = strdup(value);
471 if (!arg_root_what)
472 return log_oom();
473
474 } else if (streq(key, "rootfstype") && value) {
475
476 free(arg_root_fstype);
477 arg_root_fstype = strdup(value);
478 if (!arg_root_fstype)
479 return log_oom();
480
481 } else if (streq(key, "rootflags") && value) {
482 char *o;
483
484 o = arg_root_options ?
485 strjoin(arg_root_options, ",", value, NULL) :
486 strdup(value);
487 if (!o)
488 return log_oom();
489
490 free(arg_root_options);
491 arg_root_options = o;
492
493 } else if (streq(key, "rw") && !value)
494 arg_root_rw = true;
495 else if (streq(key, "ro") && !value)
496 arg_root_rw = false;
94734142 497
d0aa9ce5 498 return 0;
94734142
LP
499}
500
6b1dc2bd 501int main(int argc, char *argv[]) {
e48fdd84 502 int r = 0;
6b1dc2bd 503
07719a21
LP
504 if (argc > 1 && argc != 4) {
505 log_error("This program takes three or no arguments.");
6b1dc2bd
LP
506 return EXIT_FAILURE;
507 }
508
509 if (argc > 1)
510 arg_dest = argv[1];
511
a6903061 512 log_set_target(LOG_TARGET_SAFE);
6b1dc2bd
LP
513 log_parse_environment();
514 log_open();
515
6b1dc2bd
LP
516 umask(0022);
517
059cb385 518 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
94734142
LP
519 return EXIT_FAILURE;
520
e48fdd84 521 /* Always honour root= in the kernel command line if we are in an initrd */
ac4785b0 522 if (in_initrd())
6db615c1 523 r = add_root_mount();
5e398e54 524
e48fdd84
LP
525 /* Honour /etc/fstab only when that's enabled */
526 if (arg_fstab_enabled) {
527 int k;
ac4785b0 528
75a59316
ZJS
529 log_debug("Parsing /etc/fstab");
530
e48fdd84
LP
531 /* Parse the local /etc/fstab, possibly from the initrd */
532 k = parse_fstab(false);
533 if (k < 0)
534 r = k;
ac4785b0 535
e48fdd84
LP
536 /* If running in the initrd also parse the /etc/fstab from the host */
537 if (in_initrd()) {
75a59316
ZJS
538 log_debug("Parsing /sysroot/etc/fstab");
539
e48fdd84
LP
540 k = parse_fstab(true);
541 if (k < 0)
542 r = k;
543 }
544 }
6b1dc2bd 545
126cc760
ZJS
546 free(arg_root_what);
547
e48fdd84 548 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6b1dc2bd 549}