1
0
mirror of https://github.com/systemd/systemd synced 2026-03-11 07:34:58 +01:00

Compare commits

..

No commits in common. "71de0a22ff805954b3e6df95868ee82f9c7ff092" and "155ae657b1ae8b69fae811b28117cd7c83895c76" have entirely different histories.

43 changed files with 226 additions and 2393 deletions

1
TODO
View File

@ -124,6 +124,7 @@ Features:
* report: * report:
- should the list of metrics use JSON-SEQ? or maybe be wrapped in a json - should the list of metrics use JSON-SEQ? or maybe be wrapped in a json
array (the latter might be necessary, once we sign the combination) array (the latter might be necessary, once we sign the combination)
- "io.systemd.Manager.unit_active_state" is a weird mix of CamelCase and snake_case
- metrics from pid1: suppress metrics form units that are inactive and have nothing to report - metrics from pid1: suppress metrics form units that are inactive and have nothing to report
- how to plug facts into this? i.e. hostname, ssh keys, and so on - how to plug facts into this? i.e. hostname, ssh keys, and so on
- switch to daan's suggested hierarchy? - switch to daan's suggested hierarchy?

View File

@ -931,6 +931,13 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPEliteDragonflyG2*:pvr*
evdev:name:Intel HID events:dmi:bvn*:bvr*:bd*:svnHP*:pnHPEliteDragonflyG2*:pvr* evdev:name:Intel HID events:dmi:bvn*:bvr*:bd*:svnHP*:pnHPEliteDragonflyG2*:pvr*
KEYBOARD_KEY_08=unknown # rfkill is also reported by HP Wireless hotkeys KEYBOARD_KEY_08=unknown # rfkill is also reported by HP Wireless hotkeys
# HP Elite Dragonfly G3
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnHPEliteDragonfly13.5inchG3NotebookPC:pvr*
KEYBOARD_KEY_c9=up
KEYBOARD_KEY_d1=down
KEYBOARD_KEY_c8=pageup
KEYBOARD_KEY_d0=pagedown
# HP 430 Programmable Wireless Keypad # HP 430 Programmable Wireless Keypad
evdev:input:b0005v03F0p854Ae044C* evdev:input:b0005v03F0p854Ae044C*
KEYBOARD_KEY_700f3=macro1 KEYBOARD_KEY_700f3=macro1

View File

@ -2833,8 +2833,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
readonly as ExtraFileDescriptorNames = ['...', ...]; readonly as ExtraFileDescriptorNames = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly i ReloadSignal = ...; readonly i ReloadSignal = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as RefreshOnReload = ['...', ...];
readonly t ExecMainStartTimestamp = ...; readonly t ExecMainStartTimestamp = ...;
readonly t ExecMainStartTimestampMonotonic = ...; readonly t ExecMainStartTimestampMonotonic = ...;
readonly t ExecMainExitTimestamp = ...; readonly t ExecMainExitTimestamp = ...;
@ -3536,8 +3534,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<!--property ReloadSignal is not documented!--> <!--property ReloadSignal is not documented!-->
<!--property RefreshOnReload is not documented!-->
<!--property ExecCondition is not documented!--> <!--property ExecCondition is not documented!-->
<!--property ExecConditionEx is not documented!--> <!--property ExecConditionEx is not documented!-->
@ -4184,8 +4180,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="ReloadSignal"/> <variablelist class="dbus-property" generated="True" extra-ref="ReloadSignal"/>
<variablelist class="dbus-property" generated="True" extra-ref="RefreshOnReload"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainStartTimestamp"/> <variablelist class="dbus-property" generated="True" extra-ref="ExecMainStartTimestamp"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainStartTimestampMonotonic"/> <variablelist class="dbus-property" generated="True" extra-ref="ExecMainStartTimestampMonotonic"/>
@ -12520,9 +12514,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<varname>ManagedOOMKills</varname>, <varname>ManagedOOMKills</varname>,
<varname>ExecReloadPost</varname>, and <varname>ExecReloadPost</varname>, and
<varname>ExecReloadPostEx</varname> were added in version 259.</para> <varname>ExecReloadPostEx</varname> were added in version 259.</para>
<para><varname>BindNetworkInterface</varname>, <para><varname>BindNetworkInterface</varname>, and
<varname>MemoryTHP</varname>, and <varname>MemoryTHP</varname> were added in version 260.</para>
<varname>RefreshOnReload</varname> were added in version 260.</para>
</refsect2> </refsect2>
<refsect2> <refsect2>
<title>Socket Unit Objects</title> <title>Socket Unit Objects</title>

View File

@ -572,13 +572,14 @@
To disable the safety check that the extension-release file name matches the image file name, the To disable the safety check that the extension-release file name matches the image file name, the
<varname>x-systemd.relax-extension-release-check</varname> mount option may be appended.</para> <varname>x-systemd.relax-extension-release-check</varname> mount option may be appended.</para>
<para>If a service employs this option with <para>This option can be used together with a <option>notify-reload</option> service type and
<citerefentry><refentrytitle>systemd.v</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.v</refentrytitle><manvolnum>7</manvolnum></citerefentry>
and has <option>RefreshOnReload=extensions</option> enabled (the default), the confexts will to manage configuration updates. When such a service carrying confext images is reloaded via
be refreshed to pick up any changes on service reload. This only applies to confext extensions. <command>systemctl reload foo.service</command> or equivalent D-Bus method, the confext itself will
Note that in case a service has this configuration enabled at first, and then it is subsequently be reloaded to pick up any changes. This only applies to confext extensions. Note that in case a
removed in an update followed by a daemon-reload operation, reloading the confexts will be a no-op, service has this configuration enabled at first, and then it is subsequently removed in an update
and a full service restart is required instead. See followed by a daemon-reload operation, reloading the confexts will be a no-op, and a full service
restart is required instead. See
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
also for details.</para> also for details.</para>
@ -629,13 +630,14 @@
or the host. See: or the host. See:
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
<para>If a service employs this option with <para>This option can be used together with a <option>notify-reload</option> service type and
<citerefentry><refentrytitle>systemd.v</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.v</refentrytitle><manvolnum>7</manvolnum></citerefentry>
and has <option>RefreshOnReload=extensions</option> enabled (the default), the confexts will to manage configuration updates. When such a service carrying confext directories is reloaded via
be refreshed to pick up any changes on service reload. This only applies to confext extensions. <command>systemctl reload foo.service</command> or equivalent D-Bus method, the confext itself will
Note that in case a service has this configuration enabled at first, and then it is subsequently be reloaded to pick up any changes. This only applies to confext extensions. Note that in case a
removed in an update followed by a daemon-reload operation, reloading the confexts will be a no-op, service has this configuration enabled at first, and then it is subsequently removed in an update
and a full service restart is required instead. See followed by a daemon-reload operation, reloading the confexts will be a no-op, and a full service
restart is required instead. See
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
also for details.</para> also for details.</para>

View File

@ -1349,28 +1349,6 @@
<xi:include href="version-info.xml" xpointer="v253"/></listitem> <xi:include href="version-info.xml" xpointer="v253"/></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>RefreshOnReload=</varname></term>
<listitem><para>Takes a boolean argument, or a list of resources defined in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
Possible values are <option>extensions</option> and <option>credentials</option>, separated by space.
Prepending the list with a single tilde character (<literal>~</literal>) inverts the effect.
Defaults to <option>extensions</option>. An empty assignment resets the list to default. If enabled,
the corresponding resources (<option>ExtensionImages=</option>/<option>ExtensionDirectories=</option>
for <option>extensions</option> and <option>LoadCredential=</option>/<option>ImportCredential=</option>/
<option>SetCredential=</option> (along with their <option>Encrypted</option> counterparts)
for <option>credentials</option>) will be refreshed on service reload. If <option>yes</option>,
all resources listed above that are used by the service shall be refreshed.</para>
<para>Specially, if this option is set explicitly, and the respective resources are in use,
the service may be reloaded without any actual reload mechanism (<option>ExecReload=</option>
or <option>Type=notify-reload</option>) for notifying the main process, in which case the reload
is considered complete immediately after refreshing.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
</variablelist> </variablelist>
<para id='shared-unit-options'>Check <para id='shared-unit-options'>Check

View File

@ -44,4 +44,3 @@ kn
ar ar
km km
kw kw
kk

1185
po/kk.po

File diff suppressed because it is too large Load Diff

View File

@ -262,71 +262,6 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
return 0; return 0;
} }
static int namespace_enter_one_idempotent(int nsfd, NamespaceType type) {
int r;
/* Join a namespace, but only if we're not part of it already. This is important if we don't necessarily
* own the namespace in question, as kernel would unconditionally return EPERM otherwise. */
assert(nsfd >= 0);
assert(type >= 0 && type < _NAMESPACE_TYPE_MAX);
r = is_our_namespace(nsfd, type);
if (r < 0)
return r;
if (r > 0)
return 0;
if (setns(nsfd, namespace_info[type].clone_flag) < 0)
return -errno;
return 1;
}
int namespace_enter_delegated(int userns_fd, int pidns_fd, int mntns_fd, int netns_fd, int root_fd) {
int r;
/* Similar to namespace_enter(), but operates on a set of namespaces that are potentially owned
* by the userns ("delegated"), in which case we'll need to gain CAP_SYS_ADMIN by joining
* the userns first, and the rest later. */
assert(userns_fd >= 0);
/* Block dlopen() now, to avoid us inadvertently loading shared library from another namespace */
block_dlopen();
if (setns(userns_fd, CLONE_NEWUSER) < 0)
return -errno;
if (pidns_fd >= 0) {
r = namespace_enter_one_idempotent(pidns_fd, NAMESPACE_PID);
if (r < 0)
return r;
}
if (mntns_fd >= 0) {
r = namespace_enter_one_idempotent(mntns_fd, NAMESPACE_MOUNT);
if (r < 0)
return r;
}
if (netns_fd >= 0) {
r = namespace_enter_one_idempotent(netns_fd, NAMESPACE_NET);
if (r < 0)
return r;
}
if (root_fd >= 0) {
if (fchdir(root_fd) < 0)
return -errno;
if (chroot(".") < 0)
return -errno;
}
return maybe_setgroups(/* size = */ 0, NULL);
}
int fd_is_namespace(int fd, NamespaceType type) { int fd_is_namespace(int fd, NamespaceType type) {
int r; int r;

View File

@ -47,7 +47,6 @@ int namespace_open(
int *ret_root_fd); int *ret_root_fd);
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
int namespace_enter_delegated(int userns_fd, int pidns_fd, int mntns_fd, int netns_fd, int root_fd);
int fd_is_namespace(int fd, NamespaceType type); int fd_is_namespace(int fd, NamespaceType type);
int is_our_namespace(int fd, NamespaceType type); int is_our_namespace(int fd, NamespaceType type);

View File

@ -1778,7 +1778,6 @@ int namespace_fork_full(
int netns_fd, int netns_fd,
int userns_fd, int userns_fd,
int root_fd, int root_fd,
bool delegated,
PidRef *ret) { PidRef *ret) {
_cleanup_(pidref_done_sigkill_wait) PidRef pidref_outer = PIDREF_NULL; _cleanup_(pidref_done_sigkill_wait) PidRef pidref_outer = PIDREF_NULL;
@ -1824,10 +1823,7 @@ int namespace_fork_full(
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
if (delegated) r = namespace_enter(pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd);
r = namespace_enter_delegated(userns_fd, pidns_fd, mntns_fd, netns_fd, root_fd);
else
r = namespace_enter(pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd);
if (r < 0) { if (r < 0) {
log_full_errno(prio, r, "Failed to join namespace: %m"); log_full_errno(prio, r, "Failed to join namespace: %m");
report_errno_and_exit(errno_pipe_fd[1], r); report_errno_and_exit(errno_pipe_fd[1], r);

View File

@ -201,7 +201,6 @@ int namespace_fork_full(
int netns_fd, int netns_fd,
int userns_fd, int userns_fd,
int root_fd, int root_fd,
bool delegated,
PidRef *ret); PidRef *ret);
static inline int namespace_fork( static inline int namespace_fork(
@ -216,7 +215,7 @@ static inline int namespace_fork(
PidRef *ret) { PidRef *ret) {
return namespace_fork_full(outer_name, inner_name, NULL, 0, flags, return namespace_fork_full(outer_name, inner_name, NULL, 0, flags,
pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd, false, pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd,
ret); ret);
} }

View File

@ -223,7 +223,6 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = {
[SERVICE_RUNNING] = "running", [SERVICE_RUNNING] = "running",
[SERVICE_EXITED] = "exited", [SERVICE_EXITED] = "exited",
[SERVICE_REFRESH_EXTENSIONS] = "refresh-extensions", [SERVICE_REFRESH_EXTENSIONS] = "refresh-extensions",
[SERVICE_REFRESH_CREDENTIALS] = "refresh-credentials",
[SERVICE_RELOAD] = "reload", [SERVICE_RELOAD] = "reload",
[SERVICE_RELOAD_SIGNAL] = "reload-signal", [SERVICE_RELOAD_SIGNAL] = "reload-signal",
[SERVICE_RELOAD_NOTIFY] = "reload-notify", [SERVICE_RELOAD_NOTIFY] = "reload-notify",

View File

@ -132,7 +132,6 @@ typedef enum ServiceState {
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */ SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
SERVICE_REFRESH_EXTENSIONS, /* Refreshing extensions for a reload request */ SERVICE_REFRESH_EXTENSIONS, /* Refreshing extensions for a reload request */
SERVICE_REFRESH_CREDENTIALS, /* ditto, but for credentials */
SERVICE_RELOAD, /* Reloading via ExecReload= */ SERVICE_RELOAD, /* Reloading via ExecReload= */
SERVICE_RELOAD_SIGNAL, /* Reloading via SIGHUP requested */ SERVICE_RELOAD_SIGNAL, /* Reloading via SIGHUP requested */
SERVICE_RELOAD_NOTIFY, /* Waiting for READY=1 after RELOADING=1 notify */ SERVICE_RELOAD_NOTIFY, /* Waiting for READY=1 after RELOADING=1 notify */

View File

@ -30,7 +30,6 @@
#include "signal-util.h" #include "signal-util.h"
#include "stat-util.h" #include "stat-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h"
#include "unit.h" #include "unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType);
@ -101,29 +100,6 @@ static int property_get_extra_file_descriptors(
return sd_bus_message_close_container(reply); return sd_bus_message_close_container(reply);
} }
static int property_get_refresh_on_reload(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *reterr_error) {
Service *s = ASSERT_PTR(userdata);
_cleanup_strv_free_ char **l = NULL;
int r;
assert(bus);
assert(reply);
r = service_refresh_on_reload_to_strv(s->refresh_on_reload_flags, &l);
if (r < 0)
return r;
return sd_bus_message_append_strv(reply, l);
}
static int property_get_exit_status_set( static int property_get_exit_status_set(
sd_bus *bus, sd_bus *bus,
const char *path, const char *path,
@ -397,7 +373,6 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("OpenFile", "a(sst)", property_get_open_files, offsetof(Service, open_files), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OpenFile", "a(sst)", property_get_open_files, offsetof(Service, open_files), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ExtraFileDescriptorNames", "as", property_get_extra_file_descriptors, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ExtraFileDescriptorNames", "as", property_get_extra_file_descriptors, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ReloadSignal", "i", bus_property_get_int, offsetof(Service, reload_signal), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ReloadSignal", "i", bus_property_get_int, offsetof(Service, reload_signal), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RefreshOnReload", "as", property_get_refresh_on_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecCondition", offsetof(Service, exec_command[SERVICE_EXEC_CONDITION]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecCondition", offsetof(Service, exec_command[SERVICE_EXEC_CONDITION]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
@ -865,47 +840,6 @@ static int bus_service_set_transient_property(
return 1; return 1;
} }
if (streq(name, "RefreshOnReload")) {
const char *t;
int invert;
r = sd_bus_message_enter_container(message, 'a', "(bs)");
if (r < 0)
return r;
while ((r = sd_bus_message_read(message, "(bs)", &invert, &t)) > 0) {
ServiceRefreshOnReload f;
f = service_refresh_on_reload_flag_from_string(t);
if (f < 0)
return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Invalid RefreshOnReload= value: %s", t);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (!s->refresh_on_reload_set)
s->refresh_on_reload_flags = invert ? (SERVICE_REFRESH_ON_RELOAD_DEFAULT & ~f) : f;
else
SET_FLAG(s->refresh_on_reload_flags, f, !invert);
s->refresh_on_reload_set = true;
unit_write_settingf(u, flags, name, "%s=%s%s", name, invert ? "~" : "", t);
}
}
if (r < 0)
return r;
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags) && !s->refresh_on_reload_set) { /* empty array? */
s->refresh_on_reload_flags = 0;
s->refresh_on_reload_set = true;
unit_write_settingf(u, flags, name, "%s=no", name);
}
return 1;
}
return 0; return 0;
} }

View File

@ -16,25 +16,19 @@
#include "iovec-util.h" #include "iovec-util.h"
#include "label-util.h" #include "label-util.h"
#include "log.h" #include "log.h"
#include "manager.h"
#include "mkdir-label.h" #include "mkdir-label.h"
#include "mount-util.h" #include "mount-util.h"
#include "mountpoint-util.h" #include "mountpoint-util.h"
#include "namespace-util.h"
#include "ordered-set.h" #include "ordered-set.h"
#include "path-lookup.h" #include "path-lookup.h"
#include "path-util.h" #include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "random-util.h" #include "random-util.h"
#include "recurse-dir.h" #include "recurse-dir.h"
#include "rm-rf.h" #include "rm-rf.h"
#include "siphash24.h" #include "siphash24.h"
#include "socket-util.h"
#include "stat-util.h" #include "stat-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "unit.h"
#include "user-util.h" #include "user-util.h"
ExecSetCredential* exec_set_credential_free(ExecSetCredential *sc) { ExecSetCredential* exec_set_credential_free(ExecSetCredential *sc) {
@ -316,34 +310,6 @@ int exec_context_destroy_credentials(const ExecContext *c, const char *runtime_p
return 0; return 0;
} }
typedef struct SetupCredentialsContext {
RuntimeScope scope;
const ExecContext *exec_context;
const char *unit;
const char *runtime_prefix;
const char *received_credentials_directory;
const char *received_encrypted_credentials_directory;
bool always_ipc;
uid_t uid;
gid_t gid;
} SetupCredentialsContext;
typedef struct LoadCredentialArguments {
const SetupCredentialsContext *context;
bool encrypted;
int write_dfd;
bool ownership_ok;
uint64_t left;
} LoadCredentialArguments;
typedef enum CredentialSearchPath { typedef enum CredentialSearchPath {
CREDENTIAL_SEARCH_PATH_TRUSTED, CREDENTIAL_SEARCH_PATH_TRUSTED,
CREDENTIAL_SEARCH_PATH_ENCRYPTED, CREDENTIAL_SEARCH_PATH_ENCRYPTED,
@ -352,15 +318,11 @@ typedef enum CredentialSearchPath {
_CREDENTIAL_SEARCH_PATH_INVALID = -EINVAL, _CREDENTIAL_SEARCH_PATH_INVALID = -EINVAL,
} CredentialSearchPath; } CredentialSearchPath;
static int credential_search_path( static int credential_search_path(const ExecParameters *params, CredentialSearchPath path, char ***ret) {
const SetupCredentialsContext *context,
CredentialSearchPath path,
char ***ret) {
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
int r; int r;
assert(context); assert(params);
assert(path >= 0 && path < _CREDENTIAL_SEARCH_PATH_MAX); assert(path >= 0 && path < _CREDENTIAL_SEARCH_PATH_MAX);
assert(ret); assert(ret);
@ -369,12 +331,12 @@ static int credential_search_path(
* credentials, we'll look in /etc/credstore.encrypted/ (and similar dirs). */ * credentials, we'll look in /etc/credstore.encrypted/ (and similar dirs). */
if (IN_SET(path, CREDENTIAL_SEARCH_PATH_ENCRYPTED, CREDENTIAL_SEARCH_PATH_ALL)) { if (IN_SET(path, CREDENTIAL_SEARCH_PATH_ENCRYPTED, CREDENTIAL_SEARCH_PATH_ALL)) {
r = strv_extend(&l, context->received_encrypted_credentials_directory); r = strv_extend(&l, params->received_encrypted_credentials_directory);
if (r < 0) if (r < 0)
return r; return r;
_cleanup_strv_free_ char **add = NULL; _cleanup_strv_free_ char **add = NULL;
r = credential_store_path_encrypted(context->scope, &add); r = credential_store_path_encrypted(params->runtime_scope, &add);
if (r < 0) if (r < 0)
return r; return r;
@ -384,12 +346,12 @@ static int credential_search_path(
} }
if (IN_SET(path, CREDENTIAL_SEARCH_PATH_TRUSTED, CREDENTIAL_SEARCH_PATH_ALL)) { if (IN_SET(path, CREDENTIAL_SEARCH_PATH_TRUSTED, CREDENTIAL_SEARCH_PATH_ALL)) {
r = strv_extend(&l, context->received_credentials_directory); r = strv_extend(&l, params->received_credentials_directory);
if (r < 0) if (r < 0)
return r; return r;
_cleanup_strv_free_ char **add = NULL; _cleanup_strv_free_ char **add = NULL;
r = credential_store_path(context->scope, &add); r = credential_store_path(params->runtime_scope, &add);
if (r < 0) if (r < 0)
return r; return r;
@ -407,6 +369,23 @@ static int credential_search_path(
return 0; return 0;
} }
struct load_cred_args {
const ExecContext *context;
const ExecParameters *params;
const char *unit;
bool always_ipc;
bool encrypted;
int write_dfd;
uid_t uid;
gid_t gid;
bool ownership_ok;
uint64_t left;
};
static int write_credential( static int write_credential(
int dfd, int dfd,
const char *id, const char *id,
@ -452,7 +431,7 @@ static int write_credential(
} }
static int maybe_decrypt_and_write_credential( static int maybe_decrypt_and_write_credential(
LoadCredentialArguments *args, struct load_cred_args *args,
const char *id, const char *id,
const char *data, const char *data,
size_t size, size_t size,
@ -470,7 +449,7 @@ static int maybe_decrypt_and_write_credential(
if (args->encrypted) { if (args->encrypted) {
CredentialFlags flags = 0; /* only allow user creds in user scope */ CredentialFlags flags = 0; /* only allow user creds in user scope */
switch (args->context->scope) { switch (args->params->runtime_scope) {
case RUNTIME_SCOPE_SYSTEM: case RUNTIME_SCOPE_SYSTEM:
/* In system mode talk directly to the TPM unless we live in a device sandbox /* In system mode talk directly to the TPM unless we live in a device sandbox
@ -478,7 +457,7 @@ static int maybe_decrypt_and_write_credential(
flags |= CREDENTIAL_ANY_SCOPE; flags |= CREDENTIAL_ANY_SCOPE;
if (!args->context->always_ipc) { if (!args->always_ipc) {
r = decrypt_credential_and_warn( r = decrypt_credential_and_warn(
id, id,
now(CLOCK_REALTIME), now(CLOCK_REALTIME),
@ -527,7 +506,7 @@ static int maybe_decrypt_and_write_credential(
if (add > args->left) if (add > args->left)
return -E2BIG; return -E2BIG;
r = write_credential(args->write_dfd, id, data, size, args->context->uid, args->context->gid, args->ownership_ok); r = write_credential(args->write_dfd, id, data, size, args->uid, args->gid, args->ownership_ok);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to write credential '%s': %m", id); return log_debug_errno(r, "Failed to write credential '%s': %m", id);
@ -537,7 +516,7 @@ static int maybe_decrypt_and_write_credential(
} }
static int load_credential_glob( static int load_credential_glob(
LoadCredentialArguments *args, struct load_cred_args *args,
const ExecImportCredential *ic, const ExecImportCredential *ic,
char * const *search_path, char * const *search_path,
ReadFullFileFlags flags) { ReadFullFileFlags flags) {
@ -616,7 +595,7 @@ static int load_credential_glob(
} }
static int load_credential( static int load_credential(
LoadCredentialArguments *args, struct load_cred_args *args,
const char *id, const char *id,
int read_dfd, int read_dfd,
const char *path) { const char *path) {
@ -632,8 +611,9 @@ static int load_credential(
assert(args); assert(args);
assert(args->context); assert(args->context);
assert(args->context->exec_context); assert(args->params);
assert(args->context->unit); assert(args->unit);
assert(args->write_dfd >= 0);
assert(id); assert(id);
assert(read_dfd >= 0 || read_dfd == AT_FDCWD); assert(read_dfd >= 0 || read_dfd == AT_FDCWD);
assert(path); assert(path);
@ -661,7 +641,7 @@ static int load_credential(
/* Pass some minimal info about the unit and the credential name we are looking to acquire /* Pass some minimal info about the unit and the credential name we are looking to acquire
* via the source socket address in case we read off an AF_UNIX socket. */ * via the source socket address in case we read off an AF_UNIX socket. */
if (asprintf(&bindname, "@%" PRIx64 "/unit/%s/%s", random_u64(), args->context->unit, id) < 0) if (asprintf(&bindname, "@%" PRIx64 "/unit/%s/%s", random_u64(), args->unit, id) < 0)
return -ENOMEM; return -ENOMEM;
missing_ok = false; missing_ok = false;
@ -672,7 +652,7 @@ static int load_credential(
* directory we received ourselves. We don't support the AF_UNIX stuff in this mode, since we * directory we received ourselves. We don't support the AF_UNIX stuff in this mode, since we
* are operating on a credential store, i.e. this is guaranteed to be regular files. */ * are operating on a credential store, i.e. this is guaranteed to be regular files. */
r = credential_search_path(args->context, CREDENTIAL_SEARCH_PATH_ALL, &search_path); r = credential_search_path(args->params, CREDENTIAL_SEARCH_PATH_ALL, &search_path);
if (r < 0) if (r < 0)
return r; return r;
@ -715,20 +695,17 @@ static int load_credential(
else else
assert_not_reached(); assert_not_reached();
if (r == -ENOENT) { if (r == -ENOENT && (missing_ok || hashmap_contains(args->context->set_credentials, id))) {
bool in_set_credentials = hashmap_contains(args->context->exec_context->set_credentials, id); /* Make a missing inherited credential non-fatal, let's just continue. After all apps
if (missing_ok || in_set_credentials) { * will get clear errors if we don't pass such a missing credential on as they
/* Make a missing inherited credential non-fatal, let's just continue. After all apps * themselves will get ENOENT when trying to read them, which should not be much
* will get clear errors if we don't pass such a missing credential on as they * worse than when we handle the error here and make it fatal.
* themselves will get ENOENT when trying to read them, which should not be much *
* worse than when we handle the error here and make it fatal. * Also, if the source file doesn't exist, but a fallback is set via SetCredentials=
* * we are fine, too. */
* Also, if the source file doesn't exist, but a fallback is set via SetCredentials= log_full_errno(hashmap_contains(args->context->set_credentials, id) ? LOG_DEBUG : LOG_INFO,
* we are fine, too. */ r, "Couldn't read inherited credential '%s', skipping: %m", path);
log_full_errno(in_set_credentials ? LOG_DEBUG : LOG_INFO, return 0;
r, "Couldn't read inherited credential '%s', skipping: %m", path);
return 0;
}
} }
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to read credential '%s': %m", path); return log_debug_errno(r, "Failed to read credential '%s': %m", path);
@ -745,7 +722,7 @@ static int load_cred_recurse_dir_cb(
const struct statx *sx, const struct statx *sx,
void *userdata) { void *userdata) {
LoadCredentialArguments *args = ASSERT_PTR(userdata); struct load_cred_args *args = ASSERT_PTR(userdata);
_cleanup_free_ char *sub_id = NULL; _cleanup_free_ char *sub_id = NULL;
int r; int r;
@ -802,27 +779,38 @@ static bool device_nodes_restricted(
} }
static int acquire_credentials( static int acquire_credentials(
const SetupCredentialsContext *context, const ExecContext *context,
const CGroupContext *cgroup_context,
const ExecParameters *params,
const char *unit,
int dfd, int dfd,
uid_t uid,
gid_t gid,
bool ownership_ok) { bool ownership_ok) {
int r; int r;
assert(context); assert(context);
assert(context->exec_context); assert(cgroup_context);
assert(params);
assert(unit);
assert(dfd >= 0); assert(dfd >= 0);
LoadCredentialArguments args = { struct load_cred_args args = {
.context = context, .context = context,
.params = params,
.unit = unit,
.always_ipc = device_nodes_restricted(context, cgroup_context),
.write_dfd = dfd, .write_dfd = dfd,
.uid = uid,
.gid = gid,
.ownership_ok = ownership_ok, .ownership_ok = ownership_ok,
.left = CREDENTIALS_TOTAL_SIZE_MAX, .left = CREDENTIALS_TOTAL_SIZE_MAX,
}; };
/* First, load credentials off disk (or acquire via AF_UNIX socket) */ /* First, load credentials off disk (or acquire via AF_UNIX socket) */
ExecLoadCredential *lc; ExecLoadCredential *lc;
HASHMAP_FOREACH(lc, context->exec_context->load_credentials) { HASHMAP_FOREACH(lc, context->load_credentials) {
_cleanup_close_ int sub_fd = -EBADF; _cleanup_close_ int sub_fd = -EBADF;
args.encrypted = lc->encrypted; args.encrypted = lc->encrypted;
@ -861,10 +849,10 @@ static int acquire_credentials(
/* Next, look for system credentials and credentials in the credentials store. Note that these do not /* Next, look for system credentials and credentials in the credentials store. Note that these do not
* override any credentials found earlier. */ * override any credentials found earlier. */
ExecImportCredential *ic; ExecImportCredential *ic;
ORDERED_SET_FOREACH(ic, context->exec_context->import_credentials) { ORDERED_SET_FOREACH(ic, context->import_credentials) {
_cleanup_free_ char **search_path = NULL; _cleanup_free_ char **search_path = NULL;
r = credential_search_path(context, CREDENTIAL_SEARCH_PATH_TRUSTED, &search_path); r = credential_search_path(params, CREDENTIAL_SEARCH_PATH_TRUSTED, &search_path);
if (r < 0) if (r < 0)
return r; return r;
@ -880,7 +868,7 @@ static int acquire_credentials(
search_path = strv_free(search_path); search_path = strv_free(search_path);
r = credential_search_path(context, CREDENTIAL_SEARCH_PATH_ENCRYPTED, &search_path); r = credential_search_path(params, CREDENTIAL_SEARCH_PATH_ENCRYPTED, &search_path);
if (r < 0) if (r < 0)
return r; return r;
@ -898,7 +886,7 @@ static int acquire_credentials(
/* Finally, we add in literally specified credentials. If the credentials already exist, we'll not /* Finally, we add in literally specified credentials. If the credentials already exist, we'll not
* add them, so that they can act as a "default" if the same credential is specified multiple times. */ * add them, so that they can act as a "default" if the same credential is specified multiple times. */
ExecSetCredential *sc; ExecSetCredential *sc;
HASHMAP_FOREACH(sc, context->exec_context->set_credentials) { HASHMAP_FOREACH(sc, context->set_credentials) {
args.encrypted = sc->encrypted; args.encrypted = sc->encrypted;
if (faccessat(dfd, sc->id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) { if (faccessat(dfd, sc->id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) {
@ -946,8 +934,13 @@ static int credentials_dir_finalize_permissions(int dfd, uid_t uid, gid_t gid, b
} }
static int setup_credentials_plain_dir( static int setup_credentials_plain_dir(
const SetupCredentialsContext *context, const ExecContext *context,
const char *cred_dir) { const CGroupContext *cgroup_context,
const ExecParameters *params,
const char *unit,
const char *cred_dir,
uid_t uid,
gid_t gid) {
_cleanup_free_ char *t = NULL, *workspace = NULL; _cleanup_free_ char *t = NULL, *workspace = NULL;
_cleanup_(rm_rf_safep) const char *workspace_rm = NULL; _cleanup_(rm_rf_safep) const char *workspace_rm = NULL;
@ -955,13 +948,13 @@ static int setup_credentials_plain_dir(
int r; int r;
assert(context); assert(context);
assert(context->unit); assert(params);
assert(context->runtime_prefix); assert(unit);
assert(cred_dir); assert(cred_dir);
/* Temporary workspace, that remains inaccessible all the time. We prepare stuff there before moving /* Temporary workspace, that remains inaccessible all the time. We prepare stuff there before moving
* it into place, so that users can't access half-initialized credential stores. */ * it into place, so that users can't access half-initialized credential stores. */
t = path_join(context->runtime_prefix, "systemd/temporary-credentials"); t = path_join(params->prefix[EXEC_DIRECTORY_RUNTIME], "systemd/temporary-credentials");
if (!t) if (!t)
return -ENOMEM; return -ENOMEM;
@ -969,7 +962,7 @@ static int setup_credentials_plain_dir(
if (r < 0 && r != -EEXIST) if (r < 0 && r != -EEXIST)
return r; return r;
workspace = path_join(t, context->unit); workspace = path_join(t, unit);
if (!workspace) if (!workspace)
return -ENOMEM; return -ENOMEM;
@ -980,7 +973,7 @@ static int setup_credentials_plain_dir(
(void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0); (void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0);
r = acquire_credentials(context, dfd, /* ownership_ok= */ false); r = acquire_credentials(context, cgroup_context, params, unit, dfd, uid, gid, /* ownership_ok= */ false);
if (r < 0) if (r < 0)
return r; return r;
@ -1002,7 +995,7 @@ static int setup_credentials_plain_dir(
/* rename() requires both the source and target to be writable, hence lock down write permission /* rename() requires both the source and target to be writable, hence lock down write permission
* as last step. */ * as last step. */
r = credentials_dir_finalize_permissions(dfd, context->uid, context->gid, /* ownership_ok= */ false); r = credentials_dir_finalize_permissions(dfd, uid, gid, /* ownership_ok= */ false);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to adjust ACLs of credentials dir: %m"); return log_debug_errno(r, "Failed to adjust ACLs of credentials dir: %m");
@ -1010,47 +1003,43 @@ static int setup_credentials_plain_dir(
} }
static int setup_credentials_internal( static int setup_credentials_internal(
const SetupCredentialsContext *context, const ExecContext *context,
bool may_reuse, const CGroupContext *cgroup_context,
const char *cred_dir) { const ExecParameters *params,
const char *unit,
const char *cred_dir,
uid_t uid,
gid_t gid) {
_cleanup_close_ int fs_fd = -EBADF, mfd = -EBADF, dfd = -EBADF; _cleanup_close_ int fs_fd = -EBADF, mfd = -EBADF, dfd = -EBADF;
bool dir_mounted; bool dir_mounted;
int r; int r;
assert(context); assert(context);
assert(params);
assert(unit);
assert(cred_dir); assert(cred_dir);
if (!FLAGS_SET(params->flags, EXEC_SETUP_CREDENTIALS_FRESH)) {
/* We may reuse the previous credential dir */
r = dir_is_empty(cred_dir, /* ignore_hidden_or_backup= */ false);
if (r < 0)
return r;
if (r == 0) {
log_debug("Credential dir for unit '%s' already set up, skipping.", unit);
return 0;
}
}
r = path_is_mount_point(cred_dir); r = path_is_mount_point(cred_dir);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to determine if '%s' is a mountpoint: %m", cred_dir); return log_debug_errno(r, "Failed to determine if '%s' is a mountpoint: %m", cred_dir);
dir_mounted = r > 0; dir_mounted = r > 0;
if (may_reuse) {
bool populated;
/* If the cred dir is a mount, let's treat it as populated, and only look at the contents
* if it's a plain dir, where we can't reasonably differentiate populated yet empty vs
* not set up. */
if (dir_mounted)
populated = true;
else {
r = dir_is_empty(cred_dir, /* ignore_hidden_or_backup= */ false);
if (r < 0)
return r;
populated = r == 0;
}
if (populated) {
log_debug("Credential dir for unit '%s' already set up, skipping.", context->unit);
return 0;
}
}
mfd = fsmount_credentials_fs(&fs_fd); mfd = fsmount_credentials_fs(&fs_fd);
if (ERRNO_IS_NEG_PRIVILEGE(mfd) && !dir_mounted) { if (ERRNO_IS_NEG_PRIVILEGE(mfd) && !dir_mounted) {
log_debug_errno(mfd, "Lacking privilege to mount credentials fs, falling back to plain directory."); log_debug_errno(mfd, "Lacking privilege to mount credentials fs, falling back to plain directory.");
return setup_credentials_plain_dir(context, cred_dir); return setup_credentials_plain_dir(context, cgroup_context, params, unit, cred_dir, uid, gid);
} }
if (mfd < 0) if (mfd < 0)
return log_debug_errno(mfd, "Failed to mount credentials fs: %m"); return log_debug_errno(mfd, "Failed to mount credentials fs: %m");
@ -1061,11 +1050,11 @@ static int setup_credentials_internal(
(void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0); (void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0);
r = acquire_credentials(context, dfd, /* ownership_ok= */ true); r = acquire_credentials(context, cgroup_context, params, unit, dfd, uid, gid, /* ownership_ok= */ true);
if (r < 0) if (r < 0)
return r; return r;
r = credentials_dir_finalize_permissions(dfd, context->uid, context->gid, /* ownership_ok= */ true); r = credentials_dir_finalize_permissions(dfd, uid, gid, /* ownership_ok= */ true);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to adjust ACLs of credentials dir: %m"); return log_debug_errno(r, "Failed to adjust ACLs of credentials dir: %m");
@ -1110,6 +1099,7 @@ int exec_setup_credentials(
const ExecContext *context, const ExecContext *context,
const CGroupContext *cgroup_context, const CGroupContext *cgroup_context,
const ExecParameters *params, const ExecParameters *params,
const char *unit,
uid_t uid, uid_t uid,
gid_t gid) { gid_t gid) {
@ -1118,6 +1108,7 @@ int exec_setup_credentials(
assert(context); assert(context);
assert(params); assert(params);
assert(unit);
if (!exec_params_need_credentials(params) || !exec_context_has_credentials(context)) if (!exec_params_need_credentials(params) || !exec_context_has_credentials(context))
return 0; return 0;
@ -1135,7 +1126,7 @@ int exec_setup_credentials(
if (r < 0 && r != -EEXIST) if (r < 0 && r != -EEXIST)
return r; return r;
p = path_join(q, params->unit_id); p = path_join(q, unit);
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;
@ -1143,208 +1134,12 @@ int exec_setup_credentials(
if (r < 0 && r != -EEXIST) if (r < 0 && r != -EEXIST)
return r; return r;
SetupCredentialsContext ctx = { r = setup_credentials_internal(context, cgroup_context, params, unit, p, uid, gid);
.scope = params->runtime_scope,
.exec_context = context,
.unit = params->unit_id,
.runtime_prefix = params->prefix[EXEC_DIRECTORY_RUNTIME],
.received_credentials_directory = params->received_credentials_directory,
.received_encrypted_credentials_directory = params->received_encrypted_credentials_directory,
.always_ipc = device_nodes_restricted(context, cgroup_context),
.uid = uid,
.gid = gid,
};
r = setup_credentials_internal(&ctx, /* may_reuse = */ !FLAGS_SET(params->flags, EXEC_SETUP_CREDENTIALS_FRESH), p);
if (r < 0)
(void) rmdir(p);
/* If the credentials dir is empty and not a mount point, then there's no point in having it. Let's
* try to remove it. This matters in particular if we created the dir as mount point but then didn't
* actually end up mounting anything on it. In that case we'd rather have ENOENT than EACCESS being
* seen by users when trying access this inode. */
(void) rmdir(p);
return r; return r;
} }
static int refresh_credentials_in_namespace_child(int cfd, const char *cred_dir) {
int r;
assert(cfd >= 0);
assert(cred_dir);
/* Paranoia: before doing anything, check if the credentials tree inside the mountns is available.
*
* Note that setup_namespace() always installs a mount for cred dir, hence path_is_mount_point()
* is the appropriate check here. */
r = path_is_mount_point(cred_dir);
if (IN_SET(r, 0, -ENOENT)) {
log_full_errno_zerook(LOG_WARNING, r,
"Credentials tree in the unit mount namespace is masked, skipping refresh.");
return 0;
}
if (r < 0)
return log_error_errno(r, "Failed to check whether '%s' is a mountpoint in unit mount namespace: %m",
cred_dir);
/* Inform the parent that we're good to go */
ssize_t n = write(cfd, &r, sizeof(r));
if (n < 0)
return log_error_errno(errno, "Failed to write to socket: %m");
_cleanup_close_ int mfd = receive_one_fd(cfd, /* flags = */ 0);
if (mfd < 0)
return log_error_errno(mfd, "Failed to receive credentials tree fd from socket: %m");
r = mount_exchange_graceful(mfd, cred_dir, /* mount_beneath = */ true);
if (r < 0)
return log_error_errno(r, "Failed to update credentials mount in namespace: %m");
return 1;
}
int unit_refresh_credentials(Unit *u) {
_cleanup_free_ char *cred_dir = NULL;
int r;
/* Refresh the credentials for a unit, potentially forking off a second process to join the mountns
* if needed. Returns > 0 on successful refresh, == 0 if the credentials tree is masked and the operation
* is skipped. */
assert(u);
assert(u->manager);
r = get_credential_directory(u->manager->prefix[EXEC_DIRECTORY_RUNTIME], u->id, &cred_dir);
if (r < 0)
return log_oom();
assert(r > 0);
if (access(cred_dir, F_OK) < 0) {
if (errno == ENOENT) {
log_warning_errno(errno, "Requested to refresh credentials, but credentials aren't populated, skipping.");
return 0;
}
return log_error_errno(errno, "Failed to check if credentials dir '%s' exists: %m", cred_dir);
}
_cleanup_close_pair_ int tunnel_fds[2] = EBADF_PAIR;
_cleanup_(pidref_done) PidRef child = PIDREF_NULL;
_cleanup_close_ int userns_fd = -EBADF;
PidRef *main_pid = unit_main_pid(u);
if (pidref_is_set(main_pid)) {
_cleanup_close_ int mntns_fd = -EBADF, root_fd = -EBADF, pidns_fd = -EBADF;
r = pidref_namespace_open(main_pid,
&pidns_fd,
&mntns_fd,
/* ret_netns_fd = */ NULL,
MANAGER_IS_USER(u->manager) ? &userns_fd : NULL,
&root_fd);
if (r < 0)
return log_error_errno(r, "Failed to open namespace of unit main process '" PID_FMT "': %m",
main_pid->pid);
r = is_our_namespace(mntns_fd, NAMESPACE_MOUNT);
if (r < 0)
return log_error_errno(r, "Failed to check if main process resides in a separate mount namespace: %m");
if (r == 0) {
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, tunnel_fds) < 0)
return log_error_errno(errno, "Failed to allocate socket pair: %m");
r = namespace_fork_full("(sd-creds-ns)", "(sd-creds-ns-inner)",
(int[]) { tunnel_fds[1] }, 1,
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG,
pidns_fd, mntns_fd, /* netns_fd = */ -EBADF, userns_fd, root_fd,
/* delegated = */ MANAGER_IS_USER(u->manager),
&child);
if (r < 0)
return log_full_errno(ERRNO_IS_NEG_PRIVILEGE(r) ? LOG_WARNING : LOG_ERR, r,
"Failed to fork off process into unit namespace to refresh credentials: %m");
if (r == 0) {
r = refresh_credentials_in_namespace_child(tunnel_fds[1], cred_dir);
report_errno_and_exit(tunnel_fds[1], r);
}
tunnel_fds[1] = safe_close(tunnel_fds[1]);
/* Wait for the child to validate the creds tree in the unit namespace is populated. */
ssize_t n = read(tunnel_fds[0], &r, sizeof(r));
if (n < 0)
return log_error_errno(errno, "Failed to read from socket: %m");
if (!IN_SET(n, 0, sizeof(r)))
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Received unexpected amount of bytes (%zi) while reading errno.", n);
if (n == 0 || r == 0) {
/* The child exited without sending anything or 0 is received signifying
* the credentials are masked? Check the exit status to be sure. */
r = pidref_wait_for_terminate_and_check("(sd-creds-ns)", &child, WAIT_LOG);
if (r < 0)
return r;
if (r != EXIT_SUCCESS)
return -EPROTO;
return 0; /* skipped */
}
if (r < 0)
return r;
/* Yay! Got > 0 from child indicating all good, proceed with refreshing. */
}
}
SetupCredentialsContext ctx = {
.scope = u->manager->runtime_scope,
.exec_context = ASSERT_PTR(unit_get_exec_context(u)),
.unit = u->id,
.runtime_prefix = u->manager->prefix[EXEC_DIRECTORY_RUNTIME],
.received_credentials_directory = u->manager->received_credentials_directory,
.received_encrypted_credentials_directory = u->manager->received_encrypted_credentials_directory,
.always_ipc = false, /* we don't migrate to unit cgroup, hence cannot be restricted by cgroup bpf */
.uid = u->ref_uid,
.gid = u->ref_gid,
};
r = setup_credentials_internal(&ctx, /* may_reuse = */ false, cred_dir);
if (r < 0)
return log_error_errno(r, "Failed to set up credentials: %m");
/* The main process doesn't run in a mountns hence nothing got forked off? Then we're all set. */
if (!pidref_is_set(&child))
return 1;
if (userns_fd >= 0) {
assert(MANAGER_IS_USER(u->manager));
/* Enter the unit userns now and unshare mountns, so that we have permissions to clone
* the mount tree using open_tree() */
if (setns(userns_fd, CLONE_NEWUSER) < 0)
return log_error_errno(errno, "Failed to enter user namespace: %m");
if (unshare(CLONE_NEWNS) < 0)
return log_error_errno(errno, "Failed to unshare mount namespace: %m");
}
_cleanup_close_ int tfd = open_tree(AT_FDCWD, cred_dir, OPEN_TREE_CLONE|OPEN_TREE_CLOEXEC|AT_SYMLINK_NOFOLLOW);
if (tfd < 0)
return log_error_errno(errno, "Failed to clone mount tree at '%s': %m", cred_dir);
r = send_one_fd(tunnel_fds[0], tfd, /* flags = */ 0);
if (r < 0)
return log_error_errno(r, "Failed to send mount fd to child: %m");
r = pidref_wait_for_terminate_and_check("(sd-creds-ns)", &child, WAIT_LOG_ABNORMAL);
if (r < 0)
return r;
if (r != EXIT_SUCCESS) {
r = read_errno(tunnel_fds[0]);
if (r < 0)
return r;
return -EPROTO;
}
return 1;
}

View File

@ -57,9 +57,8 @@ int exec_setup_credentials(
const ExecContext *context, const ExecContext *context,
const CGroupContext *cgroup_context, const CGroupContext *cgroup_context,
const ExecParameters *params, const ExecParameters *params,
const char *unit,
uid_t uid, uid_t uid,
gid_t gid); gid_t gid);
int unit_refresh_credentials(Unit *u);
bool mount_point_is_credentials(const char *runtime_prefix, const char *path); bool mount_point_is_credentials(const char *runtime_prefix, const char *path);

View File

@ -5705,7 +5705,7 @@ int exec_invoke(
return log_error_errno(r, "Failed to set up special execution directory in %s: %m", params->prefix[dt]); return log_error_errno(r, "Failed to set up special execution directory in %s: %m", params->prefix[dt]);
} }
r = exec_setup_credentials(context, cgroup_context, params, uid, gid); r = exec_setup_credentials(context, cgroup_context, params, params->unit_id, uid, gid);
if (r < 0) { if (r < 0) {
*exit_status = EXIT_CREDENTIALS; *exit_status = EXIT_CREDENTIALS;
return log_error_errno(r, "Failed to set up credentials: %m"); return log_error_errno(r, "Failed to set up credentials: %m");

View File

@ -479,7 +479,6 @@ Service.USBFunctionStrings, config_parse_unit_path_printf,
Service.OOMPolicy, config_parse_oom_policy, 0, offsetof(Service, oom_policy) Service.OOMPolicy, config_parse_oom_policy, 0, offsetof(Service, oom_policy)
Service.OpenFile, config_parse_open_file, 0, offsetof(Service, open_files) Service.OpenFile, config_parse_open_file, 0, offsetof(Service, open_files)
Service.ReloadSignal, config_parse_signal, 0, offsetof(Service, reload_signal) Service.ReloadSignal, config_parse_signal, 0, offsetof(Service, reload_signal)
Service.RefreshOnReload, config_parse_service_refresh_on_reload, 0, 0
{{ EXEC_CONTEXT_CONFIG_ITEMS('Service') }} {{ EXEC_CONTEXT_CONFIG_ITEMS('Service') }}
{{ CGROUP_CONTEXT_CONFIG_ITEMS('Service') }} {{ CGROUP_CONTEXT_CONFIG_ITEMS('Service') }}
{{ KILL_CONTEXT_CONFIG_ITEMS('Service') }} {{ KILL_CONTEXT_CONFIG_ITEMS('Service') }}

View File

@ -4816,55 +4816,6 @@ int config_parse_import_credential(
return 0; return 0;
} }
int config_parse_service_refresh_on_reload(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Service *s = ASSERT_PTR(userdata);
int r;
if (isempty(rvalue)) {
s->refresh_on_reload_set = false;
return 0;
}
r = parse_boolean(rvalue);
if (r >= 0) {
s->refresh_on_reload_flags = r > 0 ? _SERVICE_REFRESH_ON_RELOAD_ALL : 0;
s->refresh_on_reload_set = true;
return 0;
}
ServiceRefreshOnReload f;
bool invert = false;
if (rvalue[0] == '~') {
invert = true;
rvalue++;
}
r = service_refresh_on_reload_from_string_many(rvalue, &f);
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
/* If the first entry is negated, mask off from default; otherwise assign "positive" values directly */
if (!s->refresh_on_reload_set)
s->refresh_on_reload_flags = invert ? (SERVICE_REFRESH_ON_RELOAD_DEFAULT & ~f) : f;
else
SET_FLAG(s->refresh_on_reload_flags, f, !invert);
s->refresh_on_reload_set = true;
return 0;
}
int config_parse_set_status( int config_parse_set_status(
const char *unit, const char *unit,
const char *filename, const char *filename,

View File

@ -105,7 +105,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_quota);
CONFIG_PARSER_PROTOTYPE(config_parse_set_credential); CONFIG_PARSER_PROTOTYPE(config_parse_set_credential);
CONFIG_PARSER_PROTOTYPE(config_parse_load_credential); CONFIG_PARSER_PROTOTYPE(config_parse_load_credential);
CONFIG_PARSER_PROTOTYPE(config_parse_import_credential); CONFIG_PARSER_PROTOTYPE(config_parse_import_credential);
CONFIG_PARSER_PROTOTYPE(config_parse_service_refresh_on_reload);
CONFIG_PARSER_PROTOTYPE(config_parse_set_status); CONFIG_PARSER_PROTOTYPE(config_parse_set_status);
CONFIG_PARSER_PROTOTYPE(config_parse_namespace_path_strv); CONFIG_PARSER_PROTOTYPE(config_parse_namespace_path_strv);
CONFIG_PARSER_PROTOTYPE(config_parse_temporary_filesystems); CONFIG_PARSER_PROTOTYPE(config_parse_temporary_filesystems);

View File

@ -1888,15 +1888,13 @@ static bool manager_dbus_is_running(Manager *m, bool deserialized) {
u = manager_get_unit(m, SPECIAL_DBUS_SERVICE); u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
if (!u) if (!u)
return false; return false;
if (!IN_SET(deserialized ? SERVICE(u)->deserialized_state : SERVICE(u)->state, if (!IN_SET((deserialized ? SERVICE(u)->deserialized_state : SERVICE(u)->state),
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS, SERVICE_MOUNTING,
SERVICE_REFRESH_CREDENTIALS,
SERVICE_RELOAD, SERVICE_RELOAD,
SERVICE_RELOAD_SIGNAL,
SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_NOTIFY,
SERVICE_RELOAD_POST, SERVICE_REFRESH_EXTENSIONS,
SERVICE_MOUNTING)) SERVICE_RELOAD_SIGNAL))
return false; return false;
return true; return true;

View File

@ -2845,6 +2845,7 @@ int setup_namespace(const NamespaceParameters *p, char **reterr_path) {
.mode = MOUNT_BIND, .mode = MOUNT_BIND,
.read_only = true, .read_only = true,
.source_const = p->creds_path, .source_const = p->creds_path,
.ignore = true,
}; };
} }

View File

@ -69,7 +69,6 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_RUNNING] = UNIT_ACTIVE, [SERVICE_RUNNING] = UNIT_ACTIVE,
[SERVICE_EXITED] = UNIT_ACTIVE, [SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING, [SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING,
[SERVICE_REFRESH_CREDENTIALS] = UNIT_REFRESHING,
[SERVICE_RELOAD] = UNIT_RELOADING, [SERVICE_RELOAD] = UNIT_RELOADING,
[SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING, [SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
[SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING, [SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
@ -103,7 +102,6 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] =
[SERVICE_RUNNING] = UNIT_ACTIVE, [SERVICE_RUNNING] = UNIT_ACTIVE,
[SERVICE_EXITED] = UNIT_ACTIVE, [SERVICE_EXITED] = UNIT_ACTIVE,
[SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING, [SERVICE_REFRESH_EXTENSIONS] = UNIT_REFRESHING,
[SERVICE_REFRESH_CREDENTIALS] = UNIT_REFRESHING,
[SERVICE_RELOAD] = UNIT_RELOADING, [SERVICE_RELOAD] = UNIT_RELOADING,
[SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING, [SERVICE_RELOAD_SIGNAL] = UNIT_RELOADING,
[SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING, [SERVICE_RELOAD_NOTIFY] = UNIT_RELOADING,
@ -136,14 +134,11 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
static void service_reload_finish(Service *s, ServiceResult f); static void service_reload_finish(Service *s, ServiceResult f);
static void service_enter_reload_by_notify(Service *s); static void service_enter_reload_by_notify(Service *s);
static bool service_can_reload_extensions(Service *s, bool warn);
static bool SERVICE_STATE_WITH_MAIN_PROCESS(ServiceState state) { static bool SERVICE_STATE_WITH_MAIN_PROCESS(ServiceState state) {
return IN_SET(state, return IN_SET(state,
SERVICE_START, SERVICE_START_POST, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS, SERVICE_REFRESH_CREDENTIALS, SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST,
SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST,
SERVICE_MOUNTING, SERVICE_MOUNTING,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL); SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL);
@ -153,7 +148,7 @@ static bool SERVICE_STATE_WITH_CONTROL_PROCESS(ServiceState state) {
return IN_SET(state, return IN_SET(state,
SERVICE_CONDITION, SERVICE_CONDITION,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_REFRESH_EXTENSIONS, SERVICE_REFRESH_CREDENTIALS, SERVICE_RELOAD, SERVICE_RELOAD_POST, SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_POST,
SERVICE_MOUNTING, SERVICE_MOUNTING,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
@ -164,8 +159,7 @@ static bool SERVICE_STATE_WITH_WATCHDOG(ServiceState state) {
return IN_SET(state, return IN_SET(state,
SERVICE_START_POST, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS, SERVICE_REFRESH_CREDENTIALS, SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST,
SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST,
SERVICE_MOUNTING); SERVICE_MOUNTING);
} }
@ -760,15 +754,6 @@ static int service_verify(Service *s) {
s->restart_usec = s->restart_max_delay_usec; s->restart_usec = s->restart_max_delay_usec;
} }
if (s->refresh_on_reload_set && s->refresh_on_reload_flags != _SERVICE_REFRESH_ON_RELOAD_ALL) {
if (FLAGS_SET(s->refresh_on_reload_flags, SERVICE_RELOAD_EXTENSIONS))
service_can_reload_extensions(s, /* warn = */ true);
if (FLAGS_SET(s->refresh_on_reload_flags, SERVICE_RELOAD_CREDENTIALS) &&
!exec_context_has_credentials(&s->exec_context))
log_unit_warning(UNIT(s), "Service has RefreshOnReload=credentials, but no credentials are in use. The credentials tree will be masked which blocks further refreshing. Continuing.");
}
return 0; return 0;
} }
@ -906,11 +891,6 @@ static int service_add_extras(Service *s) {
(IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) || s->watchdog_usec > 0 || s->n_fd_store_max > 0)) (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) || s->watchdog_usec > 0 || s->n_fd_store_max > 0))
s->notify_access = NOTIFY_MAIN; s->notify_access = NOTIFY_MAIN;
if (!s->refresh_on_reload_set) {
assert_cc(SERVICE_REFRESH_ON_RELOAD_DEFAULT == SERVICE_RELOAD_EXTENSIONS);
s->refresh_on_reload_flags = service_can_reload_extensions(s, /* warn = */ false) ? SERVICE_RELOAD_EXTENSIONS : 0;
}
/* If no OOM policy was explicitly set, then default to the configure default OOM policy. Except when /* If no OOM policy was explicitly set, then default to the configure default OOM policy. Except when
* delegation is on, in that case it we assume the payload knows better what to do and can process * delegation is on, in that case it we assume the payload knows better what to do and can process
* things in a more focused way. */ * things in a more focused way. */
@ -1316,8 +1296,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state, if (!IN_SET(state,
SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS, SERVICE_REFRESH_CREDENTIALS, SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST,
SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST,
SERVICE_MOUNTING, SERVICE_MOUNTING,
SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
@ -1388,7 +1367,6 @@ static usec_t service_coldplug_timeout(Service *s) {
case SERVICE_START: case SERVICE_START:
case SERVICE_START_POST: case SERVICE_START_POST:
case SERVICE_REFRESH_EXTENSIONS: case SERVICE_REFRESH_EXTENSIONS:
case SERVICE_REFRESH_CREDENTIALS:
case SERVICE_RELOAD: case SERVICE_RELOAD:
case SERVICE_RELOAD_SIGNAL: case SERVICE_RELOAD_SIGNAL:
case SERVICE_RELOAD_NOTIFY: case SERVICE_RELOAD_NOTIFY:
@ -1689,16 +1667,11 @@ static Service *service_get_triggering_service(Service *s) {
return NULL; return NULL;
} }
static ExecFlags service_exec_flags( static ExecFlags service_exec_flags(ServiceExecCommand command_id, ExecFlags cred_flag) {
const Service *s,
ServiceExecCommand command_id,
ExecFlags cred_flag) {
/* All service main/control processes honor sandboxing and namespacing options (except those /* All service main/control processes honor sandboxing and namespacing options (except those
explicitly excluded in service_spawn()) */ explicitly excluded in service_spawn()) */
ExecFlags flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT; ExecFlags flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT;
assert(s);
assert(command_id >= 0); assert(command_id >= 0);
assert(command_id < _SERVICE_EXEC_COMMAND_MAX); assert(command_id < _SERVICE_EXEC_COMMAND_MAX);
assert((cred_flag & ~(EXEC_SETUP_CREDENTIALS_FRESH|EXEC_SETUP_CREDENTIALS)) == 0); assert((cred_flag & ~(EXEC_SETUP_CREDENTIALS_FRESH|EXEC_SETUP_CREDENTIALS)) == 0);
@ -1730,12 +1703,6 @@ static ExecFlags service_exec_flags(
if (!IN_SET(command_id, SERVICE_EXEC_CONDITION, SERVICE_EXEC_START_PRE)) if (!IN_SET(command_id, SERVICE_EXEC_CONDITION, SERVICE_EXEC_START_PRE))
flags |= EXEC_CONTROL_CGROUP; flags |= EXEC_CONTROL_CGROUP;
/* Pass credentials to ExecReload*= too, but only if the credentials are actually refreshed,
* to make sure they have the same understanding of the world as the main process. */
if (IN_SET(command_id, SERVICE_EXEC_RELOAD, SERVICE_EXEC_RELOAD_POST) &&
FLAGS_SET(s->refreshed_mask, SERVICE_RELOAD_CREDENTIALS))
flags |= EXEC_SETUP_CREDENTIALS;
if (IN_SET(command_id, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST)) if (IN_SET(command_id, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST))
flags |= EXEC_SETENV_RESULT; flags |= EXEC_SETENV_RESULT;
@ -2261,7 +2228,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), service_exec_flags(s->control_command_id, /* cred_flag= */ 0),
s->timeout_stop_usec, s->timeout_stop_usec,
&s->control_pid); &s->control_pid);
if (r < 0) { if (r < 0) {
@ -2373,7 +2340,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), service_exec_flags(s->control_command_id, /* cred_flag= */ 0),
s->timeout_stop_usec, s->timeout_stop_usec,
&s->control_pid); &s->control_pid);
if (r < 0) { if (r < 0) {
@ -2458,7 +2425,7 @@ static void service_enter_start_post(Service *s) {
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), service_exec_flags(s->control_command_id, /* cred_flag= */ 0),
s->timeout_start_usec, s->timeout_start_usec,
&s->control_pid); &s->control_pid);
if (r < 0) { if (r < 0) {
@ -2568,7 +2535,7 @@ static void service_enter_start(Service *s) {
r = service_spawn(s, r = service_spawn(s,
c, c,
service_exec_flags(s, SERVICE_EXEC_START, EXEC_SETUP_CREDENTIALS_FRESH), service_exec_flags(SERVICE_EXEC_START, EXEC_SETUP_CREDENTIALS_FRESH),
timeout, timeout,
&pidref); &pidref);
if (r < 0) { if (r < 0) {
@ -2628,7 +2595,7 @@ static void service_enter_start_pre(Service *s) {
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), service_exec_flags(s->control_command_id, /* cred_flag= */ 0),
s->timeout_start_usec, s->timeout_start_usec,
&s->control_pid); &s->control_pid);
if (r < 0) { if (r < 0) {
@ -2664,7 +2631,7 @@ static void service_enter_condition(Service *s) {
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), service_exec_flags(s->control_command_id, /* cred_flag= */ 0),
s->timeout_start_usec, s->timeout_start_usec,
&s->control_pid); &s->control_pid);
if (r < 0) { if (r < 0) {
@ -2768,7 +2735,7 @@ static void service_enter_reload_post(Service *s) {
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), service_exec_flags(s->control_command_id, /* cred_flag= */ 0),
s->timeout_start_usec, s->timeout_start_usec,
&s->control_pid); &s->control_pid);
if (r < 0) { if (r < 0) {
@ -2843,7 +2810,7 @@ static void service_enter_reload(Service *s) {
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), service_exec_flags(s->control_command_id, /* cred_flag= */ 0),
s->timeout_start_usec, s->timeout_start_usec,
&s->control_pid); &s->control_pid);
if (r < 0) { if (r < 0) {
@ -2856,114 +2823,28 @@ static void service_enter_reload(Service *s) {
service_enter_reload_signal(s); service_enter_reload_signal(s);
} }
static bool service_get_effective_reload_credentials(Service *s) { static bool service_should_reload_extensions(Service *s) {
assert(s);
return FLAGS_SET(s->refresh_on_reload_flags, SERVICE_RELOAD_CREDENTIALS) &&
exec_context_has_credentials(&s->exec_context);
}
static void service_enter_refresh_credentials(Service *s) {
_cleanup_(pidref_done) PidRef worker = PIDREF_NULL;
int r; int r;
assert(s); assert(s);
if (!service_get_effective_reload_credentials(s)) if (!pidref_is_set(&s->main_pid)) {
return service_enter_reload(s); log_unit_debug(UNIT(s), "Not reloading extensions for service without main PID.");
return false;
service_unwatch_control_pid(s);
s->control_command = NULL;
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
r = service_arm_timer(s, /* relative = */ true, s->timeout_start_usec);
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
goto fail;
} }
r = unit_fork_helper_process_full(UNIT(s), "(sd-refresh-creds)", /* into_cgroup = */ false, r = exec_context_has_vpicked_extensions(&s->exec_context);
FORK_ALLOW_DLOPEN, /* allow loading libacl to avoid doing so in pid1 */ if (r < 0)
&worker); log_unit_warning_errno(UNIT(s), r, "Failed to determine if service should reload extensions, assuming false: %m");
if (r < 0) { if (r == 0)
log_unit_error_errno(UNIT(s), r, "Failed to fork process to refresh credentials in unit's namespace: %m"); log_unit_debug(UNIT(s), "Service has no extensions to reload.");
goto fail; if (r <= 0)
} return false;
if (r == 0) {
LOG_CONTEXT_PUSH_UNIT(UNIT(s));
r = unit_refresh_credentials(UNIT(s));
if (ERRNO_IS_NEG_PRIVILEGE(r))
_exit(EXIT_NOPERMISSION);
if (r < 0)
_exit(EXIT_FAILURE);
if (r == 0)
_exit(EXIT_NOTINSTALLED);
_exit(EXIT_SUCCESS);
}
r = unit_watch_pidref(UNIT(s), &worker, /* exclusive = */ true);
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to watch credentials refresh helper process: %m");
goto fail;
}
s->control_pid = TAKE_PIDREF(worker);
service_set_state(s, SERVICE_REFRESH_CREDENTIALS);
return;
fail:
service_reload_finish(s, SERVICE_FAILURE_RESOURCES);
}
static bool service_can_reload_extensions(Service *s, bool warn) {
assert(s);
// TODO: Add support for user services, which can use ExtensionDirectories= + notify-reload. // TODO: Add support for user services, which can use ExtensionDirectories= + notify-reload.
// For now, skip for user services. // For now, skip for user services.
if (exec_context_has_vpicked_extensions(&s->exec_context) <= 0) {
if (warn)
log_unit_warning(UNIT(s), "Service uses RefreshOnReload=extensions, but has no extensions using vpick. Ignoring.");
return false;
}
if (!s->exec_command[SERVICE_EXEC_START]) {
if (warn)
log_unit_warning(UNIT(s), "Service uses RefreshOnReload=extensions, but has no main process (ExecStart=). Ignoring.");
return false;
}
if (!MANAGER_IS_SYSTEM(UNIT(s)->manager)) { if (!MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
if (warn) log_once(LOG_WARNING, "Not reloading extensions for user services.");
log_unit_warning(UNIT(s), "Service uses RefreshOnReload=extensions, which is not supported in user mode. Ignoring.");
return false;
}
return true;
}
static bool service_get_effective_reload_extensions(Service *s) {
assert(s);
if (!FLAGS_SET(s->refresh_on_reload_flags, SERVICE_RELOAD_EXTENSIONS))
return false;
if (!service_can_reload_extensions(s, /* warn = */ false))
return false;
return true;
}
static bool service_should_reload_extensions(Service *s) {
assert(s);
if (!service_get_effective_reload_extensions(s))
return false;
if (!pidref_is_set(&s->main_pid)) {
log_unit_debug(UNIT(s), "Not reloading extensions for service without main PID.");
return false; return false;
} }
@ -2976,9 +2857,9 @@ static void service_enter_refresh_extensions(Service *s) {
assert(s); assert(s);
/* If we don't have extensions to refresh, immediately transition to next state */ /* If we don't have extensions to refresh, immediately transition to reload state */
if (!service_should_reload_extensions(s)) if (!service_should_reload_extensions(s))
return service_enter_refresh_credentials(s); return service_enter_reload(s);
service_unwatch_control_pid(s); service_unwatch_control_pid(s);
s->control_command = NULL; s->control_command = NULL;
@ -3074,7 +2955,7 @@ static void service_run_next_control(Service *s) {
r = service_spawn(s, r = service_spawn(s,
s->control_command, s->control_command,
service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), service_exec_flags(s->control_command_id, /* cred_flag= */ 0),
timeout, timeout,
&s->control_pid); &s->control_pid);
if (r < 0) { if (r < 0) {
@ -3105,7 +2986,7 @@ static void service_run_next_main(Service *s) {
r = service_spawn(s, r = service_spawn(s,
s->main_command, s->main_command,
service_exec_flags(s, SERVICE_EXEC_START, EXEC_SETUP_CREDENTIALS), service_exec_flags(SERVICE_EXEC_START, EXEC_SETUP_CREDENTIALS),
s->timeout_start_usec, s->timeout_start_usec,
&pidref); &pidref);
if (r < 0) { if (r < 0) {
@ -3243,7 +3124,6 @@ static int service_stop(Unit *u) {
service_live_mount_finish(s, SERVICE_FAILURE_PROTOCOL, BUS_ERROR_UNIT_INACTIVE); service_live_mount_finish(s, SERVICE_FAILURE_PROTOCOL, BUS_ERROR_UNIT_INACTIVE);
_fallthrough_; _fallthrough_;
case SERVICE_REFRESH_EXTENSIONS: case SERVICE_REFRESH_EXTENSIONS:
case SERVICE_REFRESH_CREDENTIALS:
service_kill_control_process(s); service_kill_control_process(s);
_fallthrough_; _fallthrough_;
case SERVICE_CONDITION: case SERVICE_CONDITION:
@ -3286,7 +3166,6 @@ static int service_reload(Unit *u) {
assert(IN_SET(s->state, SERVICE_RUNNING, SERVICE_EXITED)); assert(IN_SET(s->state, SERVICE_RUNNING, SERVICE_EXITED));
s->reload_result = SERVICE_SUCCESS; s->reload_result = SERVICE_SUCCESS;
s->refreshed_mask = 0;
service_enter_refresh_extensions(s); service_enter_refresh_extensions(s);
@ -3297,10 +3176,7 @@ static bool service_can_reload(Unit *u) {
Service *s = ASSERT_PTR(SERVICE(u)); Service *s = ASSERT_PTR(SERVICE(u));
return s->exec_command[SERVICE_EXEC_RELOAD] || return s->exec_command[SERVICE_EXEC_RELOAD] ||
s->type == SERVICE_NOTIFY_RELOAD || s->type == SERVICE_NOTIFY_RELOAD;
(s->refresh_on_reload_set &&
(service_get_effective_reload_extensions(s) ||
service_get_effective_reload_credentials(s)));
} }
static unsigned service_exec_command_index(Unit *u, ServiceExecCommand id, const ExecCommand *current) { static unsigned service_exec_command_index(Unit *u, ServiceExecCommand id, const ExecCommand *current) {
@ -3510,21 +3386,6 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
(void) serialize_usec(f, "reload-begin-usec", s->reload_begin_usec); (void) serialize_usec(f, "reload-begin-usec", s->reload_begin_usec);
if (s->refreshed_mask > 0) {
_cleanup_strv_free_ char **l = NULL;
_cleanup_free_ char *t = NULL;
r = service_refresh_on_reload_to_strv(s->refreshed_mask, &l);
if (r < 0)
return log_oom();
t = strv_join(l, " ");
if (!t)
return log_oom();
(void) serialize_item(f, "refreshed-mask", t);
}
return 0; return 0;
} }
@ -3914,11 +3775,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
} else if (streq(key, "reload-begin-usec")) } else if (streq(key, "reload-begin-usec"))
(void) deserialize_usec(value, &s->reload_begin_usec); (void) deserialize_usec(value, &s->reload_begin_usec);
else if (streq(key, "refreshed-mask")) { else
r = service_refresh_on_reload_from_string_many(value, &s->refreshed_mask);
if (r < 0)
log_unit_debug_errno(u, r, "Failed to parse refresh-mask value: %s", value);
} else
log_unit_debug(u, "Unknown serialization key: %s", key); log_unit_debug(u, "Unknown serialization key: %s", key);
return 0; return 0;
@ -4331,7 +4188,6 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SERVICE_START_POST: case SERVICE_START_POST:
case SERVICE_REFRESH_EXTENSIONS: case SERVICE_REFRESH_EXTENSIONS:
case SERVICE_REFRESH_CREDENTIALS:
case SERVICE_RELOAD: case SERVICE_RELOAD:
case SERVICE_RELOAD_SIGNAL: case SERVICE_RELOAD_SIGNAL:
case SERVICE_RELOAD_NOTIFY: case SERVICE_RELOAD_NOTIFY:
@ -4451,7 +4307,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
success, success,
code, status); code, status);
if (!IN_SET(s->state, SERVICE_REFRESH_EXTENSIONS, SERVICE_REFRESH_CREDENTIALS, SERVICE_RELOAD, SERVICE_RELOAD_POST, SERVICE_MOUNTING) && if (!IN_SET(s->state, SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_POST, SERVICE_MOUNTING) &&
s->result == SERVICE_SUCCESS) s->result == SERVICE_SUCCESS)
s->result = f; s->result = f;
@ -4540,21 +4396,10 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break; break;
case SERVICE_REFRESH_EXTENSIONS: case SERVICE_REFRESH_EXTENSIONS:
if (f == SERVICE_SUCCESS) { if (f == SERVICE_SUCCESS)
s->refreshed_mask |= SERVICE_RELOAD_EXTENSIONS; /* Remounting extensions asynchronously done, proceed to reload */
service_enter_refresh_credentials(s);
} else
service_reload_finish(s, f);
break;
case SERVICE_REFRESH_CREDENTIALS:
if (f == SERVICE_SUCCESS ||
(f == SERVICE_FAILURE_EXIT_CODE && IN_SET(status, EXIT_NOTINSTALLED, EXIT_NOPERMISSION))) {
/* Refreshing asynchronously done, proceed to reload */
s->refreshed_mask |= f == SERVICE_SUCCESS ? SERVICE_RELOAD_CREDENTIALS : 0;
service_enter_reload(s); service_enter_reload(s);
} else else
service_reload_finish(s, f); service_reload_finish(s, f);
break; break;
@ -4670,7 +4515,6 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
break; break;
case SERVICE_REFRESH_EXTENSIONS: case SERVICE_REFRESH_EXTENSIONS:
case SERVICE_REFRESH_CREDENTIALS:
case SERVICE_RELOAD: case SERVICE_RELOAD:
case SERVICE_RELOAD_SIGNAL: case SERVICE_RELOAD_SIGNAL:
case SERVICE_RELOAD_NOTIFY: case SERVICE_RELOAD_NOTIFY:
@ -4994,9 +4838,7 @@ static void service_notify_message_process_state(Service *s, char * const *tags)
if (strv_contains(tags, "STOPPING=1")) { if (strv_contains(tags, "STOPPING=1")) {
s->notify_state = NOTIFY_STOPPING; s->notify_state = NOTIFY_STOPPING;
if (IN_SET(s->state, SERVICE_RUNNING, if (IN_SET(s->state, SERVICE_RUNNING, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_REFRESH_EXTENSIONS))
SERVICE_REFRESH_EXTENSIONS, SERVICE_REFRESH_CREDENTIALS,
SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY))
service_enter_stop_by_notify(s); service_enter_stop_by_notify(s);
return; return;
@ -5093,8 +4935,7 @@ static void service_notify_message(
r = service_notify_message_parse_new_pid(u, tags, fds, &new_main_pid); r = service_notify_message_parse_new_pid(u, tags, fds, &new_main_pid);
if (r > 0 && if (r > 0 &&
IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS, SERVICE_REFRESH_CREDENTIALS, SERVICE_REFRESH_EXTENSIONS, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST,
SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_POST,
SERVICE_STOP, SERVICE_STOP_SIGTERM) && SERVICE_STOP, SERVICE_STOP_SIGTERM) &&
(!s->main_pid_known || !pidref_equal(&new_main_pid, &s->main_pid))) { (!s->main_pid_known || !pidref_equal(&new_main_pid, &s->main_pid))) {
@ -5363,7 +5204,6 @@ static bool pick_up_pid_from_bus_name(Service *s) {
SERVICE_START_POST, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS, SERVICE_REFRESH_EXTENSIONS,
SERVICE_REFRESH_CREDENTIALS,
SERVICE_RELOAD, SERVICE_RELOAD,
SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_SIGNAL,
SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_NOTIFY,
@ -5550,7 +5390,6 @@ static bool service_needs_console(Unit *u) {
SERVICE_START_POST, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RUNNING,
SERVICE_REFRESH_EXTENSIONS, SERVICE_REFRESH_EXTENSIONS,
SERVICE_REFRESH_CREDENTIALS,
SERVICE_RELOAD, SERVICE_RELOAD,
SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_SIGNAL,
SERVICE_RELOAD_NOTIFY, SERVICE_RELOAD_NOTIFY,
@ -6049,73 +5888,6 @@ static const char* const service_timeout_failure_mode_table[_SERVICE_TIMEOUT_FAI
DEFINE_STRING_TABLE_LOOKUP(service_timeout_failure_mode, ServiceTimeoutFailureMode); DEFINE_STRING_TABLE_LOOKUP(service_timeout_failure_mode, ServiceTimeoutFailureMode);
static const struct {
ServiceRefreshOnReload flag;
const char *name;
} service_refresh_on_reload_table[] = {
{ SERVICE_RELOAD_EXTENSIONS, "extensions" },
{ SERVICE_RELOAD_CREDENTIALS, "credentials" },
};
ServiceRefreshOnReload service_refresh_on_reload_flag_from_string(const char *s) {
assert(s);
FOREACH_ELEMENT(i, service_refresh_on_reload_table)
if (streq(s, i->name))
return i->flag;
return _SERVICE_REFRESH_ON_RELOAD_INVALID;
}
int service_refresh_on_reload_from_string_many(const char *s, ServiceRefreshOnReload *ret) {
ServiceRefreshOnReload flags = 0;
int r;
assert(s);
assert(ret);
for (;;) {
_cleanup_free_ char *v = NULL;
ServiceRefreshOnReload f;
r = extract_first_word(&s, &v, NULL, 0);
if (r < 0)
return r;
if (r == 0)
break;
f = service_refresh_on_reload_flag_from_string(v);
if (f < 0)
return f;
assert(f > 0);
flags |= f;
}
*ret = flags;
return 0;
}
int service_refresh_on_reload_to_strv(ServiceRefreshOnReload flags, char ***ret) {
_cleanup_strv_free_ char **l = NULL;
int r;
assert(flags >= 0);
assert(ret);
FOREACH_ELEMENT(i, service_refresh_on_reload_table) {
if (!FLAGS_SET(flags, i->flag))
continue;
r = strv_extend(&l, i->name);
if (r < 0)
return r;
}
*ret = TAKE_PTR(l);
return 0;
}
const UnitVTable service_vtable = { const UnitVTable service_vtable = {
.object_size = sizeof(Service), .object_size = sizeof(Service),
.exec_context_offset = offsetof(Service, exec_context), .exec_context_offset = offsetof(Service, exec_context),

View File

@ -96,15 +96,6 @@ typedef enum ServiceRestartMode {
_SERVICE_RESTART_MODE_INVALID = -EINVAL, _SERVICE_RESTART_MODE_INVALID = -EINVAL,
} ServiceRestartMode; } ServiceRestartMode;
typedef enum ServiceRefreshOnReload {
SERVICE_RELOAD_EXTENSIONS = 1 << 0,
SERVICE_RELOAD_CREDENTIALS = 1 << 1,
_SERVICE_REFRESH_ON_RELOAD_ALL = (1 << 2) - 1,
_SERVICE_REFRESH_ON_RELOAD_INVALID = -EINVAL,
} ServiceRefreshOnReload;
#define SERVICE_REFRESH_ON_RELOAD_DEFAULT SERVICE_RELOAD_EXTENSIONS
typedef struct ServiceFDStore { typedef struct ServiceFDStore {
Service *service; Service *service;
@ -246,10 +237,6 @@ typedef struct Service {
int reload_signal; int reload_signal;
usec_t reload_begin_usec; usec_t reload_begin_usec;
bool refresh_on_reload_set;
ServiceRefreshOnReload refresh_on_reload_flags;
ServiceRefreshOnReload refreshed_mask;
OOMPolicy oom_policy; OOMPolicy oom_policy;
char *usb_function_descriptors; char *usb_function_descriptors;
@ -301,10 +288,6 @@ DECLARE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
DECLARE_STRING_TABLE_LOOKUP(service_timeout_failure_mode, ServiceTimeoutFailureMode); DECLARE_STRING_TABLE_LOOKUP(service_timeout_failure_mode, ServiceTimeoutFailureMode);
ServiceRefreshOnReload service_refresh_on_reload_flag_from_string(const char *s) _pure_;
int service_refresh_on_reload_from_string_many(const char *s, ServiceRefreshOnReload *ret);
int service_refresh_on_reload_to_strv(ServiceRefreshOnReload flags, char ***ret);
DEFINE_CAST(SERVICE, Service); DEFINE_CAST(SERVICE, Service);
/* Only exported for unit tests */ /* Only exported for unit tests */

View File

@ -141,33 +141,33 @@ static int units_by_state_total_build_json(MetricFamilyContext *context, void *u
} }
const MetricFamily metric_family_table[] = { const MetricFamily metric_family_table[] = {
/* Keep metrics ordered alphabetically */ // Keep metrics ordered alphabetically
{ {
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "nRestarts", .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "nrestarts",
.description = "Per unit metric: number of restarts", .description = "Per unit metric: number of restarts",
.type = METRIC_FAMILY_TYPE_COUNTER, .type = METRIC_FAMILY_TYPE_COUNTER,
.generate = nrestarts_build_json, .generate = nrestarts_build_json,
}, },
{ {
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "unitActiveState", .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "unit_active_state",
.description = "Per unit metric: active state", .description = "Per unit metric: active state",
.type = METRIC_FAMILY_TYPE_STRING, .type = METRIC_FAMILY_TYPE_STRING,
.generate = unit_active_state_build_json, .generate = unit_active_state_build_json,
}, },
{ {
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "unitLoadState", .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "unit_load_state",
.description = "Per unit metric: load state", .description = "Per unit metric: load state",
.type = METRIC_FAMILY_TYPE_STRING, .type = METRIC_FAMILY_TYPE_STRING,
.generate = unit_load_state_build_json, .generate = unit_load_state_build_json,
}, },
{ {
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "unitsByStateTotal", .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "units_by_state_total",
.description = "Total number of units of different state", .description = "Total number of units of different state",
.type = METRIC_FAMILY_TYPE_GAUGE, .type = METRIC_FAMILY_TYPE_GAUGE,
.generate = units_by_state_total_build_json, .generate = units_by_state_total_build_json,
}, },
{ {
.name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "unitsByTypeTotal", .name = METRIC_IO_SYSTEMD_MANAGER_PREFIX "units_by_type_total",
.description = "Total number of units of different types", .description = "Total number of units of different types",
.type = METRIC_FAMILY_TYPE_GAUGE, .type = METRIC_FAMILY_TYPE_GAUGE,
.generate = units_by_type_total_build_json, .generate = units_by_type_total_build_json,

View File

@ -351,11 +351,10 @@ assert_cc(sizeof(long long) == sizeof(intmax_t));
#define CASE_F_19(X, ...) case X: CASE_F_18( __VA_ARGS__) #define CASE_F_19(X, ...) case X: CASE_F_18( __VA_ARGS__)
#define CASE_F_20(X, ...) case X: CASE_F_19( __VA_ARGS__) #define CASE_F_20(X, ...) case X: CASE_F_19( __VA_ARGS__)
#define CASE_F_21(X, ...) case X: CASE_F_20( __VA_ARGS__) #define CASE_F_21(X, ...) case X: CASE_F_20( __VA_ARGS__)
#define CASE_F_22(X, ...) case X: CASE_F_21( __VA_ARGS__)
#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,NAME,...) NAME #define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,NAME,...) NAME
#define FOR_EACH_MAKE_CASE(...) \ #define FOR_EACH_MAKE_CASE(...) \
GET_CASE_F(__VA_ARGS__,CASE_F_22,CASE_F_21,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12, \ GET_CASE_F(__VA_ARGS__,CASE_F_21,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12, \
CASE_F_11,CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \ CASE_F_11,CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
(__VA_ARGS__) (__VA_ARGS__)
@ -365,7 +364,7 @@ assert_cc(sizeof(long long) == sizeof(intmax_t));
/* If the build breaks in the line below, you need to extend the case macros. We use typeof(+x) \ /* If the build breaks in the line below, you need to extend the case macros. We use typeof(+x) \
* here to widen the type of x if it is a bit-field as this would otherwise be illegal. */ \ * here to widen the type of x if it is a bit-field as this would otherwise be illegal. */ \
static const typeof(+x) __assert_in_set[] _unused_ = { first, __VA_ARGS__ }; \ static const typeof(+x) __assert_in_set[] _unused_ = { first, __VA_ARGS__ }; \
assert_cc(ELEMENTSOF(__assert_in_set) <= 22); \ assert_cc(ELEMENTSOF(__assert_in_set) <= 21); \
switch (x) { \ switch (x) { \
FOR_EACH_MAKE_CASE(first, __VA_ARGS__) \ FOR_EACH_MAKE_CASE(first, __VA_ARGS__) \
_found = true; \ _found = true; \

View File

@ -13,7 +13,6 @@
#include "alloc-util.h" #include "alloc-util.h"
#include "errno-util.h" #include "errno-util.h"
#include "escape.h"
#include "extract-word.h" #include "extract-word.h"
#include "fd-util.h" #include "fd-util.h"
#include "fs-util.h" #include "fs-util.h"
@ -634,11 +633,7 @@ static int pid_notify_with_fds_internal(
return log_debug_errno(SYNTHETIC_ERRNO(EPROTO), "Unexpectedly received data on notify socket."); return log_debug_errno(SYNTHETIC_ERRNO(EPROTO), "Unexpectedly received data on notify socket.");
} }
if (DEBUG_LOGGING) { log_debug("Notify message sent to '%s': \"%s\"", e, state);
_cleanup_free_ char *escaped = xescape_full(state, "\"", /* console_width = */ SIZE_MAX, XESCAPE_8_BIT);
log_debug("Notify message sent to '%s': \"%s\"", e, escaped ?: state);
}
return 1; return 1;
} }

View File

@ -1465,7 +1465,7 @@ static int install_chroot_dropin(
ext->path, ext->path,
/* With --force tell PID1 to avoid enforcing that the image <name> and /* With --force tell PID1 to avoid enforcing that the image <name> and
* extension-release.<name> have to match. */ * extension-release.<name> have to match. */
!IN_SET(ext->type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME) && !IN_SET(type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME) &&
FLAGS_SET(flags, PORTABLE_FORCE_EXTENSION) ? FLAGS_SET(flags, PORTABLE_FORCE_EXTENSION) ?
":x-systemd.relax-extension-release-check\n" : ":x-systemd.relax-extension-release-check\n" :
"\n", "\n",
@ -1475,7 +1475,7 @@ static int install_chroot_dropin(
"LogExtraFields=PORTABLE_EXTENSION=", extension_base_name, "\n")) "LogExtraFields=PORTABLE_EXTENSION=", extension_base_name, "\n"))
return -ENOMEM; return -ENOMEM;
if (pinned_ext_image_policy && !IN_SET(ext->type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME)) { if (pinned_ext_image_policy) {
_cleanup_free_ char *policy_str = NULL; _cleanup_free_ char *policy_str = NULL;
r = image_policy_to_string(pinned_ext_image_policy, /* simplify= */ true, &policy_str); r = image_policy_to_string(pinned_ext_image_policy, /* simplify= */ true, &policy_str);

View File

@ -3007,9 +3007,7 @@ static int partition_read_definition(
} }
/* Verity partitions are read only, let's imply the RO flag hence, unless explicitly configured otherwise. */ /* Verity partitions are read only, let's imply the RO flag hence, unless explicitly configured otherwise. */
if ((partition_designator_is_verity_hash(p->type.designator) || if ((partition_designator_is_verity_hash(p->type.designator) || p->verity == VERITY_DATA) && p->read_only < 0)
partition_designator_is_verity_sig(p->type.designator) ||
IN_SET(p->verity, VERITY_DATA, VERITY_SIG)) && p->read_only < 0)
p->read_only = true; p->read_only = true;
/* Default to "growfs" on, unless read-only */ /* Default to "growfs" on, unless read-only */

View File

@ -1172,56 +1172,6 @@ static int bus_append_import_credential(sd_bus_message *m, const char *field, co
return 1; return 1;
} }
static int bus_append_refresh_on_reload(sd_bus_message *m, const char *field, const char *eq) {
int r;
r = sd_bus_message_open_container(m, 'r', "sv");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append_basic(m, 's', field);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'v', "a(bs)");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'a', "(bs)");
if (r < 0)
return bus_log_create_error(r);
bool invert = *eq == '~';
for (const char *p = eq + invert;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, 0);
if (r < 0)
return parse_log_error(r, field, eq);
if (r == 0)
break;
r = sd_bus_message_append(m, "(bs)", invert, word);
if (r < 0)
return bus_log_create_error(r);
}
r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
return 1;
}
static int bus_append_log_extra_fields(sd_bus_message *m, const char *field, const char *eq) { static int bus_append_log_extra_fields(sd_bus_message *m, const char *field, const char *eq) {
int r; int r;
@ -2715,7 +2665,6 @@ static const BusProperty service_properties[] = {
{ "SuccessExitStatus", bus_append_exit_status }, { "SuccessExitStatus", bus_append_exit_status },
{ "OpenFile", bus_append_open_file }, { "OpenFile", bus_append_open_file },
{ "ReloadSignal", bus_append_signal_from_string }, { "ReloadSignal", bus_append_signal_from_string },
{ "RefreshOnReload", bus_append_refresh_on_reload },
{} {}
}; };

View File

@ -325,8 +325,6 @@ bool gpt_partition_type_knows_read_only(GptPartitionType type) {
/* pretty much implied, but let's set the bit to make things really clear */ /* pretty much implied, but let's set the bit to make things really clear */
PARTITION_ROOT_VERITY, PARTITION_ROOT_VERITY,
PARTITION_USR_VERITY, PARTITION_USR_VERITY,
PARTITION_ROOT_VERITY_SIG,
PARTITION_USR_VERITY_SIG,
PARTITION_HOME, PARTITION_HOME,
PARTITION_SRV, PARTITION_SRV,
PARTITION_VAR, PARTITION_VAR,

View File

@ -45,8 +45,8 @@ typedef enum UserRecordLoadFlags UserRecordLoadFlags;
typedef enum UserStorage UserStorage; typedef enum UserStorage UserStorage;
typedef struct Bitmap Bitmap; typedef struct Bitmap Bitmap;
typedef struct BootConfig BootConfig;
typedef struct BPFProgram BPFProgram; typedef struct BPFProgram BPFProgram;
typedef struct BootConfig BootConfig;
typedef struct BusObjectImplementation BusObjectImplementation; typedef struct BusObjectImplementation BusObjectImplementation;
typedef struct CalendarSpec CalendarSpec; typedef struct CalendarSpec CalendarSpec;
typedef struct Condition Condition; typedef struct Condition Condition;

View File

@ -18,7 +18,7 @@ static SD_VARLINK_DEFINE_ERROR(NoSuchMetric);
static SD_VARLINK_DEFINE_METHOD_FULL( static SD_VARLINK_DEFINE_METHOD_FULL(
List, List,
SD_VARLINK_REQUIRES_MORE, SD_VARLINK_REQUIRES_MORE,
SD_VARLINK_FIELD_COMMENT("Metric name, e.g. io.systemd.Manager.unitsByTypeTotal or io.systemd.Manager.unitActiveState"), SD_VARLINK_FIELD_COMMENT("Metric name, e.g. io.systemd.Manager.units_by_type_total or io.systemd.Manager.unit_active_state"),
SD_VARLINK_DEFINE_OUTPUT(name, SD_VARLINK_STRING, 0), SD_VARLINK_DEFINE_OUTPUT(name, SD_VARLINK_STRING, 0),
/* metric value has various types depending on MetricFamilyType and actual data double/int/uint */ /* metric value has various types depending on MetricFamilyType and actual data double/int/uint */
SD_VARLINK_FIELD_COMMENT("Metric value"), SD_VARLINK_FIELD_COMMENT("Metric value"),

View File

@ -1171,7 +1171,7 @@ static int run_callout(
/* Build the filenames and paths which is normally done by transfer_acquire_instance(), but for partial /* Build the filenames and paths which is normally done by transfer_acquire_instance(), but for partial
* and pending instances which are about to be installed (in which case, transfer_acquire_instance() is * and pending instances which are about to be installed (in which case, transfer_acquire_instance() is
* skipped). */ * skipped). */
int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata *f) { static int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata *f) {
_cleanup_free_ char *formatted_pattern = NULL, *formatted_partial_pattern = NULL, *formatted_pending_pattern = NULL; _cleanup_free_ char *formatted_pattern = NULL, *formatted_partial_pattern = NULL, *formatted_pending_pattern = NULL;
int r; int r;
@ -1260,16 +1260,16 @@ int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata
return 0; return 0;
} }
int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, TransferProgress cb, void *userdata) { int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, void *userdata) {
_cleanup_free_ char *digest = NULL; _cleanup_free_ char *digest = NULL;
char offset[DECIMAL_STR_MAX(uint64_t)+1], max_size[DECIMAL_STR_MAX(uint64_t)+1]; char offset[DECIMAL_STR_MAX(uint64_t)+1], max_size[DECIMAL_STR_MAX(uint64_t)+1];
const char *where = NULL; const char *where = NULL;
InstanceMetadata f;
Instance *existing; Instance *existing;
int r; int r;
assert(t); assert(t);
assert(i); assert(i);
assert(f);
assert(i->resource == &t->source); assert(i->resource == &t->source);
assert(cb); assert(cb);
@ -1282,6 +1282,11 @@ int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, Tra
return 0; return 0;
} }
/* Compute up the temporary paths */
r = transfer_compute_temporary_paths(t, i, &f);
if (r < 0)
return r;
if (RESOURCE_IS_FILESYSTEM(t->target.type)) { if (RESOURCE_IS_FILESYSTEM(t->target.type)) {
r = mkdir_parents(t->temporary_partial_path, 0755); r = mkdir_parents(t->temporary_partial_path, 0755);
if (r < 0) if (r < 0)
@ -1497,10 +1502,10 @@ int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, Tra
assert(t->temporary_pending_path); assert(t->temporary_pending_path);
/* Apply file attributes if set */ /* Apply file attributes if set */
if (f->mtime != USEC_INFINITY) { if (f.mtime != USEC_INFINITY) {
struct timespec ts; struct timespec ts;
timespec_store(&ts, f->mtime); timespec_store(&ts, f.mtime);
if (utimensat(AT_FDCWD, t->temporary_partial_path, (struct timespec[2]) { ts, ts }, AT_SYMLINK_NOFOLLOW) < 0) if (utimensat(AT_FDCWD, t->temporary_partial_path, (struct timespec[2]) { ts, ts }, AT_SYMLINK_NOFOLLOW) < 0)
return log_error_errno(errno, "Failed to adjust mtime of '%s': %m", t->temporary_partial_path); return log_error_errno(errno, "Failed to adjust mtime of '%s': %m", t->temporary_partial_path);
@ -1508,12 +1513,12 @@ int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, Tra
need_sync = true; need_sync = true;
} }
if (f->mode != MODE_INVALID) { if (f.mode != MODE_INVALID) {
/* Try with AT_SYMLINK_NOFOLLOW first, because it's the safe thing to do. Older /* Try with AT_SYMLINK_NOFOLLOW first, because it's the safe thing to do. Older
* kernels don't support that however, in that case we fall back to chmod(). Not as * kernels don't support that however, in that case we fall back to chmod(). Not as
* safe, but shouldn't be a problem, given that we don't create symlinks here. */ * safe, but shouldn't be a problem, given that we don't create symlinks here. */
if (fchmodat(AT_FDCWD, t->temporary_partial_path, f->mode, AT_SYMLINK_NOFOLLOW) < 0 && if (fchmodat(AT_FDCWD, t->temporary_partial_path, f.mode, AT_SYMLINK_NOFOLLOW) < 0 &&
(!ERRNO_IS_NOT_SUPPORTED(errno) || chmod(t->temporary_partial_path, f->mode) < 0)) (!ERRNO_IS_NOT_SUPPORTED(errno) || chmod(t->temporary_partial_path, f.mode) < 0))
return log_error_errno(errno, "Failed to adjust mode of '%s': %m", t->temporary_partial_path); return log_error_errno(errno, "Failed to adjust mode of '%s': %m", t->temporary_partial_path);
need_sync = true; need_sync = true;
@ -1531,7 +1536,7 @@ int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, Tra
return log_error_errno(r, "Failed to synchronize file system backing '%s': %m", t->temporary_partial_path); return log_error_errno(r, "Failed to synchronize file system backing '%s': %m", t->temporary_partial_path);
} }
t->install_read_only = f->read_only; t->install_read_only = f.read_only;
/* Rename the file from `.sysupdate.partial.<VERSION>` to `.sysupdate.pending.<VERSION>` to indicate its ready to install. */ /* Rename the file from `.sysupdate.partial.<VERSION>` to `.sysupdate.pending.<VERSION>` to indicate its ready to install. */
log_debug("Renaming resource instance '%s' to '%s'.", t->temporary_partial_path, t->temporary_pending_path); log_debug("Renaming resource instance '%s' to '%s'.", t->temporary_partial_path, t->temporary_pending_path);
@ -1552,28 +1557,28 @@ int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, Tra
return r; return r;
t->partition_change = PARTITION_LABEL; t->partition_change = PARTITION_LABEL;
if (f->partition_uuid_set) { if (f.partition_uuid_set) {
t->partition_info.uuid = f->partition_uuid; t->partition_info.uuid = f.partition_uuid;
t->partition_change |= PARTITION_UUID; t->partition_change |= PARTITION_UUID;
} }
if (f->partition_flags_set) { if (f.partition_flags_set) {
t->partition_info.flags = f->partition_flags; t->partition_info.flags = f.partition_flags;
t->partition_change |= PARTITION_FLAGS; t->partition_change |= PARTITION_FLAGS;
} }
if (f->no_auto >= 0) { if (f.no_auto >= 0) {
t->partition_info.no_auto = f->no_auto; t->partition_info.no_auto = f.no_auto;
t->partition_change |= PARTITION_NO_AUTO; t->partition_change |= PARTITION_NO_AUTO;
} }
if (f->read_only >= 0) { if (f.read_only >= 0) {
t->partition_info.read_only = f->read_only; t->partition_info.read_only = f.read_only;
t->partition_change |= PARTITION_READ_ONLY; t->partition_change |= PARTITION_READ_ONLY;
} }
if (f->growfs >= 0) { if (f.growfs >= 0) {
t->partition_info.growfs = f->growfs; t->partition_info.growfs = f.growfs;
t->partition_change |= PARTITION_GROWFS; t->partition_change |= PARTITION_GROWFS;
} }

View File

@ -66,8 +66,7 @@ int transfer_resolve_paths(Transfer *t, const char *root, const char *node);
int transfer_vacuum(Transfer *t, uint64_t space, const char *extra_protected_version); int transfer_vacuum(Transfer *t, uint64_t space, const char *extra_protected_version);
int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata *f); int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, void *userdata);
int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, TransferProgress cb, void *userdata);
int transfer_process_partial_and_pending_instance(Transfer *t, Instance *i); int transfer_process_partial_and_pending_instance(Transfer *t, Instance *i);
int transfer_install_instance(Transfer *t, Instance *i, const char *root); int transfer_install_instance(Transfer *t, Instance *i, const char *root);

View File

@ -1055,23 +1055,6 @@ static int context_acquire(
log_info("Selected update '%s' for install.", us->version); log_info("Selected update '%s' for install.", us->version);
_cleanup_free_ InstanceMetadata *metadata = new0(InstanceMetadata, c->n_transfers);
if (!metadata)
return log_oom();
/* Compute up the temporary paths before vacuuming so we don't vacuum anything if we fail to compute
* any paths because of failed validations (e.g. exceeding the gpt partition label size). */
for (size_t i = 0; i < c->n_transfers; i++) {
Instance *inst = us->instances[i];
Transfer *t = c->transfers[i];
assert(inst);
r = transfer_compute_temporary_paths(t, inst, metadata + i);
if (r < 0)
return r;
}
(void) sd_notifyf(/* unset_environment= */ false, (void) sd_notifyf(/* unset_environment= */ false,
"READY=1\n" "READY=1\n"
"X_SYSUPDATE_VERSION=%s\n" "X_SYSUPDATE_VERSION=%s\n"
@ -1107,7 +1090,7 @@ static int context_acquire(
continue; continue;
} }
r = transfer_acquire_instance(t, inst, metadata + i, context_on_acquire_progress, c); r = transfer_acquire_instance(t, inst, context_on_acquire_progress, c);
if (r < 0) if (r < 0)
return r; return r;
} }

View File

@ -21,7 +21,6 @@
#include "open-file.h" #include "open-file.h"
#include "pcre2-util.h" #include "pcre2-util.h"
#include "rm-rf.h" #include "rm-rf.h"
#include "service.h"
#include "set.h" #include "set.h"
#include "specifier.h" #include "specifier.h"
#include "string-util.h" #include "string-util.h"
@ -1034,86 +1033,6 @@ TEST(config_parse_open_file) {
ASSERT_NULL(of); ASSERT_NULL(of);
} }
TEST(config_parse_service_refresh_on_reload) {
ServiceRefreshOnReload flags;
_cleanup_strv_free_ char **l = NULL;
int r;
r = service_refresh_on_reload_from_string_many("extensions", &flags);
ASSERT_OK(r);
ASSERT_EQ(flags, SERVICE_RELOAD_EXTENSIONS);
ASSERT_OK(service_refresh_on_reload_to_strv(flags, &l));
ASSERT_TRUE(strv_equal(l, STRV_MAKE("extensions")));
l = strv_free(l);
r = service_refresh_on_reload_from_string_many("credentials extensions", &flags);
ASSERT_OK(r);
ASSERT_EQ(flags, SERVICE_RELOAD_EXTENSIONS|SERVICE_RELOAD_CREDENTIALS);
ASSERT_OK(service_refresh_on_reload_to_strv(flags, &l));
ASSERT_TRUE(strv_equal(l, STRV_MAKE("extensions", "credentials")));
ASSERT_ERROR(service_refresh_on_reload_from_string_many("hoge", &flags), EINVAL);
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_(unit_freep) Unit *u = NULL;
r = manager_new(RUNTIME_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
if (manager_errno_skip_test(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return;
}
ASSERT_OK(r);
ASSERT_OK(manager_startup(m, NULL, NULL, NULL));
ASSERT_NOT_NULL(u = unit_new(m, sizeof(Service)));
ASSERT_OK_ZERO(unit_add_name(u, "foobar.service"));
ASSERT_FALSE(SERVICE(u)->refresh_on_reload_set);
ASSERT_OK(config_parse_service_refresh_on_reload(
NULL, "fake", 1, "section", 1,
"RefreshOnReload", 0, "no",
NULL, u));
ASSERT_TRUE(SERVICE(u)->refresh_on_reload_set);
ASSERT_EQ(SERVICE(u)->refresh_on_reload_flags, 0);
ASSERT_OK(config_parse_service_refresh_on_reload(
NULL, "fake", 1, "section", 1,
"RefreshOnReload", 0, "yes",
NULL, u));
ASSERT_TRUE(SERVICE(u)->refresh_on_reload_set);
ASSERT_EQ(SERVICE(u)->refresh_on_reload_flags, _SERVICE_REFRESH_ON_RELOAD_ALL);
ASSERT_OK(config_parse_service_refresh_on_reload(
NULL, "fake", 1, "section", 1,
"RefreshOnReload", 0, "~extensions",
NULL, u));
ASSERT_TRUE(SERVICE(u)->refresh_on_reload_set);
ASSERT_EQ(SERVICE(u)->refresh_on_reload_flags, _SERVICE_REFRESH_ON_RELOAD_ALL & ~SERVICE_RELOAD_EXTENSIONS);
ASSERT_OK(config_parse_service_refresh_on_reload(
NULL, "fake", 1, "section", 1,
"RefreshOnReload", 0, "~extensions credentials",
NULL, u));
ASSERT_TRUE(SERVICE(u)->refresh_on_reload_set);
ASSERT_EQ(SERVICE(u)->refresh_on_reload_flags, 0);
ASSERT_OK(config_parse_service_refresh_on_reload(
NULL, "fake", 1, "section", 1,
"RefreshOnReload", 0, "",
NULL, u));
ASSERT_FALSE(SERVICE(u)->refresh_on_reload_set);
ASSERT_OK(config_parse_service_refresh_on_reload(
NULL, "fake", 1, "section", 1,
"RefreshOnReload", 0, "~extensions",
NULL, u));
ASSERT_TRUE(SERVICE(u)->refresh_on_reload_set);
ASSERT_EQ(SERVICE(u)->refresh_on_reload_flags, SERVICE_REFRESH_ON_RELOAD_DEFAULT & ~SERVICE_RELOAD_EXTENSIONS);
}
static int intro(void) { static int intro(void) {
if (enter_cgroup_subroot(NULL) == -ENOMEDIUM) if (enter_cgroup_subroot(NULL) == -ENOMEDIUM)
return log_tests_skipped("cgroupfs not available"); return log_tests_skipped("cgroupfs not available");

View File

@ -1,29 +0,0 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
# shellcheck disable=SC2016
set -eux
set -o pipefail
OUTPUT_FILE="$1"
dump_creds_tree() {
grep . "$CREDENTIALS_DIRECTORY"/* >"$OUTPUT_FILE"
}
on_sighup() {
systemd-notify --reloading
dump_creds_tree
systemd-notify --ready
}
trap on_sighup SIGHUP
export SYSTEMD_LOG_LEVEL=debug
dump_creds_tree
systemd-notify --ready
sleep infinity &
while :; do
wait || :
done

View File

@ -351,7 +351,6 @@ if install_tests
'integration-tests/TEST-30-ONCLOCKCHANGE/TEST-30-ONCLOCKCHANGE.units', 'integration-tests/TEST-30-ONCLOCKCHANGE/TEST-30-ONCLOCKCHANGE.units',
'integration-tests/TEST-38-FREEZER/TEST-38-FREEZER.units', 'integration-tests/TEST-38-FREEZER/TEST-38-FREEZER.units',
'integration-tests/TEST-52-HONORFIRSTSHUTDOWN/TEST-52-HONORFIRSTSHUTDOWN.units', 'integration-tests/TEST-52-HONORFIRSTSHUTDOWN/TEST-52-HONORFIRSTSHUTDOWN.units',
'integration-tests/TEST-54-CREDS/TEST-54-CREDS.units',
'integration-tests/TEST-55-OOMD/TEST-55-OOMD.units', 'integration-tests/TEST-55-OOMD/TEST-55-OOMD.units',
'integration-tests/TEST-62-RESTRICT-IFACES/TEST-62-RESTRICT-IFACES.units', 'integration-tests/TEST-62-RESTRICT-IFACES/TEST-62-RESTRICT-IFACES.units',
'integration-tests/TEST-63-PATH/TEST-63-PATH.units', 'integration-tests/TEST-63-PATH/TEST-63-PATH.units',

View File

@ -127,19 +127,6 @@ test -L /run/systemd/system.attached/app0.service.d/10-profile.conf
test -L /run/systemd/system.attached/app1.service.d/10-profile.conf test -L /run/systemd/system.attached/app1.service.d/10-profile.conf
portablectl detach --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1 portablectl detach --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1
# Ensure that --force works with directory extensions, and that ExtensionDirectories=
# is not decorated with :x-systemd.relax-extension-release-check
portablectl "${ARGS[@]}" attach --force --copy=symlink --now --runtime --extension /tmp/app0 /tmp/rootdir app0
systemctl is-active app0.service
status="$(portablectl is-attached --extension app0 rootdir)"
[[ "${status}" == "running-runtime" ]]
grep -q -F "ExtensionDirectories=" /run/systemd/system.attached/app0.service.d/20-portable.conf
(! grep -q -F "x-systemd.relax-extension-release-check" /run/systemd/system.attached/app0.service.d/20-portable.conf)
portablectl detach --now --runtime --extension /tmp/app0 /tmp/rootdir app0
# Attempt to disable the app unit during detaching. Requires --copy=symlink to reproduce. # Attempt to disable the app unit during detaching. Requires --copy=symlink to reproduce.
# Provides coverage for https://github.com/systemd/systemd/issues/23481 # Provides coverage for https://github.com/systemd/systemd/issues/23481
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/rootdir minimal-app0 portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/rootdir minimal-app0

View File

@ -189,10 +189,6 @@ systemctl is-active app0.service
status="$(portablectl is-attached --extension /tmp/app10.raw /usr/share/minimal_0.raw)" status="$(portablectl is-attached --extension /tmp/app10.raw /usr/share/minimal_0.raw)"
[[ "${status}" == "running-runtime" ]] [[ "${status}" == "running-runtime" ]]
# Ensure --force adds relax-extension-release-check for image extensions
grep -q -F "ExtensionImages=" /run/systemd/system.attached/app0.service.d/20-portable.conf
grep -q -F "ExtensionImagePolicy=" /run/systemd/system.attached/app0.service.d/20-portable.conf
portablectl inspect --force --cat --extension /tmp/app10.raw /usr/share/minimal_0.raw app0 | grep -F "Extension Release: /tmp/app10.raw" >/dev/null portablectl inspect --force --cat --extension /tmp/app10.raw /usr/share/minimal_0.raw app0 | grep -F "Extension Release: /tmp/app10.raw" >/dev/null
# Ensure that we can detach even when an image has been deleted already (stop the unit manually as # Ensure that we can detach even when an image has been deleted already (stop the unit manually as
@ -249,19 +245,3 @@ status="$(portablectl is-attached --extension app1 minimal_0)"
[[ "${status}" == "attached-runtime" ]] [[ "${status}" == "attached-runtime" ]]
portablectl detach --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app portablectl detach --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app
# Ensure that when mixing directory and image extensions, ExtensionImagePolicy= is only
# applied to image extensions and not to directory extensions
mkdir -p /tmp/app1
mount /tmp/app1.raw /tmp/app1
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime --extension /tmp/app1 --extension /tmp/app0.raw /usr/share/minimal_0.raw app0
systemctl is-active app0.service
grep -q -F "ExtensionDirectories=/tmp/app1" /run/systemd/system.attached/app0.service.d/20-portable.conf
grep -q -F "ExtensionImages=/tmp/app0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
# ExtensionImagePolicy= should appear exactly once (for the image, not the directory)
[[ "$(grep -c -F "ExtensionImagePolicy=" /run/systemd/system.attached/app0.service.d/20-portable.conf)" == "1" ]]
portablectl detach --now --runtime --extension /tmp/app1 --extension /tmp/app0.raw /usr/share/minimal_0.raw app0
umount -l /tmp/app1

View File

@ -571,106 +571,4 @@ systemd-run -M testuser@ --user --wait -p ImportCredential=brummbaer \
kill "$PID" kill "$PID"
# Now test credential refreshing
UNIT_NAME="TEST-54-CREDS-refreshing-$RANDOM.service"
OUTPUT_FILE="/tmp/$UNIT_NAME.out"
POST_FLAG_FILE="/tmp/$UNIT_NAME.post-flag"
cat >/run/systemd/system/"$UNIT_NAME" <<EOF
[Service]
Type=notify-reload
ImportCredential=test.creds.*
ExecStart=/usr/lib/systemd/tests/testdata/TEST-54-CREDS.units/refresh.sh $OUTPUT_FILE
EOF
systemctl start "$UNIT_NAME"
ls -l /run/credentials/"$UNIT_NAME"/
echo "neu" >/run/credstore/test.creds.new-refresh-1
[[ ! -e /run/credentials/"$UNIT_NAME"/test.creds.new-refresh-1 ]]
systemctl reload "$UNIT_NAME"
[[ ! -e /run/credentials/"$UNIT_NAME"/test.creds.new-refresh-1 ]]
(! grep -q "test.creds.new-refresh-1" "$OUTPUT_FILE")
echo "RefreshOnReload=credentials" >>/run/systemd/system/"$UNIT_NAME"
systemctl daemon-reload
systemctl reload "$UNIT_NAME"
diff /run/credstore/test.creds.new-refresh-1 /run/credentials/"$UNIT_NAME"/test.creds.new-refresh-1
diff "$OUTPUT_FILE" <(grep . /run/credentials/"$UNIT_NAME"/*)
systemctl stop "$UNIT_NAME"
cat >>/run/systemd/system/"$UNIT_NAME" <<EOF
ProtectSystem=strict
ReadWritePaths=/tmp
ExecReloadPost=bash -c 'diff $OUTPUT_FILE <(grep . %d/*) || rm -v $POST_FLAG_FILE'
EOF
systemctl daemon-reload
systemctl start "$UNIT_NAME"
diff /run/credstore/test.creds.new-refresh-1 /run/credentials/"$UNIT_NAME"/test.creds.new-refresh-1
diff "$OUTPUT_FILE" <(grep . /run/credentials/"$UNIT_NAME"/*)
systemctl reload "$UNIT_NAME"
diff "$OUTPUT_FILE" <(grep . /run/credentials/"$UNIT_NAME"/*)
echo "2" >/run/credstore/test.creds.new-refresh-2
[[ ! -e /run/credentials/"$UNIT_NAME"/test.creds.new-refresh-2 ]]
systemctl reload "$UNIT_NAME"
diff /run/credstore/test.creds.new-refresh-2 /run/credentials/"$UNIT_NAME"/test.creds.new-refresh-2
diff "$OUTPUT_FILE" <(grep . /run/credentials/"$UNIT_NAME"/*)
echo "3" >/run/credstore/test.creds.new-refresh-3
[[ ! -e /run/credentials/"$UNIT_NAME"/test.creds.new-refresh-3 ]]
rm "$OUTPUT_FILE"
systemctl edit --runtime --stdin "$UNIT_NAME" <<EOF
[Service]
Type=notify
ExecReloadPost=
EOF
systemctl reload "$UNIT_NAME"
diff /run/credstore/test.creds.new-refresh-3 /run/credentials/"$UNIT_NAME"/test.creds.new-refresh-3
[[ ! -e "$OUTPUT_FILE" ]]
echo "RefreshOnReload=no" >>/run/systemd/system/"$UNIT_NAME"
systemctl daemon-reload
assert_eq "$(systemctl show "$UNIT_NAME" -P CanReload)" "no"
systemctl revert "$UNIT_NAME"
assert_eq "$(systemctl show "$UNIT_NAME" -P CanReload)" "yes"
echo "BOGUS" >/run/credstore/test.creds.refresh-bogus
touch "$POST_FLAG_FILE"
systemctl reload "$UNIT_NAME"
diff /run/credstore/test.creds.new-refresh-3 /run/credentials/"$UNIT_NAME"/test.creds.new-refresh-3
[[ ! -e /run/credentials/"$UNIT_NAME"/test.creds.refresh-bogus ]]
diff "$OUTPUT_FILE" <(grep . /run/credentials/"$UNIT_NAME"/*)
[[ ! -e "$POST_FLAG_FILE" ]]
OUTPUT_FILE_USER="/tmp/TEST-54-CREDS-refreshing-user.out"
systemd-notify --fork -- \
systemd-run -M testuser@ --user --wait \
--unit=brummbaer-refresh.service \
--service-type=notify-reload \
-p NotifyAccess=all \
-p 'ImportCredential=brummbaer*' \
-p RefreshOnReload=credentials \
-p ProtectSystem=strict \
-p ReadWritePaths=/tmp \
/usr/lib/systemd/tests/testdata/TEST-54-CREDS.units/refresh.sh "$OUTPUT_FILE_USER"
[[ -f "$TESTUSER_CRED_DIR/brummbaer-refresh.service/brummbaer" ]]
diff "$OUTPUT_FILE_USER" <(grep . "$TESTUSER_CRED_DIR"/brummbaer-refresh.service/*)
run0 -u testuser --pipe -i \
--property=EnvironmentFile=-/usr/lib/systemd/systemd-asan-env \
'mkdir -p .config/credstore && echo "refreshed" >.config/credstore/brummbaer.refreshed'
systemctl -M testuser@ --user reload brummbaer-refresh.service
assert_eq "$(cat "$TESTUSER_CRED_DIR"/brummbaer-refresh.service/brummbaer.refreshed)" "refreshed"
diff "$OUTPUT_FILE_USER" <(grep . "$TESTUSER_CRED_DIR"/brummbaer-refresh.service/*)
touch /testok touch /testok

View File

@ -204,7 +204,7 @@ MatchPattern=part2-@v.raw.gz
[Target] [Target]
Type=partition Type=partition
Path=$blockdev Path=$blockdev
MatchPattern=a-very-long-partition-name-@v MatchPattern=part2-@v
MatchPartitionType=root-x86-64-verity MatchPartitionType=root-x86-64-verity
EOF EOF
@ -397,7 +397,7 @@ MatchPattern=part2-@v.raw.gz
[Target] [Target]
Type=partition Type=partition
Path=$blockdev Path=$blockdev
MatchPattern=a-very-long-partition-name-@v MatchPattern=part2-@v
MatchPartitionType=root-x86-64-verity MatchPartitionType=root-x86-64-verity
EOF EOF