chiark / gitweb /
Remove src/activate
[elogind.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 add_mount(
158                 const char *what,
159                 const char *where,
160                 const char *fstype,
161                 const char *opts,
162                 int passno,
163                 bool noauto,
164                 bool nofail,
165                 bool automount,
166                 const char *post,
167                 const char *source) {
168
169         _cleanup_free_ char
170                 *name = NULL, *unit = NULL, *lnk = NULL,
171                 *automount_name = NULL, *automount_unit = NULL,
172                 *filtered = NULL;
173         _cleanup_fclose_ FILE *f = NULL;
174         int r;
175
176         assert(what);
177         assert(where);
178         assert(opts);
179         assert(source);
180
181         if (streq_ptr(fstype, "autofs"))
182                 return 0;
183
184         if (!is_path(where)) {
185                 log_warning("Mount point %s is not a valid path, ignoring.", where);
186                 return 0;
187         }
188
189         if (mount_point_is_api(where) ||
190             mount_point_ignore(where))
191                 return 0;
192
193         if (path_equal(where, "/")) {
194                 /* The root disk is not an option */
195                 automount = false;
196                 noauto = false;
197                 nofail = false;
198         }
199
200         name = unit_name_from_path(where, ".mount");
201         if (!name)
202                 return log_oom();
203
204         unit = strjoin(arg_dest, "/", name, NULL);
205         if (!unit)
206                 return log_oom();
207
208         f = fopen(unit, "wxe");
209         if (!f) {
210                 if (errno == EEXIST)
211                         log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
212                 else
213                         log_error_errno(errno, "Failed to create unit file %s: %m", unit);
214                 return -errno;
215         }
216
217         fprintf(f,
218                 "# Automatically generated by systemd-fstab-generator\n\n"
219                 "[Unit]\n"
220                 "SourcePath=%s\n"
221                 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
222                 source);
223
224         if (post && !noauto && !nofail && !automount)
225                 fprintf(f, "Before=%s\n", post);
226
227         if (passno != 0) {
228                 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
229                 if (r < 0)
230                         return r;
231         }
232
233         fprintf(f,
234                 "\n"
235                 "[Mount]\n"
236                 "What=%s\n"
237                 "Where=%s\n",
238                 what,
239                 where);
240
241         if (!isempty(fstype) && !streq(fstype, "auto"))
242                 fprintf(f, "Type=%s\n", fstype);
243
244         r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
245         if (r < 0)
246                 return r;
247
248         if (!isempty(filtered) && !streq(filtered, "defaults"))
249                 fprintf(f, "Options=%s\n", filtered);
250
251         fflush(f);
252         if (ferror(f))
253                 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
254
255         if (!noauto && post) {
256                 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
257                 if (!lnk)
258                         return log_oom();
259
260                 mkdir_parents_label(lnk, 0755);
261                 if (symlink(unit, lnk) < 0)
262                         return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
263         }
264
265         if (automount) {
266                 automount_name = unit_name_from_path(where, ".automount");
267                 if (!automount_name)
268                         return log_oom();
269
270                 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
271                 if (!automount_unit)
272                         return log_oom();
273
274                 fclose(f);
275                 f = fopen(automount_unit, "wxe");
276                 if (!f)
277                         return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
278
279                 fprintf(f,
280                         "# Automatically generated by systemd-fstab-generator\n\n"
281                         "[Unit]\n"
282                         "SourcePath=%s\n"
283                         "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
284                         source);
285
286                 if (post)
287                         fprintf(f,
288                                 "Before=%s\n",
289                                 post);
290
291                 fprintf(f,
292                         "[Automount]\n"
293                         "Where=%s\n",
294                         where);
295
296                 fflush(f);
297                 if (ferror(f))
298                         return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
299
300                 free(lnk);
301                 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
302                 if (!lnk)
303                         return log_oom();
304
305                 mkdir_parents_label(lnk, 0755);
306                 if (symlink(automount_unit, lnk) < 0)
307                         return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
308         }
309
310         return 0;
311 }
312
313 static int parse_fstab(bool initrd) {
314         _cleanup_endmntent_ FILE *f = NULL;
315         const char *fstab_path;
316         struct mntent *me;
317         int r = 0;
318
319         fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
320         f = setmntent(fstab_path, "re");
321         if (!f) {
322                 if (errno == ENOENT)
323                         return 0;
324
325                 log_error_errno(errno, "Failed to open %s: %m", fstab_path);
326                 return -errno;
327         }
328
329         while ((me = getmntent(f))) {
330                 _cleanup_free_ char *where = NULL, *what = NULL;
331                 bool noauto, nofail;
332                 int k;
333
334                 if (initrd && !mount_in_initrd(me))
335                         continue;
336
337                 what = fstab_node_to_udev_node(me->mnt_fsname);
338                 if (!what)
339                         return log_oom();
340
341                 if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
342                         log_info("Running in a container, ignoring fstab device entry for %s.", what);
343                         continue;
344                 }
345
346                 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
347                 if (!where)
348                         return log_oom();
349
350                 if (is_path(where))
351                         path_kill_slashes(where);
352
353                 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
354                 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
355                 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
356                           what, where, me->mnt_type,
357                           yes_no(noauto), yes_no(nofail));
358
359                 if (streq(me->mnt_type, "swap"))
360                         k = add_swap(what, me, noauto, nofail);
361                 else {
362                         bool automount;
363                         const char *post;
364
365                         automount = fstab_test_option(me->mnt_opts,
366                                                       "comment=systemd.automount\0"
367                                                       "x-systemd.automount\0");
368                         if (initrd)
369                                 post = SPECIAL_INITRD_FS_TARGET;
370                         else if (mount_in_initrd(me))
371                                 post = SPECIAL_INITRD_ROOT_FS_TARGET;
372                         else if (mount_is_network(me))
373                                 post = SPECIAL_REMOTE_FS_TARGET;
374                         else
375                                 post = SPECIAL_LOCAL_FS_TARGET;
376
377                         k = add_mount(what,
378                                       where,
379                                       me->mnt_type,
380                                       me->mnt_opts,
381                                       me->mnt_passno,
382                                       noauto,
383                                       nofail,
384                                       automount,
385                                       post,
386                                       fstab_path);
387                 }
388
389                 if (k < 0)
390                         r = k;
391         }
392
393         return r;
394 }
395
396 static int add_root_mount(void) {
397         _cleanup_free_ char *what = NULL;
398         const char *opts;
399
400         if (isempty(arg_root_what)) {
401                 log_debug("Could not find a root= entry on the kernel command line.");
402                 return 0;
403         }
404
405         what = fstab_node_to_udev_node(arg_root_what);
406         if (!what)
407                 log_oom();
408
409         if (!arg_root_options)
410                 opts = arg_root_rw > 0 ? "rw" : "ro";
411         else if (arg_root_rw >= 0 ||
412                  !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
413                 opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
414         else
415                 opts = arg_root_options;
416
417         log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
418         return add_mount(what,
419                          "/sysroot",
420                          arg_root_fstype,
421                          opts,
422                          is_device_path(what) ? 1 : 0,
423                          false,
424                          false,
425                          false,
426                          SPECIAL_INITRD_ROOT_FS_TARGET,
427                          "/proc/cmdline");
428 }
429
430 static int add_usr_mount(void) {
431         _cleanup_free_ char *what = NULL;
432         const char *opts;
433
434         if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
435                 return 0;
436
437         if (arg_root_what && !arg_usr_what) {
438                 arg_usr_what = strdup(arg_root_what);
439
440                 if (!arg_usr_what)
441                         return log_oom();
442         }
443
444         if (arg_root_fstype && !arg_usr_fstype) {
445                 arg_usr_fstype = strdup(arg_root_fstype);
446
447                 if (!arg_usr_fstype)
448                         return log_oom();
449         }
450
451         if (arg_root_options && !arg_usr_options) {
452                 arg_usr_options = strdup(arg_root_options);
453
454                 if (!arg_usr_options)
455                         return log_oom();
456         }
457
458         if (!arg_usr_what)
459                 return 0;
460
461         what = fstab_node_to_udev_node(arg_usr_what);
462         if (!path_is_absolute(what)) {
463                 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
464                 return -1;
465         }
466
467         if (!arg_usr_options)
468                 opts = arg_root_rw > 0 ? "rw" : "ro";
469         else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
470                 opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
471         else
472                 opts = arg_usr_options;
473
474         log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
475         return add_mount(what,
476                          "/sysroot/usr",
477                          arg_usr_fstype,
478                          opts,
479                          1,
480                          false,
481                          false,
482                          false,
483                          SPECIAL_INITRD_ROOT_FS_TARGET,
484                          "/proc/cmdline");
485 }
486
487 static int parse_proc_cmdline_item(const char *key, const char *value) {
488         int r;
489
490         /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
491          * instance should take precedence.  In the case of multiple rootflags=
492          * or usrflags= the arguments should be concatenated */
493
494         if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
495
496                 r = parse_boolean(value);
497                 if (r < 0)
498                         log_warning("Failed to parse fstab switch %s. Ignoring.", value);
499                 else
500                         arg_fstab_enabled = r;
501
502         } else if (streq(key, "root") && value) {
503
504                 if (free_and_strdup(&arg_root_what, value) < 0)
505                         return log_oom();
506
507         } else if (streq(key, "rootfstype") && value) {
508
509                 if (free_and_strdup(&arg_root_fstype, value) < 0)
510                         return log_oom();
511
512         } else if (streq(key, "rootflags") && value) {
513                 char *o;
514
515                 o = arg_root_options ?
516                         strjoin(arg_root_options, ",", value, NULL) :
517                         strdup(value);
518                 if (!o)
519                         return log_oom();
520
521                 free(arg_root_options);
522                 arg_root_options = o;
523
524         } else if (streq(key, "mount.usr") && value) {
525
526                 if (free_and_strdup(&arg_usr_what, value) < 0)
527                         return log_oom();
528
529         } else if (streq(key, "mount.usrfstype") && value) {
530
531                 if (free_and_strdup(&arg_usr_fstype, value) < 0)
532                         return log_oom();
533
534         } else if (streq(key, "mount.usrflags") && value) {
535                 char *o;
536
537                 o = arg_usr_options ?
538                         strjoin(arg_usr_options, ",", value, NULL) :
539                         strdup(value);
540                 if (!o)
541                         return log_oom();
542
543                 free(arg_usr_options);
544                 arg_usr_options = o;
545
546         } else if (streq(key, "rw") && !value)
547                 arg_root_rw = true;
548         else if (streq(key, "ro") && !value)
549                 arg_root_rw = false;
550
551         return 0;
552 }
553
554 int main(int argc, char *argv[]) {
555         int r = 0;
556
557         if (argc > 1 && argc != 4) {
558                 log_error("This program takes three or no arguments.");
559                 return EXIT_FAILURE;
560         }
561
562         if (argc > 1)
563                 arg_dest = argv[1];
564
565         log_set_target(LOG_TARGET_SAFE);
566         log_parse_environment();
567         log_open();
568
569         umask(0022);
570
571         r = parse_proc_cmdline(parse_proc_cmdline_item);
572         if (r < 0)
573                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
574
575         /* Always honour root= and usr= in the kernel command line if we are in an initrd */
576         if (in_initrd()) {
577                 r = add_root_mount();
578                 if (r == 0)
579                         r = add_usr_mount();
580         }
581
582         /* Honour /etc/fstab only when that's enabled */
583         if (arg_fstab_enabled) {
584                 int k;
585
586                 log_debug("Parsing /etc/fstab");
587
588                 /* Parse the local /etc/fstab, possibly from the initrd */
589                 k = parse_fstab(false);
590                 if (k < 0)
591                         r = k;
592
593                 /* If running in the initrd also parse the /etc/fstab from the host */
594                 if (in_initrd()) {
595                         log_debug("Parsing /sysroot/etc/fstab");
596
597                         k = parse_fstab(true);
598                         if (k < 0)
599                                 r = k;
600                 }
601         }
602
603         free(arg_root_what);
604         free(arg_root_fstype);
605         free(arg_root_options);
606
607         free(arg_usr_what);
608         free(arg_usr_fstype);
609         free(arg_usr_options);
610
611         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
612 }