summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/org.freedesktop.systemd1.xml6
-rw-r--r--man/systemd.automount.xml9
-rw-r--r--src/core/automount.c36
-rw-r--r--src/core/automount.h1
-rw-r--r--src/core/dbus-automount.c4
-rw-r--r--src/core/load-fragment-gperf.gperf.in1
-rw-r--r--src/shared/bus-unit-util.c3
-rw-r--r--test/fuzz/fuzz-unit-file/directives.automount1
-rw-r--r--test/test-functions22
-rwxr-xr-xtest/units/testsuite-55.sh19
10 files changed, 81 insertions, 21 deletions
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 86bf7ef108..e878f65de1 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -7595,6 +7595,8 @@ node /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s Where = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly s ExtraOptions = '...';
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly u DirectoryMode = ...;
readonly s Result = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -7609,6 +7611,8 @@ node /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount
<!--property Where is not documented!-->
+ <!--property ExtraOptions is not documented!-->
+
<!--property DirectoryMode is not documented!-->
<!--property TimeoutIdleUSec is not documented!-->
@@ -7625,6 +7629,8 @@ node /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount
<variablelist class="dbus-property" generated="True" extra-ref="Where"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="ExtraOptions"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="DirectoryMode"/>
<variablelist class="dbus-property" generated="True" extra-ref="Result"/>
diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml
index 37fd743552..da35a7d26b 100644
--- a/man/systemd.automount.xml
+++ b/man/systemd.automount.xml
@@ -145,6 +145,15 @@
</varlistentry>
<varlistentry>
+ <term><varname>ExtraOptions=</varname></term>
+ <listitem><para>Extra mount options to use when creating the autofs
+ mountpoint. This takes a comma-separated list of options. This setting
+ is optional. Note that the usual specifier expansion is applied to this
+ setting, literal percent characters should hence be written as
+ <literal class='specifiers'>%%</literal>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>DirectoryMode=</varname></term>
<listitem><para>Directories of automount points (and any
parent directories) are automatically created if needed. This
diff --git a/src/core/automount.c b/src/core/automount.c
index 0bb58fdcd1..02089aed4e 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -19,6 +19,7 @@
#include "dbus-unit.h"
#include "fd-util.h"
#include "format-util.h"
+#include "fstab-util.h"
#include "io-util.h"
#include "label.h"
#include "mkdir-label.h"
@@ -109,6 +110,7 @@ static void automount_done(Unit *u) {
unmount_autofs(a);
a->where = mfree(a->where);
+ a->extra_options = mfree(a->extra_options);
a->tokens = set_free(a->tokens);
a->expire_tokens = set_free(a->expire_tokens);
@@ -168,6 +170,15 @@ static int automount_add_default_dependencies(Automount *a) {
}
static int automount_verify(Automount *a) {
+ static const char *const reserved_options[] = {
+ "fd\0",
+ "pgrp\0",
+ "minproto\0",
+ "maxproto\0",
+ "direct\0",
+ "indirect\0",
+ };
+
_cleanup_free_ char *e = NULL;
int r;
@@ -184,6 +195,14 @@ static int automount_verify(Automount *a) {
if (!unit_has_name(UNIT(a), e))
return log_unit_error_errno(UNIT(a), SYNTHETIC_ERRNO(ENOEXEC), "Where= setting doesn't match unit name. Refusing.");
+ for (size_t i = 0; i < ELEMENTSOF(reserved_options); i++)
+ if (fstab_test_option(a->extra_options, reserved_options[i]))
+ return log_unit_error_errno(
+ UNIT(a),
+ SYNTHETIC_ERRNO(ENOEXEC),
+ "ExtraOptions= setting may not contain reserved option %s.",
+ reserved_options[i]);
+
return 0;
}
@@ -313,11 +332,13 @@ static void automount_dump(Unit *u, FILE *f, const char *prefix) {
"%sAutomount State: %s\n"
"%sResult: %s\n"
"%sWhere: %s\n"
+ "%sExtraOptions: %s\n"
"%sDirectoryMode: %04o\n"
"%sTimeoutIdleUSec: %s\n",
prefix, automount_state_to_string(a->state),
prefix, automount_result_to_string(a->result),
prefix, a->where,
+ prefix, a->extra_options,
prefix, a->directory_mode,
prefix, FORMAT_TIMESPAN(a->timeout_idle_usec, USEC_PER_SEC));
}
@@ -552,8 +573,7 @@ static void automount_enter_waiting(Automount *a) {
_cleanup_close_ int ioctl_fd = -1;
int p[2] = { -1, -1 };
char name[STRLEN("systemd-") + DECIMAL_STR_MAX(pid_t) + 1];
- char options[STRLEN("fd=,pgrp=,minproto=5,maxproto=5,direct")
- + DECIMAL_STR_MAX(int) + DECIMAL_STR_MAX(gid_t) + 1];
+ _cleanup_free_ char *options = NULL;
bool mounted = false;
int r, dev_autofs_fd;
struct stat st;
@@ -586,7 +606,17 @@ static void automount_enter_waiting(Automount *a) {
if (r < 0)
goto fail;
- xsprintf(options, "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct", p[1], getpgrp());
+ if (asprintf(
+ &options,
+ "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct%s%s",
+ p[1],
+ getpgrp(),
+ isempty(a->extra_options) ? "" : ",",
+ strempty(a->extra_options)) < 0) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
xsprintf(name, "systemd-"PID_FMT, getpid_cached());
r = mount_nofollow(name, a->where, "autofs", 0, options);
if (r < 0)
diff --git a/src/core/automount.h b/src/core/automount.h
index 4b0c633b79..684f2759a6 100644
--- a/src/core/automount.h
+++ b/src/core/automount.h
@@ -22,6 +22,7 @@ struct Automount {
AutomountState state, deserialized_state;
char *where;
+ char *extra_options;
usec_t timeout_idle_usec;
int pipe_fd;
diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c
index 3f74488dad..881bf50b6e 100644
--- a/src/core/dbus-automount.c
+++ b/src/core/dbus-automount.c
@@ -11,6 +11,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, Autom
const sd_bus_vtable bus_automount_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Automount, where), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ExtraOptions", "s", NULL, offsetof(Automount, extra_options), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Automount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Automount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("TimeoutIdleUSec", "t", bus_property_get_usec, offsetof(Automount, timeout_idle_usec), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -35,6 +36,9 @@ static int bus_automount_set_transient_property(
if (streq(name, "Where"))
return bus_set_transient_path(u, name, &a->where, message, flags, error);
+ if (streq(name, "ExtraOptions"))
+ return bus_set_transient_string(u, name, &a->extra_options, message, flags, error);
+
if (streq(name, "TimeoutIdleUSec"))
return bus_set_transient_usec_fix_0(u, name, &a->timeout_idle_usec, message, flags, error);
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 71a5904a70..67cb2d70a2 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -503,6 +503,7 @@ Mount.ReadWriteOnly, config_parse_bool,
{{ CGROUP_CONTEXT_CONFIG_ITEMS('Mount') }}
{{ KILL_CONTEXT_CONFIG_ITEMS('Mount') }}
Automount.Where, config_parse_unit_path_printf, 0, offsetof(Automount, where)
+Automount.ExtraOptions, config_parse_unit_string_printf, 0, offsetof(Automount, extra_options)
Automount.DirectoryMode, config_parse_mode, 0, offsetof(Automount, directory_mode)
Automount.TimeoutIdleSec, config_parse_sec_fix_0, 0, offsetof(Automount, timeout_idle_usec)
Swap.What, config_parse_unit_path_printf, 0, offsetof(Swap, parameters_fragment.what)
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index bbf7499e57..b8fd85a191 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -894,7 +894,8 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
}
static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
- if (streq(field, "Where"))
+ if (STR_IN_SET(field, "Where",
+ "ExtraOptions"))
return bus_append_string(m, field, eq);
if (streq(field, "DirectoryMode"))
diff --git a/test/fuzz/fuzz-unit-file/directives.automount b/test/fuzz/fuzz-unit-file/directives.automount
index 70772ba06d..fd0ce64a2e 100644
--- a/test/fuzz/fuzz-unit-file/directives.automount
+++ b/test/fuzz/fuzz-unit-file/directives.automount
@@ -3,3 +3,4 @@ automount
DirectoryMode=
TimeoutIdleSec=
Where=
+ExtraOptions=
diff --git a/test/test-functions b/test/test-functions
index 00a808bf28..a4b7efb5ec 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -778,9 +778,23 @@ if [[ ! -e "$ASAN_RT_PATH" ]]; then
exit 1
fi
+# Suppress certain leaks reported by LSan (either in external tools or bogus
+# ones)
+# Docs: # https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer#suppressions
+#
+# - fsck is called by systemd-homed and is reporting a leak we're not interested
+# in
+# - libLLVM is a "side effect" caused by the previous fsck leak
+cat >/systemd-lsan.supp <<INNER_EOF
+leak:/bin/fsck$
+leak:/sbin/fsck$
+leak:/lib/libLLVM
+INNER_EOF
+
+DEFAULT_LSAN_OPTIONS=${LSAN_OPTIONS:-}:suppressions=/systemd-lsan.supp
DEFAULT_ASAN_OPTIONS=${ASAN_OPTIONS:-strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1}
DEFAULT_UBSAN_OPTIONS=${UBSAN_OPTIONS:-print_stacktrace=1:print_summary=1:halt_on_error=1}
-DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS"
+DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS LSAN_OPTIONS=\$DEFAULT_LSAN_OPTIONS"
# As right now bash is the PID 1, we can't expect PATH to have a sane value.
# Let's make one to prevent unexpected "<bin> not found" issues in the future
@@ -2083,7 +2097,7 @@ dfatal() {
# Generic substring function. If $2 is in $1, return 0.
-strstr() { [ "${1#*$2*}" != "$1" ]; }
+strstr() { [ "${1#*"$2"*}" != "$1" ]; }
# normalize_path <path>
# Prints the normalized path, where it removes any duplicated
@@ -2498,12 +2512,12 @@ image_install() {
install_kmod_with_fw() {
local module="${1:?}"
# no need to go further if the module is already installed
- [[ -e "${initdir:?}/lib/modules/${KERNEL_VER:?}/${module##*/lib/modules/$KERNEL_VER/}" ]] && return 0
+ [[ -e "${initdir:?}/lib/modules/${KERNEL_VER:?}/${module##*"/lib/modules/$KERNEL_VER/"}" ]] && return 0
[[ -e "$initdir/.kernelmodseen/${module##*/}" ]] && return 0
[ -d "$initdir/.kernelmodseen" ] && : >"$initdir/.kernelmodseen/${module##*/}"
- inst_simple "$module" "/lib/modules/$KERNEL_VER/${module##*/lib/modules/$KERNEL_VER/}" || return $?
+ inst_simple "$module" "/lib/modules/$KERNEL_VER/${module##*"/lib/modules/$KERNEL_VER/"}" || return $?
local modname="${module##*/}"
local fwdir found fw
diff --git a/test/units/testsuite-55.sh b/test/units/testsuite-55.sh
index b265c8cce7..db13964311 100755
--- a/test/units/testsuite-55.sh
+++ b/test/units/testsuite-55.sh
@@ -60,36 +60,29 @@ if ! systemctl status testsuite-55-testchill.service; then exit 24; fi
# Make sure we also work correctly on user units.
-runas() {
- declare userid=$1
- shift
- # shellcheck disable=SC2016
- su "$userid" -s /bin/sh -c 'XDG_RUNTIME_DIR=/run/user/$UID exec "$@"' -- sh "$@"
-}
-
-runas testuser systemctl start --user testsuite-55-testchill.service
-runas testuser systemctl start --user testsuite-55-testbloat.service
+systemctl start --machine "testuser@.host" --user testsuite-55-testchill.service
+systemctl start --machine "testuser@.host" --user testsuite-55-testbloat.service
# Verify systemd-oomd is monitoring the expected units
oomctl | grep -E "/user.slice.*/testsuite-55-workload.slice"
oomctl | grep "20.00%"
oomctl | grep "Default Memory Pressure Duration: 2s"
-runas testuser systemctl --user status testsuite-55-testchill.service
+systemctl --machine "testuser@.host" --user status testsuite-55-testchill.service
# systemd-oomd watches for elevated pressure for 2 seconds before acting.
# It can take time to build up pressure so either wait 2 minutes or for the service to fail.
timeout="$(date -ud "2 minutes" +%s)"
while [[ $(date -u +%s) -le $timeout ]]; do
- if ! runas testuser systemctl --user status testsuite-55-testbloat.service; then
+ if ! systemctl --machine "testuser@.host" --user status testsuite-55-testbloat.service; then
break
fi
sleep 2
done
# testbloat should be killed and testchill should be fine
-if runas testuser systemctl --user status testsuite-55-testbloat.service; then exit 42; fi
-if ! runas testuser systemctl --user status testsuite-55-testchill.service; then exit 24; fi
+if systemctl --machine "testuser@.host" --user status testsuite-55-testbloat.service; then exit 42; fi
+if ! systemctl --machine "testuser@.host" --user status testsuite-55-testchill.service; then exit 24; fi
# only run this portion of the test if we can set xattrs
if setfattr -n user.xattr_test -v 1 /sys/fs/cgroup/; then