/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-***/
#include <sys/mount.h>
#include <sys/prctl.h>
-#include <stdio_ext.h>
#if HAVE_SECCOMP
#include <seccomp.h>
#include "ioprio.h"
#include "journal-util.h"
#include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
#include "namespace.h"
#include "parse-util.h"
#include "path-util.h"
assert(reply);
assert(c);
- return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
+ return sd_bus_message_append_array(reply, 'y', c->cpu_set.set, c->cpu_set.allocated);
}
static int property_get_timer_slack_nsec(
SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogLevelMax", "i", bus_property_get_int, offsetof(ExecContext, log_level_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LogRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(ExecContext, log_rate_limit_interval_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LogRateLimitBurst", "u", bus_property_get_unsigned, offsetof(ExecContext, log_rate_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogExtraFields", "aay", property_get_log_extra_fields, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CapabilityBoundingSet", "t", NULL, offsetof(ExecContext, capability_bounding_set), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ConfigurationDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].paths), 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),
+ SD_BUS_PROPERTY("RestrictSUIDSGID", "b", bus_property_get_bool, offsetof(ExecContext, restrict_suid_sgid), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestrictNamespaces", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BindPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BindReadOnlyPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TemporaryFileSystem", "a(ss)", property_get_temporary_filesystems, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MountAPIVFS", "b", bus_property_get_bool, offsetof(ExecContext, mount_apivfs), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KeyringMode", "s", property_get_exec_keyring_mode, offsetof(ExecContext, keyring_mode), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ProtectHostname", "b", bus_property_get_bool, offsetof(ExecContext, protect_hostname), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NetworkNamespacePath", "s", NULL, offsetof(ExecContext, network_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
/* Obsolete/redundant properties: */
SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
return sd_bus_message_close_container(reply);
}
+static int append_exec_ex_command(sd_bus_message *reply, ExecCommand *c) {
+ _cleanup_strv_free_ char **ex_opts = NULL;
+ int r;
+
+ assert(reply);
+ assert(c);
+
+ if (!c->path)
+ return 0;
+
+ r = sd_bus_message_open_container(reply, 'r', "sasasttttuii");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "s", c->path);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append_strv(reply, c->argv);
+ if (r < 0)
+ return r;
+
+ r = exec_command_flags_to_strv(c->flags, &ex_opts);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append_strv(reply, ex_opts);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "ttttuii",
+ c->exec_status.start_timestamp.realtime,
+ c->exec_status.start_timestamp.monotonic,
+ c->exec_status.exit_timestamp.realtime,
+ c->exec_status.exit_timestamp.monotonic,
+ (uint32_t) c->exec_status.pid,
+ (int32_t) c->exec_status.code,
+ (int32_t) c->exec_status.status);
+ if (r < 0)
+ return r;
+
+ return sd_bus_message_close_container(reply);
+}
+
int bus_property_get_exec_command(
sd_bus *bus,
const char *path,
return sd_bus_message_close_container(reply);
}
+int bus_property_get_exec_ex_command_list(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *ret_error) {
+
+ ExecCommand *c, *exec_command = *(ExecCommand**) userdata;
+ int r;
+
+ assert(bus);
+ assert(reply);
+
+ r = sd_bus_message_open_container(reply, 'a', "(sasasttttuii)");
+ if (r < 0)
+ return r;
+
+ LIST_FOREACH(command, c, exec_command) {
+ r = append_exec_ex_command(reply, c);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(reply);
+}
+
+static char *exec_command_flags_to_exec_chars(ExecCommandFlags flags) {
+ char *res = NULL;
+
+ asprintf(&res, "%s%s%s%s%s",
+ FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE) ? "-" : "",
+ FLAGS_SET(flags, EXEC_COMMAND_NO_ENV_EXPAND) ? ":" : "",
+ FLAGS_SET(flags, EXEC_COMMAND_FULLY_PRIVILEGED) ? "+" : "",
+ FLAGS_SET(flags, EXEC_COMMAND_NO_SETUID) ? "!" : "",
+ FLAGS_SET(flags, EXEC_COMMAND_AMBIENT_MAGIC) ? "!!" : "");
+
+ return res;
+}
+
int bus_set_transient_exec_command(
Unit *u,
const char *name,
sd_bus_message *message,
UnitWriteFlags flags,
sd_bus_error *error) {
+ bool is_ex_prop = endswith(name, "Ex");
unsigned n = 0;
int r;
- r = sd_bus_message_enter_container(message, 'a', "(sasb)");
+ r = sd_bus_message_enter_container(message, 'a', is_ex_prop ? "(sasas)" : "(sasb)");
if (r < 0)
return r;
- while ((r = sd_bus_message_enter_container(message, 'r', "sasb")) > 0) {
- _cleanup_strv_free_ char **argv = NULL;
+ while ((r = sd_bus_message_enter_container(message, 'r', is_ex_prop ? "sasas" : "sasb")) > 0) {
+ _cleanup_strv_free_ char **argv = NULL, **ex_opts = NULL;
const char *path;
int b;
if (r < 0)
return r;
- r = sd_bus_message_read(message, "b", &b);
+ r = is_ex_prop ? sd_bus_message_read_strv(message, &ex_opts) : sd_bus_message_read(message, "b", &b);
if (r < 0)
return r;
c->argv = TAKE_PTR(argv);
- c->flags = b ? EXEC_COMMAND_IGNORE_FAILURE : 0;
+ if (is_ex_prop) {
+ r = exec_command_flags_from_strv(ex_opts, &c->flags);
+ if (r < 0)
+ return r;
+ } else
+ c->flags = b ? EXEC_COMMAND_IGNORE_FAILURE : 0;
path_simplify(c->path, false);
exec_command_append_list(exec_command, c);
if (n == 0)
*exec_command = exec_command_free_list(*exec_command);
- f = open_memstream(&buf, &size);
+ f = open_memstream_unlocked(&buf, &size);
if (!f)
return -ENOMEM;
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
-
fputs("ExecStart=\n", f);
LIST_FOREACH(command, c, *exec_command) {
- _cleanup_free_ char *a = NULL, *t = NULL;
+ _cleanup_free_ char *a = NULL, *t = NULL, *exec_chars = NULL;
const char *p;
p = unit_escape_setting(c->path, UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS, &t);
if (!a)
return -ENOMEM;
- fprintf(f, "%s=%s@%s %s\n",
- name,
- c->flags & EXEC_COMMAND_IGNORE_FAILURE ? "-" : "",
- p,
- a);
+ exec_chars = exec_command_flags_to_exec_chars(c->flags);
+ if (!exec_chars)
+ return -ENOMEM;
+
+ fprintf(f, "%s=%s@%s %s\n", name, exec_chars, p, a);
}
r = fflush_and_check(f);
#if HAVE_SECCOMP
static BUS_DEFINE_SET_TRANSIENT_IS_VALID(errno, "i", int32_t, int, "%" PRIi32, errno_is_valid);
#endif
-static BUS_DEFINE_SET_TRANSIENT_IS_VALID(sched_priority, "i", int32_t, int, "%" PRIi32, sched_priority_is_valid);
-static BUS_DEFINE_SET_TRANSIENT_IS_VALID(nice, "i", int32_t, int, "%" PRIi32, nice_is_valid);
static BUS_DEFINE_SET_TRANSIENT_PARSE(std_input, ExecInput, exec_input_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(std_output, ExecOutput, exec_output_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(utmp_mode, ExecUtmpMode, exec_utmp_mode_from_string);
-static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_system, ProtectSystem, protect_system_or_bool_from_string);
-static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_home, ProtectHome, protect_home_or_bool_from_string);
+static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_system, ProtectSystem, protect_system_from_string);
+static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_home, ProtectHome, protect_home_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(keyring_mode, ExecKeyringMode, exec_keyring_mode_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE(preserve_mode, ExecPreserveMode, exec_preserve_mode_from_string);
static BUS_DEFINE_SET_TRANSIENT_PARSE_PTR(personality, unsigned long, parse_personality);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(secure_bits, "i", int32_t, int, "%" PRIi32, secure_bits_to_string_alloc_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(capability, "t", uint64_t, uint64_t, "%" PRIu64, capability_set_to_string_alloc);
-static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(sched_policy, "i", int32_t, int, "%" PRIi32, sched_policy_to_string_alloc_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(namespace_flag, "t", uint64_t, unsigned long, "%" PRIu64, namespace_flags_to_string);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(mount_flags, "t", uint64_t, unsigned long, "%" PRIu64, mount_propagation_flags_to_string_with_check);
if (streq(name, "LogLevelMax"))
return bus_set_transient_log_level(u, name, &c->log_level_max, message, flags, error);
- if (streq(name, "CPUSchedulingPriority"))
- return bus_set_transient_sched_priority(u, name, &c->cpu_sched_priority, message, flags, error);
+ if (streq(name, "LogRateLimitIntervalUSec"))
+ return bus_set_transient_usec(u, name, &c->log_rate_limit_interval_usec, message, flags, error);
+
+ if (streq(name, "LogRateLimitBurst"))
+ return bus_set_transient_unsigned(u, name, &c->log_rate_limit_burst, message, flags, error);
if (streq(name, "Personality"))
return bus_set_transient_personality(u, name, &c->personality, message, flags, error);
- if (streq(name, "Nice"))
- return bus_set_transient_nice(u, name, &c->nice, message, flags, error);
-
if (streq(name, "StandardInput"))
return bus_set_transient_std_input(u, name, &c->std_input, message, flags, error);
if (streq(name, "RestrictRealtime"))
return bus_set_transient_bool(u, name, &c->restrict_realtime, message, flags, error);
+ if (streq(name, "RestrictSUIDSGID"))
+ return bus_set_transient_bool(u, name, &c->restrict_suid_sgid, message, flags, error);
+
if (streq(name, "DynamicUser"))
return bus_set_transient_bool(u, name, &c->dynamic_user, message, flags, error);
if (streq(name, "LockPersonality"))
return bus_set_transient_bool(u, name, &c->lock_personality, message, flags, error);
+ if (streq(name, "ProtectHostname"))
+ return bus_set_transient_bool(u, name, &c->protect_hostname, message, flags, error);
+
if (streq(name, "UtmpIdentifier"))
return bus_set_transient_string(u, name, &c->utmp_id, message, flags, error);
if (streq(name, "AmbientCapabilities"))
return bus_set_transient_capability(u, name, &c->capability_ambient_set, message, flags, error);
- if (streq(name, "CPUSchedulingPolicy"))
- return bus_set_transient_sched_policy(u, name, &c->cpu_sched_policy, message, flags, error);
-
if (streq(name, "RestrictNamespaces"))
return bus_set_transient_namespace_flag(u, name, &c->restrict_namespaces, message, flags, error);
if (streq(name, "MountFlags"))
return bus_set_transient_mount_flags(u, name, &c->mount_flags, message, flags, error);
+ if (streq(name, "NetworkNamespacePath"))
+ return bus_set_transient_path(u, name, &c->network_namespace_path, message, flags, error);
+
if (streq(name, "SupplementaryGroups")) {
_cleanup_strv_free_ char **l = NULL;
char **p;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
_cleanup_free_ char *joined = NULL;
- bool invert = !whitelist;
+ SeccompParseFlags invert_flag = whitelist ? 0 : SECCOMP_PARSE_INVERT;
char **s;
if (strv_isempty(l)) {
c->syscall_whitelist = whitelist;
if (c->syscall_whitelist) {
- r = seccomp_parse_syscall_filter("@default", -1, c->syscall_filter, SECCOMP_PARSE_WHITELIST | (invert ? SECCOMP_PARSE_INVERT : 0));
+ r = seccomp_parse_syscall_filter("@default",
+ -1,
+ c->syscall_filter,
+ SECCOMP_PARSE_WHITELIST | invert_flag,
+ u->id,
+ NULL, 0);
if (r < 0)
return r;
}
if (r < 0)
return r;
- r = seccomp_parse_syscall_filter(n, e, c->syscall_filter, (invert ? SECCOMP_PARSE_INVERT : 0) | (c->syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0));
+ r = seccomp_parse_syscall_filter(n,
+ e,
+ c->syscall_filter,
+ (c->syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0) | invert_flag,
+ u->id,
+ NULL, 0);
if (r < 0)
return r;
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
_cleanup_free_ char *joined = NULL;
- bool invert = !whitelist;
char **s;
if (strv_isempty(l)) {
int af;
af = af_from_name(*s);
- if (af <= 0)
- return -EINVAL;
+ if (af < 0)
+ return af;
- if (!invert == c->address_families_whitelist) {
+ if (whitelist == c->address_families_whitelist) {
r = set_put(c->address_families, INT_TO_PTR(af));
if (r < 0)
return r;
#endif
if (streq(name, "CPUAffinity")) {
const void *a;
- size_t n = 0;
+ size_t n;
+ _cleanup_(cpu_set_reset) CPUSet set = {};
r = sd_bus_message_read_array(message, 'y', &a, &n);
if (r < 0)
return r;
+ r = cpu_set_from_dbus(a, n, &set);
+ if (r < 0)
+ return r;
+
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (n == 0) {
- c->cpuset = cpu_set_mfree(c->cpuset);
- c->cpuset_ncpus = 0;
+ cpu_set_reset(&c->cpu_set);
unit_write_settingf(u, flags, name, "%s=", name);
} else {
_cleanup_free_ char *str = NULL;
- size_t allocated = 0, len = 0, i, ncpus;
- ncpus = CPU_SIZE_TO_NUM(n);
+ str = cpu_set_to_string(&set);
+ if (!str)
+ return -ENOMEM;
- for (i = 0; i < ncpus; i++) {
- _cleanup_free_ char *p = NULL;
- size_t add;
+ /* We forego any optimizations here, and always create the structure using
+ * cpu_set_add_all(), because we don't want to care if the existing size we
+ * got over dbus is appropriate. */
+ r = cpu_set_add_all(&c->cpu_set, &set);
+ if (r < 0)
+ return r;
- if (!CPU_ISSET_S(i, n, (cpu_set_t*) a))
- continue;
+ unit_write_settingf(u, flags, name, "%s=%s", name, str);
+ }
+ }
- r = asprintf(&p, "%zu", i);
- if (r < 0)
- return -ENOMEM;
+ return 1;
- add = strlen(p);
+ } else if (streq(name, "Nice")) {
+ int32_t q;
- if (!GREEDY_REALLOC(str, allocated, len + add + 2))
- return -ENOMEM;
+ r = sd_bus_message_read(message, "i", &q);
+ if (r < 0)
+ return r;
- strcpy(mempcpy(str + len, p, add), " ");
- len += add + 1;
- }
+ if (!nice_is_valid(q))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Nice value: %i", q);
- if (len != 0)
- str[len - 1] = '\0';
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ c->nice = q;
+ c->nice_set = true;
- if (!c->cpuset || c->cpuset_ncpus < ncpus) {
- cpu_set_t *cpuset;
+ unit_write_settingf(u, flags, name, "Nice=%i", q);
+ }
- cpuset = CPU_ALLOC(ncpus);
- if (!cpuset)
- return -ENOMEM;
+ return 1;
- CPU_ZERO_S(n, cpuset);
- if (c->cpuset) {
- CPU_OR_S(CPU_ALLOC_SIZE(c->cpuset_ncpus), cpuset, c->cpuset, (cpu_set_t*) a);
- CPU_FREE(c->cpuset);
- } else
- CPU_OR_S(n, cpuset, cpuset, (cpu_set_t*) a);
+ } else if (streq(name, "CPUSchedulingPolicy")) {
+ int32_t q;
- c->cpuset = cpuset;
- c->cpuset_ncpus = ncpus;
- } else
- CPU_OR_S(n, c->cpuset, c->cpuset, (cpu_set_t*) a);
+ r = sd_bus_message_read(message, "i", &q);
+ if (r < 0)
+ return r;
- unit_write_settingf(u, flags, name, "%s=%s", name, str);
- }
+ if (!sched_policy_is_valid(q))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling policy: %i", q);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ _cleanup_free_ char *s = NULL;
+
+ r = sched_policy_to_string_alloc(q, &s);
+ if (r < 0)
+ return r;
+
+ c->cpu_sched_policy = q;
+ c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(q), sched_get_priority_max(q));
+ c->cpu_sched_set = true;
+
+ unit_write_settingf(u, flags, name, "CPUSchedulingPolicy=%s", s);
+ }
+
+ return 1;
+
+ } else if (streq(name, "CPUSchedulingPriority")) {
+ int32_t p, min, max;
+
+ r = sd_bus_message_read(message, "i", &p);
+ if (r < 0)
+ return r;
+
+ min = sched_get_priority_min(c->cpu_sched_policy);
+ max = sched_get_priority_max(c->cpu_sched_policy);
+ if (p < min || p > max)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling priority: %i", p);
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ c->cpu_sched_priority = p;
+ c->cpu_sched_set = true;
+
+ unit_write_settingf(u, flags, name, "CPUSchedulingPriority=%i", p);
}
return 1;
return 1;
- } else if (STR_IN_SET(name, "StandardInputFile", "StandardOutputFile", "StandardErrorFile")) {
+ } else if (STR_IN_SET(name,
+ "StandardInputFile",
+ "StandardOutputFile", "StandardOutputFileToAppend",
+ "StandardErrorFile", "StandardErrorFileToAppend")) {
const char *s;
r = sd_bus_message_read(message, "s", &s);
c->std_input = EXEC_INPUT_FILE;
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=file:%s", s);
- } else if (streq(name, "StandardOutputFile")) {
+ } else if (STR_IN_SET(name, "StandardOutputFile", "StandardOutputFileToAppend")) {
r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], empty_to_null(s));
if (r < 0)
return r;
- c->std_output = EXEC_OUTPUT_FILE;
- unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
-
+ if (streq(name, "StandardOutputFile")) {
+ c->std_output = EXEC_OUTPUT_FILE;
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
+ } else {
+ assert(streq(name, "StandardOutputFileToAppend"));
+ c->std_output = EXEC_OUTPUT_FILE_APPEND;
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=append:%s", s);
+ }
} else {
- assert(streq(name, "StandardErrorFile"));
+ assert(STR_IN_SET(name, "StandardErrorFile", "StandardErrorFileToAppend"));
r = free_and_strdup(&c->stdio_file[STDERR_FILENO], empty_to_null(s));
if (r < 0)
return r;
- c->std_error = EXEC_OUTPUT_FILE;
- unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=file:%s", s);
+ if (streq(name, "StandardErrorFile")) {
+ c->std_error = EXEC_OUTPUT_FILE;
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=file:%s", s);
+ } else {
+ assert(streq(name, "StandardErrorFileToAppend"));
+ c->std_error = EXEC_OUTPUT_FILE_APPEND;
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=append:%s", s);
+ }
}
}
if (r < 0)
return r;
- f = open_memstream(&joined, &size);
+ f = open_memstream_unlocked(&joined, &size);
if (!f)
return -ENOMEM;
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
-
fputs("EnvironmentFile=\n", f);
STRV_FOREACH(i, c->environment_files) {
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- char ***dirs = NULL;
ExecDirectoryType i;
+ ExecDirectory *d;
- for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++)
- if (streq(name, exec_directory_type_to_string(i))) {
- dirs = &c->directories[i].paths;
- break;
- }
-
- assert(dirs);
+ assert_se((i = exec_directory_type_from_string(name)) >= 0);
+ d = c->directories + i;
if (strv_isempty(l)) {
- *dirs = strv_free(*dirs);
+ d->paths = strv_free(d->paths);
unit_write_settingf(u, flags, name, "%s=", name);
} else {
_cleanup_free_ char *joined = NULL;
- r = strv_extend_strv(dirs, l, true);
+ r = strv_extend_strv(&d->paths, l, true);
if (r < 0)
- return -ENOMEM;
+ return r;
joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS);
if (!joined)