diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile-man.am | 7 | ||||
-rw-r--r-- | Makefile.am | 10 | ||||
-rw-r--r-- | man/kernel-command-line.xml | 23 | ||||
-rw-r--r-- | man/systemd-fstab-generator.xml | 46 | ||||
-rw-r--r-- | man/systemd-nspawn.xml | 15 | ||||
-rw-r--r-- | man/systemd-volatile-root.service.xml | 79 | ||||
-rw-r--r-- | src/fstab-generator/fstab-generator.c | 85 | ||||
-rw-r--r-- | src/shared/volatile-util.c | 27 | ||||
-rw-r--r-- | src/shared/volatile-util.h | 2 | ||||
l--------- | src/volatile-root/Makefile | 1 | ||||
-rw-r--r-- | src/volatile-root/volatile-root.c | 157 | ||||
-rw-r--r-- | units/.gitignore | 1 | ||||
-rw-r--r-- | units/systemd-volatile-root.service.in | 21 |
14 files changed, 456 insertions, 19 deletions
diff --git a/.gitignore b/.gitignore index ec4b7bd67..f246d3e6d 100644 --- a/.gitignore +++ b/.gitignore @@ -126,6 +126,7 @@ /systemd-update-utmp /systemd-user-sessions /systemd-vconsole-setup +/systemd-volatile-root /tags /test-acd /test-acl-util diff --git a/Makefile-man.am b/Makefile-man.am index 5e6eee5e3..27660ef1c 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -142,6 +142,7 @@ MANPAGES += \ man/systemd-tty-ask-password-agent.1 \ man/systemd-udevd.service.8 \ man/systemd-update-done.service.8 \ + man/systemd-volatile-root.service.8 \ man/systemd.1 \ man/systemd.automount.5 \ man/systemd.device.5 \ @@ -482,6 +483,7 @@ MANPAGES_ALIAS += \ man/systemd-udevd.8 \ man/systemd-update-done.8 \ man/systemd-user.conf.5 \ + man/systemd-volatile-root.8 \ man/udev_device_get_action.3 \ man/udev_device_get_devlinks_list_entry.3 \ man/udev_device_get_devnode.3 \ @@ -837,6 +839,7 @@ man/systemd-udevd-kernel.socket.8: man/systemd-udevd.service.8 man/systemd-udevd.8: man/systemd-udevd.service.8 man/systemd-update-done.8: man/systemd-update-done.service.8 man/systemd-user.conf.5: man/systemd-system.conf.5 +man/systemd-volatile-root.8: man/systemd-volatile-root.service.8 man/udev_device_get_action.3: man/udev_device_get_syspath.3 man/udev_device_get_devlinks_list_entry.3: man/udev_device_has_tag.3 man/udev_device_get_devnode.3: man/udev_device_get_syspath.3 @@ -1790,6 +1793,9 @@ man/systemd-update-done.html: man/systemd-update-done.service.html man/systemd-user.conf.html: man/systemd-system.conf.html $(html-alias) +man/systemd-volatile-root.html: man/systemd-volatile-root.service.html + $(html-alias) + man/udev_device_get_action.html: man/udev_device_get_syspath.html $(html-alias) @@ -2804,6 +2810,7 @@ EXTRA_DIST += \ man/systemd-update-utmp.service.xml \ man/systemd-user-sessions.service.xml \ man/systemd-vconsole-setup.service.xml \ + man/systemd-volatile-root.service.xml \ man/systemd.automount.xml \ man/systemd.device.xml \ man/systemd.exec.xml \ diff --git a/Makefile.am b/Makefile.am index 56b8aa3fe..92a368046 100644 --- a/Makefile.am +++ b/Makefile.am @@ -397,6 +397,7 @@ rootlibexec_PROGRAMS = \ systemd-initctl \ systemd-shutdown \ systemd-remount-fs \ + systemd-volatile-root \ systemd-reply-password \ systemd-fsck \ systemd-ac-power \ @@ -538,6 +539,7 @@ nodist_systemunit_DATA = \ units/system-update-cleanup.service \ units/systemd-initctl.service \ units/systemd-remount-fs.service \ + units/systemd-volatile-root.service \ units/systemd-ask-password-wall.service \ units/systemd-ask-password-console.service \ units/systemd-sysctl.service \ @@ -602,6 +604,7 @@ EXTRA_DIST += \ units/system-update-cleanup.service.in \ units/systemd-initctl.service.in \ units/systemd-remount-fs.service.in \ + units/systemd-volatile-root.service.in \ units/systemd-update-utmp.service.in \ units/systemd-update-utmp-runlevel.service.in \ units/systemd-ask-password-wall.service.in \ @@ -3068,6 +3071,13 @@ systemd_remount_fs_LDADD = \ libsystemd-shared.la # ------------------------------------------------------------------------------ +systemd_volatile_root_SOURCES = \ + src/volatile-root/volatile-root.c + +systemd_volatile_root_LDADD = \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ systemd_cgroups_agent_SOURCES = \ src/cgroups-agent/cgroups-agent.c diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 78e45e66a..7e1d408de 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -125,6 +125,28 @@ </varlistentry> <varlistentry> + <term><varname>systemd.volatile=</varname></term> + <listitem> + <para>This parameter controls whether the system shall boot up in volatile mode. Takes a boolean argument, or + the special value <literal>state</literal>. If false (the default), normal boot mode is selected, the root + directory and <filename>/var</filename> are mounted as specified on the kernel command line or + <filename>/etc/fstab</filename>, or otherwise configured. If true, full state-less boot mode is selected. In + this case the root directory is mounted as volatile memory file system (<literal>tmpfs</literal>), and only + <filename>/usr</filename> is mounted from the file system configured as root device, in read-only mode. This + enables fully state-less boots were the vendor-supplied OS is used as shipped, with only default + configuration and no stored state in effect, as <filename>/etc</filename> and <filename>/var</filename> (as + well as all other resources shipped in the root file system) are reset at boot and lost on shutdown. If this + setting is set to <literal>state</literal> the root file system is mounted as usual, however + <filename>/var</filename> is mounted as a volatile memory file system (<literal>tmpfs</literal>), so that the + system boots up with the normal configuration applied, but all state reset at boot and lost at shutdown. For details, + see + <citerefentry><refentrytitle>systemd-volatile-root.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> + and + <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para> + </listitem> + </varlistentry> + + <varlistentry> <term><varname>quiet</varname></term> <listitem> <para>Parameter understood by both the kernel and the system @@ -382,6 +404,7 @@ <citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd-volatile-root.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-modules-load.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-backlight@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-rfkill.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml index a971cb367..5f37e9193 100644 --- a/man/systemd-fstab-generator.xml +++ b/man/systemd-fstab-generator.xml @@ -89,12 +89,13 @@ <listitem><para>Takes a boolean argument. Defaults to <literal>yes</literal>. If <literal>no</literal>, causes the - generator to ignore any mounts or swaps configured in + generator to ignore any mounts or swap devices configured in <filename>/etc/fstab</filename>. <varname>rd.fstab=</varname> - is honored only by initial RAM disk (initrd) while + is honored only by the initial RAM disk (initrd) while <varname>fstab=</varname> is honored by both the main system and the initrd.</para></listitem> </varlistentry> + <varlistentry> <term><varname>root=</varname></term> @@ -102,6 +103,7 @@ initrd. <varname>root=</varname> is honored by the initrd.</para></listitem> </varlistentry> + <varlistentry> <term><varname>rootfstype=</varname></term> @@ -109,6 +111,7 @@ passed to the mount command. <varname>rootfstype=</varname> is honored by the initrd.</para></listitem> </varlistentry> + <varlistentry> <term><varname>rootflags=</varname></term> @@ -116,6 +119,7 @@ use. <varname>rootflags=</varname> is honored by the initrd.</para></listitem> </varlistentry> + <varlistentry> <term><varname>mount.usr=</varname></term> @@ -133,6 +137,7 @@ <para><varname>mount.usr=</varname> is honored by the initrd. </para></listitem> </varlistentry> + <varlistentry> <term><varname>mount.usrfstype=</varname></term> @@ -150,6 +155,7 @@ <para><varname>mount.usrfstype=</varname> is honored by the initrd.</para></listitem> </varlistentry> + <varlistentry> <term><varname>mount.usrflags=</varname></term> @@ -166,6 +172,39 @@ <para><varname>mount.usrflags=</varname> is honored by the initrd.</para></listitem> </varlistentry> + + <varlistentry> + <term><varname>systemd.volatile=</varname></term> + + <listitem><para>Controls whether the system shall boot up in volatile mode. Takes a boolean argument or the + special value <option>state</option>.</para> + + <para>If false (the default), this generator makes no changes to the mount tree and the system is booted up in + normal mode.</para> + + <para>If true the generator ensures + <citerefentry><refentrytitle>systemd-volatile-root.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> + is run as part of the initial RAM disk ("initrd"). This service changes the mount table before transitioning to + the host system, so that a volatile memory file system (<literal>tmpfs</literal>) is used as root directory, + with only <filename>/usr</filename> mounted into it from the configured root file system, in read-only + mode. This way the system operates in fully stateless mode, with all configuration and state reset at boot and + lost at shutdown, as <filename>/etc</filename> and <filename>/var</filename> will be served from the (initially + unpopulated) volatile memory file system.</para> + + <para>If set to <option>state</option> the generator will leave the root + directory mount point unaltered, however will mount a <literal>tmpfs</literal> file system to + <filename>/var</filename>. In this mode the normal system configuration (i.e the contents of + <literal>/etc</literal>) is in effect (and may be modified during system runtime), however the system state + (i.e. the contents of <literal>/var</literal>) is reset at boot and lost at shutdown.</para> + + <para>Note that in none of these modes the root directory, <filename>/etc</filename>, <filename>/var</filename> + or any other resources stored in the root file system are physically removed. It's thus safe to boot a system + that is normally operated in non-volatile mode temporarily into volatile mode, without losing data.</para> + + <para>Note that enabling this setting will only work correctly on operating systems that can boot up with only + <filename>/usr</filename> mounted, and are able to automatically populate <filename>/etc</filename>, and also + <filename>/var</filename> in case of <literal>systemd.volatile=yes</literal>.</para></listitem> + </varlistentry> </variablelist> </refsect1> @@ -176,7 +215,8 @@ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.swap</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry> + <citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>, + <citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 2bc81ea1a..f6b3f57fc 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -939,12 +939,15 @@ <option>no</option> (the default), the whole OS tree is made available writable.</para> - <para>Note that setting this to <option>yes</option> or - <option>state</option> will only work correctly with - operating systems in the container that can boot up with only - <filename>/usr</filename> mounted, and are able to populate - <filename>/var</filename> automatically, as - needed.</para></listitem> + <para>This option provides similar functionality for containers as the <literal>systemd.volatile=</literal> + kernel command line switch provides for host systems. See + <citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry> for + details.</para> + + <para>Note that enabling this setting will only work correctly with operating systems in the container that can + boot up with only <filename>/usr</filename> mounted, and are able to automatically populate + <filename>/var</filename>, and also <filename>/etc</filename> in case of + <literal>--volatile=yes</literal>.</para></listitem> </varlistentry> <varlistentry> diff --git a/man/systemd-volatile-root.service.xml b/man/systemd-volatile-root.service.xml new file mode 100644 index 000000000..b90a3261f --- /dev/null +++ b/man/systemd-volatile-root.service.xml @@ -0,0 +1,79 @@ +<?xml version="1.0"?> +<!--*-nxml-*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> +<!-- + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +--> +<refentry id="systemd-volatile-root.service"> + + <refentryinfo> + <title>systemd-volatile-root.service</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>systemd-volatile-root.service</refentrytitle> + <manvolnum>8</manvolnum> + </refmeta> + + <refnamediv> + <refname>systemd-volatile-root.service</refname> + <refname>systemd-volatile-root</refname> + <refpurpose>Make the root file system volatile</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <para><filename>systemd-volatile-root.service</filename></para> + <para><filename>/usr/lib/systemd/systemd-volatile-root</filename></para> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><filename>systemd-volatile-root.service</filename> is a service that replaces the root directory with a + volatile memory file system (<literal>tmpfs</literal>), mounting the original (non-volatile) + <filename>/usr</filename> inside it read-only. This way, vendor data from <filename>/usr</filename> is available as + usual, but all configuration data in <filename>/etc</filename>, all state data in <filename>/var</filename> and all + other resources stored directly under the root directory are reset on boot and lost at shutdown, enabling fully + stateless systems.</para> + + <para>This service is only enabled if full volatile mode is selected, for example by specifying + <literal>systemd.volatile=yes</literal> on the kernel command line. This service runs only in the initial RAM disk + ("initrd"), before the system transitions to the host's root directory. Note that this service is not used if + <literal>systemd.volatile=state</literal> is used, as in that mode the root directory is non-volatile.</para> + </refsect1> + + <refsect1> + <title>See Also</title> + <para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>, + <citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 84163abbc..f58aa27df 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -42,8 +42,10 @@ #include "unit-name.h" #include "util.h" #include "virt.h" +#include "volatile-util.h" static const char *arg_dest = "/tmp"; +static const char *arg_dest_late = "/tmp"; static bool arg_fstab_enabled = true; static char *arg_root_what = NULL; static char *arg_root_fstype = NULL; @@ -52,6 +54,7 @@ static int arg_root_rw = -1; static char *arg_usr_what = NULL; static char *arg_usr_fstype = NULL; static char *arg_usr_options = NULL; +static VolatileMode arg_volatile_mode = _VOLATILE_MODE_INVALID; static int add_swap( const char *what, @@ -235,6 +238,7 @@ static int write_requires_mounts_for(FILE *f, const char *opts) { } static int add_mount( + const char *dest, const char *what, const char *where, const char *fstype, @@ -286,7 +290,7 @@ static int add_mount( if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); - unit = strjoin(arg_dest, "/", name); + unit = strjoin(dest, "/", name); if (!unit) return log_oom(); @@ -318,7 +322,7 @@ static int add_mount( } if (passno != 0) { - r = generator_write_fsck_deps(f, arg_dest, what, where, fstype); + r = generator_write_fsck_deps(f, dest, what, where, fstype); if (r < 0) return r; } @@ -334,7 +338,7 @@ static int add_mount( if (!isempty(fstype) && !streq(fstype, "auto")) fprintf(f, "Type=%s\n", fstype); - r = generator_write_timeouts(arg_dest, what, where, opts, &filtered); + r = generator_write_timeouts(dest, what, where, opts, &filtered); if (r < 0) return r; @@ -350,7 +354,7 @@ static int add_mount( return log_error_errno(r, "Failed to write unit file %s: %m", unit); if (!noauto && !automount) { - lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", name); + lnk = strjoin(dest, "/", post, nofail ? ".wants/" : ".requires/", name); if (!lnk) return log_oom(); @@ -364,7 +368,7 @@ static int add_mount( if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); - automount_unit = strjoin(arg_dest, "/", automount_name); + automount_unit = strjoin(dest, "/", automount_name); if (!automount_unit) return log_oom(); @@ -406,7 +410,7 @@ static int add_mount( return log_error_errno(r, "Failed to write unit file %s: %m", automount_unit); free(lnk); - lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name); + lnk = strjoin(dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name); if (!lnk) return log_oom(); @@ -479,7 +483,8 @@ static int parse_fstab(bool initrd) { else post = SPECIAL_LOCAL_FS_TARGET; - k = add_mount(what, + k = add_mount(arg_dest, + what, where, me->mnt_type, me->mnt_opts, @@ -540,7 +545,8 @@ static int add_sysroot_mount(void) { return r; } - return add_mount(what, + return add_mount(arg_dest, + what, "/sysroot", arg_root_fstype, opts, @@ -593,7 +599,8 @@ static int add_sysroot_usr_mount(void) { opts = arg_usr_options; log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype)); - return add_mount(what, + return add_mount(arg_dest, + what, "/sysroot/usr", arg_usr_fstype, opts, @@ -605,6 +612,46 @@ static int add_sysroot_usr_mount(void) { "/proc/cmdline"); } +static int add_volatile_root(void) { + const char *from, *to; + + if (arg_volatile_mode != VOLATILE_YES) + return 0; + + /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is + * requested, leaving only /usr from the root mount inside. */ + + from = strjoina(SYSTEM_DATA_UNIT_PATH "/systemd-volatile-root.service"); + to = strjoina(arg_dest, "/" SPECIAL_INITRD_ROOT_FS_TARGET, ".requires/systemd-volatile-root.service"); + + (void) mkdir_parents(to, 0755); + + if (symlink(from, to) < 0) + return log_error_errno(errno, "Failed to hook in volatile remount service: %m"); + + return 0; +} + +static int add_volatile_var(void) { + + if (arg_volatile_mode != VOLATILE_STATE) + return 0; + + /* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */ + + return add_mount(arg_dest_late, + "tmpfs", + "/var", + "tmpfs", + "mode=0755", + 0, + false, + false, + false, + SPECIAL_LOCAL_FS_TARGET, + "/proc/cmdline"); +} + static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { int r; @@ -686,6 +733,18 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat arg_root_rw = true; else if (streq(key, "ro") && !value) arg_root_rw = false; + else if (streq(key, "systemd.volatile")) { + VolatileMode m; + + if (value) { + m = volatile_mode_from_string(value); + if (m < 0) + log_warning("Failed to parse systemd.volatile= argument: %s", value); + else + arg_volatile_mode = m; + } else + arg_volatile_mode = VOLATILE_YES; + } return 0; } @@ -700,6 +759,8 @@ int main(int argc, char *argv[]) { if (argc > 1) arg_dest = argv[1]; + if (argc > 3) + arg_dest_late = argv[3]; log_set_target(LOG_TARGET_SAFE); log_parse_environment(); @@ -720,8 +781,12 @@ int main(int argc, char *argv[]) { k = add_sysroot_usr_mount(); if (k < 0) r = k; + + k = add_volatile_root(); + if (k < 0) + r = k; } else - r = 0; + r = add_volatile_var(); /* Honour /etc/fstab only when that's enabled */ if (arg_fstab_enabled) { diff --git a/src/shared/volatile-util.c b/src/shared/volatile-util.c index 1329b51f4..e7e972141 100644 --- a/src/shared/volatile-util.c +++ b/src/shared/volatile-util.c @@ -17,8 +17,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "macro.h" #include "parse-util.h" +#include "proc-cmdline.h" #include "string-util.h" #include "volatile-util.h" @@ -39,3 +41,28 @@ VolatileMode volatile_mode_from_string(const char *s) { return _VOLATILE_MODE_INVALID; } + +int query_volatile_mode(VolatileMode *ret) { + _cleanup_free_ char *mode = NULL; + VolatileMode m = VOLATILE_NO; + int r; + + r = proc_cmdline_get_key("systemd.volatile", PROC_CMDLINE_VALUE_OPTIONAL, &mode); + if (r < 0) + return r; + if (r == 0) + goto finish; + + if (mode) { + m = volatile_mode_from_string(mode); + if (m < 0) + return -EINVAL; + } else + m = VOLATILE_YES; + + r = 1; + +finish: + *ret = m; + return r; +} diff --git a/src/shared/volatile-util.h b/src/shared/volatile-util.h index d012940c7..17930ba6a 100644 --- a/src/shared/volatile-util.h +++ b/src/shared/volatile-util.h @@ -28,3 +28,5 @@ typedef enum VolatileMode { } VolatileMode; VolatileMode volatile_mode_from_string(const char *s); + +int query_volatile_mode(VolatileMode *ret); diff --git a/src/volatile-root/Makefile b/src/volatile-root/Makefile new file mode 120000 index 000000000..d0b0e8e00 --- /dev/null +++ b/src/volatile-root/Makefile @@ -0,0 +1 @@ +../Makefile
\ No newline at end of file diff --git a/src/volatile-root/volatile-root.c b/src/volatile-root/volatile-root.c new file mode 100644 index 000000000..3c0b6fa1d --- /dev/null +++ b/src/volatile-root/volatile-root.c @@ -0,0 +1,157 @@ +/*** + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/mount.h> + +#include "alloc-util.h" +#include "fs-util.h" +#include "mkdir.h" +#include "mount-util.h" +#include "stat-util.h" +#include "volatile-util.h" +#include "string-util.h" +#include "path-util.h" + +static int make_volatile(const char *path) { + _cleanup_free_ char *old_usr = NULL; + int r; + + r = path_is_mount_point(path, NULL, AT_SYMLINK_FOLLOW); + if (r < 0) + return log_error_errno(r, "Couldn't determine whether %s is a mount point: %m", path); + if (r == 0) { + log_error("%s is not a mount point.", path); + return -EINVAL; + } + + r = path_is_temporary_fs(path); + if (r < 0) + return log_error_errno(r, "Couldn't determine whether %s is a temporary file system: %m", path); + if (r > 0) { + log_info("%s already is a temporary file system.", path); + return 0; + } + + r = chase_symlinks("/usr", path, CHASE_PREFIX_ROOT, &old_usr); + if (r < 0) + return log_error_errno(r, "/usr not available in old root: %m"); + + r = mkdir_p("/run/systemd/volatile-sysroot", 0700); + if (r < 0) + return log_error_errno(r, "Couldn't generate volatile sysroot directory: %m"); + + r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/volatile-sysroot", "tmpfs", MS_STRICTATIME, "mode=755"); + if (r < 0) + goto finish_rmdir; + + if (mkdir("/run/systemd/volatile-sysroot/usr", 0755) < 0) { + r = -errno; + goto finish_umount; + } + + r = mount_verbose(LOG_ERR, old_usr, "/run/systemd/volatile-sysroot/usr", NULL, MS_BIND|MS_REC, NULL); + if (r < 0) + goto finish_umount; + + r = bind_remount_recursive("/run/systemd/volatile-sysroot/usr", true, NULL); + if (r < 0) + goto finish_umount; + + r = umount_recursive(path, 0); + if (r < 0) { + log_error_errno(r, "Failed to unmount %s: %m", path); + goto finish_umount; + } + + if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) + log_warning_errno(errno, "Failed to remount %s MS_SLAVE|MS_REC: %m", path); + + r = mount_verbose(LOG_ERR, "/run/systemd/volatile-sysroot", path, NULL, MS_MOVE, NULL); + +finish_umount: + (void) umount_recursive("/run/systemd/volatile-sysroot", 0); + +finish_rmdir: + (void) rmdir("/run/systemd/volatile-sysroot"); + + return r; +} + +int main(int argc, char *argv[]) { + VolatileMode m = _VOLATILE_MODE_INVALID; + const char *path; + int r; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + if (argc > 3) { + log_error("Too many arguments. Expected directory and mode."); + r = -EINVAL; + goto finish; + } + + r = query_volatile_mode(&m); + if (r < 0) { + log_error_errno(r, "Failed to determine volatile mode from kernel command line."); + goto finish; + } + if (r == 0 && argc >= 2) { + /* The kernel command line always wins. However if nothing was set there, the argument passed here wins instead. */ + m = volatile_mode_from_string(argv[1]); + if (m < 0) { + log_error("Couldn't parse volatile mode: %s", argv[1]); + r = -EINVAL; + goto finish; + } + } + + if (argc < 3) + path = "/sysroot"; + else { + path = argv[2]; + + if (isempty(path)) { + log_error("Directory name cannot be empty."); + r = -EINVAL; + goto finish; + } + if (!path_is_absolute(path)) { + log_error("Directory must be specified as absolute path."); + r = -EINVAL; + goto finish; + } + if (path_equal(path, "/")) { + log_error("Directory cannot be the root directory."); + r = -EINVAL; + goto finish; + } + } + + if (m != VOLATILE_YES) { + r = 0; + goto finish; + } + + r = make_volatile(path); + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/units/.gitignore b/units/.gitignore index 8fdb6e9ab..4398a59f9 100644 --- a/units/.gitignore +++ b/units/.gitignore @@ -75,5 +75,6 @@ /systemd-update-utmp.service /systemd-user-sessions.service /systemd-vconsole-setup.service +/systemd-volatile-root.service /tmp.mount /user@.service diff --git a/units/systemd-volatile-root.service.in b/units/systemd-volatile-root.service.in new file mode 100644 index 000000000..cc4e604e4 --- /dev/null +++ b/units/systemd-volatile-root.service.in @@ -0,0 +1,21 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Enforce Volatile Root File Systems +Documentation=man:systemd-volatile-root.service(8) +DefaultDependencies=no +Conflicts=shutdown.target +After=sysroot.mount +Before=initrd-root-fs.target shutdown.target +Conflicts=shutdown.target +AssertPathExists=/etc/initrd-release + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=@rootlibexecdir@/systemd-volatile-root yes /sysroot |