diff --git a/.gitignore b/.gitignore
index ec4b7bd6729..f246d3e6d55 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 5e6eee5e325..27660ef1c25 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 56b8aa3fe8f..92a3680461b 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 \
@@ -3067,6 +3070,13 @@ systemd_remount_fs_SOURCES = \
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 78e45e66a97..7e1d408ded1 100644
--- a/man/kernel-command-line.xml
+++ b/man/kernel-command-line.xml
@@ -124,6 +124,28 @@
+
+ systemd.volatile=
+
+ This parameter controls whether the system shall boot up in volatile mode. Takes a boolean argument, or
+ the special value state. If false (the default), normal boot mode is selected, the root
+ directory and /var are mounted as specified on the kernel command line or
+ /etc/fstab, 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 (tmpfs), and only
+ /usr 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 /etc and /var (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 state the root file system is mounted as usual, however
+ /var is mounted as a volatile memory file system (tmpfs), so that the
+ system boots up with the normal configuration applied, but all state reset at boot and lost at shutdown. For details,
+ see
+ systemd-volatile-root.service8
+ and
+ systemd-fstab-generator8.
+
+
+
quiet
@@ -382,6 +404,7 @@
systemd-cryptsetup-generator8,
systemd-fstab-generator8,
systemd-gpt-auto-generator8,
+ systemd-volatile-root.service8,
systemd-modules-load.service8,
systemd-backlight@.service8,
systemd-rfkill.service8,
diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml
index a971cb36750..5f37e9193e7 100644
--- a/man/systemd-fstab-generator.xml
+++ b/man/systemd-fstab-generator.xml
@@ -89,12 +89,13 @@
Takes a boolean argument. Defaults to
yes. If no, causes the
- generator to ignore any mounts or swaps configured in
+ generator to ignore any mounts or swap devices configured in
/etc/fstab. rd.fstab=
- is honored only by initial RAM disk (initrd) while
+ is honored only by the initial RAM disk (initrd) while
fstab= is honored by both the main system
and the initrd.
+
root=
@@ -102,6 +103,7 @@
initrd. root= is honored by the
initrd.
+
rootfstype=
@@ -109,6 +111,7 @@
passed to the mount command. rootfstype= is
honored by the initrd.
+
rootflags=
@@ -116,6 +119,7 @@
use. rootflags= is honored by the
initrd.
+
mount.usr=
@@ -133,6 +137,7 @@
mount.usr= is honored by the initrd.
+
mount.usrfstype=
@@ -150,6 +155,7 @@
mount.usrfstype= is honored by the
initrd.
+
mount.usrflags=
@@ -166,6 +172,39 @@
mount.usrflags= is honored by the
initrd.
+
+
+ systemd.volatile=
+
+ Controls whether the system shall boot up in volatile mode. Takes a boolean argument or the
+ special value .
+
+ If false (the default), this generator makes no changes to the mount tree and the system is booted up in
+ normal mode.
+
+ If true the generator ensures
+ systemd-volatile-root.service8
+ 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 (tmpfs) is used as root directory,
+ with only /usr 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 /etc and /var will be served from the (initially
+ unpopulated) volatile memory file system.
+
+ If set to the generator will leave the root
+ directory mount point unaltered, however will mount a tmpfs file system to
+ /var. In this mode the normal system configuration (i.e the contents of
+ /etc) is in effect (and may be modified during system runtime), however the system state
+ (i.e. the contents of /var) is reset at boot and lost at shutdown.
+
+ Note that in none of these modes the root directory, /etc, /var
+ 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.
+
+ Note that enabling this setting will only work correctly on operating systems that can boot up with only
+ /usr mounted, and are able to automatically populate /etc, and also
+ /var in case of systemd.volatile=yes.
+
@@ -176,7 +215,8 @@
fstab5,
systemd.mount5,
systemd.swap5,
- systemd-cryptsetup-generator8
+ systemd-cryptsetup-generator8,
+ kernel-command-line7
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index 2bc81ea1aa2..f6b3f57fc77 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -939,12 +939,15 @@
(the default), the whole OS tree is made
available writable.
- Note that setting this to or
- will only work correctly with
- operating systems in the container that can boot up with only
- /usr mounted, and are able to populate
- /var automatically, as
- needed.
+ This option provides similar functionality for containers as the systemd.volatile=
+ kernel command line switch provides for host systems. See
+ kernel-command-line7 for
+ details.
+
+ Note that enabling this setting will only work correctly with operating systems in the container that can
+ boot up with only /usr mounted, and are able to automatically populate
+ /var, and also /etc in case of
+ --volatile=yes.
diff --git a/man/systemd-volatile-root.service.xml b/man/systemd-volatile-root.service.xml
new file mode 100644
index 00000000000..b90a3261fa5
--- /dev/null
+++ b/man/systemd-volatile-root.service.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+ systemd-volatile-root.service
+ systemd
+
+
+
+ Developer
+ Lennart
+ Poettering
+ lennart@poettering.net
+
+
+
+
+
+ systemd-volatile-root.service
+ 8
+
+
+
+ systemd-volatile-root.service
+ systemd-volatile-root
+ Make the root file system volatile
+
+
+
+ systemd-volatile-root.service
+ /usr/lib/systemd/systemd-volatile-root
+
+
+
+ Description
+
+ systemd-volatile-root.service is a service that replaces the root directory with a
+ volatile memory file system (tmpfs), mounting the original (non-volatile)
+ /usr inside it read-only. This way, vendor data from /usr is available as
+ usual, but all configuration data in /etc, all state data in /var and all
+ other resources stored directly under the root directory are reset on boot and lost at shutdown, enabling fully
+ stateless systems.
+
+ This service is only enabled if full volatile mode is selected, for example by specifying
+ systemd.volatile=yes 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
+ systemd.volatile=state is used, as in that mode the root directory is non-volatile.
+
+
+
+ See Also
+
+ systemd1,
+ systemd-fstab-generator8,
+ kernel-command-line7
+
+
+
+
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 84163abbc53..f58aa27df22 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 1329b51f4e4..e7e9721411e 100644
--- a/src/shared/volatile-util.c
+++ b/src/shared/volatile-util.c
@@ -17,8 +17,10 @@
along with systemd; If not, see .
***/
+#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 d012940c761..17930ba6aec 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 00000000000..d0b0e8e0086
--- /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 00000000000..3c0b6fa1de4
--- /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 .
+***/
+
+#include
+
+#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 8fdb6e9ab5d..4398a59f911 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 00000000000..cc4e604e4c3
--- /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