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