mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
parent
48a0ab391c
commit
566b7d23eb
@ -1756,8 +1756,8 @@ SystemCallErrorNumber=EPERM</programlisting>
|
|||||||
of <option>inherit</option>, <option>null</option>, <option>tty</option>, <option>journal</option>,
|
of <option>inherit</option>, <option>null</option>, <option>tty</option>, <option>journal</option>,
|
||||||
<option>syslog</option>, <option>kmsg</option>, <option>journal+console</option>,
|
<option>syslog</option>, <option>kmsg</option>, <option>journal+console</option>,
|
||||||
<option>syslog+console</option>, <option>kmsg+console</option>,
|
<option>syslog+console</option>, <option>kmsg+console</option>,
|
||||||
<option>file:<replaceable>path</replaceable></option>, <option>socket</option> or
|
<option>file:<replaceable>path</replaceable></option>, <option>append:<replaceable>path</replaceable></option>,
|
||||||
<option>fd:<replaceable>name</replaceable></option>.</para>
|
<option>socket</option> or<option>fd:<replaceable>name</replaceable></option>.</para>
|
||||||
|
|
||||||
<para><option>inherit</option> duplicates the file descriptor of standard input for standard output.</para>
|
<para><option>inherit</option> duplicates the file descriptor of standard input for standard output.</para>
|
||||||
|
|
||||||
@ -1788,11 +1788,17 @@ SystemCallErrorNumber=EPERM</programlisting>
|
|||||||
|
|
||||||
<para>The <option>file:<replaceable>path</replaceable></option> option may be used to connect a specific file
|
<para>The <option>file:<replaceable>path</replaceable></option> option may be used to connect a specific file
|
||||||
system object to standard output. The semantics are similar to the same option of
|
system object to standard output. The semantics are similar to the same option of
|
||||||
<varname>StandardInput=</varname>, see above. If standard input and output are directed to the same file path,
|
<varname>StandardInput=</varname>, see above. If <replaceable>path</replaceable> refers to a regular file
|
||||||
it is opened only once, for reading as well as writing and duplicated. This is particular useful when the
|
on the filesystem, it is opened (created if it doesn't exist yet) for writing at the beginning of the file,
|
||||||
specified path refers to an <constant>AF_UNIX</constant> socket in the file system, as in that case only a
|
but without truncating it.
|
||||||
|
If standard input and output are directed to the same file path, it is opened only once, for reading as well
|
||||||
|
as writing and duplicated. This is particularly useful when the specified path refers to an
|
||||||
|
<constant>AF_UNIX</constant> socket in the file system, as in that case only a
|
||||||
single stream connection is created for both input and output.</para>
|
single stream connection is created for both input and output.</para>
|
||||||
|
|
||||||
|
<para><option>append:<replaceable>path</replaceable></option> is similar to <option>file:<replaceable>path
|
||||||
|
</replaceable></option> above, but it opens the file in append mode.</para>
|
||||||
|
|
||||||
<para><option>socket</option> connects standard output to a socket acquired via socket activation. The
|
<para><option>socket</option> connects standard output to a socket acquired via socket activation. The
|
||||||
semantics are similar to the same option of <varname>StandardInput=</varname>, see above.</para>
|
semantics are similar to the same option of <varname>StandardInput=</varname>, see above.</para>
|
||||||
|
|
||||||
|
@ -1731,7 +1731,10 @@ int bus_exec_context_set_transient_property(
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
} else if (STR_IN_SET(name, "StandardInputFile", "StandardOutputFile", "StandardErrorFile")) {
|
} else if (STR_IN_SET(name,
|
||||||
|
"StandardInputFile",
|
||||||
|
"StandardOutputFile", "StandardOutputFileToCreate", "StandardOutputFileToAppend",
|
||||||
|
"StandardErrorFile", "StandardErrorFileToCreate", "StandardErrorFileToAppend")) {
|
||||||
const char *s;
|
const char *s;
|
||||||
|
|
||||||
r = sd_bus_message_read(message, "s", &s);
|
r = sd_bus_message_read(message, "s", &s);
|
||||||
@ -1755,23 +1758,34 @@ int bus_exec_context_set_transient_property(
|
|||||||
c->std_input = EXEC_INPUT_FILE;
|
c->std_input = EXEC_INPUT_FILE;
|
||||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=file:%s", s);
|
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));
|
r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], empty_to_null(s));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
c->std_output = EXEC_OUTPUT_FILE;
|
if (streq(name, "StandardOutputFile")) {
|
||||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
|
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 {
|
} 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));
|
r = free_and_strdup(&c->stdio_file[STDERR_FILENO], empty_to_null(s));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
c->std_error = EXEC_OUTPUT_FILE;
|
if (streq(name, "StandardErrorFile")) {
|
||||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=file:%s", s);
|
c->std_error = EXEC_OUTPUT_FILE;
|
||||||
|
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
|
||||||
|
} else {
|
||||||
|
assert(streq(name, "StandardErrorFileToAppend"));
|
||||||
|
c->std_error = EXEC_OUTPUT_FILE_APPEND;
|
||||||
|
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=append:%s", s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@
|
|||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "syslog-util.h"
|
#include "syslog-util.h"
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
|
#include "umask-util.h"
|
||||||
#include "unit.h"
|
#include "unit.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -675,9 +676,10 @@ static int setup_output(
|
|||||||
(void) fd_nonblock(named_iofds[fileno], false);
|
(void) fd_nonblock(named_iofds[fileno], false);
|
||||||
return dup2(named_iofds[fileno], fileno) < 0 ? -errno : fileno;
|
return dup2(named_iofds[fileno], fileno) < 0 ? -errno : fileno;
|
||||||
|
|
||||||
case EXEC_OUTPUT_FILE: {
|
case EXEC_OUTPUT_FILE:
|
||||||
|
case EXEC_OUTPUT_FILE_APPEND: {
|
||||||
bool rw;
|
bool rw;
|
||||||
int fd;
|
int fd, flags;
|
||||||
|
|
||||||
assert(context->stdio_file[fileno]);
|
assert(context->stdio_file[fileno]);
|
||||||
|
|
||||||
@ -687,11 +689,16 @@ static int setup_output(
|
|||||||
if (rw)
|
if (rw)
|
||||||
return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
|
return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
|
||||||
|
|
||||||
fd = acquire_path(context->stdio_file[fileno], O_WRONLY, 0666 & ~context->umask);
|
flags = O_WRONLY;
|
||||||
|
if (o == EXEC_OUTPUT_FILE_APPEND)
|
||||||
|
flags |= O_APPEND;
|
||||||
|
|
||||||
|
fd = acquire_path(context->stdio_file[fileno], flags, 0666 & ~context->umask);
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
return move_fd(fd, fileno, false);
|
return move_fd(fd, fileno, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -4036,8 +4043,12 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
|||||||
fprintf(f, "%sStandardInputFile: %s\n", prefix, c->stdio_file[STDIN_FILENO]);
|
fprintf(f, "%sStandardInputFile: %s\n", prefix, c->stdio_file[STDIN_FILENO]);
|
||||||
if (c->std_output == EXEC_OUTPUT_FILE)
|
if (c->std_output == EXEC_OUTPUT_FILE)
|
||||||
fprintf(f, "%sStandardOutputFile: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
|
fprintf(f, "%sStandardOutputFile: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
|
||||||
|
if (c->std_output == EXEC_OUTPUT_FILE_APPEND)
|
||||||
|
fprintf(f, "%sStandardOutputFileToAppend: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
|
||||||
if (c->std_error == EXEC_OUTPUT_FILE)
|
if (c->std_error == EXEC_OUTPUT_FILE)
|
||||||
fprintf(f, "%sStandardErrorFile: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
|
fprintf(f, "%sStandardErrorFile: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
|
||||||
|
if (c->std_error == EXEC_OUTPUT_FILE_APPEND)
|
||||||
|
fprintf(f, "%sStandardErrorFileToAppend: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
|
||||||
|
|
||||||
if (c->tty_path)
|
if (c->tty_path)
|
||||||
fprintf(f,
|
fprintf(f,
|
||||||
@ -4968,6 +4979,7 @@ static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
|
|||||||
[EXEC_OUTPUT_SOCKET] = "socket",
|
[EXEC_OUTPUT_SOCKET] = "socket",
|
||||||
[EXEC_OUTPUT_NAMED_FD] = "fd",
|
[EXEC_OUTPUT_NAMED_FD] = "fd",
|
||||||
[EXEC_OUTPUT_FILE] = "file",
|
[EXEC_OUTPUT_FILE] = "file",
|
||||||
|
[EXEC_OUTPUT_FILE_APPEND] = "append",
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
|
DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
|
||||||
|
@ -56,6 +56,7 @@ typedef enum ExecOutput {
|
|||||||
EXEC_OUTPUT_SOCKET,
|
EXEC_OUTPUT_SOCKET,
|
||||||
EXEC_OUTPUT_NAMED_FD,
|
EXEC_OUTPUT_NAMED_FD,
|
||||||
EXEC_OUTPUT_FILE,
|
EXEC_OUTPUT_FILE,
|
||||||
|
EXEC_OUTPUT_FILE_APPEND,
|
||||||
_EXEC_OUTPUT_MAX,
|
_EXEC_OUTPUT_MAX,
|
||||||
_EXEC_OUTPUT_INVALID = -1
|
_EXEC_OUTPUT_INVALID = -1
|
||||||
} ExecOutput;
|
} ExecOutput;
|
||||||
|
@ -1015,6 +1015,17 @@ int config_parse_exec_output(
|
|||||||
|
|
||||||
eo = EXEC_OUTPUT_FILE;
|
eo = EXEC_OUTPUT_FILE;
|
||||||
|
|
||||||
|
} else if ((n = startswith(rvalue, "append:"))) {
|
||||||
|
|
||||||
|
r = unit_full_printf(u, n, &resolved);
|
||||||
|
if (r < 0)
|
||||||
|
return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
|
||||||
|
|
||||||
|
r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
|
||||||
|
if (r < 0)
|
||||||
|
return -ENOEXEC;
|
||||||
|
|
||||||
|
eo = EXEC_OUTPUT_FILE_APPEND;
|
||||||
} else {
|
} else {
|
||||||
eo = exec_output_from_string(rvalue);
|
eo = exec_output_from_string(rvalue);
|
||||||
if (eo < 0) {
|
if (eo < 0) {
|
||||||
|
@ -604,8 +604,8 @@ static int config_parse_output_restricted(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE)) {
|
if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Standard output types socket, fd:, file: are not supported as defaults, ignoring: %s", rvalue);
|
log_syntax(unit, LOG_ERR, filename, line, 0, "Standard output types socket, fd:, file:, append: are not supported as defaults, ignoring: %s", rvalue);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,6 +625,14 @@ static void test_exec_standardinput(Manager *m) {
|
|||||||
test(m, "exec-standardinput-file.service", 0, CLD_EXITED);
|
test(m, "exec-standardinput-file.service", 0, CLD_EXITED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_exec_standardoutput(Manager *m) {
|
||||||
|
test(m, "exec-standardoutput-file.service", 0, CLD_EXITED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_exec_standardoutput_append(Manager *m) {
|
||||||
|
test(m, "exec-standardoutput-append.service", 0, CLD_EXITED);
|
||||||
|
}
|
||||||
|
|
||||||
static int run_tests(UnitFileScope scope, const test_function_t *tests) {
|
static int run_tests(UnitFileScope scope, const test_function_t *tests) {
|
||||||
const test_function_t *test = NULL;
|
const test_function_t *test = NULL;
|
||||||
_cleanup_(manager_freep) Manager *m = NULL;
|
_cleanup_(manager_freep) Manager *m = NULL;
|
||||||
@ -672,6 +680,8 @@ int main(int argc, char *argv[]) {
|
|||||||
test_exec_restrictnamespaces,
|
test_exec_restrictnamespaces,
|
||||||
test_exec_runtimedirectory,
|
test_exec_runtimedirectory,
|
||||||
test_exec_standardinput,
|
test_exec_standardinput,
|
||||||
|
test_exec_standardoutput,
|
||||||
|
test_exec_standardoutput_append,
|
||||||
test_exec_supplementarygroups,
|
test_exec_supplementarygroups,
|
||||||
test_exec_systemcallerrornumber,
|
test_exec_systemcallerrornumber,
|
||||||
test_exec_systemcallfilter,
|
test_exec_systemcallfilter,
|
||||||
|
@ -115,6 +115,8 @@ test_data_files = '''
|
|||||||
test-execute/exec-specifier@.service
|
test-execute/exec-specifier@.service
|
||||||
test-execute/exec-standardinput-data.service
|
test-execute/exec-standardinput-data.service
|
||||||
test-execute/exec-standardinput-file.service
|
test-execute/exec-standardinput-file.service
|
||||||
|
test-execute/exec-standardoutput-file.service
|
||||||
|
test-execute/exec-standardoutput-append.service
|
||||||
test-execute/exec-supplementarygroups-multiple-groups-default-group-user.service
|
test-execute/exec-supplementarygroups-multiple-groups-default-group-user.service
|
||||||
test-execute/exec-supplementarygroups-multiple-groups-withgid.service
|
test-execute/exec-supplementarygroups-multiple-groups-withgid.service
|
||||||
test-execute/exec-supplementarygroups-multiple-groups-withuid.service
|
test-execute/exec-supplementarygroups-multiple-groups-withuid.service
|
||||||
|
13
test/test-execute/exec-standardoutput-append.service
Normal file
13
test/test-execute/exec-standardoutput-append.service
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for StandardOutput=append:
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStartPre=sh -c 'printf "hello\n" > /tmp/test-exec-standardoutput-output'
|
||||||
|
ExecStartPre=sh -c 'printf "hello\nhello\n" > /tmp/test-exec-standardoutput-expected'
|
||||||
|
StandardInput=data
|
||||||
|
StandardInputText=hello
|
||||||
|
StandardOutput=append:/tmp/test-exec-standardoutput-output
|
||||||
|
StandardError=null
|
||||||
|
ExecStart=cat
|
||||||
|
ExecStart=cmp /tmp/test-exec-standardoutput-output /tmp/test-exec-standardoutput-expected
|
||||||
|
Type=oneshot
|
13
test/test-execute/exec-standardoutput-file.service
Normal file
13
test/test-execute/exec-standardoutput-file.service
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for StandardOutput=file:
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStartPre=sh -c 'printf "nooo\nhello\n" > /tmp/test-exec-standardoutput-output'
|
||||||
|
ExecStartPre=sh -c 'printf "hello\nello\n" > /tmp/test-exec-standardoutput-expected'
|
||||||
|
StandardInput=data
|
||||||
|
StandardInputText=hello
|
||||||
|
StandardOutput=file:/tmp/test-exec-standardoutput-output
|
||||||
|
StandardError=null
|
||||||
|
ExecStart=cat
|
||||||
|
ExecStart=cmp /tmp/test-exec-standardoutput-expected /tmp/test-exec-standardoutput-output
|
||||||
|
Type=oneshot
|
Loading…
Reference in New Issue
Block a user