]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/fstab-generator/fstab-generator.c
man: fix path in crypttab(5)
[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
6b1dc2bd
LP
47static 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);
8333c77e 62 if (errno > 0)
6b1dc2bd
LP
63 return -errno;
64
65 if (end == pri || (*end != ',' && *end != 0))
66 return -EINVAL;
67
68 *ret = (int) r;
69 return 1;
70}
71
72static int add_swap(const char *what, struct mntent *me) {
1dc2ced4 73 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
7fd1b19b 74 _cleanup_fclose_ FILE *f = NULL;
4e82fe52 75 bool noauto;
6b1dc2bd
LP
76 int r, pri = -1;
77
78 assert(what);
79 assert(me);
80
689aede8
LP
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
6b1dc2bd
LP
86 r = mount_find_pri(me, &pri);
87 if (r < 0) {
88 log_error("Failed to parse priority");
89 return pri;
90 }
91
4e82fe52
TG
92 noauto = !!hasmntopt(me, "noauto");
93
6b1dc2bd 94 name = unit_name_from_path(what, ".swap");
d0aa9ce5
ZJS
95 if (!name)
96 return log_oom();
6b1dc2bd 97
b7def684 98 unit = strjoin(arg_dest, "/", name, NULL);
d0aa9ce5
ZJS
99 if (!unit)
100 return log_oom();
6b1dc2bd
LP
101
102 f = fopen(unit, "wxe");
103 if (!f) {
67ab5f76
TG
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);
d0aa9ce5 108 return -errno;
6b1dc2bd
LP
109 }
110
6b1dc2bd 111 fprintf(f,
64347fc2
TG
112 "# Automatically generated by systemd-fstab-generator\n\n"
113 "[Unit]\n"
c3834f9b
LP
114 "SourcePath=/etc/fstab\n"
115 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
6b1dc2bd
LP
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)) {
40b8acd0 127 log_error("Failed to write unit file %s: %m", unit);
d0aa9ce5 128 return -errno;
6b1dc2bd
LP
129 }
130
4e82fe52
TG
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
d0aa9ce5 143 return 0;
6b1dc2bd
LP
144}
145
6b1dc2bd
LP
146static 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
3d22d1ab
TG
154static 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
e8d2f6cd
LP
162static int add_mount(
163 const char *what,
164 const char *where,
6db615c1 165 const char *fstype,
e8d2f6cd
LP
166 const char *opts,
167 int passno,
168 bool noauto,
169 bool nofail,
170 bool automount,
e8d2f6cd 171 const char *post,
e8d2f6cd 172 const char *source) {
e48fdd84 173
7fd1b19b 174 _cleanup_free_ char
1dc2ced4 175 *name = NULL, *unit = NULL, *lnk = NULL,
d0aa9ce5 176 *automount_name = NULL, *automount_unit = NULL;
7fd1b19b 177 _cleanup_fclose_ FILE *f = NULL;
94192cda 178 int r;
6b1dc2bd
LP
179
180 assert(what);
181 assert(where);
5e398e54
TG
182 assert(opts);
183 assert(source);
6b1dc2bd 184
6db615c1 185 if (streq_ptr(fstype, "autofs"))
6b1dc2bd
LP
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
e48fdd84 197 if (path_equal(where, "/")) {
5ecdcf41 198 /* The root disk is not an option */
e48fdd84
LP
199 automount = false;
200 noauto = false;
201 nofail = false;
202 }
203
6b1dc2bd 204 name = unit_name_from_path(where, ".mount");
d0aa9ce5
ZJS
205 if (!name)
206 return log_oom();
6b1dc2bd 207
b7def684 208 unit = strjoin(arg_dest, "/", name, NULL);
d0aa9ce5
ZJS
209 if (!unit)
210 return log_oom();
6b1dc2bd
LP
211
212 f = fopen(unit, "wxe");
213 if (!f) {
67ab5f76
TG
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);
d0aa9ce5 218 return -errno;
6b1dc2bd
LP
219 }
220
5e398e54 221 fprintf(f,
c3834f9b
LP
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);
6b1dc2bd 227
700e07ff 228 if (post && !noauto && !nofail && !automount)
5ecdcf41 229 fprintf(f, "Before=%s\n", post);
6b1dc2bd 230
e48fdd84 231 if (passno != 0) {
6db615c1 232 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
e48fdd84
LP
233 if (r < 0)
234 return r;
235 }
64e70e4b 236
6b1dc2bd
LP
237 fprintf(f,
238 "\n"
239 "[Mount]\n"
240 "What=%s\n"
6db615c1 241 "Where=%s\n",
6b1dc2bd 242 what,
6db615c1
LP
243 where);
244
245 if (!isempty(fstype) && !streq(fstype, "auto"))
246 fprintf(f, "Type=%s\n", fstype);
6b1dc2bd 247
e48fdd84 248 if (!isempty(opts) && !streq(opts, "defaults"))
6db615c1 249 fprintf(f, "Options=%s\n", opts);
5e398e54 250
6b1dc2bd
LP
251 fflush(f);
252 if (ferror(f)) {
40b8acd0 253 log_error("Failed to write unit file %s: %m", unit);
d0aa9ce5 254 return -errno;
6b1dc2bd
LP
255 }
256
5ecdcf41
LP
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;
6b1dc2bd 266 }
6b1dc2bd
LP
267 }
268
e48fdd84 269 if (automount) {
6b1dc2bd 270 automount_name = unit_name_from_path(where, ".automount");
01264ad1 271 if (!automount_name)
d0aa9ce5 272 return log_oom();
6b1dc2bd 273
b7def684 274 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
d0aa9ce5
ZJS
275 if (!automount_unit)
276 return log_oom();
6b1dc2bd
LP
277
278 fclose(f);
279 f = fopen(automount_unit, "wxe");
280 if (!f) {
40b8acd0 281 log_error("Failed to create unit file %s: %m", automount_unit);
d0aa9ce5 282 return -errno;
6b1dc2bd
LP
283 }
284
285 fprintf(f,
286 "# Automatically generated by systemd-fstab-generator\n\n"
287 "[Unit]\n"
c3834f9b
LP
288 "SourcePath=%s\n"
289 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
700e07ff
HH
290 source);
291
292 if (post)
293 fprintf(f,
e48fdd84 294 "Before=%s\n",
700e07ff
HH
295 post);
296
297 fprintf(f,
6b1dc2bd
LP
298 "[Automount]\n"
299 "Where=%s\n",
6b1dc2bd
LP
300 where);
301
302 fflush(f);
303 if (ferror(f)) {
40b8acd0 304 log_error("Failed to write unit file %s: %m", automount_unit);
d0aa9ce5 305 return -errno;
6b1dc2bd
LP
306 }
307
308 free(lnk);
b7def684 309 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
d0aa9ce5
ZJS
310 if (!lnk)
311 return log_oom();
6b1dc2bd 312
d2e54fae 313 mkdir_parents_label(lnk, 0755);
6b1dc2bd 314 if (symlink(automount_unit, lnk) < 0) {
40b8acd0 315 log_error("Failed to create symlink %s: %m", lnk);
d0aa9ce5 316 return -errno;
6b1dc2bd
LP
317 }
318 }
319
d0aa9ce5 320 return 0;
6b1dc2bd
LP
321}
322
e48fdd84 323static int parse_fstab(bool initrd) {
6db615c1 324 _cleanup_endmntent_ FILE *f = NULL;
e48fdd84 325 const char *fstab_path;
6b1dc2bd 326 struct mntent *me;
e48fdd84 327 int r = 0;
6b1dc2bd 328
e48fdd84
LP
329 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
330 f = setmntent(fstab_path, "re");
6b1dc2bd
LP
331 if (!f) {
332 if (errno == ENOENT)
333 return 0;
334
e48fdd84 335 log_error("Failed to open %s: %m", fstab_path);
6b1dc2bd
LP
336 return -errno;
337 }
338
339 while ((me = getmntent(f))) {
7fd1b19b 340 _cleanup_free_ char *where = NULL, *what = NULL;
6b1dc2bd
LP
341 int k;
342
3d22d1ab
TG
343 if (initrd && !mount_in_initrd(me))
344 continue;
345
6b1dc2bd 346 what = fstab_node_to_udev_node(me->mnt_fsname);
e48fdd84
LP
347 if (!what)
348 return log_oom();
349
689aede8
LP
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
e48fdd84
LP
355 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
356 if (!where)
5862d652 357 return log_oom();
6b1dc2bd 358
ec6ceb18 359 if (is_path(where))
6b1dc2bd
LP
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);
5e398e54 366 else {
5073f89f 367 bool noauto, nofail, automount;
80c3b720 368 const char *post;
5e398e54
TG
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");
700e07ff 375
e48fdd84 376 if (initrd)
700e07ff 377 post = SPECIAL_INITRD_FS_TARGET;
e48fdd84 378 else if (mount_in_initrd(me))
9e5f0f92 379 post = SPECIAL_INITRD_ROOT_FS_TARGET;
e48fdd84 380 else if (mount_is_network(me))
0c17fbce 381 post = SPECIAL_REMOTE_FS_TARGET;
e48fdd84 382 else
0c17fbce 383 post = SPECIAL_LOCAL_FS_TARGET;
5e398e54 384
6db615c1
LP
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);
5e398e54 395 }
6b1dc2bd 396
6b1dc2bd
LP
397 if (k < 0)
398 r = k;
399 }
400
6b1dc2bd
LP
401 return r;
402}
403
6db615c1
LP
404static int add_root_mount(void) {
405 _cleanup_free_ char *o = NULL, *what = NULL;
5e398e54 406
6db615c1 407 if (isempty(arg_root_what)) {
4e5ed9b6 408 log_debug("Could not find a root= entry on the kernel commandline.");
135b5212
HH
409 return 0;
410 }
5e398e54 411
6db615c1
LP
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));
135b5212
HH
415 return 0;
416 }
5e398e54 417
6db615c1
LP
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();
5e398e54 430
6db615c1
LP
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,
5ecdcf41
LP
437 false,
438 false,
6db615c1
LP
439 false,
440 SPECIAL_INITRD_ROOT_FS_TARGET,
441 "/proc/cmdline");
5e398e54
TG
442}
443
059cb385 444static int parse_proc_cmdline_item(const char *key, const char *value) {
74df0fca 445 int r;
94734142 446
6db615c1
LP
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
059cb385 451 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
e48fdd84 452
059cb385 453 r = parse_boolean(value);
141a79f4 454 if (r < 0)
059cb385 455 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
141a79f4 456 else
e48fdd84 457 arg_fstab_enabled = r;
94734142 458
6db615c1
LP
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;
94734142 489
d0aa9ce5 490 return 0;
94734142
LP
491}
492
6b1dc2bd 493int main(int argc, char *argv[]) {
e48fdd84 494 int r = 0;
6b1dc2bd 495
07719a21
LP
496 if (argc > 1 && argc != 4) {
497 log_error("This program takes three or no arguments.");
6b1dc2bd
LP
498 return EXIT_FAILURE;
499 }
500
501 if (argc > 1)
502 arg_dest = argv[1];
503
a6903061 504 log_set_target(LOG_TARGET_SAFE);
6b1dc2bd
LP
505 log_parse_environment();
506 log_open();
507
6b1dc2bd
LP
508 umask(0022);
509
059cb385 510 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
94734142
LP
511 return EXIT_FAILURE;
512
e48fdd84 513 /* Always honour root= in the kernel command line if we are in an initrd */
ac4785b0 514 if (in_initrd())
6db615c1 515 r = add_root_mount();
5e398e54 516
e48fdd84
LP
517 /* Honour /etc/fstab only when that's enabled */
518 if (arg_fstab_enabled) {
519 int k;
ac4785b0 520
e48fdd84
LP
521 /* Parse the local /etc/fstab, possibly from the initrd */
522 k = parse_fstab(false);
523 if (k < 0)
524 r = k;
ac4785b0 525
e48fdd84
LP
526 /* If running in the initrd also parse the /etc/fstab from the host */
527 if (in_initrd()) {
528 k = parse_fstab(true);
529 if (k < 0)
530 r = k;
531 }
532 }
6b1dc2bd 533
e48fdd84 534 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6b1dc2bd 535}