From: Lucas Werkmeister Date: Thu, 14 Jan 2021 21:32:55 +0000 (+0100) Subject: Add truncate: to StandardOutput= etc. X-Git-Tag: v248-rc1~344 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8d7dab1fda99a294a5538747bdb1a5960a3c2f43;p=thirdparty%2Fsystemd.git Add truncate: to StandardOutput= etc. This adds the ability to specify truncate:PATH for StandardOutput= and StandardError=, similar to the existing append:PATH. The code is mostly copied from the related append: code. Fixes #8983. --- diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index ed8ab6205c3..7328f9b9659 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -2383,8 +2383,8 @@ SystemCallErrorNumber=EPERM to. Takes one of , , , , , , , , - , or - . + , , + or . duplicates the file descriptor of standard input for standard output. @@ -2424,6 +2424,10 @@ SystemCallErrorNumber=EPERM above, but it opens the file in append mode. + is similar to + above, but it truncates the file when opening it. + + connects standard output to a socket acquired via socket activation. The semantics are similar to the same option of StandardInput=, see above. diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 04735354a33..4ad91819939 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -2727,8 +2727,8 @@ int bus_exec_context_set_transient_property( } else if (STR_IN_SET(name, "StandardInputFile", - "StandardOutputFile", "StandardOutputFileToAppend", - "StandardErrorFile", "StandardErrorFileToAppend")) { + "StandardOutputFile", "StandardOutputFileToAppend", "StandardOutputFileToTruncate", + "StandardErrorFile", "StandardErrorFileToAppend", "StandardErrorFileToTruncate")) { const char *s; r = sd_bus_message_read(message, "s", &s); @@ -2752,7 +2752,7 @@ int bus_exec_context_set_transient_property( c->std_input = EXEC_INPUT_FILE; unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=file:%s", s); - } else if (STR_IN_SET(name, "StandardOutputFile", "StandardOutputFileToAppend")) { + } else if (STR_IN_SET(name, "StandardOutputFile", "StandardOutputFileToAppend", "StandardOutputFileToTruncate")) { r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], empty_to_null(s)); if (r < 0) return r; @@ -2760,13 +2760,16 @@ int bus_exec_context_set_transient_property( 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")); + } else if (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, "StandardOutputFileToTruncate")); + c->std_output = EXEC_OUTPUT_FILE_TRUNCATE; + unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=truncate:%s", s); } } else { - assert(STR_IN_SET(name, "StandardErrorFile", "StandardErrorFileToAppend")); + assert(STR_IN_SET(name, "StandardErrorFile", "StandardErrorFileToAppend", "StandardErrorFileToTruncate")); r = free_and_strdup(&c->stdio_file[STDERR_FILENO], empty_to_null(s)); if (r < 0) @@ -2775,10 +2778,13 @@ int bus_exec_context_set_transient_property( 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")); + } else if (streq(name, "StandardErrorFileToAppend")) { c->std_error = EXEC_OUTPUT_FILE_APPEND; unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=append:%s", s); + } else { + assert(streq(name, "StandardErrorFileToTruncate")); + c->std_error = EXEC_OUTPUT_FILE_TRUNCATE; + unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=truncate:%s", s); } } } diff --git a/src/core/execute.c b/src/core/execute.c index 8f901fa7154..ee5f082783b 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -562,7 +562,7 @@ static bool can_inherit_stderr_from_stdout( if (e == EXEC_OUTPUT_NAMED_FD) return streq_ptr(context->stdio_fdname[STDOUT_FILENO], context->stdio_fdname[STDERR_FILENO]); - if (IN_SET(e, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) + if (IN_SET(e, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND, EXEC_OUTPUT_FILE_TRUNCATE)) return streq_ptr(context->stdio_file[STDOUT_FILENO], context->stdio_file[STDERR_FILENO]); return true; @@ -698,7 +698,8 @@ static int setup_output( return dup2(named_iofds[fileno], fileno) < 0 ? -errno : fileno; case EXEC_OUTPUT_FILE: - case EXEC_OUTPUT_FILE_APPEND: { + case EXEC_OUTPUT_FILE_APPEND: + case EXEC_OUTPUT_FILE_TRUNCATE: { bool rw; int fd, flags; @@ -713,6 +714,8 @@ static int setup_output( flags = O_WRONLY; if (o == EXEC_OUTPUT_FILE_APPEND) flags |= O_APPEND; + else if (o == EXEC_OUTPUT_FILE_TRUNCATE) + flags |= O_TRUNC; fd = acquire_path(context->stdio_file[fileno], flags, 0666 & ~context->umask); if (fd < 0) @@ -5357,10 +5360,14 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { 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_output == EXEC_OUTPUT_FILE_TRUNCATE) + fprintf(f, "%sStandardOutputFileToTruncate: %s\n", prefix, c->stdio_file[STDOUT_FILENO]); if (c->std_error == EXEC_OUTPUT_FILE) 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->std_error == EXEC_OUTPUT_FILE_TRUNCATE) + fprintf(f, "%sStandardErrorFileToTruncate: %s\n", prefix, c->stdio_file[STDERR_FILENO]); if (c->tty_path) fprintf(f, @@ -6449,6 +6456,7 @@ static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = { [EXEC_OUTPUT_NAMED_FD] = "fd", [EXEC_OUTPUT_FILE] = "file", [EXEC_OUTPUT_FILE_APPEND] = "append", + [EXEC_OUTPUT_FILE_TRUNCATE] = "truncate", }; DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput); diff --git a/src/core/execute.h b/src/core/execute.h index 33d7e1693d6..da8d6ae2729 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -61,6 +61,7 @@ typedef enum ExecOutput { EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND, + EXEC_OUTPUT_FILE_TRUNCATE, _EXEC_OUTPUT_MAX, _EXEC_OUTPUT_INVALID = -1 } ExecOutput; diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 4964249bf21..4401e598b5c 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1202,6 +1202,20 @@ int config_parse_exec_output( return 0; eo = EXEC_OUTPUT_FILE_APPEND; + + } else if ((n = startswith(rvalue, "truncate:"))) { + + r = unit_full_printf(u, n, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", n); + return 0; + } + + r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue); + if (r < 0) + return 0; + + eo = EXEC_OUTPUT_FILE_TRUNCATE; } else { eo = exec_output_from_string(rvalue); if (eo < 0) { @@ -5761,8 +5775,8 @@ int config_parse_output_restricted( return 0; } - if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Standard output types socket, fd:, file:, append: are not supported as defaults, ignoring: %s", rvalue); + if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND, EXEC_OUTPUT_FILE_TRUNCATE)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Standard output types socket, fd:, file:, append:, truncate: are not supported as defaults, ignoring: %s", rvalue); return 0; } } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index bc17b6e1fbe..07f936dc6cb 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1144,6 +1144,9 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con } else if ((n = startswith(eq, "append:"))) { appended = strjoina(field, "FileToAppend"); r = sd_bus_message_append(m, "(sv)", appended, "s", n); + } else if ((n = startswith(eq, "truncate:"))) { + appended = strjoina(field, "FileToTruncate"); + r = sd_bus_message_append(m, "(sv)", appended, "s", n); } else r = sd_bus_message_append(m, "(sv)", field, "s", eq); if (r < 0) diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 83816f474c5..01e2443777c 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -811,6 +811,10 @@ static void test_exec_standardoutput_append(Manager *m) { test(m, "exec-standardoutput-append.service", 0, CLD_EXITED); } +static void test_exec_standardoutput_truncate(Manager *m) { + test(m, "exec-standardoutput-truncate.service", 0, CLD_EXITED); +} + static void test_exec_condition(Manager *m) { test_service(m, "exec-condition-failed.service", SERVICE_FAILURE_EXIT_CODE); test_service(m, "exec-condition-skip.service", SERVICE_SKIP_CONDITION); @@ -876,6 +880,7 @@ int main(int argc, char *argv[]) { entry(test_exec_standardinput), entry(test_exec_standardoutput), entry(test_exec_standardoutput_append), + entry(test_exec_standardoutput_truncate), entry(test_exec_supplementarygroups), entry(test_exec_systemcallerrornumber), entry(test_exec_systemcallfilter), diff --git a/test/test-execute/exec-standardoutput-truncate.service b/test/test-execute/exec-standardoutput-truncate.service new file mode 100644 index 00000000000..7a12a069232 --- /dev/null +++ b/test/test-execute/exec-standardoutput-truncate.service @@ -0,0 +1,13 @@ +[Unit] +Description=Test for StandardOutput=truncate: + +[Service] +ExecStartPre=sh -c 'printf "hello\n" > /tmp/test-exec-standardoutput-output' +ExecStartPre=sh -c 'printf "hi\n" > /tmp/test-exec-standardoutput-expected' +StandardInput=data +StandardInputText=hi +StandardOutput=truncate:/tmp/test-exec-standardoutput-output +StandardError=null +ExecStart=cat +ExecStartPost=cmp /tmp/test-exec-standardoutput-output /tmp/test-exec-standardoutput-expected +Type=oneshot diff --git a/test/units/testsuite-27.sh b/test/units/testsuite-27.sh index 9d92e6e5742..0e9ffe11892 100755 --- a/test/units/testsuite-27.sh +++ b/test/units/testsuite-27.sh @@ -43,6 +43,18 @@ a c EOF +systemd-run --wait --unit=test27-four \ + -p StandardOutput=truncate:/tmp/stdout \ + -p StandardError=truncate:/tmp/stderr \ + -p Type=exec \ + sh -c 'echo a ; echo b >&2' +cmp /tmp/stdout </testok