mirror of
https://github.com/systemd/systemd.git
synced 2025-02-27 01:57:35 +03:00
core: introduce new RuntimeDirectory= and RuntimeDirectoryMode= unit settings
As discussed on the ML these are useful to manage runtime directories below /run for services.
This commit is contained in:
parent
b64a3d86bc
commit
e66cf1a3f9
@ -1195,6 +1195,46 @@
|
||||
kernel.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RuntimeDirectory=</varname></term>
|
||||
<term><varname>RuntimeDirectoryMode=</varname></term>
|
||||
|
||||
<listitem><para>Takes a list of
|
||||
directory names. If set one or more
|
||||
directories by the specified names
|
||||
will be created below
|
||||
<filename>/run</filename> (for system
|
||||
services) or below
|
||||
<varname>$XDG_RUNTIME_DIR</varname>
|
||||
(for user services) when the unit is
|
||||
started and removed when the unit is
|
||||
stopped. The directories will have the
|
||||
access mode specified in
|
||||
<varname>RuntimeDirectoryMode=</varname>,
|
||||
and will be owned by the user and
|
||||
group specified in
|
||||
<varname>User=</varname> and
|
||||
<varname>Group=</varname>. Use this to
|
||||
manage one or more runtime directories
|
||||
of the unit and bind their lifetime to
|
||||
the daemon runtime. The specified
|
||||
directory names must be relative, and
|
||||
may not include a
|
||||
<literal>/</literal>, i.e. must refer
|
||||
to simple directories to create or
|
||||
remove. This is particularly useful
|
||||
for unpriviliges daemons that cannot
|
||||
create runtime directories in
|
||||
<filename>/run</filename> due to lack
|
||||
of privileges, and to make sure the
|
||||
runtime directory is cleaned up
|
||||
automatically after use. For runtime
|
||||
directories that require more complex
|
||||
or different configuration or lifetime
|
||||
guarantees, please consider using
|
||||
<citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
@ -1352,6 +1392,7 @@
|
||||
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>exec</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
@ -61,6 +61,23 @@
|
||||
temporary files and directories which usually reside
|
||||
in directories such as <filename>/run</filename>
|
||||
or <filename>/tmp</filename>.</para>
|
||||
|
||||
<para>Volatile and temporary files and directories are
|
||||
those located in <filename>/run</filename> (and its
|
||||
alias <filename>/var/run</filename>),
|
||||
<filename>/tmp</filename>,
|
||||
<filename>/var/tmp</filename>, the API file systems
|
||||
such as <filename>/sys</filename> or
|
||||
<filename>/proc</filename>, as well as some other
|
||||
directories below <filename>/var</filename>.</para>
|
||||
|
||||
<para>System daemons frequently require private
|
||||
runtime directories below <filename>/run</filename> to
|
||||
place communication sockets and similar in. For these
|
||||
consider declaring them in their unit files using
|
||||
<varname>RuntimeDirectory=</varname>
|
||||
(see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details),
|
||||
if this is feasible.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@ -458,7 +475,8 @@ x /var/tmp/abrt/*</programlisting>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-delta</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>systemd-delta</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -635,6 +635,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||
SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
|
@ -82,6 +82,7 @@
|
||||
#include "selinux-util.h"
|
||||
#include "errno-list.h"
|
||||
#include "af-list.h"
|
||||
#include "mkdir.h"
|
||||
#include "apparmor-util.h"
|
||||
|
||||
#ifdef HAVE_SECCOMP
|
||||
@ -1247,6 +1248,7 @@ int exec_spawn(ExecCommand *command,
|
||||
bool confirm_spawn,
|
||||
CGroupControllerMask cgroup_supported,
|
||||
const char *cgroup_path,
|
||||
const char *runtime_prefix,
|
||||
const char *unit_id,
|
||||
usec_t watchdog_usec,
|
||||
int idle_pipe[4],
|
||||
@ -1544,6 +1546,27 @@ int exec_spawn(ExecCommand *command,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!strv_isempty(context->runtime_directory) && runtime_prefix) {
|
||||
char **rt;
|
||||
|
||||
STRV_FOREACH(rt, context->runtime_directory) {
|
||||
_cleanup_free_ char *p;
|
||||
|
||||
p = strjoin(runtime_prefix, "/", *rt, NULL);
|
||||
if (!p) {
|
||||
r = EXIT_RUNTIME_DIRECTORY;
|
||||
err = -ENOMEM;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
err = mkdir_safe(p, context->runtime_directory_mode, uid, gid);
|
||||
if (err < 0) {
|
||||
r = EXIT_RUNTIME_DIRECTORY;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (apply_permissions) {
|
||||
err = enforce_groups(context, username, gid);
|
||||
if (err < 0) {
|
||||
@ -1840,6 +1863,7 @@ void exec_context_init(ExecContext *c) {
|
||||
c->ignore_sigpipe = true;
|
||||
c->timer_slack_nsec = (nsec_t) -1;
|
||||
c->personality = 0xffffffffUL;
|
||||
c->runtime_directory_mode = 0755;
|
||||
}
|
||||
|
||||
void exec_context_done(ExecContext *c) {
|
||||
@ -1918,6 +1942,33 @@ void exec_context_done(ExecContext *c) {
|
||||
|
||||
set_free(c->address_families);
|
||||
c->address_families = NULL;
|
||||
|
||||
strv_free(c->runtime_directory);
|
||||
c->runtime_directory = NULL;
|
||||
}
|
||||
|
||||
int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_prefix) {
|
||||
char **i;
|
||||
|
||||
assert(c);
|
||||
|
||||
if (!runtime_prefix)
|
||||
return 0;
|
||||
|
||||
STRV_FOREACH(i, c->runtime_directory) {
|
||||
_cleanup_free_ char *p;
|
||||
|
||||
p = strjoin(runtime_prefix, "/", *i, NULL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
/* We execute this synchronously, since we need to be
|
||||
* sure this is gone when we start the service
|
||||
* next. */
|
||||
rm_rf_dangerous(p, false, true, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exec_command_done(ExecCommand *c) {
|
||||
|
@ -177,6 +177,9 @@ struct ExecContext {
|
||||
Set *address_families;
|
||||
bool address_families_whitelist:1;
|
||||
|
||||
char **runtime_directory;
|
||||
mode_t runtime_directory_mode;
|
||||
|
||||
bool oom_score_adjust_set:1;
|
||||
bool nice_set:1;
|
||||
bool ioprio_set:1;
|
||||
@ -196,6 +199,7 @@ int exec_spawn(ExecCommand *command,
|
||||
bool confirm_spawn,
|
||||
CGroupControllerMask cgroup_mask,
|
||||
const char *cgroup_path,
|
||||
const char *runtime_prefix,
|
||||
const char *unit_id,
|
||||
usec_t watchdog_usec,
|
||||
int pipe_fd[2],
|
||||
@ -219,6 +223,8 @@ void exec_context_init(ExecContext *c);
|
||||
void exec_context_done(ExecContext *c);
|
||||
void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
|
||||
|
||||
int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_root);
|
||||
|
||||
int exec_context_load_environment(const ExecContext *c, char ***l);
|
||||
|
||||
bool exec_context_may_touch_console(ExecContext *c);
|
||||
|
@ -82,6 +82,8 @@ $1.PrivateNetwork, config_parse_bool, 0,
|
||||
$1.PrivateDevices, config_parse_bool, 0, offsetof($1, exec_context.private_devices)
|
||||
$1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context)
|
||||
$1.Personality, config_parse_personality, 0, offsetof($1, exec_context.personality)
|
||||
$1.RuntimeDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.runtime_directory_mode)
|
||||
$1.RuntimeDirectory, config_parse_runtime_directory, 0, offsetof($1, exec_context.runtime_directory)
|
||||
m4_ifdef(`HAVE_LIBWRAP',
|
||||
`$1.TCPWrapName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.tcpwrap_name)',
|
||||
`$1.TCPWrapName, config_parse_warn_compat, 0, 0')
|
||||
|
@ -2719,6 +2719,56 @@ int config_parse_personality(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_runtime_directory(
|
||||
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) {
|
||||
|
||||
char***rt = data, *w, *state;
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
/* Empty assignment resets the list */
|
||||
strv_free(*rt);
|
||||
*rt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
|
||||
_cleanup_free_ char *n;
|
||||
|
||||
n = strndup(w, l);
|
||||
if (!n)
|
||||
return log_oom();
|
||||
|
||||
if (!filename_is_safe(n)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = strv_push(rt, n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
n = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FOLLOW_MAX 8
|
||||
|
||||
static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
|
||||
|
@ -91,6 +91,7 @@ int config_parse_exec_selinux_context(const char *unit, const char *filename, un
|
||||
int config_parse_personality(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);
|
||||
int config_parse_exec_apparmor_profile(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);
|
||||
int config_parse_address_families(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);
|
||||
int config_parse_runtime_directory(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);
|
||||
|
||||
/* gperf prototypes */
|
||||
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
|
||||
|
@ -2851,3 +2851,10 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
|
||||
|
||||
return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p);
|
||||
}
|
||||
|
||||
const char *manager_get_runtime_prefix(Manager *m) {
|
||||
|
||||
return m->running_as == SYSTEMD_SYSTEM ?
|
||||
"/run" :
|
||||
getenv("XDG_RUNTIME_DIR");
|
||||
}
|
||||
|
@ -318,3 +318,5 @@ void manager_status_printf(Manager *m, bool ephemeral, const char *status, const
|
||||
void manager_flip_auto_status(Manager *m, bool enable);
|
||||
|
||||
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path);
|
||||
|
||||
const char *manager_get_runtime_prefix(Manager *m);
|
||||
|
@ -788,6 +788,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
|
||||
UNIT(m)->manager->confirm_spawn,
|
||||
UNIT(m)->manager->cgroup_supported,
|
||||
UNIT(m)->cgroup_path,
|
||||
manager_get_runtime_prefix(UNIT(m)->manager),
|
||||
UNIT(m)->id,
|
||||
0,
|
||||
NULL,
|
||||
@ -820,6 +821,8 @@ static void mount_enter_dead(Mount *m, MountResult f) {
|
||||
exec_runtime_destroy(m->exec_runtime);
|
||||
m->exec_runtime = exec_runtime_unref(m->exec_runtime);
|
||||
|
||||
exec_context_destroy_runtime_directory(&m->exec_context, manager_get_runtime_prefix(UNIT(m)->manager));
|
||||
|
||||
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
|
||||
}
|
||||
|
||||
|
@ -1770,6 +1770,7 @@ static int service_spawn(
|
||||
UNIT(s)->manager->confirm_spawn,
|
||||
UNIT(s)->manager->cgroup_supported,
|
||||
path,
|
||||
manager_get_runtime_prefix(UNIT(s)->manager),
|
||||
UNIT(s)->id,
|
||||
s->watchdog_usec,
|
||||
s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
|
||||
@ -1871,10 +1872,13 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||
|
||||
s->forbid_restart = false;
|
||||
|
||||
/* we want fresh tmpdirs in case service is started again immediately */
|
||||
/* We want fresh tmpdirs in case service is started again immediately */
|
||||
exec_runtime_destroy(s->exec_runtime);
|
||||
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
|
||||
|
||||
/* Also, remove the runtime directory in */
|
||||
exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
|
||||
|
||||
/* Try to delete the pid file. At this point it will be
|
||||
* out-of-date, and some software might be confused by it, so
|
||||
* let's remove it. */
|
||||
|
@ -1255,6 +1255,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
|
||||
UNIT(s)->manager->confirm_spawn,
|
||||
UNIT(s)->manager->cgroup_supported,
|
||||
UNIT(s)->cgroup_path,
|
||||
manager_get_runtime_prefix(UNIT(s)->manager),
|
||||
UNIT(s)->id,
|
||||
0,
|
||||
NULL,
|
||||
@ -1289,6 +1290,8 @@ static void socket_enter_dead(Socket *s, SocketResult f) {
|
||||
exec_runtime_destroy(s->exec_runtime);
|
||||
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
|
||||
|
||||
exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
|
||||
|
||||
socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
|
||||
}
|
||||
|
||||
|
@ -646,6 +646,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
|
||||
UNIT(s)->manager->confirm_spawn,
|
||||
UNIT(s)->manager->cgroup_supported,
|
||||
UNIT(s)->cgroup_path,
|
||||
manager_get_runtime_prefix(UNIT(s)->manager),
|
||||
UNIT(s)->id,
|
||||
0,
|
||||
NULL,
|
||||
@ -678,6 +679,8 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
|
||||
exec_runtime_destroy(s->exec_runtime);
|
||||
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
|
||||
|
||||
exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
|
||||
|
||||
swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
|
||||
}
|
||||
|
||||
|
@ -142,6 +142,9 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
|
||||
|
||||
case EXIT_ADDRESS_FAMILIES:
|
||||
return "ADDRESS_FAMILIES";
|
||||
|
||||
case EXIT_RUNTIME_DIRECTORY:
|
||||
return "RUNTIME_DIRECTORY";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,7 @@ typedef enum ExitStatus {
|
||||
EXIT_PERSONALITY, /* 230 */
|
||||
EXIT_APPARMOR_PROFILE,
|
||||
EXIT_ADDRESS_FAMILIES,
|
||||
EXIT_RUNTIME_DIRECTORY
|
||||
} ExitStatus;
|
||||
|
||||
typedef enum ExitStatusLevel {
|
||||
|
@ -42,8 +42,8 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkd
|
||||
return -errno;
|
||||
|
||||
if ((st.st_mode & 0777) != mode ||
|
||||
st.st_uid != uid ||
|
||||
st.st_gid != gid ||
|
||||
(uid != (uid_t) -1 && st.st_uid != uid) ||
|
||||
(gid != (gid_t) -1 && st.st_gid != gid) ||
|
||||
!S_ISDIR(st.st_mode)) {
|
||||
errno = EEXIST;
|
||||
return -errno;
|
||||
|
Loading…
x
Reference in New Issue
Block a user