X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fbasic%2Fterminal-util.c;h=fa4f60826c9821b3f26f87ac2c6a355fde8ade02;hp=8e101c60a18f18af2c859a9a6063434e2a574d0b;hb=7b4a8335022121d06336eae363f3d7fcbcac1c45;hpb=d1325d57413c007e17847074c70005c40e32bc9d diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 8e101c60a..fa4f60826 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -17,26 +17,43 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "io-util.h" +#include "log.h" +#include "macro.h" +#include "parse-util.h" +#include "process-util.h" +#include "socket-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" #include "terminal-util.h" #include "time-util.h" -#include "process-util.h" #include "util.h" -#include "fileio.h" -#include "path-util.h" static volatile unsigned cached_columns = 0; static volatile unsigned cached_lines = 0; @@ -48,7 +65,7 @@ int chvt(int vt) { if (fd < 0) return -errno; - if (vt < 0) { + if (vt <= 0) { int tiocl[2] = { TIOCL_GETKMSGREDIRECT, 0 @@ -66,6 +83,7 @@ int chvt(int vt) { return 0; } +#if 0 /// UNNEEDED by elogind int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { struct termios old_termios, new_termios; char c, line[LINE_MAX]; @@ -112,7 +130,7 @@ int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { errno = 0; if (!fgets(line, sizeof(line), f)) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; truncate_nl(line); @@ -126,8 +144,6 @@ int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { return 0; } -/// UNNEEDED by elogind -#if 0 int ask_char(char *ret, const char *replies, const char *text, ...) { int r; @@ -140,15 +156,15 @@ int ask_char(char *ret, const char *replies, const char *text, ...) { char c; bool need_nl = true; - if (on_tty()) - fputs(ANSI_HIGHLIGHT_ON, stdout); + if (colors_enabled()) + fputs(ANSI_HIGHLIGHT, stdout); va_start(ap, text); vprintf(text, ap); va_end(ap); - if (on_tty()) - fputs(ANSI_HIGHLIGHT_OFF, stdout); + if (colors_enabled()) + fputs(ANSI_NORMAL, stdout); fflush(stdout); @@ -184,21 +200,21 @@ int ask_string(char **ret, const char *text, ...) { char line[LINE_MAX]; va_list ap; - if (on_tty()) - fputs(ANSI_HIGHLIGHT_ON, stdout); + if (colors_enabled()) + fputs(ANSI_HIGHLIGHT, stdout); va_start(ap, text); vprintf(text, ap); va_end(ap); - if (on_tty()) - fputs(ANSI_HIGHLIGHT_OFF, stdout); + if (colors_enabled()) + fputs(ANSI_NORMAL, stdout); fflush(stdout); errno = 0; if (!fgets(line, sizeof(line), stdin)) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; if (!endswith(line, "\n")) putchar('\n'); @@ -218,7 +234,6 @@ int ask_string(char **ret, const char *text, ...) { } } } -#endif // 0 int reset_terminal_fd(int fd, bool switch_to_text) { struct termios termios; @@ -297,6 +312,7 @@ int reset_terminal(const char *name) { return reset_terminal_fd(fd, true); } +#endif // 0 int open_terminal(const char *name, int mode) { int fd, r; @@ -344,6 +360,7 @@ int open_terminal(const char *name, int mode) { return fd; } +#if 0 /// UNNEEDED by elogind int acquire_terminal( const char *name, bool fail, @@ -415,7 +432,7 @@ int acquire_terminal( assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0); - /* Sometimes it makes sense to ignore TIOCSCTTY + /* Sometimes, it makes sense to ignore TIOCSCTTY * returning EPERM, i.e. when very likely we already * are have this controlling terminal. */ if (r < 0 && r == -EPERM && ignore_tiocstty_eperm) @@ -483,10 +500,6 @@ int acquire_terminal( safe_close(notify); - r = reset_terminal_fd(fd, true); - if (r < 0) - log_warning_errno(r, "Failed to reset terminal: %m"); - return fd; fail: @@ -495,9 +508,9 @@ fail: return r; } +#endif // 0 -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind int release_terminal(void) { static const struct sigaction sa_new = { .sa_handler = SIG_IGN, @@ -523,7 +536,6 @@ int release_terminal(void) { return r; } -#endif // 0 int terminal_vhangup_fd(int fd) { assert(fd >= 0); @@ -545,8 +557,9 @@ int terminal_vhangup(const char *name) { } int vt_disallocate(const char *name) { - int fd, r; + _cleanup_close_ int fd = -1; unsigned u; + int r; /* Deallocate the VT if possible. If not possible * (i.e. because it is the active one), at least clear it @@ -568,8 +581,6 @@ int vt_disallocate(const char *name) { "\033[H" /* move home */ "\033[2J", /* clear screen */ 10, false); - safe_close(fd); - return 0; } @@ -589,7 +600,7 @@ int vt_disallocate(const char *name) { return fd; r = ioctl(fd, VT_DISALLOCATE, u); - safe_close(fd); + fd = safe_close(fd); if (r >= 0) return 0; @@ -608,34 +619,9 @@ int vt_disallocate(const char *name) { "\033[H" /* move home */ "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */ 10, false); - safe_close(fd); - return 0; } -void warn_melody(void) { - _cleanup_close_ int fd = -1; - - fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return; - - /* Yeah, this is synchronous. Kinda sucks. But well... */ - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/440)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/220)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/220)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, 0); -} - -/// UNNEEDED by elogind -#if 0 int make_console_stdio(void) { int fd, r; @@ -645,6 +631,10 @@ int make_console_stdio(void) { if (fd < 0) return log_error_errno(fd, "Failed to acquire terminal: %m"); + r = reset_terminal_fd(fd, true); + if (r < 0) + log_warning_errno(r, "Failed to reset terminal, ignoring: %m"); + r = make_stdio(fd); if (r < 0) return log_error_errno(r, "Failed to duplicate terminal fd: %m"); @@ -653,84 +643,6 @@ int make_console_stdio(void) { } #endif // 0 -int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) { - static const char status_indent[] = " "; /* "[" STATUS "] " */ - _cleanup_free_ char *s = NULL; - _cleanup_close_ int fd = -1; - struct iovec iovec[6] = {}; - int n = 0; - static bool prev_ephemeral; - - assert(format); - - /* This is independent of logging, as status messages are - * optional and go exclusively to the console. */ - - if (vasprintf(&s, format, ap) < 0) - return log_oom(); - - fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - if (ellipse) { - char *e; - size_t emax, sl; - int c; - - c = fd_columns(fd); - if (c <= 0) - c = 80; - - sl = status ? sizeof(status_indent)-1 : 0; - - emax = c - sl - 1; - if (emax < 3) - emax = 3; - - e = ellipsize(s, emax, 50); - if (e) { - free(s); - s = e; - } - } - - if (prev_ephemeral) - IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE); - prev_ephemeral = ephemeral; - - if (status) { - if (!isempty(status)) { - IOVEC_SET_STRING(iovec[n++], "["); - IOVEC_SET_STRING(iovec[n++], status); - IOVEC_SET_STRING(iovec[n++], "] "); - } else - IOVEC_SET_STRING(iovec[n++], status_indent); - } - - IOVEC_SET_STRING(iovec[n++], s); - if (!ephemeral) - IOVEC_SET_STRING(iovec[n++], "\n"); - - if (writev(fd, iovec, n) < 0) - return -errno; - - return 0; -} - -int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) { - va_list ap; - int r; - - assert(format); - - va_start(ap, format); - r = status_vprintf(status, ellipse, ephemeral, format, ap); - va_end(ap); - - return r; -} - bool tty_is_vc(const char *tty) { assert(tty); @@ -770,6 +682,7 @@ int vtnr_from_tty(const char *tty) { return i; } +#if 0 /// UNNEEDED by elogind char *resolve_dev_console(char **active) { char *tty; @@ -803,6 +716,64 @@ char *resolve_dev_console(char **active) { return tty; } +int get_kernel_consoles(char ***consoles) { + _cleanup_strv_free_ char **con = NULL; + _cleanup_free_ char *line = NULL; + const char *active; + int r; + + assert(consoles); + + r = read_one_line_file("/sys/class/tty/console/active", &line); + if (r < 0) + return r; + + active = line; + for (;;) { + _cleanup_free_ char *tty = NULL; + char *path; + + r = extract_first_word(&active, &tty, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; + + if (streq(tty, "tty0")) { + tty = mfree(tty); + r = read_one_line_file("/sys/class/tty/tty0/active", &tty); + if (r < 0) + return r; + } + + path = strappend("/dev/", tty); + if (!path) + return -ENOMEM; + + if (access(path, F_OK) < 0) { + log_debug_errno(errno, "Console device %s is not accessible, skipping: %m", path); + free(path); + continue; + } + + r = strv_consume(&con, path); + if (r < 0) + return r; + } + + if (strv_isempty(con)) { + log_debug("No devices found for system console"); + + r = strv_extend(&con, "/dev/console"); + if (r < 0) + return r; + } + + *consoles = con; + con = NULL; + return 0; +} + bool tty_is_vc_resolve(const char *tty) { _cleanup_free_ char *active = NULL; @@ -820,12 +791,8 @@ bool tty_is_vc_resolve(const char *tty) { return tty_is_vc(tty); } -/// UNNEEDED by elogind -#if 0 const char *default_term_for_tty(const char *tty) { - assert(tty); - - return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220"; + return tty && tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220"; } #endif // 0 @@ -898,8 +865,7 @@ unsigned lines(void) { } /* intended to be used as a SIGWINCH sighandler */ -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind void columns_lines_cache_reset(int signum) { cached_columns = 0; cached_lines = 0; @@ -982,8 +948,6 @@ int getttyname_malloc(int fd, char **ret) { return 0; } -/// UNNEEDED by elogind -#if 0 int getttyname_harder(int fd, char **r) { int k; char *s = NULL; @@ -1000,7 +964,6 @@ int getttyname_harder(int fd, char **r) { *r = s; return 0; } -#endif // 0 int get_ctty_devnr(pid_t pid, dev_t *d) { int r; @@ -1093,8 +1056,34 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { return 0; } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind +int ptsname_malloc(int fd, char **ret) { + size_t l = 100; + + assert(fd >= 0); + assert(ret); + + for (;;) { + char *c; + + c = new(char, l); + if (!c) + return -ENOMEM; + + if (ptsname_r(fd, c, l) == 0) { + *ret = c; + return 0; + } + if (errno != ERANGE) { + free(c); + return -errno; + } + + free(c); + l *= 2; + } +} + int ptsname_namespace(int pty, char **ret) { int no = -1, r; @@ -1113,4 +1102,123 @@ int ptsname_namespace(int pty, char **ret) { return 0; } + +int openpt_in_namespace(pid_t pid, int flags) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + siginfo_t si; + pid_t child; + int r; + + assert(pid > 0); + + r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + int master; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC); + if (master < 0) + _exit(EXIT_FAILURE); + + if (unlockpt(master) < 0) + _exit(EXIT_FAILURE); + + if (send_one_fd(pair[1], master, 0) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + pair[1] = safe_close(pair[1]); + + r = wait_for_terminate(child, &si); + if (r < 0) + return r; + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return -EIO; + + return receive_one_fd(pair[0], 0); +} + +int open_terminal_in_namespace(pid_t pid, const char *name, int mode) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + siginfo_t si; + pid_t child; + int r; + + r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + int master; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC); + if (master < 0) + _exit(EXIT_FAILURE); + + if (send_one_fd(pair[1], master, 0) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + pair[1] = safe_close(pair[1]); + + r = wait_for_terminate(child, &si); + if (r < 0) + return r; + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return -EIO; + + return receive_one_fd(pair[0], 0); +} #endif // 0 + +bool colors_enabled(void) { + static int enabled = -1; + + if (_unlikely_(enabled < 0)) { + const char *colors; + + colors = getenv("SYSTEMD_COLORS"); + if (colors) + enabled = parse_boolean(colors) != 0; + else if (streq_ptr(getenv("TERM"), "dumb")) + enabled = false; + else + enabled = on_tty(); + } + + return enabled; +}