core: allow preserving contents of RuntimeDirectory= over process restart

This introduces RuntimeDirectoryPreserve= option which takes a boolean
argument or 'restart'.

Closes #6087.
This commit is contained in:
Yu Watanabe 2017-07-17 16:22:25 +09:00
parent b2392ff31c
commit 53f47dfc7b
9 changed files with 109 additions and 4 deletions

View file

@ -1658,7 +1658,10 @@
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
the unit is started, and removed when the unit is stopped.
It is possible to preserve the directories if
<varname>RuntimeDirectoryPreserve=</varname> is configured to
<option>restart</option> or <option>yes</option>. 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
@ -1686,6 +1689,21 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>RuntimeDirectoryPreserve=</varname></term>
<listitem><para>Takes a boolean argument or <option>restart</option>.
If set to <option>no</option> (the default), the directories specified in <varname>RuntimeDirectory=</varname>
are always removed when the service stops. If set to <option>restart</option> the directories are preserved
when the service is both automatically and manually restarted. Here, the automatic restart means the operation
specified in <varname>Restart=</varname>, and manual restart means the one triggered by
<command>systemctl restart foo.service</command>. If set to <option>yes</option>, then the directories are not
removed when the service is stopped. Note that since the runtime directory <filename>/run</filename> is a mount
point of <literal>tmpfs</literal>, then for system services the directories specified in
<varname>RuntimeDirectory=</varname> are removed when the system is rebooted.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>MemoryDenyWriteExecute=</varname></term>

View file

@ -55,6 +55,8 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInp
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_preserve_mode, exec_preserve_mode, ExecPreserveMode);
static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_home, protect_home, ProtectHome);
static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_system, protect_system, ProtectSystem);
@ -850,6 +852,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
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("RuntimeDirectoryPreserve", "s", property_get_exec_preserve_mode, offsetof(ExecContext, runtime_directory_preserve_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST),
@ -1678,6 +1681,41 @@ int bus_exec_context_set_transient_property(
return 1;
} else if (streq(name, "RuntimeDirectoryPreserve")) {
const char *s;
ExecPreserveMode m;
r = sd_bus_message_read(message, "s", &s);
if (r < 0)
return r;
m = exec_preserve_mode_from_string(s);
if (m < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid preserve mode");
if (mode != UNIT_CHECK) {
c->runtime_directory_preserve_mode = m;
unit_write_drop_in_private_format(u, mode, name, "RuntimeDirectoryPreserve=%s", exec_preserve_mode_to_string(m));
}
return 1;
} else if (streq(name, "RuntimeDirectoryMode")) {
mode_t m;
r = sd_bus_message_read(message, "u", &m);
if (r < 0)
return r;
if (mode != UNIT_CHECK) {
c->runtime_directory_mode = m;
unit_write_drop_in_private_format(u, mode, name, "RuntimeDirectoryMode=%040o", m);
}
return 1;
} else if (streq(name, "RuntimeDirectory")) {
_cleanup_strv_free_ char **l = NULL;
char **p;

View file

@ -3428,6 +3428,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode);
fprintf(f, "%sRuntimeDirectoryPreserve: %s\n", prefix, exec_preserve_mode_to_string(c->runtime_directory_preserve_mode));
STRV_FOREACH(d, c->runtime_directory)
fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d);
@ -4160,3 +4162,11 @@ static const char* const exec_utmp_mode_table[_EXEC_UTMP_MODE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(exec_utmp_mode, ExecUtmpMode);
static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = {
[EXEC_PRESERVE_NO] = "no",
[EXEC_PRESERVE_YES] = "yes",
[EXEC_PRESERVE_RESTART] = "restart",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES);

View file

@ -72,6 +72,14 @@ typedef enum ExecOutput {
_EXEC_OUTPUT_INVALID = -1
} ExecOutput;
typedef enum ExecPreserveMode {
EXEC_PRESERVE_NO,
EXEC_PRESERVE_YES,
EXEC_PRESERVE_RESTART,
_EXEC_PRESERVE_MODE_MAX,
_EXEC_PRESERVE_MODE_INVALID = -1
} ExecPreserveMode;
struct ExecStatus {
dual_timestamp start_timestamp;
dual_timestamp exit_timestamp;
@ -211,6 +219,7 @@ struct ExecContext {
char **runtime_directory;
mode_t runtime_directory_mode;
ExecPreserveMode runtime_directory_preserve_mode;
bool memory_deny_write_execute;
bool restrict_realtime;
@ -330,3 +339,6 @@ ExecInput exec_input_from_string(const char *s) _pure_;
const char* exec_utmp_mode_to_string(ExecUtmpMode i) _const_;
ExecUtmpMode exec_utmp_mode_from_string(const char *s) _pure_;
const char* exec_preserve_mode_to_string(ExecPreserveMode i) _const_;
ExecPreserveMode exec_preserve_mode_from_string(const char *s) _pure_;

View file

@ -105,6 +105,7 @@ $1.MountFlags, config_parse_exec_mount_flags, 0,
$1.MountAPIVFS, config_parse_bool, 0, offsetof($1, exec_context.mount_apivfs)
$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.RuntimeDirectoryPreserve, config_parse_runtime_preserve_mode, 0, offsetof($1, exec_context.runtime_directory_preserve_mode)
$1.RuntimeDirectory, config_parse_runtime_directory, 0, offsetof($1, exec_context.runtime_directory)
m4_ifdef(`HAVE_PAM',
`$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name)',

View file

@ -3701,6 +3701,8 @@ int config_parse_job_mode_isolate(
return 0;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
int config_parse_runtime_directory(
const char *unit,
const char *filename,

View file

@ -102,6 +102,7 @@ int config_parse_exec_selinux_context(const char *unit, const char *filename, un
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_exec_smack_process_label(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_preserve_mode(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);
int config_parse_set_status(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_namespace_path_strv(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);

View file

@ -1480,6 +1480,18 @@ static bool service_shall_restart(Service *s) {
}
}
static bool service_will_restart(Service *s) {
assert(s);
if (s->state == SERVICE_AUTO_RESTART)
return true;
if (!UNIT(s)->job)
return false;
if (UNIT(s)->job->type == JOB_START)
return true;
return false;
}
static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
int r;
assert(s);
@ -1510,8 +1522,10 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
exec_runtime_destroy(s->exec_runtime);
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
/* Also, remove the runtime directory */
exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
if (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_NO ||
(s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_RESTART && !service_will_restart(s)))
/* Also, remove the runtime directory */
exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
/* Get rid of the IPC bits of the user */
unit_unref_uid_gid(UNIT(s), true);

View file

@ -267,7 +267,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
"Description", "Slice", "Type", "WorkingDirectory",
"RootDirectory", "SyslogIdentifier", "ProtectSystem",
"ProtectHome", "SELinuxContext", "Restart", "RootImage",
"NotifyAccess"))
"NotifyAccess", "RuntimeDirectoryPreserve"))
r = sd_bus_message_append(m, "v", "s", eq);
else if (streq(field, "SyslogLevel")) {
@ -548,6 +548,15 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_close_container(m);
} else if (streq(field, "RuntimeDirectoryMode")) {
mode_t mode;
r = parse_mode(eq, &mode);
if (r < 0)
return log_error_errno(r, "Failed to parse %s value %s", field, eq);
r = sd_bus_message_append(m, "v", "u", mode);
} else if (streq(field, "RuntimeDirectory")) {
const char *p;