summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fstab-generator/fstab-generator.c85
-rw-r--r--src/shared/volatile-util.c27
-rw-r--r--src/shared/volatile-util.h2
l---------src/volatile-root/Makefile1
-rw-r--r--src/volatile-root/volatile-root.c157
5 files changed, 262 insertions, 10 deletions
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 84163abbc5..f58aa27df2 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 1329b51f4e..e7e9721411 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 d012940c76..17930ba6ae 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 0000000000..d0b0e8e008
--- /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 0000000000..3c0b6fa1de
--- /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;
+}