]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/fstab-generator/fstab-generator.c
main: don't mount /sys, /dev and friends when we run with PID != 1
[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"
94734142 35#include "virt.h"
a5c32cff 36#include "fileio.h"
6b1dc2bd
LP
37
38static const char *arg_dest = "/tmp";
94734142 39static bool arg_enabled = true;
6b1dc2bd
LP
40
41static int device_name(const char *path, char **unit) {
42 char *p;
43
44 assert(path);
45
46 if (!is_device_path(path))
47 return 0;
48
49 p = unit_name_from_path(path, ".device");
50 if (!p)
0d0f0c50 51 return log_oom();
6b1dc2bd
LP
52
53 *unit = p;
54 return 1;
55}
56
57static int mount_find_pri(struct mntent *me, int *ret) {
58 char *end, *pri;
59 unsigned long r;
60
61 assert(me);
62 assert(ret);
63
64 pri = hasmntopt(me, "pri");
65 if (!pri)
66 return 0;
67
68 pri += 4;
69
70 errno = 0;
71 r = strtoul(pri, &end, 10);
72 if (errno != 0)
73 return -errno;
74
75 if (end == pri || (*end != ',' && *end != 0))
76 return -EINVAL;
77
78 *ret = (int) r;
79 return 1;
80}
81
82static int add_swap(const char *what, struct mntent *me) {
d0aa9ce5
ZJS
83 char _cleanup_free_ *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL;
84 FILE _cleanup_fclose_ *f = NULL;
6b1dc2bd
LP
85 bool noauto, nofail;
86 int r, pri = -1;
87
88 assert(what);
89 assert(me);
90
91 r = mount_find_pri(me, &pri);
92 if (r < 0) {
93 log_error("Failed to parse priority");
94 return pri;
95 }
96
97 noauto = !!hasmntopt(me, "noauto");
98 nofail = !!hasmntopt(me, "nofail");
99
100 name = unit_name_from_path(what, ".swap");
d0aa9ce5
ZJS
101 if (!name)
102 return log_oom();
6b1dc2bd 103
b7def684 104 unit = strjoin(arg_dest, "/", name, NULL);
d0aa9ce5
ZJS
105 if (!unit)
106 return log_oom();
6b1dc2bd
LP
107
108 f = fopen(unit, "wxe");
109 if (!f) {
67ab5f76
TG
110 if (errno == EEXIST)
111 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
112 else
113 log_error("Failed to create unit file %s: %m", unit);
d0aa9ce5 114 return -errno;
6b1dc2bd
LP
115 }
116
117 fputs("# Automatically generated by systemd-fstab-generator\n\n"
118 "[Unit]\n"
1b64d026 119 "SourcePath=/etc/fstab\n"
6b1dc2bd
LP
120 "DefaultDependencies=no\n"
121 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
122 "Before=" SPECIAL_UMOUNT_TARGET "\n", f);
123
124 if (!noauto && !nofail)
125 fputs("Before=" SPECIAL_SWAP_TARGET "\n", f);
126
127 fprintf(f,
128 "\n"
129 "[Swap]\n"
130 "What=%s\n",
131 what);
132
133 if (pri >= 0)
134 fprintf(f,
135 "Priority=%i\n",
136 pri);
137
138 fflush(f);
139 if (ferror(f)) {
40b8acd0 140 log_error("Failed to write unit file %s: %m", unit);
d0aa9ce5 141 return -errno;
6b1dc2bd
LP
142 }
143
144 if (!noauto) {
b7def684 145 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
d0aa9ce5
ZJS
146 if (!lnk)
147 return log_oom();
6b1dc2bd 148
d2e54fae 149 mkdir_parents_label(lnk, 0755);
6b1dc2bd 150 if (symlink(unit, lnk) < 0) {
40b8acd0 151 log_error("Failed to create symlink %s: %m", lnk);
d0aa9ce5 152 return -errno;
6b1dc2bd
LP
153 }
154
155 r = device_name(what, &device);
0d0f0c50 156 if (r < 0)
d0aa9ce5 157 return r;
6b1dc2bd
LP
158
159 if (r > 0) {
160 free(lnk);
b7def684 161 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
d0aa9ce5
ZJS
162 if (!lnk)
163 return log_oom();
6b1dc2bd 164
d2e54fae 165 mkdir_parents_label(lnk, 0755);
6b1dc2bd 166 if (symlink(unit, lnk) < 0) {
40b8acd0 167 log_error("Failed to create symlink %s: %m", lnk);
d0aa9ce5 168 return -errno;
6b1dc2bd
LP
169 }
170 }
171 }
172
d0aa9ce5 173 return 0;
6b1dc2bd
LP
174}
175
f9ea108e
LP
176static bool mount_is_bind(struct mntent *me) {
177 assert(me);
178
179 return
180 hasmntopt(me, "bind") ||
3f8ee791
FC
181 streq(me->mnt_type, "bind") ||
182 hasmntopt(me, "rbind") ||
183 streq(me->mnt_type, "rbind");
f9ea108e
LP
184}
185
6b1dc2bd
LP
186static bool mount_is_network(struct mntent *me) {
187 assert(me);
188
189 return
190 hasmntopt(me, "_netdev") ||
191 fstype_is_network(me->mnt_type);
192}
193
3d22d1ab
TG
194static bool mount_in_initrd(struct mntent *me) {
195 assert(me);
196
197 return
198 hasmntopt(me, "x-initrd.mount") ||
199 streq(me->mnt_dir, "/usr");
200}
201
5e398e54 202static int add_mount(const char *what, const char *where, const char *type, const char *opts,
700e07ff
HH
203 int passno, bool noauto, bool nofail, bool automount, bool isbind,
204 const char *pre, const char *post, const char *source) {
d0aa9ce5
ZJS
205 char _cleanup_free_
206 *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL,
207 *automount_name = NULL, *automount_unit = NULL;
208 FILE _cleanup_fclose_ *f = NULL;
6b1dc2bd 209 int r;
6b1dc2bd
LP
210
211 assert(what);
212 assert(where);
5e398e54
TG
213 assert(type);
214 assert(opts);
215 assert(source);
6b1dc2bd 216
5e398e54 217 if (streq(type, "autofs"))
6b1dc2bd
LP
218 return 0;
219
220 if (!is_path(where)) {
221 log_warning("Mount point %s is not a valid path, ignoring.", where);
222 return 0;
223 }
224
225 if (mount_point_is_api(where) ||
226 mount_point_ignore(where))
227 return 0;
228
6b1dc2bd 229 name = unit_name_from_path(where, ".mount");
d0aa9ce5
ZJS
230 if (!name)
231 return log_oom();
6b1dc2bd 232
b7def684 233 unit = strjoin(arg_dest, "/", name, NULL);
d0aa9ce5
ZJS
234 if (!unit)
235 return log_oom();
6b1dc2bd
LP
236
237 f = fopen(unit, "wxe");
238 if (!f) {
67ab5f76
TG
239 if (errno == EEXIST)
240 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
241 else
242 log_error("Failed to create unit file %s: %m", unit);
d0aa9ce5 243 return -errno;
6b1dc2bd
LP
244 }
245
5e398e54
TG
246 fprintf(f,
247 "# Automatically generated by systemd-fstab-generator\n\n"
6b1dc2bd 248 "[Unit]\n"
5e398e54
TG
249 "SourcePath=%s\n"
250 "DefaultDependencies=no\n",
251 source);
6b1dc2bd 252
700e07ff
HH
253 if (!path_equal(where, "/")) {
254 if (pre)
255 fprintf(f,
256 "After=%s\n"
257 "Wants=%s\n",
258 pre,
259 pre);
6b1dc2bd 260 fprintf(f,
6b1dc2bd 261 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
700e07ff
HH
262 "Before=" SPECIAL_UMOUNT_TARGET "\n");
263 }
6b1dc2bd 264
700e07ff 265 if (post && !noauto && !nofail && !automount)
6b1dc2bd
LP
266 fprintf(f,
267 "Before=%s\n",
268 post);
269
270 fprintf(f,
271 "\n"
272 "[Mount]\n"
273 "What=%s\n"
274 "Where=%s\n"
275 "Type=%s\n"
276 "FsckPassNo=%i\n",
277 what,
278 where,
5e398e54
TG
279 type,
280 passno);
6b1dc2bd 281
5e398e54
TG
282 if (!isempty(opts) &&
283 !streq(opts, "defaults"))
6b1dc2bd
LP
284 fprintf(f,
285 "Options=%s\n",
5e398e54
TG
286 opts);
287
6b1dc2bd
LP
288 fflush(f);
289 if (ferror(f)) {
40b8acd0 290 log_error("Failed to write unit file %s: %m", unit);
d0aa9ce5 291 return -errno;
6b1dc2bd
LP
292 }
293
294 if (!noauto) {
700e07ff
HH
295 if (post) {
296 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
297 if (!lnk)
298 return log_oom();
6b1dc2bd 299
700e07ff
HH
300 mkdir_parents_label(lnk, 0755);
301 if (symlink(unit, lnk) < 0) {
302 log_error("Failed to create symlink %s: %m", lnk);
303 return -errno;
304 }
6b1dc2bd
LP
305 }
306
307 if (!isbind &&
308 !path_equal(where, "/")) {
309
310 r = device_name(what, &device);
0d0f0c50 311 if (r < 0)
d0aa9ce5 312 return r;
6b1dc2bd
LP
313
314 if (r > 0) {
315 free(lnk);
b7def684 316 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
d0aa9ce5
ZJS
317 if (!lnk)
318 return log_oom();
6b1dc2bd 319
d2e54fae 320 mkdir_parents_label(lnk, 0755);
6b1dc2bd 321 if (symlink(unit, lnk) < 0) {
40b8acd0 322 log_error("Failed to create symlink %s: %m", lnk);
d0aa9ce5 323 return -errno;
6b1dc2bd
LP
324 }
325 }
326 }
327 }
328
329 if (automount && !path_equal(where, "/")) {
330 automount_name = unit_name_from_path(where, ".automount");
d0aa9ce5
ZJS
331 if (!name)
332 return log_oom();
6b1dc2bd 333
b7def684 334 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
d0aa9ce5
ZJS
335 if (!automount_unit)
336 return log_oom();
6b1dc2bd
LP
337
338 fclose(f);
339 f = fopen(automount_unit, "wxe");
340 if (!f) {
40b8acd0 341 log_error("Failed to create unit file %s: %m", automount_unit);
d0aa9ce5 342 return -errno;
6b1dc2bd
LP
343 }
344
345 fprintf(f,
346 "# Automatically generated by systemd-fstab-generator\n\n"
347 "[Unit]\n"
3d22d1ab 348 "SourcePath=%s\n"
6b1dc2bd
LP
349 "DefaultDependencies=no\n"
350 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
700e07ff
HH
351 "Before=" SPECIAL_UMOUNT_TARGET "\n",
352 source);
353
354 if (post)
355 fprintf(f,
356 "Before= %s\n",
357 post);
358
359 fprintf(f,
6b1dc2bd
LP
360 "[Automount]\n"
361 "Where=%s\n",
6b1dc2bd
LP
362 where);
363
364 fflush(f);
365 if (ferror(f)) {
40b8acd0 366 log_error("Failed to write unit file %s: %m", automount_unit);
d0aa9ce5 367 return -errno;
6b1dc2bd
LP
368 }
369
370 free(lnk);
b7def684 371 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
d0aa9ce5
ZJS
372 if (!lnk)
373 return log_oom();
6b1dc2bd 374
d2e54fae 375 mkdir_parents_label(lnk, 0755);
6b1dc2bd 376 if (symlink(automount_unit, lnk) < 0) {
40b8acd0 377 log_error("Failed to create symlink %s: %m", lnk);
d0aa9ce5 378 return -errno;
6b1dc2bd
LP
379 }
380 }
381
d0aa9ce5 382 return 0;
6b1dc2bd
LP
383}
384
3d22d1ab 385static int parse_fstab(const char *prefix, bool initrd) {
6b1dc2bd 386 FILE *f;
3d22d1ab 387 _cleanup_free_ char *fstab_path = NULL;
6b1dc2bd
LP
388 int r = 0;
389 struct mntent *me;
390
391 errno = 0;
3d22d1ab
TG
392 fstab_path = strjoin(prefix, "/etc/fstab", NULL);
393 f = setmntent(fstab_path, "r");
6b1dc2bd
LP
394 if (!f) {
395 if (errno == ENOENT)
396 return 0;
397
3d22d1ab 398 log_error("Failed to open %s/etc/fstab: %m", prefix);
6b1dc2bd
LP
399 return -errno;
400 }
401
402 while ((me = getmntent(f))) {
d0aa9ce5 403 char _cleanup_free_ *where = NULL, *what = NULL;
6b1dc2bd
LP
404 int k;
405
3d22d1ab
TG
406 if (initrd && !mount_in_initrd(me))
407 continue;
408
6b1dc2bd 409 what = fstab_node_to_udev_node(me->mnt_fsname);
3d22d1ab 410 where = strjoin(prefix, me->mnt_dir, NULL);
d0aa9ce5 411 if (!what || !where) {
0d0f0c50 412 r = log_oom();
6b1dc2bd
LP
413 goto finish;
414 }
415
ec6ceb18 416 if (is_path(where))
6b1dc2bd
LP
417 path_kill_slashes(where);
418
419 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
420
421 if (streq(me->mnt_type, "swap"))
422 k = add_swap(what, me);
5e398e54 423 else {
700e07ff
HH
424 bool noauto, nofail, automount, isbind;
425 const char *pre, *post;
5e398e54
TG
426
427 noauto = !!hasmntopt(me, "noauto");
428 nofail = !!hasmntopt(me, "nofail");
429 automount =
430 hasmntopt(me, "comment=systemd.automount") ||
431 hasmntopt(me, "x-systemd.automount");
432 isbind = mount_is_bind(me);
700e07ff
HH
433
434 if (initrd) {
435 post = SPECIAL_INITRD_FS_TARGET;
436 pre = NULL;
437 } else if (mount_is_network(me)) {
438 post = SPECIAL_REMOTE_FS_TARGET;
439 pre = SPECIAL_REMOTE_FS_PRE_TARGET;
440 } else {
441 post = SPECIAL_LOCAL_FS_TARGET;
442 pre = SPECIAL_LOCAL_FS_PRE_TARGET;
443 }
5e398e54
TG
444
445 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
ac4785b0 446 me->mnt_passno, noauto, nofail, automount,
700e07ff 447 isbind, pre, post, fstab_path);
5e398e54 448 }
6b1dc2bd 449
6b1dc2bd
LP
450 if (k < 0)
451 r = k;
452 }
453
454finish:
455 endmntent(f);
456 return r;
457}
458
5e398e54
TG
459static int parse_new_root_from_proc_cmdline(void) {
460 char *w, *state;
ac4785b0 461 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
5e398e54
TG
462 int r;
463 size_t l;
5e398e54
TG
464
465 r = read_one_line_file("/proc/cmdline", &line);
466 if (r < 0) {
467 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
468 return 0;
469 }
470
945d1442 471 opts = strdup("ro");
5e398e54 472 type = strdup("auto");
945d1442 473 if (!opts || !type)
5e398e54
TG
474 return log_oom();
475
b929bf04
TA
476 /* root= and roofstype= may occur more than once, the last instance should take precedence.
477 * In the case of multiple rootflags= the arguments should be concatenated */
5e398e54
TG
478 FOREACH_WORD_QUOTED(w, l, line, state) {
479 char *word, *tmp_word;
480
481 word = strndup(w, l);
482 if (!word)
483 return log_oom();
484
485 else if (startswith(word, "root=")) {
486 free(what);
487 what = fstab_node_to_udev_node(word+5);
488 if (!what)
489 return log_oom();
490
491 } else if (startswith(word, "rootfstype=")) {
492 free(type);
493 type = strdup(word + 11);
494 if (!type)
495 return log_oom();
496
497 } else if (startswith(word, "rootflags=")) {
498 tmp_word = opts;
499 opts = strjoin(opts, ",", word + 10, NULL);
500 free(tmp_word);
501 if (!opts)
502 return log_oom();
503
504 } else if (streq(word, "ro") || streq(word, "rw")) {
505 tmp_word = opts;
506 opts = strjoin(opts, ",", word, NULL);
507 free(tmp_word);
508 if (!opts)
509 return log_oom();
510
533740e1 511 }
5e398e54
TG
512
513 free(word);
514 }
515
135b5212
HH
516 if (!what) {
517 log_error("Could not find a root= entry on the kernel commandline.");
518 return 0;
519 }
5e398e54 520
135b5212
HH
521 if (what[0] != '/') {
522 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
523 return 0;
524 }
5e398e54 525
135b5212
HH
526 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
527 r = add_mount(what, "/sysroot", type, opts, 0, false, false, false,
700e07ff 528 false, NULL, SPECIAL_ROOT_FS_TARGET, "/proc/cmdline");
5e398e54 529
135b5212 530 return (r < 0) ? r : 0;
5e398e54
TG
531}
532
94734142 533static int parse_proc_cmdline(void) {
d0aa9ce5
ZJS
534 char _cleanup_free_ *line = NULL;
535 char *w, *state;
94734142
LP
536 int r;
537 size_t l;
538
539 if (detect_container(NULL) > 0)
540 return 0;
541
542 r = read_one_line_file("/proc/cmdline", &line);
543 if (r < 0) {
544 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
545 return 0;
546 }
547
548 FOREACH_WORD_QUOTED(w, l, line, state) {
d0aa9ce5 549 char _cleanup_free_ *word = NULL;
94734142
LP
550
551 word = strndup(w, l);
d0aa9ce5
ZJS
552 if (!word)
553 return log_oom();
94734142
LP
554
555 if (startswith(word, "fstab=")) {
556 r = parse_boolean(word + 6);
557 if (r < 0)
558 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
559 else
560 arg_enabled = r;
561
562 } else if (startswith(word, "rd.fstab=")) {
563
564 if (in_initrd()) {
565 r = parse_boolean(word + 6);
566 if (r < 0)
567 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
568 else
569 arg_enabled = r;
570 }
571
572 } else if (startswith(word, "fstab.") ||
573 (in_initrd() && startswith(word, "rd.fstab."))) {
574
575 log_warning("Unknown kernel switch %s. Ignoring.", word);
576 }
94734142
LP
577 }
578
d0aa9ce5 579 return 0;
94734142
LP
580}
581
6b1dc2bd 582int main(int argc, char *argv[]) {
ac4785b0 583 int r = 0, k, l = 0;
6b1dc2bd 584
07719a21
LP
585 if (argc > 1 && argc != 4) {
586 log_error("This program takes three or no arguments.");
6b1dc2bd
LP
587 return EXIT_FAILURE;
588 }
589
590 if (argc > 1)
591 arg_dest = argv[1];
592
a6903061 593 log_set_target(LOG_TARGET_SAFE);
6b1dc2bd
LP
594 log_parse_environment();
595 log_open();
596
6b1dc2bd
LP
597 umask(0022);
598
94734142
LP
599 if (parse_proc_cmdline() < 0)
600 return EXIT_FAILURE;
601
ac4785b0
HH
602 if (in_initrd())
603 r = parse_new_root_from_proc_cmdline();
5e398e54 604
ac4785b0
HH
605 if (!arg_enabled)
606 return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
607
608 k = parse_fstab("", false);
609
610 if (in_initrd())
611 l = parse_fstab("/sysroot", true);
6b1dc2bd 612
3d22d1ab 613 return (r < 0) || (k < 0) || (l < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
6b1dc2bd 614}