<option>null</option>,
<option>tty</option>,
<option>tty-force</option>,
- <option>tty-fail</option> or
- <option>socket</option>.</para>
+ <option>tty-fail</option>,
+ <option>socket</option> or
+ <option>fd</option>.</para>
<para>If <option>null</option> is selected, standard input
will be connected to <filename>/dev/null</filename>, i.e. all
<citerefentry project='freebsd'><refentrytitle>inetd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
daemon.</para>
+ <para>The <option>fd</option> option connects
+ the input stream to a single file descriptor provided by a socket unit.
+ A custom named file descriptor can be specified as part of this option,
+ after a <literal>:</literal> (e.g. <literal>fd:<replaceable>foobar</replaceable></literal>).
+ If no name is specified, <literal>stdin</literal> is assumed
+ (i.e. <literal>fd</literal> is equivalent to <literal>fd:stdin</literal>).
+ At least one socket unit defining such name must be explicitly provided via the
+ <varname>Sockets=</varname> option, and file descriptor name may differ
+ from the name of its containing socket unit.
+ If multiple matches are found, the first one will be used.
+ See <varname>FileDescriptorName=</varname> in
+ <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for more details about named descriptors and ordering.</para>
+
<para>This setting defaults to
<option>null</option>.</para></listitem>
</varlistentry>
<option>kmsg</option>,
<option>journal+console</option>,
<option>syslog+console</option>,
- <option>kmsg+console</option> or
- <option>socket</option>.</para>
+ <option>kmsg+console</option>,
+ <option>socket</option> or
+ <option>fd</option>.</para>
<para><option>inherit</option> duplicates the file descriptor
of standard input for standard output.</para>
similar to the same option of
<varname>StandardInput=</varname>.</para>
+ <para>The <option>fd</option> option connects
+ the output stream to a single file descriptor provided by a socket unit.
+ A custom named file descriptor can be specified as part of this option,
+ after a <literal>:</literal> (e.g. <literal>fd:<replaceable>foobar</replaceable></literal>).
+ If no name is specified, <literal>stdout</literal> is assumed
+ (i.e. <literal>fd</literal> is equivalent to <literal>fd:stdout</literal>).
+ At least one socket unit defining such name must be explicitly provided via the
+ <varname>Sockets=</varname> option, and file descriptor name may differ
+ from the name of its containing socket unit.
+ If multiple matches are found, the first one will be used.
+ See <varname>FileDescriptorName=</varname> in
+ <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for more details about named descriptors and ordering.</para>
+
<para>If the standard output (or error output, see below) of a unit is connected to the journal, syslog or the
kernel log buffer, the unit will implicitly gain a dependency of type <varname>After=</varname> on
<filename>systemd-journald.socket</filename> (also see the automatic dependencies section above).</para>
<listitem><para>Controls where file descriptor 2 (STDERR) of
the executed processes is connected to. The available options
are identical to those of <varname>StandardOutput=</varname>,
- with one exception: if set to <option>inherit</option> the
+ with some exceptions: if set to <option>inherit</option> the
file descriptor used for standard output is duplicated for
- standard error. This setting defaults to the value set with
+ standard error, while <option>fd</option> operates on the error
+ stream and will look by default for a descriptor named
+ <literal>stderr</literal>.</para>
+
+ <para>This setting defaults to the value set with
<option>DefaultStandardError=</option> in
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
which defaults to <option>inherit</option>. Note that setting
return sd_bus_message_append(reply, "i", LOG_FAC(c->syslog_priority));
}
+static int property_get_input_fdname(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+ const char *name;
+
+ assert(bus);
+ assert(c);
+ assert(property);
+ assert(reply);
+
+ name = exec_context_fdname(c, STDIN_FILENO);
+
+ return sd_bus_message_append(reply, "s", name);
+}
+
+static int property_get_output_fdname(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+ const char *name = NULL;
+
+ assert(bus);
+ assert(c);
+ assert(property);
+ assert(reply);
+
+ if (c->std_output == EXEC_OUTPUT_NAMED_FD && streq(property, "StandardOutputFileDescriptorName"))
+ name = exec_context_fdname(c, STDOUT_FILENO);
+ else if (c->std_error == EXEC_OUTPUT_NAMED_FD && streq(property, "StandardErrorFileDescriptorName"))
+ name = exec_context_fdname(c, STDERR_FILENO);
+
+ return sd_bus_message_append(reply, "s", name);
+}
+
const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("StandardInputFileDescriptorName", "s", property_get_input_fdname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("StandardOutputFileDescriptorName", "s", property_get_output_fdname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("StandardErrorFileDescriptorName", "s", property_get_output_fdname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
return 1;
-
} else if (streq(name, "StandardOutput")) {
const char *s;
ExecOutput p;
return 1;
} else if (STR_IN_SET(name,
+ "StandardInputFileDescriptorName", "StandardOutputFileDescriptorName", "StandardErrorFileDescriptorName")) {
+ const char *s;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ if (!fdname_is_valid(s))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid file descriptor name");
+
+ if (mode != UNIT_CHECK) {
+ if (streq(name, "StandardInputFileDescriptorName")) {
+ c->std_input = EXEC_INPUT_NAMED_FD;
+ r = free_and_strdup(&c->stdio_fdname[STDIN_FILENO], s);
+ if (r < 0)
+ return r;
+ unit_write_drop_in_private_format(u, mode, name, "StandardInput=fd:%s", s);
+ } else if (streq(name, "StandardOutputFileDescriptorName")) {
+ c->std_output = EXEC_OUTPUT_NAMED_FD;
+ r = free_and_strdup(&c->stdio_fdname[STDOUT_FILENO], s);
+ if (r < 0)
+ return r;
+ unit_write_drop_in_private_format(u, mode, name, "StandardOutput=fd:%s", s);
+ } else if (streq(name, "StandardErrorFileDescriptorName")) {
+ c->std_error = EXEC_OUTPUT_NAMED_FD;
+ r = free_and_strdup(&c->stdio_fdname[STDERR_FILENO], s);
+ if (r < 0)
+ return r;
+ unit_write_drop_in_private_format(u, mode, name, "StandardError=fd:%s", s);
+ }
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name,
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset",
"PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
"NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute",
static int setup_input(
const ExecContext *context,
const ExecParameters *params,
- int socket_fd) {
+ int socket_fd,
+ int named_iofds[3]) {
ExecInput i;
case EXEC_INPUT_SOCKET:
return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
+ case EXEC_INPUT_NAMED_FD:
+ (void) fd_nonblock(named_iofds[STDIN_FILENO], false);
+ return dup2(named_iofds[STDIN_FILENO], STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
+
default:
assert_not_reached("Unknown input type");
}
const ExecParameters *params,
int fileno,
int socket_fd,
+ int named_iofds[3],
const char *ident,
uid_t uid,
gid_t gid,
return fileno;
/* Duplicate from stdout if possible */
- if (e == o || e == EXEC_OUTPUT_INHERIT)
+ if ((e == o && e != EXEC_OUTPUT_NAMED_FD) || e == EXEC_OUTPUT_INHERIT)
return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno;
o = e;
assert(socket_fd >= 0);
return dup2(socket_fd, fileno) < 0 ? -errno : fileno;
+ case EXEC_OUTPUT_NAMED_FD:
+ (void) fd_nonblock(named_iofds[fileno], false);
+ return dup2(named_iofds[fileno], fileno) < 0 ? -errno : fileno;
+
default:
assert_not_reached("Unknown error type");
}
DynamicCreds *dcreds,
char **argv,
int socket_fd,
+ int named_iofds[3],
int *fds, unsigned n_fds,
char **files_env,
int user_lookup_fd,
if (socket_fd >= 0)
(void) fd_nonblock(socket_fd, false);
- r = setup_input(context, params, socket_fd);
+ r = setup_input(context, params, socket_fd, named_iofds);
if (r < 0) {
*exit_status = EXIT_STDIN;
return r;
}
- r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
+ r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDOUT;
return r;
}
- r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
+ r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDERR;
return r;
int *fds = NULL; unsigned n_fds = 0;
_cleanup_free_ char *line = NULL;
int socket_fd, r;
+ int named_iofds[3] = { -1, -1, -1 };
char **argv;
pid_t pid;
n_fds = params->n_fds;
}
+ r = exec_context_named_iofds(unit, context, params, named_iofds);
+ if (r < 0)
+ return log_unit_error_errno(unit, r, "Failed to load a named file descriptor: %m");
+
r = exec_context_load_environment(unit, context, &files_env);
if (r < 0)
return log_unit_error_errno(unit, r, "Failed to load environment files: %m");
dcreds,
argv,
socket_fd,
+ named_iofds,
fds, n_fds,
files_env,
unit->manager->user_lookup_fds[1],
for (l = 0; l < ELEMENTSOF(c->rlimit); l++)
c->rlimit[l] = mfree(c->rlimit[l]);
+ for (l = 0; l < 3; l++)
+ c->stdio_fdname[l] = mfree(c->stdio_fdname[l]);
+
c->working_directory = mfree(c->working_directory);
c->root_directory = mfree(c->root_directory);
c->tty_path = mfree(c->tty_path);
log_unit_error(info->unit, "Ignoring invalid environment assignment '%s': %s", p, info->path);
}
+const char* exec_context_fdname(const ExecContext *c, int fd_index) {
+ assert(c);
+
+ switch (fd_index) {
+ case STDIN_FILENO:
+ if (c->std_input != EXEC_INPUT_NAMED_FD)
+ return NULL;
+ return c->stdio_fdname[STDIN_FILENO] ?: "stdin";
+ case STDOUT_FILENO:
+ if (c->std_output != EXEC_OUTPUT_NAMED_FD)
+ return NULL;
+ return c->stdio_fdname[STDOUT_FILENO] ?: "stdout";
+ case STDERR_FILENO:
+ if (c->std_error != EXEC_OUTPUT_NAMED_FD)
+ return NULL;
+ return c->stdio_fdname[STDERR_FILENO] ?: "stderr";
+ default:
+ return NULL;
+ }
+}
+
+int exec_context_named_iofds(Unit *unit, const ExecContext *c, const ExecParameters *p, int named_iofds[3]) {
+ unsigned i, targets;
+ const char *stdio_fdname[3];
+
+ assert(c);
+ assert(p);
+
+ targets = (c->std_input == EXEC_INPUT_NAMED_FD) +
+ (c->std_output == EXEC_OUTPUT_NAMED_FD) +
+ (c->std_error == EXEC_OUTPUT_NAMED_FD);
+
+ for (i = 0; i < 3; i++)
+ stdio_fdname[i] = exec_context_fdname(c, i);
+
+ for (i = 0; i < p->n_fds && targets > 0; i++)
+ if (named_iofds[STDIN_FILENO] < 0 && c->std_input == EXEC_INPUT_NAMED_FD && stdio_fdname[STDIN_FILENO] && streq(p->fd_names[i], stdio_fdname[STDIN_FILENO])) {
+ named_iofds[STDIN_FILENO] = p->fds[i];
+ targets--;
+ } else if (named_iofds[STDOUT_FILENO] < 0 && c->std_output == EXEC_OUTPUT_NAMED_FD && stdio_fdname[STDOUT_FILENO] && streq(p->fd_names[i], stdio_fdname[STDOUT_FILENO])) {
+ named_iofds[STDOUT_FILENO] = p->fds[i];
+ targets--;
+ } else if (named_iofds[STDERR_FILENO] < 0 && c->std_error == EXEC_OUTPUT_NAMED_FD && stdio_fdname[STDERR_FILENO] && streq(p->fd_names[i], stdio_fdname[STDERR_FILENO])) {
+ named_iofds[STDERR_FILENO] = p->fds[i];
+ targets--;
+ }
+
+ return (targets == 0 ? 0 : -ENOENT);
+}
+
int exec_context_load_environment(Unit *unit, const ExecContext *c, char ***l) {
char **i, **r = NULL;
[EXEC_INPUT_TTY] = "tty",
[EXEC_INPUT_TTY_FORCE] = "tty-force",
[EXEC_INPUT_TTY_FAIL] = "tty-fail",
- [EXEC_INPUT_SOCKET] = "socket"
+ [EXEC_INPUT_SOCKET] = "socket",
+ [EXEC_INPUT_NAMED_FD] = "fd",
};
DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
[EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
[EXEC_OUTPUT_JOURNAL] = "journal",
[EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
- [EXEC_OUTPUT_SOCKET] = "socket"
+ [EXEC_OUTPUT_SOCKET] = "socket",
+ [EXEC_OUTPUT_NAMED_FD] = "fd",
};
DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
EXEC_INPUT_TTY_FORCE,
EXEC_INPUT_TTY_FAIL,
EXEC_INPUT_SOCKET,
+ EXEC_INPUT_NAMED_FD,
_EXEC_INPUT_MAX,
_EXEC_INPUT_INVALID = -1
} ExecInput;
EXEC_OUTPUT_JOURNAL,
EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
EXEC_OUTPUT_SOCKET,
+ EXEC_OUTPUT_NAMED_FD,
_EXEC_OUTPUT_MAX,
_EXEC_OUTPUT_INVALID = -1
} ExecOutput;
ExecInput std_input;
ExecOutput std_output;
ExecOutput std_error;
+ char *stdio_fdname[3];
nsec_t timer_slack_nsec;
int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_root);
int exec_context_load_environment(Unit *unit, const ExecContext *c, char ***l);
+int exec_context_named_iofds(Unit *unit, const ExecContext *c, const ExecParameters *p, int named_iofds[3]);
+const char* exec_context_fdname(const ExecContext *c, int fd_index);
bool exec_context_may_touch_console(ExecContext *c);
bool exec_context_maintains_privileges(ExecContext *c);
$1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files)
$1.PassEnvironment, config_parse_pass_environ, 0, offsetof($1, exec_context.pass_environment)
$1.DynamicUser, config_parse_bool, 0, offsetof($1, exec_context.dynamic_user)
-$1.StandardInput, config_parse_input, 0, offsetof($1, exec_context.std_input)
-$1.StandardOutput, config_parse_output, 0, offsetof($1, exec_context.std_output)
-$1.StandardError, config_parse_output, 0, offsetof($1, exec_context.std_error)
+$1.StandardInput, config_parse_exec_input, 0, offsetof($1, exec_context)
+$1.StandardOutput, config_parse_exec_output, 0, offsetof($1, exec_context)
+$1.StandardError, config_parse_exec_output, 0, offsetof($1, exec_context)
$1.TTYPath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.tty_path)
$1.TTYReset, config_parse_bool, 0, offsetof($1, exec_context.tty_reset)
$1.TTYVHangup, config_parse_bool, 0, offsetof($1, exec_context.tty_vhangup)
return 0;
}
-DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input literal specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output literal specifier");
+
+int config_parse_exec_input(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) {
+ ExecContext *c = data;
+ const char *name;
+ int r;
+
+ assert(data);
+ assert(filename);
+ assert(line);
+ assert(rvalue);
+
+ name = startswith(rvalue, "fd:");
+ if (name) {
+ /* Strip prefix and validate fd name */
+ if (!fdname_is_valid(name)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", name);
+ return 0;
+ }
+ c->std_input = EXEC_INPUT_NAMED_FD;
+ r = free_and_strdup(&c->stdio_fdname[STDIN_FILENO], name);
+ if (r < 0)
+ log_oom();
+ return r;
+ } else {
+ ExecInput ei = exec_input_from_string(rvalue);
+ if (ei == _EXEC_INPUT_INVALID)
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse input specifier, ignoring: %s", rvalue);
+ else
+ c->std_input = ei;
+ return 0;
+ }
+}
+
+int config_parse_exec_output(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) {
+ ExecContext *c = data;
+ ExecOutput eo;
+ const char *name;
+ int r;
+
+ assert(data);
+ assert(filename);
+ assert(line);
+ assert(lvalue);
+ assert(rvalue);
+
+ name = startswith(rvalue, "fd:");
+ if (name) {
+ /* Strip prefix and validate fd name */
+ if (!fdname_is_valid(name)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", name);
+ return 0;
+ }
+ eo = EXEC_OUTPUT_NAMED_FD;
+ } else {
+ eo = exec_output_from_string(rvalue);
+ if (eo == _EXEC_OUTPUT_INVALID) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output specifier, ignoring: %s", rvalue);
+ return 0;
+ }
+ }
+
+ if (streq(lvalue, "StandardOutput")) {
+ c->std_output = eo;
+ r = free_and_strdup(&c->stdio_fdname[STDOUT_FILENO], name);
+ if (r < 0)
+ log_oom();
+ return r;
+ } else if (streq(lvalue, "StandardError")) {
+ c->std_error = eo;
+ r = free_and_strdup(&c->stdio_fdname[STDERR_FILENO], name);
+ if (r < 0)
+ log_oom();
+ return r;
+ } else {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output property, ignoring: %s", lvalue);
+ return 0;
+ }
+}
int config_parse_exec_io_class(const char *unit,
const char *filename,
{ config_parse_exec_cpu_affinity, "CPUAFFINITY" },
{ config_parse_mode, "MODE" },
{ config_parse_unit_env_file, "FILE" },
- { config_parse_output, "OUTPUT" },
- { config_parse_input, "INPUT" },
+ { config_parse_exec_output, "OUTPUT" },
+ { config_parse_exec_input, "INPUT" },
{ config_parse_log_facility, "FACILITY" },
{ config_parse_log_level, "LEVEL" },
{ config_parse_exec_secure_bits, "SECUREBITS" },
int config_parse_service_type(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_service_restart(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_socket_bindtodevice(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_output(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_output(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_input(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_input(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_io_class(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_io_priority(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);
return r;
}
- if (c->std_output != EXEC_OUTPUT_KMSG &&
- c->std_output != EXEC_OUTPUT_SYSLOG &&
- c->std_output != EXEC_OUTPUT_JOURNAL &&
- c->std_output != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
- c->std_output != EXEC_OUTPUT_SYSLOG_AND_CONSOLE &&
- c->std_output != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
- c->std_error != EXEC_OUTPUT_KMSG &&
- c->std_error != EXEC_OUTPUT_SYSLOG &&
- c->std_error != EXEC_OUTPUT_JOURNAL &&
- c->std_error != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
- c->std_error != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
- c->std_error != EXEC_OUTPUT_SYSLOG_AND_CONSOLE)
+ if (!IN_SET(c->std_output,
+ EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
+ EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE,
+ EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE) &&
+ !IN_SET(c->std_error,
+ EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
+ EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE,
+ EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE))
return 0;
/* If syslog or kernel logging is requested, make sure our own