mirror of
https://github.com/systemd/systemd
synced 2024-10-14 20:17:52 +00:00
core/exec: add a named-descriptor option ("fd") for streams (#4179)
This commit adds a `fd` option to `StandardInput=`, `StandardOutput=` and `StandardError=` properties in order to connect standard streams to externally named descriptors provided by some socket units. This option looks for a file descriptor named as the corresponding stream. Custom names can be specified, separated by a colon. If multiple name-matches exist, the first matching fd will be used.
This commit is contained in:
parent
c7458f9399
commit
52c239d770
|
@ -409,8 +409,9 @@
|
|||
<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
|
||||
|
@ -448,6 +449,20 @@
|
|||
<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>
|
||||
|
@ -464,8 +479,9 @@
|
|||
<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>
|
||||
|
@ -514,6 +530,20 @@
|
|||
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>
|
||||
|
@ -531,9 +561,13 @@
|
|||
<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
|
||||
|
|
|
@ -627,6 +627,53 @@ static int property_get_syslog_facility(
|
|||
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),
|
||||
|
@ -677,8 +724,11 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
|||
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),
|
||||
|
@ -1030,7 +1080,6 @@ int bus_exec_context_set_transient_property(
|
|||
|
||||
return 1;
|
||||
|
||||
|
||||
} else if (streq(name, "StandardOutput")) {
|
||||
const char *s;
|
||||
ExecOutput p;
|
||||
|
@ -1071,6 +1120,41 @@ int bus_exec_context_set_transient_property(
|
|||
|
||||
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",
|
||||
|
|
|
@ -411,7 +411,8 @@ static int fixup_output(ExecOutput std_output, int socket_fd) {
|
|||
static int setup_input(
|
||||
const ExecContext *context,
|
||||
const ExecParameters *params,
|
||||
int socket_fd) {
|
||||
int socket_fd,
|
||||
int named_iofds[3]) {
|
||||
|
||||
ExecInput i;
|
||||
|
||||
|
@ -461,6 +462,10 @@ static int setup_input(
|
|||
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");
|
||||
}
|
||||
|
@ -472,6 +477,7 @@ static int setup_output(
|
|||
const ExecParameters *params,
|
||||
int fileno,
|
||||
int socket_fd,
|
||||
int named_iofds[3],
|
||||
const char *ident,
|
||||
uid_t uid,
|
||||
gid_t gid,
|
||||
|
@ -523,7 +529,7 @@ static int setup_output(
|
|||
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;
|
||||
|
@ -585,6 +591,10 @@ static int setup_output(
|
|||
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");
|
||||
}
|
||||
|
@ -2157,6 +2167,7 @@ static int exec_child(
|
|||
DynamicCreds *dcreds,
|
||||
char **argv,
|
||||
int socket_fd,
|
||||
int named_iofds[3],
|
||||
int *fds, unsigned n_fds,
|
||||
char **files_env,
|
||||
int user_lookup_fd,
|
||||
|
@ -2298,19 +2309,19 @@ static int exec_child(
|
|||
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;
|
||||
|
@ -2829,6 +2840,7 @@ int exec_spawn(Unit *unit,
|
|||
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;
|
||||
|
||||
|
@ -2855,6 +2867,10 @@ int exec_spawn(Unit *unit,
|
|||
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");
|
||||
|
@ -2884,6 +2900,7 @@ int exec_spawn(Unit *unit,
|
|||
dcreds,
|
||||
argv,
|
||||
socket_fd,
|
||||
named_iofds,
|
||||
fds, n_fds,
|
||||
files_env,
|
||||
unit->manager->user_lookup_fds[1],
|
||||
|
@ -2946,6 +2963,9 @@ void exec_context_done(ExecContext *c) {
|
|||
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);
|
||||
|
@ -3044,6 +3064,56 @@ static void invalid_env(const char *p, void *userdata) {
|
|||
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;
|
||||
|
||||
|
@ -3896,7 +3966,8 @@ static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
|
|||
[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);
|
||||
|
@ -3911,7 +3982,8 @@ static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
|
|||
[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);
|
||||
|
|
|
@ -50,6 +50,7 @@ typedef enum ExecInput {
|
|||
EXEC_INPUT_TTY_FORCE,
|
||||
EXEC_INPUT_TTY_FAIL,
|
||||
EXEC_INPUT_SOCKET,
|
||||
EXEC_INPUT_NAMED_FD,
|
||||
_EXEC_INPUT_MAX,
|
||||
_EXEC_INPUT_INVALID = -1
|
||||
} ExecInput;
|
||||
|
@ -65,6 +66,7 @@ typedef enum ExecOutput {
|
|||
EXEC_OUTPUT_JOURNAL,
|
||||
EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
|
||||
EXEC_OUTPUT_SOCKET,
|
||||
EXEC_OUTPUT_NAMED_FD,
|
||||
_EXEC_OUTPUT_MAX,
|
||||
_EXEC_OUTPUT_INVALID = -1
|
||||
} ExecOutput;
|
||||
|
@ -120,6 +122,7 @@ struct ExecContext {
|
|||
ExecInput std_input;
|
||||
ExecOutput std_output;
|
||||
ExecOutput std_error;
|
||||
char *stdio_fdname[3];
|
||||
|
||||
nsec_t timer_slack_nsec;
|
||||
|
||||
|
@ -284,6 +287,8 @@ 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(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);
|
||||
|
|
|
@ -35,9 +35,9 @@ $1.Environment, config_parse_environ, 0,
|
|||
$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)
|
||||
|
|
|
@ -776,8 +776,104 @@ int config_parse_socket_bindtodevice(
|
|||
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,
|
||||
|
@ -4183,8 +4279,8 @@ void unit_dump_config_items(FILE *f) {
|
|||
{ 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" },
|
||||
|
|
|
@ -45,7 +45,9 @@ int config_parse_service_timeout(const char *unit, const char *filename, unsigne
|
|||
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);
|
||||
|
|
|
@ -858,18 +858,14 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
|
|||
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
|
||||
|
|
Loading…
Reference in a new issue