From: Zbigniew Jędrzejewski-Szmek Date: Mon, 19 May 2025 13:50:42 +0000 (+0200) Subject: basic/terminal-util: add a heuristic check whether terminfo file exists X-Git-Tag: v258-rc1~446^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e3b050a5c2ed2cdb5b0ea85f964c17e6ad29cd41;p=thirdparty%2Fsystemd.git basic/terminal-util: add a heuristic check whether terminfo file exists --- diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 4b1b0ecf6c8..9f34148d2a5 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -2584,6 +2584,57 @@ finish: return r; } +int have_terminfo_file(const char *name) { + /* This is a heuristic check if we have the file, using the directory layout used on + * current Linux systems. Checks for other layouts can be added later if appropriate. */ + int r; + + assert(filename_is_valid(name)); + + _cleanup_free_ char *p = path_join("/usr/share/terminfo", CHAR_TO_STR(name[0]), name); + if (!p) + return log_oom_debug(); + + r = RET_NERRNO(access(p, F_OK)); + if (r == -ENOENT) + return false; + if (r < 0) + return r; + return true; +} + +int query_term_for_tty(const char *tty, char **ret_term) { + _cleanup_free_ char *dcs_term = NULL; + int r; + + assert(tty); + assert(ret_term); + + if (tty_is_vc_resolve(tty)) + return strdup_to(ret_term, "linux"); + + /* Try to query the terminal implementation that we're on. This will not work in all + * cases, which is fine, since this is intended to be used as a fallback. */ + + _cleanup_close_ int tty_fd = open_terminal(tty, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); + if (tty_fd < 0) + return log_debug_errno(tty_fd, "Failed to open %s to query terminfo: %m", tty); + + r = terminal_get_terminfo_by_dcs(tty_fd, &dcs_term); + if (r < 0) + return log_debug_errno(r, "Failed to query %s for terminfo: %m", tty); + + r = have_terminfo_file(dcs_term); + if (r < 0) + return log_debug_errno(r, "Failed to look for terminfo %s: %m", dcs_term); + if (r == 0) + return log_info_errno(SYNTHETIC_ERRNO(ENODATA), + "Terminfo %s not found for %s.", dcs_term, tty); + + *ret_term = TAKE_PTR(dcs_term); + return 0; +} + int terminal_is_pty_fd(int fd) { int r; diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index 79683f5a857..688d6808a67 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -148,6 +148,8 @@ int terminal_get_size_by_dsr(int input_fd, int output_fd, unsigned *ret_rows, un int terminal_fix_size(int input_fd, int output_fd); int terminal_get_terminfo_by_dcs(int fd, char **ret_name); +int have_terminfo_file(const char *name); +int query_term_for_tty(const char *tty, char **ret_term); int terminal_is_pty_fd(int fd); diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c index ba045bedce4..6ab3c7fa164 100644 --- a/src/test/test-terminal-util.c +++ b/src/test/test-terminal-util.c @@ -242,6 +242,35 @@ TEST(terminal_get_terminfo_by_dcs) { log_info("terminal terminfo via DCS: %s, $TERM: %s", name, strnull(getenv("TERM"))); } +TEST(have_terminfo_file) { + int r; + + FOREACH_STRING(s, + "linux", + "xterm", + "vt220", + "xterm-256color", + "nosuchfile") { + r = have_terminfo_file(s); + log_info("%s: %s → %s", __func__+5, s, r >= 0 ? yes_no(r) : STRERROR(r)); + ASSERT_OK(r); + } +} + +TEST(query_term_for_tty) { + int r; + + FOREACH_STRING(s, + "/dev/console", + "/dev/stdin", + "/dev/stdout") { + _cleanup_free_ char *term = NULL; + + r = query_term_for_tty(s, &term); + log_info("%s: %s → %s/%s", __func__+5, s, STRERROR(r), strnull(term)); + } +} + TEST(terminal_is_pty_fd) { _cleanup_close_ int fd1 = -EBADF, fd2 = -EBADF; int r;