diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md
index 83c2d25134..4882cab600 100644
--- a/docs/ENVIRONMENT.md
+++ b/docs/ENVIRONMENT.md
@@ -41,6 +41,12 @@ All tools:
debugging, in order to test generators and other code against specific kernel
command lines.
+* `$SYSTEMD_FSTAB` — if set, use this path instead of /etc/fstab. Only useful
+ for debugging.
+
+* `$SYSTEMD_CRYPTTAB` — if set, use this path instead of /etc/crypttab. Only
+ useful for debugging. Currently only supported by systemd-cryptsetup-generator.
+
* `$SYSTEMD_EFI_OPTIONS` — if set, used instead of the string in SystemdOptions
EFI variable. Analogous to `$SYSTEMD_PROC_CMDLINE`.
@@ -61,6 +67,10 @@ All tools:
this only controls use of Unicode emoji glyphs, and has no effect on other
Unicode glyphs.
+* `$RUNTIME_DIRECTORY` — various tools use this variable to locate the
+ appropriate path under /run. This variable is also set by the manager when
+ RuntimeDirectory= is used, see systemd.exec(5).
+
systemctl:
* `$SYSTEMCTL_FORCE_BUS=1` — if set, do not connect to PID1's private D-Bus
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 8701005e6b..0d3645f19f 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -2436,6 +2436,20 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
information.
+
+ $RUNTIME_DIRECTORY
+ $STATE_DIRECTORY
+ $CACHE_DIRECTORY
+ $LOGS_DIRECTORY
+ $CONFIGURATION_DIRECTORY
+
+ Contains and absolute paths to the directories defined with
+ RuntimeDirectory=, StateDirectory=,
+ CacheDirectory=, LogsDirectory=, and
+ ConfigurationDirectory= when those settings are used.
+
+
+
$MAINPID
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 4815ded753..811a9468c1 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -37,6 +37,8 @@ typedef struct crypto_device {
static const char *arg_dest = NULL;
static bool arg_enabled = true;
static bool arg_read_crypttab = true;
+static const char *arg_crypttab = NULL;
+static const char *arg_runtime_directory = NULL;
static bool arg_whitelist = false;
static Hashmap *arg_disks = NULL;
static char *arg_default_options = NULL;
@@ -60,17 +62,36 @@ static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_key
c = strrchr(keyspec, ':');
if (c) {
- keyfile = strndup(keyspec, c-keyspec);
- keydev = strdup(c + 1);
- if (!keyfile || !keydev)
+ /* The keydev part has to be either an absolute path to device node (/dev/something,
+ * /dev/foo/something, or even possibly /dev/foo/something:part), or a fstab device
+ * specification starting with LABEL= or similar. The keyfile part has the same syntax.
+ *
+ * Let's try to guess if the second part looks like a keydev specification, or just part of a
+ * filename with a colon. fstab_node_to_udev_node() will convert the fstab device syntax to
+ * an absolute path. If we didn't get an absolute path, assume that it is just part of the
+ * first keyfile argument. */
+
+ keydev = fstab_node_to_udev_node(c + 1);
+ if (!keydev)
return log_oom();
- } else {
+
+ if (path_is_absolute(keydev))
+ keyfile = strndup(keyspec, c-keyspec);
+ else {
+ log_debug("Keyspec argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
+ "Assuming that \"%s\" is a single device specification.",
+ c + 1, keyspec);
+ keydev = mfree(keydev);
+ c = NULL;
+ }
+ }
+
+ if (!c)
/* No keydev specified */
keyfile = strdup(keyspec);
- keydev = NULL;
- if (!keyfile)
- return log_oom();
- }
+
+ if (!keyfile)
+ return log_oom();
*ret_keyfile = TAKE_PTR(keyfile);
*ret_keydev = TAKE_PTR(keydev);
@@ -79,7 +100,7 @@ static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_key
}
static int generate_keydev_mount(const char *name, const char *keydev, const char *keydev_timeout, bool canfail, char **unit, char **mount) {
- _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *name_escaped = NULL, *device_unit = NULL;
+ _cleanup_free_ char *u = NULL, *where = NULL, *name_escaped = NULL, *device_unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
usec_t timeout_us;
@@ -89,11 +110,11 @@ static int generate_keydev_mount(const char *name, const char *keydev, const cha
assert(unit);
assert(mount);
- r = mkdir_parents("/run/systemd/cryptsetup", 0755);
+ r = mkdir_parents(arg_runtime_directory, 0755);
if (r < 0)
return r;
- r = mkdir("/run/systemd/cryptsetup", 0700);
+ r = mkdir(arg_runtime_directory, 0700);
if (r < 0 && errno != EEXIST)
return -errno;
@@ -101,7 +122,7 @@ static int generate_keydev_mount(const char *name, const char *keydev, const cha
if (!name_escaped)
return -ENOMEM;
- where = strjoin("/run/systemd/cryptsetup/keydev-", name_escaped);
+ where = strjoin(arg_runtime_directory, "/keydev-", name_escaped);
if (!where)
return -ENOMEM;
@@ -117,22 +138,18 @@ static int generate_keydev_mount(const char *name, const char *keydev, const cha
if (r < 0)
return r;
- what = fstab_node_to_udev_node(keydev);
- if (!what)
- return -ENOMEM;
-
fprintf(f,
"[Unit]\n"
"DefaultDependencies=no\n\n"
"[Mount]\n"
"What=%s\n"
"Where=%s\n"
- "Options=ro%s\n", what, where, canfail ? ",nofail" : "");
+ "Options=ro%s\n", keydev, where, canfail ? ",nofail" : "");
if (keydev_timeout) {
r = parse_sec_fix_0(keydev_timeout, &timeout_us);
if (r >= 0) {
- r = unit_name_from_path(what, ".device", &device_unit);
+ r = unit_name_from_path(keydev, ".device", &device_unit);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
@@ -271,11 +288,12 @@ static int create_disk(
"[Unit]\n"
"Description=Cryptography Setup for %%I\n"
"Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
- "SourcePath=/etc/crypttab\n"
+ "SourcePath=%s\n"
"DefaultDependencies=no\n"
"Conflicts=umount.target\n"
"IgnoreOnIsolate=true\n"
"After=%s\n",
+ arg_crypttab,
netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");
if (password) {
@@ -558,15 +576,15 @@ static int add_crypttab_devices(void) {
if (!arg_read_crypttab)
return 0;
- r = fopen_unlocked("/etc/crypttab", "re", &f);
+ r = fopen_unlocked(arg_crypttab, "re", &f);
if (r < 0) {
if (errno != ENOENT)
- log_error_errno(errno, "Failed to open /etc/crypttab: %m");
+ log_error_errno(errno, "Failed to open %s: %m", arg_crypttab);
return 0;
}
if (fstat(fileno(f), &st) < 0) {
- log_error_errno(errno, "Failed to stat /etc/crypttab: %m");
+ log_error_errno(errno, "Failed to stat %s: %m", arg_crypttab);
return 0;
}
@@ -578,7 +596,7 @@ static int add_crypttab_devices(void) {
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
- return log_error_errno(r, "Failed to read /etc/crypttab: %m");
+ return log_error_errno(r, "Failed to read %s: %m", arg_crypttab);
if (r == 0)
break;
@@ -590,7 +608,7 @@ static int add_crypttab_devices(void) {
k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &keyspec, &options);
if (k < 2 || k > 4) {
- log_error("Failed to parse /etc/crypttab:%u, ignoring.", crypttab_line);
+ log_error("Failed to parse %s:%u, ignoring.", arg_crypttab, crypttab_line);
continue;
}
@@ -667,6 +685,9 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
assert_se(arg_dest = dest);
+ arg_crypttab = getenv("SYSTEMD_CRYPTTAB") ?: "/etc/crypttab";
+ arg_runtime_directory = getenv("RUNTIME_DIRECTORY") ?: "/run/systemd/cryptsetup";
+
arg_disks = hashmap_new(&crypt_device_hash_ops);
if (!arg_disks)
return log_oom();
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index dd8c178fcb..dd1504dc9d 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -15,6 +15,7 @@
#include "device-util.h"
#include "escape.h"
#include "fileio.h"
+#include "fstab-util.h"
#include "log.h"
#include "main-func.h"
#include "mount-util.h"
@@ -302,7 +303,7 @@ static char *disk_mount_point(const char *label) {
if (asprintf(&device, "/dev/mapper/%s", label) < 0)
return NULL;
- f = setmntent("/etc/fstab", "re");
+ f = setmntent(fstab_path(), "re");
if (!f)
return NULL;
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index abe4413f92..6fd6fbdf1c 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -112,14 +112,16 @@ static int add_swap(
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
- r = generator_open_unit_file(arg_dest, "/etc/fstab", name, &f);
+ r = generator_open_unit_file(arg_dest, fstab_path(), name, &f);
if (r < 0)
return r;
- fputs("[Unit]\n"
- "SourcePath=/etc/fstab\n"
- "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
- "[Swap]\n", f);
+ fprintf(f,
+ "[Unit]\n"
+ "SourcePath=%s\n"
+ "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
+ "[Swap]\n",
+ fstab_path());
r = write_what(f, what);
if (r < 0)
@@ -340,7 +342,7 @@ static int add_mount(
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
- r = generator_open_unit_file(dest, "/etc/fstab", name, &f);
+ r = generator_open_unit_file(dest, fstab_path(), name, &f);
if (r < 0)
return r;
@@ -463,7 +465,7 @@ static int add_mount(
f = safe_fclose(f);
- r = generator_open_unit_file(dest, "/etc/fstab", automount_name, &f);
+ r = generator_open_unit_file(dest, fstab_path(), automount_name, &f);
if (r < 0)
return r;
@@ -515,19 +517,19 @@ static int add_mount(
static int parse_fstab(bool initrd) {
_cleanup_endmntent_ FILE *f = NULL;
- const char *fstab_path;
+ const char *fstab;
struct mntent *me;
int r = 0;
- fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
- log_debug("Parsing %s...", fstab_path);
+ fstab = initrd ? "/sysroot/etc/fstab" : fstab_path();
+ log_debug("Parsing %s...", fstab);
- f = setmntent(fstab_path, "re");
+ f = setmntent(fstab, "re");
if (!f) {
if (errno == ENOENT)
return 0;
- return log_error_errno(errno, "Failed to open %s: %m", fstab_path);
+ return log_error_errno(errno, "Failed to open %s: %m", fstab);
}
while ((me = getmntent(f))) {
@@ -606,7 +608,7 @@ static int parse_fstab(bool initrd) {
me->mnt_passno,
makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT,
post,
- fstab_path);
+ fstab);
}
if (r >= 0 && k < 0)
diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c
index 5891013427..7386f70529 100644
--- a/src/remount-fs/remount-fs.c
+++ b/src/remount-fs/remount-fs.c
@@ -9,6 +9,7 @@
#include "env-util.h"
#include "exit-status.h"
+#include "fstab-util.h"
#include "log.h"
#include "main-func.h"
#include "mount-setup.h"
@@ -86,10 +87,10 @@ static int run(int argc, char *argv[]) {
umask(0022);
- f = setmntent("/etc/fstab", "re");
+ f = setmntent(fstab_path(), "re");
if (!f) {
if (errno != ENOENT)
- return log_error_errno(errno, "Failed to open /etc/fstab: %m");
+ return log_error_errno(errno, "Failed to open %s: %m", fstab_path());
} else
while ((me = getmntent(f))) {
/* Remount the root fs, /usr, and all API VFSs */
diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
index 75e4784c38..f90501eb92 100644
--- a/src/shared/fstab-util.c
+++ b/src/shared/fstab-util.c
@@ -19,7 +19,7 @@ int fstab_has_fstype(const char *fstype) {
_cleanup_endmntent_ FILE *f = NULL;
struct mntent *m;
- f = setmntent("/etc/fstab", "re");
+ f = setmntent(fstab_path(), "re");
if (!f)
return errno == ENOENT ? false : -errno;
@@ -39,7 +39,7 @@ int fstab_is_mount_point(const char *mount) {
_cleanup_endmntent_ FILE *f = NULL;
struct mntent *m;
- f = setmntent("/etc/fstab", "re");
+ f = setmntent(fstab_path(), "re");
if (!f)
return errno == ENOENT ? false : -errno;
diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h
index 0862256511..f575ed0bb2 100644
--- a/src/shared/fstab-util.h
+++ b/src/shared/fstab-util.h
@@ -31,3 +31,7 @@ static inline bool fstab_test_yes_no_option(const char *opts, const char *yes_no
}
char *fstab_node_to_udev_node(const char *p);
+
+static inline const char* fstab_path(void) {
+ return secure_getenv("SYSTEMD_FSTAB") ?: "/etc/fstab";
+}