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;
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);
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;