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