diff --git a/profile.d/80-systemd-osc-context.sh b/profile.d/80-systemd-osc-context.sh index 85983dc68d..ee37c2507a 100644 --- a/profile.d/80-systemd-osc-context.sh +++ b/profile.d/80-systemd-osc-context.sh @@ -53,7 +53,7 @@ __systemd_osc_context_precmdline() { read -r systemd_osc_context_cmd_id syslog_priority, !!context->syslog_level_prefix, false, - is_kmsg_output(output), - is_terminal_output(output)) < 0) + exec_output_is_kmsg(output), + exec_output_is_terminal(output)) < 0) return -errno; return move_fd(TAKE_FD(fd), nfd, false); @@ -325,7 +305,7 @@ static int fixup_input( std_input = context->std_input; - if (is_terminal_input(std_input) && !apply_tty_stdin) + if (exec_input_is_terminal(std_input) && !apply_tty_stdin) return EXEC_INPUT_NULL; if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0) @@ -531,7 +511,7 @@ static int setup_output( if (e == EXEC_OUTPUT_INHERIT && o == EXEC_OUTPUT_INHERIT && i == EXEC_INPUT_NULL && - !is_terminal_input(context->std_input) && + !exec_input_is_terminal(context->std_input) && getppid() != 1) return fileno; @@ -543,7 +523,7 @@ static int setup_output( } else if (o == EXEC_OUTPUT_INHERIT) { /* If input got downgraded, inherit the original value */ - if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input)) + if (i == EXEC_INPUT_NULL && exec_input_is_terminal(context->std_input)) return open_terminal_as(exec_context_tty_path(context), O_WRONLY, fileno); /* If the input is connected to anything that's not a /dev/null or a data fd, inherit that... */ @@ -564,7 +544,7 @@ static int setup_output( return open_null_as(O_WRONLY, fileno); case EXEC_OUTPUT_TTY: - if (is_terminal_input(i)) + if (exec_input_is_terminal(i)) return RET_NERRNO(dup2(STDIN_FILENO, fileno)); return open_terminal_as(exec_context_tty_path(context), O_WRONLY, fileno); @@ -4880,8 +4860,8 @@ static void prepare_terminal( assert(p); /* We only try to reset things if we there's the chance our stdout points to a TTY */ - if (!(is_terminal_output(context->std_output) || - (context->std_output == EXEC_OUTPUT_INHERIT && is_terminal_input(context->std_input)) || + if (!(context->std_output == EXEC_OUTPUT_TTY || + (context->std_output == EXEC_OUTPUT_INHERIT && exec_input_is_terminal(context->std_input)) || context->std_output == EXEC_OUTPUT_NAMED_FD || p->stdout_fd >= 0)) return; @@ -4921,10 +4901,7 @@ static int setup_term_environment(const ExecContext *context, char ***env) { return 0; /* Do we need $TERM at all? */ - if (!is_terminal_input(context->std_input) && - !is_terminal_output(context->std_output) && - !is_terminal_output(context->std_error) && - !context->tty_path) + if (!exec_context_has_tty(context)) return 0; const char *tty_path = exec_context_tty_path(context); diff --git a/src/core/execute.c b/src/core/execute.c index a4de33baec..c384e9dd63 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -65,20 +65,6 @@ #include "utmp-wtmp.h" #include "vpick.h" -static bool is_terminal_input(ExecInput i) { - return IN_SET(i, - EXEC_INPUT_TTY, - EXEC_INPUT_TTY_FORCE, - EXEC_INPUT_TTY_FAIL); -} - -static bool is_terminal_output(ExecOutput o) { - return IN_SET(o, - EXEC_OUTPUT_TTY, - EXEC_OUTPUT_KMSG_AND_CONSOLE, - EXEC_OUTPUT_JOURNAL_AND_CONSOLE); -} - const char* exec_context_tty_path(const ExecContext *context) { assert(context); @@ -151,8 +137,7 @@ void exec_context_tty_reset(const ExecContext *context, const ExecParameters *pa if (parameters && parameters->stdout_fd >= 0 && isatty_safe(parameters->stdout_fd)) fd = parameters->stdout_fd; - else if (path && (context->tty_path || is_terminal_input(context->std_input) || - is_terminal_output(context->std_output) || is_terminal_output(context->std_error))) { + else if (path && exec_context_has_tty(context)) { fd = _fd = open_terminal(path, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); if (fd < 0) return (void) log_debug_errno(fd, "Failed to open terminal '%s', ignoring: %m", path); @@ -180,7 +165,7 @@ void exec_context_tty_reset(const ExecContext *context, const ExecParameters *pa if (r < 0) log_debug_errno(r, "Failed to configure TTY dimensions, ignoring: %m"); - if (!sd_id128_is_null(invocation_id)) { + if (!sd_id128_is_null(invocation_id) && exec_context_shall_ansi_seq_reset(context)) { sd_id128_t context_id; r = osc_context_id_from_invocation_id(invocation_id, &context_id); @@ -1000,9 +985,9 @@ static bool exec_context_may_touch_tty(const ExecContext *ec) { return ec->tty_reset || ec->tty_vhangup || ec->tty_vt_disallocate || - is_terminal_input(ec->std_input) || - is_terminal_output(ec->std_output) || - is_terminal_output(ec->std_error); + exec_input_is_terminal(ec->std_input) || + ec->std_output == EXEC_OUTPUT_TTY || + ec->std_error == EXEC_OUTPUT_TTY; } bool exec_context_may_touch_console(const ExecContext *ec) { @@ -1024,6 +1009,9 @@ bool exec_context_shall_ansi_seq_reset(const ExecContext *c) { if (!c->tty_reset) return false; + /* FIXME: + * On invocation, we generate $TERM based on settings for StandardOutput= and friends and the kernel + * command line options, or propagate $TERM from the service manager. See setup_term_environment(). */ return !streq_ptr(strv_env_get(c->environment, "TERM"), "dumb"); } diff --git a/src/core/execute.h b/src/core/execute.h index 64e8896062..2e30374830 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -458,6 +458,36 @@ typedef struct ExecParameters { .pidref_transport_fd = -EBADF, \ } +static inline bool exec_input_is_terminal(ExecInput i) { + return IN_SET(i, + EXEC_INPUT_TTY, + EXEC_INPUT_TTY_FORCE, + EXEC_INPUT_TTY_FAIL); +} + +static inline bool exec_output_is_terminal(ExecOutput o) { + return IN_SET(o, + EXEC_OUTPUT_TTY, + EXEC_OUTPUT_KMSG_AND_CONSOLE, + EXEC_OUTPUT_JOURNAL_AND_CONSOLE); +} + +static inline bool exec_output_is_kmsg(ExecOutput o) { + return IN_SET(o, + EXEC_OUTPUT_KMSG, + EXEC_OUTPUT_KMSG_AND_CONSOLE); +} + +static inline bool exec_context_has_tty(const ExecContext *context) { + assert(context); + + return + context->tty_path || + exec_input_is_terminal(context->std_input) || + context->std_output == EXEC_OUTPUT_TTY || + context->std_error == EXEC_OUTPUT_TTY; +} + int exec_spawn( Unit *unit, ExecCommand *command, diff --git a/src/import/import-compress.c b/src/import/import-compress.c index 012fd2c3ed..666a2c3aab 100644 --- a/src/import/import-compress.c +++ b/src/import/import-compress.c @@ -4,6 +4,7 @@ #include #include "import-compress.h" +#include "log.h" #include "string-table.h" void import_compress_free(ImportCompress *c) { @@ -104,6 +105,7 @@ int import_uncompress_detect(ImportCompress *c, const void *data, size_t size) { c->encoding = false; + log_debug("Detected compression type: %s", import_compress_type_to_string(c->type)); return 1; } @@ -589,15 +591,15 @@ int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size } static const char* const import_compress_type_table[_IMPORT_COMPRESS_TYPE_MAX] = { - [IMPORT_COMPRESS_UNKNOWN] = "unknown", + [IMPORT_COMPRESS_UNKNOWN] = "unknown", [IMPORT_COMPRESS_UNCOMPRESSED] = "uncompressed", - [IMPORT_COMPRESS_XZ] = "xz", - [IMPORT_COMPRESS_GZIP] = "gzip", + [IMPORT_COMPRESS_XZ] = "xz", + [IMPORT_COMPRESS_GZIP] = "gzip", #if HAVE_BZIP2 - [IMPORT_COMPRESS_BZIP2] = "bzip2", + [IMPORT_COMPRESS_BZIP2] = "bzip2", #endif #if HAVE_ZSTD - [IMPORT_COMPRESS_ZSTD] = "zstd", + [IMPORT_COMPRESS_ZSTD] = "zstd", #endif }; diff --git a/src/import/importd.c b/src/import/importd.c index 84cc9ca86a..f2715691ab 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -721,7 +721,7 @@ static int manager_new(Manager **ret) { r = notify_socket_prepare( m->event, - SD_EVENT_PRIORITY_NORMAL, + SD_EVENT_PRIORITY_NORMAL - 1, /* Make this processed before SIGCHLD. */ manager_on_notify, m, &m->notify_socket_path); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 4e3138b2ff..fd37bde874 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1400,18 +1400,25 @@ static int shell_machine(int argc, char *argv[], void *userdata) { return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Shell only supported on local machines."); - /* Pass $TERM & Co. to shell session, if not explicitly specified. */ - FOREACH_STRING(v, "TERM=", "COLORTERM=", "NO_COLOR=") { - if (strv_find_prefix(arg_setenv, v)) - continue; + if (terminal_is_dumb()) { + /* Set TERM=dumb if we are running on a dumb terminal or with a pipe. + * Otherwise, we will get unwanted OSC sequences. */ + if (!strv_find_prefix(arg_setenv, "TERM=")) + if (strv_extend(&arg_setenv, "TERM=dumb") < 0) + return log_oom(); + } else + /* Pass $TERM & Co. to shell session, if not explicitly specified. */ + FOREACH_STRING(v, "TERM=", "COLORTERM=", "NO_COLOR=") { + if (strv_find_prefix(arg_setenv, v)) + continue; - const char *t = strv_find_prefix(environ, v); - if (!t) - continue; + const char *t = strv_find_prefix(environ, v); + if (!t) + continue; - if (strv_extend(&arg_setenv, t) < 0) - return log_oom(); - } + if (strv_extend(&arg_setenv, t) < 0) + return log_oom(); + } (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 8013aa94c3..22bbdc1132 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3551,7 +3551,7 @@ static int inner_child( envp[n_env++] = strjoina("container=", arg_container_service_name); /* Propagate $TERM & Co. unless we are invoked in pipe mode and stdin/stdout/stderr don't refer to a TTY */ - if (arg_console_mode != CONSOLE_PIPE || on_tty()) { + if (arg_console_mode != CONSOLE_PIPE && !terminal_is_dumb()) FOREACH_STRING(v, "TERM=", "COLORTERM=", "NO_COLOR=") { char *t = strv_find_prefix(environ, v); if (!t) @@ -3559,7 +3559,7 @@ static int inner_child( envp[n_env++] = t; } - } else + else envp[n_env++] = (char*) "TERM=dumb"; if (home || !uid_is_valid(arg_uid) || arg_uid == 0) diff --git a/src/shared/pretty-print.c b/src/shared/pretty-print.c index cbcf2a4be2..c7e77fd8e2 100644 --- a/src/shared/pretty-print.c +++ b/src/shared/pretty-print.c @@ -530,6 +530,9 @@ bool shall_tint_background(void) { } void draw_progress_bar_unbuffered(const char *prefix, double percentage) { + if (!on_tty()) + return; + fputc('\r', stderr); if (prefix) { fputs(prefix, stderr); @@ -593,6 +596,9 @@ void draw_progress_bar_unbuffered(const char *prefix, double percentage) { } void clear_progress_bar_unbuffered(const char *prefix) { + if (!on_tty()) + return; + fputc('\r', stderr); if (terminal_is_dumb()) @@ -609,6 +615,9 @@ void clear_progress_bar_unbuffered(const char *prefix) { } void draw_progress_bar(const char *prefix, double percentage) { + if (!on_tty()) + return; + /* We are going output a bunch of small strings that shall appear as a single line to STDERR which is * unbuffered by default. Let's temporarily turn on full buffering, so that this is passed to the tty * as a single buffer, to make things more efficient. */ @@ -621,6 +630,9 @@ int draw_progress_barf(double percentage, const char *prefixf, ...) { va_list ap; int r; + if (!on_tty()) + return 0; + va_start(ap, prefixf); r = vasprintf(&s, prefixf, ap); va_end(ap); @@ -633,6 +645,9 @@ int draw_progress_barf(double percentage, const char *prefixf, ...) { } void clear_progress_bar(const char *prefix) { + if (!on_tty()) + return; + WITH_BUFFERED_STDERR; clear_progress_bar_unbuffered(prefix); } diff --git a/src/sysupdate/sysupdated.c b/src/sysupdate/sysupdated.c index cc45ca0657..b1438ff825 100644 --- a/src/sysupdate/sysupdated.c +++ b/src/sysupdate/sysupdated.c @@ -1746,7 +1746,7 @@ static int manager_new(Manager **ret) { r = notify_socket_prepare( m->event, - SD_EVENT_PRIORITY_NORMAL, + SD_EVENT_PRIORITY_NORMAL - 1, /* Make this processed before SIGCHLD. */ manager_on_notify, m, &m->notify_socket_path); diff --git a/test/units/TEST-72-SYSUPDATE.sh b/test/units/TEST-72-SYSUPDATE.sh index e5c62c635e..93a5ffb87f 100755 --- a/test/units/TEST-72-SYSUPDATE.sh +++ b/test/units/TEST-72-SYSUPDATE.sh @@ -54,15 +54,18 @@ at_exit() { trap at_exit EXIT update_checksums() { - (cd "$WORKDIR/source" && sha256sum uki* part* dir-*.tar.gz >SHA256SUMS) + (cd "$WORKDIR/source" && sha256sum uki* part* dir-*.tar.gz >SHA256SUMS) } new_version() { local sector_size="${1:?}" local version="${2:?}" - # Create a pair of random partition payloads, and compress one - dd if=/dev/urandom of="$WORKDIR/source/part1-$version.raw" bs="$sector_size" count=2048 + # Create a pair of random partition payloads, and compress one. + # To make not the initial bytes of part1-xxx.raw accidentally match one of the compression header, + # let's make the first sector filled by zero. + dd if=/dev/zero of="$WORKDIR/source/part1-$version.raw" bs="$sector_size" count=1 + dd if=/dev/urandom of="$WORKDIR/source/part1-$version.raw" bs="$sector_size" count=2047 conv=notrunc oflag=append dd if=/dev/urandom of="$WORKDIR/source/part2-$version.raw" bs="$sector_size" count=2048 gzip -k -f "$WORKDIR/source/part2-$version.raw" @@ -354,7 +357,7 @@ EOF updatectl check rm -r /run/sysupdate.test.d fi - + # Create seventh version, and update through a file:// URL. This should be # almost as good as testing HTTP, but is simpler for us to set up. file:// is # abstracted in curl for us, and since our main goal is to test our own code