shared: add terminal-util.[ch]
authorRonny Chevalier <chevalier.ronny@gmail.com>
Fri, 10 Apr 2015 21:15:59 +0000 (23:15 +0200)
committerRonny Chevalier <chevalier.ronny@gmail.com>
Fri, 10 Apr 2015 22:34:02 +0000 (00:34 +0200)
52 files changed:
.gitignore
Makefile.am
src/analyze/analyze.c
src/cgtop/cgtop.c
src/core/execute.c
src/core/failure-action.c
src/core/job.c
src/core/killall.c
src/core/main.c
src/core/manager.c
src/core/shutdown.c
src/core/transaction.c
src/delta/delta.c
src/firstboot/firstboot.c
src/getty-generator/getty-generator.c
src/journal/coredumpctl.c
src/journal/journal-verify.c
src/journal/journalctl.c
src/journal/journald-console.c
src/journal/test-journal-verify.c
src/libsystemd/sd-bus/bus-dump.c
src/libsystemd/sd-bus/busctl.c
src/login/loginctl.c
src/login/logind-action.c
src/login/logind-core.c
src/login/logind-dbus.c
src/login/logind-seat.c
src/login/logind-session.c
src/login/pam_systemd.c
src/login/sysfs-show.c
src/machine/machinectl.c
src/network/networkctl.c
src/nspawn/nspawn.c
src/shared/ask-password-api.c
src/shared/cgroup-show.c
src/shared/log.c
src/shared/logs-show.c
src/shared/pager.c
src/shared/terminal-util.c [new file with mode: 0644]
src/shared/terminal-util.h [new file with mode: 0644]
src/shared/util.c
src/shared/util.h
src/shared/utmp-wtmp.c
src/systemctl/systemctl.c
src/test/test-ellipsize.c
src/test/test-process-util.c
src/test/test-strip-tab-ansi.c
src/test/test-terminal-util.c [new file with mode: 0644]
src/test/test-util.c
src/timedate/timedatectl.c
src/tty-ask-password-agent/tty-ask-password-agent.c
src/vconsole/vconsole-setup.c

index 7330c80..bcf21fe 100644 (file)
 /test-tables
 /test-term-page
 /test-term-parser
+/test-terminal-util
 /test-time
 /test-tmpfiles
 /test-udev
index f348ef9..114d4a1 100644 (file)
@@ -903,6 +903,8 @@ libsystemd_shared_la_SOURCES = \
        src/shared/process-util.h \
        src/shared/random-util.c \
        src/shared/random-util.h \
+       src/shared/terminal-util.c \
+       src/shared/terminal-util.h \
        src/shared/uid-range.c \
        src/shared/uid-range.h \
        src/shared/nss-util.h \
@@ -1394,6 +1396,7 @@ tests += \
        test-ellipsize \
        test-util \
        test-process-util \
+       test-terminal-util \
        test-path-lookup \
        test-ring \
        test-barrier \
@@ -1675,6 +1678,12 @@ test_process_util_SOURCES = \
 test_process_util_LDADD = \
        libsystemd-shared.la
 
+test_terminal_util_SOURCES = \
+       src/test/test-terminal-util.c
+
+test_terminal_util_LDADD = \
+       libsystemd-shared.la
+
 test_path_lookup_SOURCES = \
        src/test/test-path-lookup.c
 
index 7abe969..17fc5c8 100644 (file)
@@ -38,6 +38,7 @@
 #include "hashmap.h"
 #include "pager.h"
 #include "analyze-verify.h"
+#include "terminal-util.h"
 
 #define SCALE_X (0.1 / 1000.0)   /* pixels per us */
 #define SCALE_Y (20.0)
index f951c37..a390cf3 100644 (file)
@@ -29,6 +29,7 @@
 #include <getopt.h>
 
 #include "path-util.h"
+#include "terminal-util.h"
 #include "util.h"
 #include "hashmap.h"
 #include "cgroup-util.h"
index b00d510..bbd0d2c 100644 (file)
@@ -78,6 +78,7 @@
 #include "cap-list.h"
 #include "formats-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 #ifdef HAVE_APPARMOR
 #include "apparmor-util.h"
index ffeb5cd..7c6abb3 100644 (file)
@@ -27,6 +27,7 @@
 #include "bus-error.h"
 #include "special.h"
 #include "failure-action.h"
+#include "terminal-util.h"
 
 static void log_and_status(Manager *m, const char *message) {
         log_warning("%s", message);
index 0230f93..e92e24e 100644 (file)
@@ -33,6 +33,7 @@
 #include "async.h"
 #include "virt.h"
 #include "dbus.h"
+#include "terminal-util.h"
 
 Job* job_new_raw(Unit *unit) {
         Job *j;
index 31bec01..6e85923 100644 (file)
@@ -29,6 +29,7 @@
 #include "set.h"
 #include "formats-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 #define TIMEOUT_USEC (10 * USEC_PER_SEC)
 
index 80a51ee..af28ac6 100644 (file)
@@ -74,6 +74,7 @@
 #include "kmod-setup.h"
 #include "formats-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 static enum {
         ACTION_RUN,
index 6d1729b..2b04644 100644 (file)
@@ -72,6 +72,7 @@
 #include "bus-kernel.h"
 #include "time-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 /* Initial delay and the interval for printing status messages about running jobs */
 #define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
index f037a38..aba16b4 100644 (file)
@@ -43,6 +43,7 @@
 #include "def.h"
 #include "switch-root.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 #define FINALIZE_ATTEMPTS 50
 
index 64c2af5..5974b1e 100644 (file)
@@ -25,6 +25,7 @@
 #include "bus-common-errors.h"
 #include "bus-error.h"
 #include "transaction.h"
+#include "terminal-util.h"
 
 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
 
index 106c036..c764bb4 100644 (file)
@@ -33,6 +33,7 @@
 #include "build.h"
 #include "strv.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 static const char prefixes[] =
         "/etc\0"
index c92f379..37326df 100644 (file)
@@ -35,6 +35,7 @@
 #include "random-util.h"
 #include "locale-util.h"
 #include "ask-password-api.h"
+#include "terminal-util.h"
 
 static char *arg_root = NULL;
 static char *arg_locale = NULL;  /* $LANG */
index 0f59f5a..d4688d3 100644 (file)
@@ -32,6 +32,7 @@
 #include "fileio.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 static const char *arg_dest = "/tmp";
 
index 4f6ddfa..bcb0ff9 100644 (file)
@@ -38,6 +38,7 @@
 #include "compress.h"
 #include "sigbus.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 static enum {
         ACTION_NONE,
index 146c10b..ce734d8 100644 (file)
@@ -32,6 +32,7 @@
 #include "journal-verify.h"
 #include "lookup3.h"
 #include "compress.h"
+#include "terminal-util.h"
 
 static void draw_progress(uint64_t p, usec_t *last_usec) {
         unsigned n, i, j, k;
index 40c84b9..a5ed41d 100644 (file)
@@ -60,6 +60,7 @@
 #include "mkdir.h"
 #include "bus-util.h"
 #include "bus-error.h"
+#include "terminal-util.h"
 
 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
 
index 6c15530..307bdc3 100644 (file)
@@ -28,6 +28,7 @@
 #include "journald-console.h"
 #include "formats-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 static bool prefix_timestamp(void) {
 
index 8008f74..d24502d 100644 (file)
@@ -28,6 +28,7 @@
 #include "rm-rf.h"
 #include "journal-file.h"
 #include "journal-verify.h"
+#include "terminal-util.h"
 
 #define N_ENTRIES 6000
 #define RANDOM_RANGE 77
index d722680..9165dd7 100644 (file)
@@ -25,6 +25,7 @@
 #include "macro.h"
 #include "cap-list.h"
 #include "formats-util.h"
+#include "terminal-util.h"
 
 #include "bus-message.h"
 #include "bus-internal.h"
index d52dbdf..39caa4e 100644 (file)
@@ -36,6 +36,7 @@
 #include "bus-signature.h"
 #include "bus-type.h"
 #include "busctl-introspect.h"
+#include "terminal-util.h"
 
 static bool arg_no_pager = false;
 static bool arg_legend = true;
index 7393eb3..4a5a618 100644 (file)
@@ -42,6 +42,7 @@
 #include "spawn-polkit-agent.h"
 #include "verbs.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 static char **arg_property = NULL;
 static bool arg_all = false;
index 29e7ed0..f635fb1 100644 (file)
@@ -29,6 +29,7 @@
 #include "logind-action.h"
 #include "formats-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 int manager_handle_action(
                 Manager *m,
index e8da59a..440c32a 100644 (file)
@@ -31,6 +31,7 @@
 #include "bus-error.h"
 #include "udev-util.h"
 #include "logind.h"
+#include "terminal-util.h"
 
 int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
         Device *d;
index 6bf9205..76070a3 100644 (file)
@@ -42,6 +42,7 @@
 #include "logind.h"
 #include "formats-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
index 4c0bebd..11d24ce 100644 (file)
@@ -30,6 +30,7 @@
 #include "util.h"
 #include "mkdir.h"
 #include "formats-util.h"
+#include "terminal-util.h"
 
 Seat *seat_new(Manager *m, const char *id) {
         Seat *s;
index cebc90c..6a450b0 100644 (file)
@@ -38,6 +38,7 @@
 #include "bus-error.h"
 #include "logind-session.h"
 #include "formats-util.h"
+#include "terminal-util.h"
 
 #define RELEASE_USEC (20*USEC_PER_SEC)
 
index a0fabfe..cdd45ac 100644 (file)
@@ -41,6 +41,7 @@
 #include "fileio.h"
 #include "bus-error.h"
 #include "formats-util.h"
+#include "terminal-util.h"
 
 static int parse_argv(
                 pam_handle_t *handle,
index 9bd9152..9a9fb76 100644 (file)
@@ -27,6 +27,7 @@
 #include "sysfs-show.h"
 #include "path-util.h"
 #include "udev-util.h"
+#include "terminal-util.h"
 
 static int show_sysfs_one(
                 struct udev *udev,
index 87e15d7..26cd5b8 100644 (file)
@@ -53,6 +53,7 @@
 #include "verbs.h"
 #include "import-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 static char **arg_property = NULL;
 static bool arg_all = false;
index 9716499..69b4ab4 100644 (file)
@@ -41,6 +41,7 @@
 #include "socket-util.h"
 #include "ether-addr-util.h"
 #include "verbs.h"
+#include "terminal-util.h"
 
 static bool arg_no_pager = false;
 static bool arg_legend = true;
index 6417a8c..6d4aadd 100644 (file)
@@ -94,6 +94,7 @@
 #include "local-addresses.h"
 #include "formats-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 #ifdef HAVE_SECCOMP
 #include "seccomp-util.h"
index ad1a773..a3a2e51 100644 (file)
@@ -36,6 +36,7 @@
 #include "mkdir.h"
 #include "strv.h"
 #include "random-util.h"
+#include "terminal-util.h"
 
 #include "ask-password-api.h"
 
index 0f263e9..1a2c4b2 100644 (file)
@@ -31,6 +31,7 @@
 #include "path-util.h"
 #include "cgroup-util.h"
 #include "cgroup-show.h"
+#include "terminal-util.h"
 
 static int compare(const void *a, const void *b) {
         const pid_t *p = a, *q = b;
index 7edcf1f..85c0605 100644 (file)
@@ -36,6 +36,7 @@
 #include "socket-util.h"
 #include "formats-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 #define SNDBUF_SIZE (8*1024*1024)
 
index 7a7a1e9..27f4072 100644 (file)
@@ -33,6 +33,7 @@
 #include "journal-internal.h"
 #include "formats-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 /* up to three lines (each up to 100 characters),
    or 300 characters, whichever is less */
index b5a584b..58b62fd 100644 (file)
@@ -29,6 +29,7 @@
 #include "util.h"
 #include "process-util.h"
 #include "macro.h"
+#include "terminal-util.h"
 
 static pid_t pager_pid = 0;
 
diff --git a/src/shared/terminal-util.c b/src/shared/terminal-util.c
new file mode 100644 (file)
index 0000000..f5b6590
--- /dev/null
@@ -0,0 +1,1072 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <assert.h>
+#include <poll.h>
+#include <linux/vt.h>
+#include <linux/tiocl.h>
+#include <linux/kd.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;
+
+int chvt(int vt) {
+        _cleanup_close_ int fd;
+
+        fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        if (vt < 0) {
+                int tiocl[2] = {
+                        TIOCL_GETKMSGREDIRECT,
+                        0
+                };
+
+                if (ioctl(fd, TIOCLINUX, tiocl) < 0)
+                        return -errno;
+
+                vt = tiocl[0] <= 0 ? 1 : tiocl[0];
+        }
+
+        if (ioctl(fd, VT_ACTIVATE, vt) < 0)
+                return -errno;
+
+        return 0;
+}
+
+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];
+
+        assert(f);
+        assert(ret);
+
+        if (tcgetattr(fileno(f), &old_termios) >= 0) {
+                new_termios = old_termios;
+
+                new_termios.c_lflag &= ~ICANON;
+                new_termios.c_cc[VMIN] = 1;
+                new_termios.c_cc[VTIME] = 0;
+
+                if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
+                        size_t k;
+
+                        if (t != USEC_INFINITY) {
+                                if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) {
+                                        tcsetattr(fileno(f), TCSADRAIN, &old_termios);
+                                        return -ETIMEDOUT;
+                                }
+                        }
+
+                        k = fread(&c, 1, 1, f);
+
+                        tcsetattr(fileno(f), TCSADRAIN, &old_termios);
+
+                        if (k <= 0)
+                                return -EIO;
+
+                        if (need_nl)
+                                *need_nl = c != '\n';
+
+                        *ret = c;
+                        return 0;
+                }
+        }
+
+        if (t != USEC_INFINITY) {
+                if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0)
+                        return -ETIMEDOUT;
+        }
+
+        errno = 0;
+        if (!fgets(line, sizeof(line), f))
+                return errno ? -errno : -EIO;
+
+        truncate_nl(line);
+
+        if (strlen(line) != 1)
+                return -EBADMSG;
+
+        if (need_nl)
+                *need_nl = false;
+
+        *ret = line[0];
+        return 0;
+}
+
+int ask_char(char *ret, const char *replies, const char *text, ...) {
+        int r;
+
+        assert(ret);
+        assert(replies);
+        assert(text);
+
+        for (;;) {
+                va_list ap;
+                char c;
+                bool need_nl = true;
+
+                if (on_tty())
+                        fputs(ANSI_HIGHLIGHT_ON, stdout);
+
+                va_start(ap, text);
+                vprintf(text, ap);
+                va_end(ap);
+
+                if (on_tty())
+                        fputs(ANSI_HIGHLIGHT_OFF, stdout);
+
+                fflush(stdout);
+
+                r = read_one_char(stdin, &c, USEC_INFINITY, &need_nl);
+                if (r < 0) {
+
+                        if (r == -EBADMSG) {
+                                puts("Bad input, please try again.");
+                                continue;
+                        }
+
+                        putchar('\n');
+                        return r;
+                }
+
+                if (need_nl)
+                        putchar('\n');
+
+                if (strchr(replies, c)) {
+                        *ret = c;
+                        return 0;
+                }
+
+                puts("Read unexpected character, please try again.");
+        }
+}
+
+int ask_string(char **ret, const char *text, ...) {
+        assert(ret);
+        assert(text);
+
+        for (;;) {
+                char line[LINE_MAX];
+                va_list ap;
+
+                if (on_tty())
+                        fputs(ANSI_HIGHLIGHT_ON, stdout);
+
+                va_start(ap, text);
+                vprintf(text, ap);
+                va_end(ap);
+
+                if (on_tty())
+                        fputs(ANSI_HIGHLIGHT_OFF, stdout);
+
+                fflush(stdout);
+
+                errno = 0;
+                if (!fgets(line, sizeof(line), stdin))
+                        return errno ? -errno : -EIO;
+
+                if (!endswith(line, "\n"))
+                        putchar('\n');
+                else {
+                        char *s;
+
+                        if (isempty(line))
+                                continue;
+
+                        truncate_nl(line);
+                        s = strdup(line);
+                        if (!s)
+                                return -ENOMEM;
+
+                        *ret = s;
+                        return 0;
+                }
+        }
+}
+
+int reset_terminal_fd(int fd, bool switch_to_text) {
+        struct termios termios;
+        int r = 0;
+
+        /* Set terminal to some sane defaults */
+
+        assert(fd >= 0);
+
+        /* We leave locked terminal attributes untouched, so that
+         * Plymouth may set whatever it wants to set, and we don't
+         * interfere with that. */
+
+        /* Disable exclusive mode, just in case */
+        ioctl(fd, TIOCNXCL);
+
+        /* Switch to text mode */
+        if (switch_to_text)
+                ioctl(fd, KDSETMODE, KD_TEXT);
+
+        /* Enable console unicode mode */
+        ioctl(fd, KDSKBMODE, K_UNICODE);
+
+        if (tcgetattr(fd, &termios) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        /* We only reset the stuff that matters to the software. How
+         * hardware is set up we don't touch assuming that somebody
+         * else will do that for us */
+
+        termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
+        termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
+        termios.c_oflag |= ONLCR;
+        termios.c_cflag |= CREAD;
+        termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
+
+        termios.c_cc[VINTR]    =   03;  /* ^C */
+        termios.c_cc[VQUIT]    =  034;  /* ^\ */
+        termios.c_cc[VERASE]   = 0177;
+        termios.c_cc[VKILL]    =  025;  /* ^X */
+        termios.c_cc[VEOF]     =   04;  /* ^D */
+        termios.c_cc[VSTART]   =  021;  /* ^Q */
+        termios.c_cc[VSTOP]    =  023;  /* ^S */
+        termios.c_cc[VSUSP]    =  032;  /* ^Z */
+        termios.c_cc[VLNEXT]   =  026;  /* ^V */
+        termios.c_cc[VWERASE]  =  027;  /* ^W */
+        termios.c_cc[VREPRINT] =  022;  /* ^R */
+        termios.c_cc[VEOL]     =    0;
+        termios.c_cc[VEOL2]    =    0;
+
+        termios.c_cc[VTIME]  = 0;
+        termios.c_cc[VMIN]   = 1;
+
+        if (tcsetattr(fd, TCSANOW, &termios) < 0)
+                r = -errno;
+
+finish:
+        /* Just in case, flush all crap out */
+        tcflush(fd, TCIOFLUSH);
+
+        return r;
+}
+
+int reset_terminal(const char *name) {
+        _cleanup_close_ int fd = -1;
+
+        fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return fd;
+
+        return reset_terminal_fd(fd, true);
+}
+
+int open_terminal(const char *name, int mode) {
+        int fd, r;
+        unsigned c = 0;
+
+        /*
+         * If a TTY is in the process of being closed opening it might
+         * cause EIO. This is horribly awful, but unlikely to be
+         * changed in the kernel. Hence we work around this problem by
+         * retrying a couple of times.
+         *
+         * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
+         */
+
+        assert(!(mode & O_CREAT));
+
+        for (;;) {
+                fd = open(name, mode, 0);
+                if (fd >= 0)
+                        break;
+
+                if (errno != EIO)
+                        return -errno;
+
+                /* Max 1s in total */
+                if (c >= 20)
+                        return -errno;
+
+                usleep(50 * USEC_PER_MSEC);
+                c++;
+        }
+
+        r = isatty(fd);
+        if (r < 0) {
+                safe_close(fd);
+                return -errno;
+        }
+
+        if (!r) {
+                safe_close(fd);
+                return -ENOTTY;
+        }
+
+        return fd;
+}
+
+int acquire_terminal(
+                const char *name,
+                bool fail,
+                bool force,
+                bool ignore_tiocstty_eperm,
+                usec_t timeout) {
+
+        int fd = -1, notify = -1, r = 0, wd = -1;
+        usec_t ts = 0;
+
+        assert(name);
+
+        /* We use inotify to be notified when the tty is closed. We
+         * create the watch before checking if we can actually acquire
+         * it, so that we don't lose any event.
+         *
+         * Note: strictly speaking this actually watches for the
+         * device being closed, it does *not* really watch whether a
+         * tty loses its controlling process. However, unless some
+         * rogue process uses TIOCNOTTY on /dev/tty *after* closing
+         * its tty otherwise this will not become a problem. As long
+         * as the administrator makes sure not configure any service
+         * on the same tty as an untrusted user this should not be a
+         * problem. (Which he probably should not do anyway.) */
+
+        if (timeout != USEC_INFINITY)
+                ts = now(CLOCK_MONOTONIC);
+
+        if (!fail && !force) {
+                notify = inotify_init1(IN_CLOEXEC | (timeout != USEC_INFINITY ? IN_NONBLOCK : 0));
+                if (notify < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+
+                wd = inotify_add_watch(notify, name, IN_CLOSE);
+                if (wd < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+        }
+
+        for (;;) {
+                struct sigaction sa_old, sa_new = {
+                        .sa_handler = SIG_IGN,
+                        .sa_flags = SA_RESTART,
+                };
+
+                if (notify >= 0) {
+                        r = flush_fd(notify);
+                        if (r < 0)
+                                goto fail;
+                }
+
+                /* We pass here O_NOCTTY only so that we can check the return
+                 * value TIOCSCTTY and have a reliable way to figure out if we
+                 * successfully became the controlling process of the tty */
+                fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+                if (fd < 0)
+                        return fd;
+
+                /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
+                 * if we already own the tty. */
+                assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
+
+                /* First, try to get the tty */
+                if (ioctl(fd, TIOCSCTTY, force) < 0)
+                        r = -errno;
+
+                assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
+
+                /* 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)
+                        r = 0;
+
+                if (r < 0 && (force || fail || r != -EPERM)) {
+                        goto fail;
+                }
+
+                if (r >= 0)
+                        break;
+
+                assert(!fail);
+                assert(!force);
+                assert(notify >= 0);
+
+                for (;;) {
+                        union inotify_event_buffer buffer;
+                        struct inotify_event *e;
+                        ssize_t l;
+
+                        if (timeout != USEC_INFINITY) {
+                                usec_t n;
+
+                                n = now(CLOCK_MONOTONIC);
+                                if (ts + timeout < n) {
+                                        r = -ETIMEDOUT;
+                                        goto fail;
+                                }
+
+                                r = fd_wait_for_event(fd, POLLIN, ts + timeout - n);
+                                if (r < 0)
+                                        goto fail;
+
+                                if (r == 0) {
+                                        r = -ETIMEDOUT;
+                                        goto fail;
+                                }
+                        }
+
+                        l = read(notify, &buffer, sizeof(buffer));
+                        if (l < 0) {
+                                if (errno == EINTR || errno == EAGAIN)
+                                        continue;
+
+                                r = -errno;
+                                goto fail;
+                        }
+
+                        FOREACH_INOTIFY_EVENT(e, buffer, l) {
+                                if (e->wd != wd || !(e->mask & IN_CLOSE)) {
+                                        r = -EIO;
+                                        goto fail;
+                                }
+                        }
+
+                        break;
+                }
+
+                /* We close the tty fd here since if the old session
+                 * ended our handle will be dead. It's important that
+                 * we do this after sleeping, so that we don't enter
+                 * an endless loop. */
+                fd = safe_close(fd);
+        }
+
+        safe_close(notify);
+
+        r = reset_terminal_fd(fd, true);
+        if (r < 0)
+                log_warning_errno(r, "Failed to reset terminal: %m");
+
+        return fd;
+
+fail:
+        safe_close(fd);
+        safe_close(notify);
+
+        return r;
+}
+
+int release_terminal(void) {
+        static const struct sigaction sa_new = {
+                .sa_handler = SIG_IGN,
+                .sa_flags = SA_RESTART,
+        };
+
+        _cleanup_close_ int fd = -1;
+        struct sigaction sa_old;
+        int r = 0;
+
+        fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
+         * by our own TIOCNOTTY */
+        assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
+
+        if (ioctl(fd, TIOCNOTTY) < 0)
+                r = -errno;
+
+        assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
+
+        return r;
+}
+
+int terminal_vhangup_fd(int fd) {
+        assert(fd >= 0);
+
+        if (ioctl(fd, TIOCVHANGUP) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int terminal_vhangup(const char *name) {
+        _cleanup_close_ int fd;
+
+        fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return fd;
+
+        return terminal_vhangup_fd(fd);
+}
+
+int vt_disallocate(const char *name) {
+        int fd, r;
+        unsigned u;
+
+        /* Deallocate the VT if possible. If not possible
+         * (i.e. because it is the active one), at least clear it
+         * entirely (including the scrollback buffer) */
+
+        if (!startswith(name, "/dev/"))
+                return -EINVAL;
+
+        if (!tty_is_vc(name)) {
+                /* So this is not a VT. I guess we cannot deallocate
+                 * it then. But let's at least clear the screen */
+
+                fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+                if (fd < 0)
+                        return fd;
+
+                loop_write(fd,
+                           "\033[r"    /* clear scrolling region */
+                           "\033[H"    /* move home */
+                           "\033[2J",  /* clear screen */
+                           10, false);
+                safe_close(fd);
+
+                return 0;
+        }
+
+        if (!startswith(name, "/dev/tty"))
+                return -EINVAL;
+
+        r = safe_atou(name+8, &u);
+        if (r < 0)
+                return r;
+
+        if (u <= 0)
+                return -EINVAL;
+
+        /* Try to deallocate */
+        fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return fd;
+
+        r = ioctl(fd, VT_DISALLOCATE, u);
+        safe_close(fd);
+
+        if (r >= 0)
+                return 0;
+
+        if (errno != EBUSY)
+                return -errno;
+
+        /* Couldn't deallocate, so let's clear it fully with
+         * scrollback */
+        fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return fd;
+
+        loop_write(fd,
+                   "\033[r"   /* clear scrolling region */
+                   "\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... */
+
+        ioctl(fd, KIOCSOUND, (int)(1193180/440));
+        usleep(125*USEC_PER_MSEC);
+
+        ioctl(fd, KIOCSOUND, (int)(1193180/220));
+        usleep(125*USEC_PER_MSEC);
+
+        ioctl(fd, KIOCSOUND, (int)(1193180/220));
+        usleep(125*USEC_PER_MSEC);
+
+        ioctl(fd, KIOCSOUND, 0);
+}
+
+int make_console_stdio(void) {
+        int fd, r;
+
+        /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
+
+        fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY);
+        if (fd < 0)
+                return log_error_errno(fd, "Failed to acquire terminal: %m");
+
+        r = make_stdio(fd);
+        if (r < 0)
+                return log_error_errno(r, "Failed to duplicate terminal fd: %m");
+
+        return 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);
+
+        return vtnr_from_tty(tty) >= 0;
+}
+
+bool tty_is_console(const char *tty) {
+        assert(tty);
+
+        if (startswith(tty, "/dev/"))
+                tty += 5;
+
+        return streq(tty, "console");
+}
+
+int vtnr_from_tty(const char *tty) {
+        int i, r;
+
+        assert(tty);
+
+        if (startswith(tty, "/dev/"))
+                tty += 5;
+
+        if (!startswith(tty, "tty") )
+                return -EINVAL;
+
+        if (tty[3] < '0' || tty[3] > '9')
+                return -EINVAL;
+
+        r = safe_atoi(tty+3, &i);
+        if (r < 0)
+                return r;
+
+        if (i < 0 || i > 63)
+                return -EINVAL;
+
+        return i;
+}
+
+char *resolve_dev_console(char **active) {
+        char *tty;
+
+        /* Resolve where /dev/console is pointing to, if /sys is actually ours
+         * (i.e. not read-only-mounted which is a sign for container setups) */
+
+        if (path_is_read_only_fs("/sys") > 0)
+                return NULL;
+
+        if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
+                return NULL;
+
+        /* If multiple log outputs are configured the last one is what
+         * /dev/console points to */
+        tty = strrchr(*active, ' ');
+        if (tty)
+                tty++;
+        else
+                tty = *active;
+
+        if (streq(tty, "tty0")) {
+                char *tmp;
+
+                /* Get the active VC (e.g. tty1) */
+                if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) {
+                        free(*active);
+                        tty = *active = tmp;
+                }
+        }
+
+        return tty;
+}
+
+bool tty_is_vc_resolve(const char *tty) {
+        _cleanup_free_ char *active = NULL;
+
+        assert(tty);
+
+        if (startswith(tty, "/dev/"))
+                tty += 5;
+
+        if (streq(tty, "console")) {
+                tty = resolve_dev_console(&active);
+                if (!tty)
+                        return false;
+        }
+
+        return tty_is_vc(tty);
+}
+
+const char *default_term_for_tty(const char *tty) {
+        assert(tty);
+
+        return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
+}
+
+int fd_columns(int fd) {
+        struct winsize ws = {};
+
+        if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
+                return -errno;
+
+        if (ws.ws_col <= 0)
+                return -EIO;
+
+        return ws.ws_col;
+}
+
+unsigned columns(void) {
+        const char *e;
+        int c;
+
+        if (_likely_(cached_columns > 0))
+                return cached_columns;
+
+        c = 0;
+        e = getenv("COLUMNS");
+        if (e)
+                (void) safe_atoi(e, &c);
+
+        if (c <= 0)
+                c = fd_columns(STDOUT_FILENO);
+
+        if (c <= 0)
+                c = 80;
+
+        cached_columns = c;
+        return cached_columns;
+}
+
+int fd_lines(int fd) {
+        struct winsize ws = {};
+
+        if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
+                return -errno;
+
+        if (ws.ws_row <= 0)
+                return -EIO;
+
+        return ws.ws_row;
+}
+
+unsigned lines(void) {
+        const char *e;
+        int l;
+
+        if (_likely_(cached_lines > 0))
+                return cached_lines;
+
+        l = 0;
+        e = getenv("LINES");
+        if (e)
+                (void) safe_atoi(e, &l);
+
+        if (l <= 0)
+                l = fd_lines(STDOUT_FILENO);
+
+        if (l <= 0)
+                l = 24;
+
+        cached_lines = l;
+        return cached_lines;
+}
+
+/* intended to be used as a SIGWINCH sighandler */
+void columns_lines_cache_reset(int signum) {
+        cached_columns = 0;
+        cached_lines = 0;
+}
+
+bool on_tty(void) {
+        static int cached_on_tty = -1;
+
+        if (_unlikely_(cached_on_tty < 0))
+                cached_on_tty = isatty(STDOUT_FILENO) > 0;
+
+        return cached_on_tty;
+}
+
+int make_stdio(int fd) {
+        int r, s, t;
+
+        assert(fd >= 0);
+
+        r = dup2(fd, STDIN_FILENO);
+        s = dup2(fd, STDOUT_FILENO);
+        t = dup2(fd, STDERR_FILENO);
+
+        if (fd >= 3)
+                safe_close(fd);
+
+        if (r < 0 || s < 0 || t < 0)
+                return -errno;
+
+        /* Explicitly unset O_CLOEXEC, since if fd was < 3, then
+         * dup2() was a NOP and the bit hence possibly set. */
+        fd_cloexec(STDIN_FILENO, false);
+        fd_cloexec(STDOUT_FILENO, false);
+        fd_cloexec(STDERR_FILENO, false);
+
+        return 0;
+}
+
+int make_null_stdio(void) {
+        int null_fd;
+
+        null_fd = open("/dev/null", O_RDWR|O_NOCTTY);
+        if (null_fd < 0)
+                return -errno;
+
+        return make_stdio(null_fd);
+}
+
+int getttyname_malloc(int fd, char **ret) {
+        size_t l = 100;
+        int r;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        for (;;) {
+                char path[l];
+
+                r = ttyname_r(fd, path, sizeof(path));
+                if (r == 0) {
+                        const char *p;
+                        char *c;
+
+                        p = startswith(path, "/dev/");
+                        c = strdup(p ?: path);
+                        if (!c)
+                                return -ENOMEM;
+
+                        *ret = c;
+                        return 0;
+                }
+
+                if (r != ERANGE)
+                        return -r;
+
+                l *= 2;
+        }
+
+        return 0;
+}
+
+int getttyname_harder(int fd, char **r) {
+        int k;
+        char *s = NULL;
+
+        k = getttyname_malloc(fd, &s);
+        if (k < 0)
+                return k;
+
+        if (streq(s, "tty")) {
+                free(s);
+                return get_ctty(0, NULL, r);
+        }
+
+        *r = s;
+        return 0;
+}
+
+int get_ctty_devnr(pid_t pid, dev_t *d) {
+        int r;
+        _cleanup_free_ char *line = NULL;
+        const char *p;
+        unsigned long ttynr;
+
+        assert(pid >= 0);
+
+        p = procfs_file_alloca(pid, "stat");
+        r = read_one_line_file(p, &line);
+        if (r < 0)
+                return r;
+
+        p = strrchr(line, ')');
+        if (!p)
+                return -EIO;
+
+        p++;
+
+        if (sscanf(p, " "
+                   "%*c "  /* state */
+                   "%*d "  /* ppid */
+                   "%*d "  /* pgrp */
+                   "%*d "  /* session */
+                   "%lu ", /* ttynr */
+                   &ttynr) != 1)
+                return -EIO;
+
+        if (major(ttynr) == 0 && minor(ttynr) == 0)
+                return -ENOENT;
+
+        if (d)
+                *d = (dev_t) ttynr;
+
+        return 0;
+}
+
+int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
+        char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL;
+        _cleanup_free_ char *s = NULL;
+        const char *p;
+        dev_t devnr;
+        int k;
+
+        assert(r);
+
+        k = get_ctty_devnr(pid, &devnr);
+        if (k < 0)
+                return k;
+
+        sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
+
+        k = readlink_malloc(fn, &s);
+        if (k < 0) {
+
+                if (k != -ENOENT)
+                        return k;
+
+                /* This is an ugly hack */
+                if (major(devnr) == 136) {
+                        if (asprintf(&b, "pts/%u", minor(devnr)) < 0)
+                                return -ENOMEM;
+                } else {
+                        /* Probably something like the ptys which have no
+                         * symlink in /dev/char. Let's return something
+                         * vaguely useful. */
+
+                        b = strdup(fn + 5);
+                        if (!b)
+                                return -ENOMEM;
+                }
+        } else {
+                if (startswith(s, "/dev/"))
+                        p = s + 5;
+                else if (startswith(s, "../"))
+                        p = s + 3;
+                else
+                        p = s;
+
+                b = strdup(p);
+                if (!b)
+                        return -ENOMEM;
+        }
+
+        *r = b;
+        if (_devnr)
+                *_devnr = devnr;
+
+        return 0;
+}
diff --git a/src/shared/terminal-util.h b/src/shared/terminal-util.h
new file mode 100644 (file)
index 0000000..188714f
--- /dev/null
@@ -0,0 +1,109 @@
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "macro.h"
+#include "time-util.h"
+
+#define ANSI_HIGHLIGHT_ON "\x1B[1;39m"
+#define ANSI_RED_ON "\x1B[31m"
+#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m"
+#define ANSI_GREEN_ON "\x1B[32m"
+#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m"
+#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m"
+#define ANSI_HIGHLIGHT_BLUE_ON "\x1B[1;34m"
+#define ANSI_HIGHLIGHT_OFF "\x1B[0m"
+#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
+
+int reset_terminal_fd(int fd, bool switch_to_text);
+int reset_terminal(const char *name);
+
+int open_terminal(const char *name, int mode);
+int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm, usec_t timeout);
+int release_terminal(void);
+
+int terminal_vhangup_fd(int fd);
+int terminal_vhangup(const char *name);
+
+int chvt(int vt);
+
+int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl);
+int ask_char(char *ret, const char *replies, const char *text, ...) _printf_(3, 4);
+int ask_string(char **ret, const char *text, ...) _printf_(2, 3);
+
+int vt_disallocate(const char *name);
+
+char *resolve_dev_console(char **active);
+bool tty_is_vc(const char *tty);
+bool tty_is_vc_resolve(const char *tty);
+bool tty_is_console(const char *tty) _pure_;
+int vtnr_from_tty(const char *tty);
+const char *default_term_for_tty(const char *tty);
+
+void warn_melody(void);
+
+int make_stdio(int fd);
+int make_null_stdio(void);
+int make_console_stdio(void);
+
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
+
+int fd_columns(int fd);
+unsigned columns(void);
+int fd_lines(int fd);
+unsigned lines(void);
+void columns_lines_cache_reset(int _unused_ signum);
+
+bool on_tty(void);
+
+static inline const char *ansi_highlight(void) {
+        return on_tty() ? ANSI_HIGHLIGHT_ON : "";
+}
+
+static inline const char *ansi_highlight_red(void) {
+        return on_tty() ? ANSI_HIGHLIGHT_RED_ON : "";
+}
+
+static inline const char *ansi_highlight_green(void) {
+        return on_tty() ? ANSI_HIGHLIGHT_GREEN_ON : "";
+}
+
+static inline const char *ansi_highlight_yellow(void) {
+        return on_tty() ? ANSI_HIGHLIGHT_YELLOW_ON : "";
+}
+
+static inline const char *ansi_highlight_blue(void) {
+        return on_tty() ? ANSI_HIGHLIGHT_BLUE_ON : "";
+}
+
+static inline const char *ansi_highlight_off(void) {
+        return on_tty() ? ANSI_HIGHLIGHT_OFF : "";
+}
+
+int get_ctty_devnr(pid_t pid, dev_t *d);
+int get_ctty(pid_t, dev_t *_devnr, char **r);
+
+int getttyname_malloc(int fd, char **r);
+int getttyname_harder(int fd, char **r);
index e4c4dd9..508b5d1 100644 (file)
@@ -35,9 +35,6 @@
 #include <fcntl.h>
 #include <dirent.h>
 #include <sys/ioctl.h>
-#include <linux/vt.h>
-#include <linux/tiocl.h>
-#include <termios.h>
 #include <stdarg.h>
 #include <poll.h>
 #include <ctype.h>
@@ -45,7 +42,6 @@
 #include <sys/utsname.h>
 #include <pwd.h>
 #include <netinet/ip.h>
-#include <linux/kd.h>
 #include <sys/wait.h>
 #include <sys/time.h>
 #include <glob.h>
@@ -95,6 +91,7 @@
 #include "formats-util.h"
 #include "process-util.h"
 #include "random-util.h"
+#include "terminal-util.h"
 
 /* Put this test here for a lack of better place */
 assert_cc(EAGAIN == EWOULDBLOCK);
@@ -102,9 +99,6 @@ assert_cc(EAGAIN == EWOULDBLOCK);
 int saved_argc = 0;
 char **saved_argv = NULL;
 
-static volatile unsigned cached_columns = 0;
-static volatile unsigned cached_lines = 0;
-
 size_t page_size(void) {
         static thread_local size_t pgsz = 0;
         long r;
@@ -1509,301 +1503,6 @@ bool fstype_is_network(const char *fstype) {
         return nulstr_contains(table, fstype);
 }
 
-int chvt(int vt) {
-        _cleanup_close_ int fd;
-
-        fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        if (vt < 0) {
-                int tiocl[2] = {
-                        TIOCL_GETKMSGREDIRECT,
-                        0
-                };
-
-                if (ioctl(fd, TIOCLINUX, tiocl) < 0)
-                        return -errno;
-
-                vt = tiocl[0] <= 0 ? 1 : tiocl[0];
-        }
-
-        if (ioctl(fd, VT_ACTIVATE, vt) < 0)
-                return -errno;
-
-        return 0;
-}
-
-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];
-
-        assert(f);
-        assert(ret);
-
-        if (tcgetattr(fileno(f), &old_termios) >= 0) {
-                new_termios = old_termios;
-
-                new_termios.c_lflag &= ~ICANON;
-                new_termios.c_cc[VMIN] = 1;
-                new_termios.c_cc[VTIME] = 0;
-
-                if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
-                        size_t k;
-
-                        if (t != USEC_INFINITY) {
-                                if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) {
-                                        tcsetattr(fileno(f), TCSADRAIN, &old_termios);
-                                        return -ETIMEDOUT;
-                                }
-                        }
-
-                        k = fread(&c, 1, 1, f);
-
-                        tcsetattr(fileno(f), TCSADRAIN, &old_termios);
-
-                        if (k <= 0)
-                                return -EIO;
-
-                        if (need_nl)
-                                *need_nl = c != '\n';
-
-                        *ret = c;
-                        return 0;
-                }
-        }
-
-        if (t != USEC_INFINITY) {
-                if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0)
-                        return -ETIMEDOUT;
-        }
-
-        errno = 0;
-        if (!fgets(line, sizeof(line), f))
-                return errno ? -errno : -EIO;
-
-        truncate_nl(line);
-
-        if (strlen(line) != 1)
-                return -EBADMSG;
-
-        if (need_nl)
-                *need_nl = false;
-
-        *ret = line[0];
-        return 0;
-}
-
-int ask_char(char *ret, const char *replies, const char *text, ...) {
-        int r;
-
-        assert(ret);
-        assert(replies);
-        assert(text);
-
-        for (;;) {
-                va_list ap;
-                char c;
-                bool need_nl = true;
-
-                if (on_tty())
-                        fputs(ANSI_HIGHLIGHT_ON, stdout);
-
-                va_start(ap, text);
-                vprintf(text, ap);
-                va_end(ap);
-
-                if (on_tty())
-                        fputs(ANSI_HIGHLIGHT_OFF, stdout);
-
-                fflush(stdout);
-
-                r = read_one_char(stdin, &c, USEC_INFINITY, &need_nl);
-                if (r < 0) {
-
-                        if (r == -EBADMSG) {
-                                puts("Bad input, please try again.");
-                                continue;
-                        }
-
-                        putchar('\n');
-                        return r;
-                }
-
-                if (need_nl)
-                        putchar('\n');
-
-                if (strchr(replies, c)) {
-                        *ret = c;
-                        return 0;
-                }
-
-                puts("Read unexpected character, please try again.");
-        }
-}
-
-int ask_string(char **ret, const char *text, ...) {
-        assert(ret);
-        assert(text);
-
-        for (;;) {
-                char line[LINE_MAX];
-                va_list ap;
-
-                if (on_tty())
-                        fputs(ANSI_HIGHLIGHT_ON, stdout);
-
-                va_start(ap, text);
-                vprintf(text, ap);
-                va_end(ap);
-
-                if (on_tty())
-                        fputs(ANSI_HIGHLIGHT_OFF, stdout);
-
-                fflush(stdout);
-
-                errno = 0;
-                if (!fgets(line, sizeof(line), stdin))
-                        return errno ? -errno : -EIO;
-
-                if (!endswith(line, "\n"))
-                        putchar('\n');
-                else {
-                        char *s;
-
-                        if (isempty(line))
-                                continue;
-
-                        truncate_nl(line);
-                        s = strdup(line);
-                        if (!s)
-                                return -ENOMEM;
-
-                        *ret = s;
-                        return 0;
-                }
-        }
-}
-
-int reset_terminal_fd(int fd, bool switch_to_text) {
-        struct termios termios;
-        int r = 0;
-
-        /* Set terminal to some sane defaults */
-
-        assert(fd >= 0);
-
-        /* We leave locked terminal attributes untouched, so that
-         * Plymouth may set whatever it wants to set, and we don't
-         * interfere with that. */
-
-        /* Disable exclusive mode, just in case */
-        ioctl(fd, TIOCNXCL);
-
-        /* Switch to text mode */
-        if (switch_to_text)
-                ioctl(fd, KDSETMODE, KD_TEXT);
-
-        /* Enable console unicode mode */
-        ioctl(fd, KDSKBMODE, K_UNICODE);
-
-        if (tcgetattr(fd, &termios) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        /* We only reset the stuff that matters to the software. How
-         * hardware is set up we don't touch assuming that somebody
-         * else will do that for us */
-
-        termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
-        termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
-        termios.c_oflag |= ONLCR;
-        termios.c_cflag |= CREAD;
-        termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
-
-        termios.c_cc[VINTR]    =   03;  /* ^C */
-        termios.c_cc[VQUIT]    =  034;  /* ^\ */
-        termios.c_cc[VERASE]   = 0177;
-        termios.c_cc[VKILL]    =  025;  /* ^X */
-        termios.c_cc[VEOF]     =   04;  /* ^D */
-        termios.c_cc[VSTART]   =  021;  /* ^Q */
-        termios.c_cc[VSTOP]    =  023;  /* ^S */
-        termios.c_cc[VSUSP]    =  032;  /* ^Z */
-        termios.c_cc[VLNEXT]   =  026;  /* ^V */
-        termios.c_cc[VWERASE]  =  027;  /* ^W */
-        termios.c_cc[VREPRINT] =  022;  /* ^R */
-        termios.c_cc[VEOL]     =    0;
-        termios.c_cc[VEOL2]    =    0;
-
-        termios.c_cc[VTIME]  = 0;
-        termios.c_cc[VMIN]   = 1;
-
-        if (tcsetattr(fd, TCSANOW, &termios) < 0)
-                r = -errno;
-
-finish:
-        /* Just in case, flush all crap out */
-        tcflush(fd, TCIOFLUSH);
-
-        return r;
-}
-
-int reset_terminal(const char *name) {
-        _cleanup_close_ int fd = -1;
-
-        fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return fd;
-
-        return reset_terminal_fd(fd, true);
-}
-
-int open_terminal(const char *name, int mode) {
-        int fd, r;
-        unsigned c = 0;
-
-        /*
-         * If a TTY is in the process of being closed opening it might
-         * cause EIO. This is horribly awful, but unlikely to be
-         * changed in the kernel. Hence we work around this problem by
-         * retrying a couple of times.
-         *
-         * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
-         */
-
-        assert(!(mode & O_CREAT));
-
-        for (;;) {
-                fd = open(name, mode, 0);
-                if (fd >= 0)
-                        break;
-
-                if (errno != EIO)
-                        return -errno;
-
-                /* Max 1s in total */
-                if (c >= 20)
-                        return -errno;
-
-                usleep(50 * USEC_PER_MSEC);
-                c++;
-        }
-
-        r = isatty(fd);
-        if (r < 0) {
-                safe_close(fd);
-                return -errno;
-        }
-
-        if (!r) {
-                safe_close(fd);
-                return -ENOTTY;
-        }
-
-        return fd;
-}
-
 int flush_fd(int fd) {
         struct pollfd pollfd = {
                 .fd = fd,
@@ -1840,185 +1539,6 @@ int flush_fd(int fd) {
         }
 }
 
-int acquire_terminal(
-                const char *name,
-                bool fail,
-                bool force,
-                bool ignore_tiocstty_eperm,
-                usec_t timeout) {
-
-        int fd = -1, notify = -1, r = 0, wd = -1;
-        usec_t ts = 0;
-
-        assert(name);
-
-        /* We use inotify to be notified when the tty is closed. We
-         * create the watch before checking if we can actually acquire
-         * it, so that we don't lose any event.
-         *
-         * Note: strictly speaking this actually watches for the
-         * device being closed, it does *not* really watch whether a
-         * tty loses its controlling process. However, unless some
-         * rogue process uses TIOCNOTTY on /dev/tty *after* closing
-         * its tty otherwise this will not become a problem. As long
-         * as the administrator makes sure not configure any service
-         * on the same tty as an untrusted user this should not be a
-         * problem. (Which he probably should not do anyway.) */
-
-        if (timeout != USEC_INFINITY)
-                ts = now(CLOCK_MONOTONIC);
-
-        if (!fail && !force) {
-                notify = inotify_init1(IN_CLOEXEC | (timeout != USEC_INFINITY ? IN_NONBLOCK : 0));
-                if (notify < 0) {
-                        r = -errno;
-                        goto fail;
-                }
-
-                wd = inotify_add_watch(notify, name, IN_CLOSE);
-                if (wd < 0) {
-                        r = -errno;
-                        goto fail;
-                }
-        }
-
-        for (;;) {
-                struct sigaction sa_old, sa_new = {
-                        .sa_handler = SIG_IGN,
-                        .sa_flags = SA_RESTART,
-                };
-
-                if (notify >= 0) {
-                        r = flush_fd(notify);
-                        if (r < 0)
-                                goto fail;
-                }
-
-                /* We pass here O_NOCTTY only so that we can check the return
-                 * value TIOCSCTTY and have a reliable way to figure out if we
-                 * successfully became the controlling process of the tty */
-                fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
-                if (fd < 0)
-                        return fd;
-
-                /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
-                 * if we already own the tty. */
-                assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
-
-                /* First, try to get the tty */
-                if (ioctl(fd, TIOCSCTTY, force) < 0)
-                        r = -errno;
-
-                assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
-
-                /* 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)
-                        r = 0;
-
-                if (r < 0 && (force || fail || r != -EPERM)) {
-                        goto fail;
-                }
-
-                if (r >= 0)
-                        break;
-
-                assert(!fail);
-                assert(!force);
-                assert(notify >= 0);
-
-                for (;;) {
-                        union inotify_event_buffer buffer;
-                        struct inotify_event *e;
-                        ssize_t l;
-
-                        if (timeout != USEC_INFINITY) {
-                                usec_t n;
-
-                                n = now(CLOCK_MONOTONIC);
-                                if (ts + timeout < n) {
-                                        r = -ETIMEDOUT;
-                                        goto fail;
-                                }
-
-                                r = fd_wait_for_event(fd, POLLIN, ts + timeout - n);
-                                if (r < 0)
-                                        goto fail;
-
-                                if (r == 0) {
-                                        r = -ETIMEDOUT;
-                                        goto fail;
-                                }
-                        }
-
-                        l = read(notify, &buffer, sizeof(buffer));
-                        if (l < 0) {
-                                if (errno == EINTR || errno == EAGAIN)
-                                        continue;
-
-                                r = -errno;
-                                goto fail;
-                        }
-
-                        FOREACH_INOTIFY_EVENT(e, buffer, l) {
-                                if (e->wd != wd || !(e->mask & IN_CLOSE)) {
-                                        r = -EIO;
-                                        goto fail;
-                                }
-                        }
-
-                        break;
-                }
-
-                /* We close the tty fd here since if the old session
-                 * ended our handle will be dead. It's important that
-                 * we do this after sleeping, so that we don't enter
-                 * an endless loop. */
-                fd = safe_close(fd);
-        }
-
-        safe_close(notify);
-
-        r = reset_terminal_fd(fd, true);
-        if (r < 0)
-                log_warning_errno(r, "Failed to reset terminal: %m");
-
-        return fd;
-
-fail:
-        safe_close(fd);
-        safe_close(notify);
-
-        return r;
-}
-
-int release_terminal(void) {
-        static const struct sigaction sa_new = {
-                .sa_handler = SIG_IGN,
-                .sa_flags = SA_RESTART,
-        };
-
-        _cleanup_close_ int fd = -1;
-        struct sigaction sa_old;
-        int r = 0;
-
-        fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
-         * by our own TIOCNOTTY */
-        assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
-
-        if (ioctl(fd, TIOCNOTTY) < 0)
-                r = -errno;
-
-        assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
-
-        return r;
-}
-
 int sigaction_many(const struct sigaction *sa, ...) {
         va_list ap;
         int r = 0, sig;
@@ -2303,40 +1823,6 @@ int parse_size(const char *t, off_t base, off_t *size) {
         return 0;
 }
 
-int make_stdio(int fd) {
-        int r, s, t;
-
-        assert(fd >= 0);
-
-        r = dup2(fd, STDIN_FILENO);
-        s = dup2(fd, STDOUT_FILENO);
-        t = dup2(fd, STDERR_FILENO);
-
-        if (fd >= 3)
-                safe_close(fd);
-
-        if (r < 0 || s < 0 || t < 0)
-                return -errno;
-
-        /* Explicitly unset O_CLOEXEC, since if fd was < 3, then
-         * dup2() was a NOP and the bit hence possibly set. */
-        fd_cloexec(STDIN_FILENO, false);
-        fd_cloexec(STDOUT_FILENO, false);
-        fd_cloexec(STDERR_FILENO, false);
-
-        return 0;
-}
-
-int make_null_stdio(void) {
-        int null_fd;
-
-        null_fd = open("/dev/null", O_RDWR|O_NOCTTY);
-        if (null_fd < 0)
-                return -errno;
-
-        return make_stdio(null_fd);
-}
-
 bool is_device_path(const char *path) {
 
         /* Returns true on paths that refer to a device, either in
@@ -2460,202 +1946,61 @@ char* gethostname_malloc(void) {
         return strdup(u.sysname);
 }
 
-bool hostname_is_set(void) {
-        struct utsname u;
-
-        assert_se(uname(&u) >= 0);
-
-        return !isempty(u.nodename) && !streq(u.nodename, "(none)");
-}
-
-char *lookup_uid(uid_t uid) {
-        long bufsize;
-        char *name;
-        _cleanup_free_ char *buf = NULL;
-        struct passwd pwbuf, *pw = NULL;
-
-        /* Shortcut things to avoid NSS lookups */
-        if (uid == 0)
-                return strdup("root");
-
-        bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
-        if (bufsize <= 0)
-                bufsize = 4096;
-
-        buf = malloc(bufsize);
-        if (!buf)
-                return NULL;
-
-        if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw)
-                return strdup(pw->pw_name);
-
-        if (asprintf(&name, UID_FMT, uid) < 0)
-                return NULL;
-
-        return name;
-}
-
-char* getlogname_malloc(void) {
-        uid_t uid;
-        struct stat st;
-
-        if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
-                uid = st.st_uid;
-        else
-                uid = getuid();
-
-        return lookup_uid(uid);
-}
-
-char *getusername_malloc(void) {
-        const char *e;
-
-        e = getenv("USER");
-        if (e)
-                return strdup(e);
-
-        return lookup_uid(getuid());
-}
-
-int getttyname_malloc(int fd, char **ret) {
-        size_t l = 100;
-        int r;
-
-        assert(fd >= 0);
-        assert(ret);
-
-        for (;;) {
-                char path[l];
-
-                r = ttyname_r(fd, path, sizeof(path));
-                if (r == 0) {
-                        const char *p;
-                        char *c;
-
-                        p = startswith(path, "/dev/");
-                        c = strdup(p ?: path);
-                        if (!c)
-                                return -ENOMEM;
-
-                        *ret = c;
-                        return 0;
-                }
-
-                if (r != ERANGE)
-                        return -r;
-
-                l *= 2;
-        }
-
-        return 0;
-}
-
-int getttyname_harder(int fd, char **r) {
-        int k;
-        char *s = NULL;
-
-        k = getttyname_malloc(fd, &s);
-        if (k < 0)
-                return k;
-
-        if (streq(s, "tty")) {
-                free(s);
-                return get_ctty(0, NULL, r);
-        }
-
-        *r = s;
-        return 0;
-}
-
-int get_ctty_devnr(pid_t pid, dev_t *d) {
-        int r;
-        _cleanup_free_ char *line = NULL;
-        const char *p;
-        unsigned long ttynr;
-
-        assert(pid >= 0);
-
-        p = procfs_file_alloca(pid, "stat");
-        r = read_one_line_file(p, &line);
-        if (r < 0)
-                return r;
-
-        p = strrchr(line, ')');
-        if (!p)
-                return -EIO;
-
-        p++;
+bool hostname_is_set(void) {
+        struct utsname u;
 
-        if (sscanf(p, " "
-                   "%*c "  /* state */
-                   "%*d "  /* ppid */
-                   "%*d "  /* pgrp */
-                   "%*d "  /* session */
-                   "%lu ", /* ttynr */
-                   &ttynr) != 1)
-                return -EIO;
+        assert_se(uname(&u) >= 0);
 
-        if (major(ttynr) == 0 && minor(ttynr) == 0)
-                return -ENOENT;
+        return !isempty(u.nodename) && !streq(u.nodename, "(none)");
+}
 
-        if (d)
-                *d = (dev_t) ttynr;
+char *lookup_uid(uid_t uid) {
+        long bufsize;
+        char *name;
+        _cleanup_free_ char *buf = NULL;
+        struct passwd pwbuf, *pw = NULL;
 
-        return 0;
-}
+        /* Shortcut things to avoid NSS lookups */
+        if (uid == 0)
+                return strdup("root");
 
-int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
-        char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL;
-        _cleanup_free_ char *s = NULL;
-        const char *p;
-        dev_t devnr;
-        int k;
+        bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+        if (bufsize <= 0)
+                bufsize = 4096;
 
-        assert(r);
+        buf = malloc(bufsize);
+        if (!buf)
+                return NULL;
 
-        k = get_ctty_devnr(pid, &devnr);
-        if (k < 0)
-                return k;
+        if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw)
+                return strdup(pw->pw_name);
 
-        sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
+        if (asprintf(&name, UID_FMT, uid) < 0)
+                return NULL;
 
-        k = readlink_malloc(fn, &s);
-        if (k < 0) {
+        return name;
+}
 
-                if (k != -ENOENT)
-                        return k;
+char* getlogname_malloc(void) {
+        uid_t uid;
+        struct stat st;
 
-                /* This is an ugly hack */
-                if (major(devnr) == 136) {
-                        if (asprintf(&b, "pts/%u", minor(devnr)) < 0)
-                                return -ENOMEM;
-                } else {
-                        /* Probably something like the ptys which have no
-                         * symlink in /dev/char. Let's return something
-                         * vaguely useful. */
+        if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
+                uid = st.st_uid;
+        else
+                uid = getuid();
 
-                        b = strdup(fn + 5);
-                        if (!b)
-                                return -ENOMEM;
-                }
-        } else {
-                if (startswith(s, "/dev/"))
-                        p = s + 5;
-                else if (startswith(s, "../"))
-                        p = s + 3;
-                else
-                        p = s;
+        return lookup_uid(uid);
+}
 
-                b = strdup(p);
-                if (!b)
-                        return -ENOMEM;
-        }
+char *getusername_malloc(void) {
+        const char *e;
 
-        *r = b;
-        if (_devnr)
-                *_devnr = devnr;
+        e = getenv("USER");
+        if (e)
+                return strdup(e);
 
-        return 0;
+        return lookup_uid(getuid());
 }
 
 bool is_temporary_fs(const struct statfs *s) {
@@ -2738,84 +2083,6 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
         }
 }
 
-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;
-}
-
 char *replace_env(const char *format, char **env) {
         enum {
                 WORD,
@@ -2960,89 +2227,6 @@ char **replace_env_argv(char **argv, char **env) {
         return ret;
 }
 
-int fd_columns(int fd) {
-        struct winsize ws = {};
-
-        if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
-                return -errno;
-
-        if (ws.ws_col <= 0)
-                return -EIO;
-
-        return ws.ws_col;
-}
-
-unsigned columns(void) {
-        const char *e;
-        int c;
-
-        if (_likely_(cached_columns > 0))
-                return cached_columns;
-
-        c = 0;
-        e = getenv("COLUMNS");
-        if (e)
-                (void) safe_atoi(e, &c);
-
-        if (c <= 0)
-                c = fd_columns(STDOUT_FILENO);
-
-        if (c <= 0)
-                c = 80;
-
-        cached_columns = c;
-        return cached_columns;
-}
-
-int fd_lines(int fd) {
-        struct winsize ws = {};
-
-        if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
-                return -errno;
-
-        if (ws.ws_row <= 0)
-                return -EIO;
-
-        return ws.ws_row;
-}
-
-unsigned lines(void) {
-        const char *e;
-        int l;
-
-        if (_likely_(cached_lines > 0))
-                return cached_lines;
-
-        l = 0;
-        e = getenv("LINES");
-        if (e)
-                (void) safe_atoi(e, &l);
-
-        if (l <= 0)
-                l = fd_lines(STDOUT_FILENO);
-
-        if (l <= 0)
-                l = 24;
-
-        cached_lines = l;
-        return cached_lines;
-}
-
-/* intended to be used as a SIGWINCH sighandler */
-void columns_lines_cache_reset(int signum) {
-        cached_columns = 0;
-        cached_lines = 0;
-}
-
-bool on_tty(void) {
-        static int cached_on_tty = -1;
-
-        if (_unlikely_(cached_on_tty < 0))
-                cached_on_tty = isatty(STDOUT_FILENO) > 0;
-
-        return cached_on_tty;
-}
-
 int files_same(const char *filea, const char *fileb) {
         struct stat a, b;
 
@@ -3351,101 +2535,6 @@ char *fstab_node_to_udev_node(const char *p) {
         return strdup(p);
 }
 
-bool tty_is_vc(const char *tty) {
-        assert(tty);
-
-        return vtnr_from_tty(tty) >= 0;
-}
-
-bool tty_is_console(const char *tty) {
-        assert(tty);
-
-        if (startswith(tty, "/dev/"))
-                tty += 5;
-
-        return streq(tty, "console");
-}
-
-int vtnr_from_tty(const char *tty) {
-        int i, r;
-
-        assert(tty);
-
-        if (startswith(tty, "/dev/"))
-                tty += 5;
-
-        if (!startswith(tty, "tty") )
-                return -EINVAL;
-
-        if (tty[3] < '0' || tty[3] > '9')
-                return -EINVAL;
-
-        r = safe_atoi(tty+3, &i);
-        if (r < 0)
-                return r;
-
-        if (i < 0 || i > 63)
-                return -EINVAL;
-
-        return i;
-}
-
-char *resolve_dev_console(char **active) {
-        char *tty;
-
-        /* Resolve where /dev/console is pointing to, if /sys is actually ours
-         * (i.e. not read-only-mounted which is a sign for container setups) */
-
-        if (path_is_read_only_fs("/sys") > 0)
-                return NULL;
-
-        if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
-                return NULL;
-
-        /* If multiple log outputs are configured the last one is what
-         * /dev/console points to */
-        tty = strrchr(*active, ' ');
-        if (tty)
-                tty++;
-        else
-                tty = *active;
-
-        if (streq(tty, "tty0")) {
-                char *tmp;
-
-                /* Get the active VC (e.g. tty1) */
-                if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) {
-                        free(*active);
-                        tty = *active = tmp;
-                }
-        }
-
-        return tty;
-}
-
-bool tty_is_vc_resolve(const char *tty) {
-        _cleanup_free_ char *active = NULL;
-
-        assert(tty);
-
-        if (startswith(tty, "/dev/"))
-                tty += 5;
-
-        if (streq(tty, "console")) {
-                tty = resolve_dev_console(&active);
-                if (!tty)
-                        return false;
-        }
-
-        return tty_is_vc(tty);
-}
-
-const char *default_term_for_tty(const char *tty) {
-        assert(tty);
-
-        return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
-}
-
 bool dirent_is_file(const struct dirent *de) {
         assert(de);
 
@@ -3798,94 +2887,6 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
         return 0;
 }
 
-int terminal_vhangup_fd(int fd) {
-        assert(fd >= 0);
-
-        if (ioctl(fd, TIOCVHANGUP) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int terminal_vhangup(const char *name) {
-        _cleanup_close_ int fd;
-
-        fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return fd;
-
-        return terminal_vhangup_fd(fd);
-}
-
-int vt_disallocate(const char *name) {
-        int fd, r;
-        unsigned u;
-
-        /* Deallocate the VT if possible. If not possible
-         * (i.e. because it is the active one), at least clear it
-         * entirely (including the scrollback buffer) */
-
-        if (!startswith(name, "/dev/"))
-                return -EINVAL;
-
-        if (!tty_is_vc(name)) {
-                /* So this is not a VT. I guess we cannot deallocate
-                 * it then. But let's at least clear the screen */
-
-                fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
-                if (fd < 0)
-                        return fd;
-
-                loop_write(fd,
-                           "\033[r"    /* clear scrolling region */
-                           "\033[H"    /* move home */
-                           "\033[2J",  /* clear screen */
-                           10, false);
-                safe_close(fd);
-
-                return 0;
-        }
-
-        if (!startswith(name, "/dev/tty"))
-                return -EINVAL;
-
-        r = safe_atou(name+8, &u);
-        if (r < 0)
-                return r;
-
-        if (u <= 0)
-                return -EINVAL;
-
-        /* Try to deallocate */
-        fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return fd;
-
-        r = ioctl(fd, VT_DISALLOCATE, u);
-        safe_close(fd);
-
-        if (r >= 0)
-                return 0;
-
-        if (errno != EBUSY)
-                return -errno;
-
-        /* Couldn't deallocate, so let's clear it fully with
-         * scrollback */
-        fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return fd;
-
-        loop_write(fd,
-                   "\033[r"   /* clear scrolling region */
-                   "\033[H"   /* move home */
-                   "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
-                   10, false);
-        safe_close(fd);
-
-        return 0;
-}
-
 int symlink_atomic(const char *from, const char *to) {
         _cleanup_free_ char *t = NULL;
         int r;
@@ -4898,43 +3899,6 @@ bool in_initrd(void) {
         return saved;
 }
 
-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... */
-
-        ioctl(fd, KIOCSOUND, (int)(1193180/440));
-        usleep(125*USEC_PER_MSEC);
-
-        ioctl(fd, KIOCSOUND, (int)(1193180/220));
-        usleep(125*USEC_PER_MSEC);
-
-        ioctl(fd, KIOCSOUND, (int)(1193180/220));
-        usleep(125*USEC_PER_MSEC);
-
-        ioctl(fd, KIOCSOUND, 0);
-}
-
-int make_console_stdio(void) {
-        int fd, r;
-
-        /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
-
-        fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY);
-        if (fd < 0)
-                return log_error_errno(fd, "Failed to acquire terminal: %m");
-
-        r = make_stdio(fd);
-        if (r < 0)
-                return log_error_errno(r, "Failed to duplicate terminal fd: %m");
-
-        return 0;
-}
-
 int get_home_dir(char **_h) {
         struct passwd *p;
         const char *e;
index 4d5162f..f54722f 100644 (file)
 
 #define FORMAT_BYTES_MAX 8
 
-#define ANSI_HIGHLIGHT_ON "\x1B[1;39m"
-#define ANSI_RED_ON "\x1B[31m"
-#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m"
-#define ANSI_GREEN_ON "\x1B[32m"
-#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m"
-#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m"
-#define ANSI_HIGHLIGHT_BLUE_ON "\x1B[1;34m"
-#define ANSI_HIGHLIGHT_OFF "\x1B[0m"
-#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
-
 size_t page_size(void) _pure_;
 #define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
 
@@ -279,10 +269,6 @@ bool hidden_file(const char *filename) _pure_;
 
 bool chars_intersect(const char *a, const char *b) _pure_;
 
-int make_stdio(int fd);
-int make_null_stdio(void);
-int make_console_stdio(void);
-
 /* For basic lookup tables with strictly enumerated entries */
 #define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope)          \
         scope const char *name##_to_string(type i) {                    \
@@ -348,19 +334,6 @@ int close_all_fds(const int except[], unsigned n_except);
 
 bool fstype_is_network(const char *fstype);
 
-int chvt(int vt);
-
-int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl);
-int ask_char(char *ret, const char *replies, const char *text, ...) _printf_(3, 4);
-int ask_string(char **ret, const char *text, ...) _printf_(2, 3);
-
-int reset_terminal_fd(int fd, bool switch_to_text);
-int reset_terminal(const char *name);
-
-int open_terminal(const char *name, int mode);
-int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm, usec_t timeout);
-int release_terminal(void);
-
 int flush_fd(int fd);
 
 int ignore_signals(int sig, ...);
@@ -388,12 +361,6 @@ char* gethostname_malloc(void);
 char* getlogname_malloc(void);
 char* getusername_malloc(void);
 
-int getttyname_malloc(int fd, char **r);
-int getttyname_harder(int fd, char **r);
-
-int get_ctty_devnr(pid_t pid, dev_t *d);
-int get_ctty(pid_t, dev_t *_devnr, char **r);
-
 int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
 int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
 
@@ -404,43 +371,8 @@ int pipe_eof(int fd);
 
 cpu_set_t* cpu_set_malloc(unsigned *ncpus);
 
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
-
 #define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf))
 
-int fd_columns(int fd);
-unsigned columns(void);
-int fd_lines(int fd);
-unsigned lines(void);
-void columns_lines_cache_reset(int _unused_ signum);
-
-bool on_tty(void);
-
-static inline const char *ansi_highlight(void) {
-        return on_tty() ? ANSI_HIGHLIGHT_ON : "";
-}
-
-static inline const char *ansi_highlight_red(void) {
-        return on_tty() ? ANSI_HIGHLIGHT_RED_ON : "";
-}
-
-static inline const char *ansi_highlight_green(void) {
-        return on_tty() ? ANSI_HIGHLIGHT_GREEN_ON : "";
-}
-
-static inline const char *ansi_highlight_yellow(void) {
-        return on_tty() ? ANSI_HIGHLIGHT_YELLOW_ON : "";
-}
-
-static inline const char *ansi_highlight_blue(void) {
-        return on_tty() ? ANSI_HIGHLIGHT_BLUE_ON : "";
-}
-
-static inline const char *ansi_highlight_off(void) {
-        return on_tty() ? ANSI_HIGHLIGHT_OFF : "";
-}
-
 int files_same(const char *filea, const char *fileb);
 
 int running_in_chroot(void);
@@ -462,13 +394,6 @@ DIR *xopendirat(int dirfd, const char *name, int flags);
 
 char *fstab_node_to_udev_node(const char *p);
 
-char *resolve_dev_console(char **active);
-bool tty_is_vc(const char *tty);
-bool tty_is_vc_resolve(const char *tty);
-bool tty_is_console(const char *tty) _pure_;
-int vtnr_from_tty(const char *tty);
-const char *default_term_for_tty(const char *tty);
-
 void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
 
 bool nulstr_contains(const char*nulstr, const char *needle);
@@ -482,10 +407,6 @@ bool machine_name_is_valid(const char *s) _pure_;
 
 char* strshorten(char *s, size_t l);
 
-int terminal_vhangup_fd(int fd);
-int terminal_vhangup(const char *name);
-
-int vt_disallocate(const char *name);
 
 int symlink_atomic(const char *from, const char *to);
 int mknod_atomic(const char *path, mode_t mode, dev_t dev);
@@ -583,8 +504,6 @@ bool http_etag_is_valid(const char *etag);
 
 bool in_initrd(void);
 
-void warn_melody(void);
-
 int get_home_dir(char **ret);
 int get_shell(char **_ret);
 
index 7fb6fe3..d6c4cc8 100644 (file)
@@ -30,6 +30,7 @@
 #include "macro.h"
 #include "path-util.h"
 #include "utmp-wtmp.h"
+#include "terminal-util.h"
 
 int utmp_get_runlevel(int *runlevel, int *previous) {
         struct utmpx *found, lookup = { .ut_type = RUN_LVL };
index 04b7e7b..75d709d 100644 (file)
@@ -71,6 +71,7 @@
 #include "efivars.h"
 #include "formats-util.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 static char **arg_types = NULL;
 static char **arg_states = NULL;
index 6a2f9aa..27df908 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdio.h>
 
 #include "util.h"
+#include "terminal-util.h"
 #include "def.h"
 
 static void test_one(const char *p) {
index a17ef14..1de100c 100644 (file)
@@ -28,6 +28,7 @@
 #include "util.h"
 #include "macro.h"
 #include "virt.h"
+#include "terminal-util.h"
 
 static void test_get_process_comm(void) {
         struct stat st;
index 5016906..3584548 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdio.h>
 
 #include "util.h"
+#include "terminal-util.h"
 
 int main(int argc, char *argv[]) {
         char *p;
diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c
new file mode 100644 (file)
index 0000000..d81fdb9
--- /dev/null
@@ -0,0 +1,84 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+  Copyright 2013 Thomas H.P. Andersen
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <stdbool.h>
+
+#include "terminal-util.h"
+#include "macro.h"
+#include "util.h"
+#include "log.h"
+
+static void test_default_term_for_tty(void) {
+        puts(default_term_for_tty("/dev/tty23"));
+        puts(default_term_for_tty("/dev/ttyS23"));
+        puts(default_term_for_tty("/dev/tty0"));
+        puts(default_term_for_tty("/dev/pty0"));
+        puts(default_term_for_tty("/dev/pts/0"));
+        puts(default_term_for_tty("/dev/console"));
+        puts(default_term_for_tty("tty23"));
+        puts(default_term_for_tty("ttyS23"));
+        puts(default_term_for_tty("tty0"));
+        puts(default_term_for_tty("pty0"));
+        puts(default_term_for_tty("pts/0"));
+        puts(default_term_for_tty("console"));
+}
+
+static void test_read_one_char(void) {
+        _cleanup_fclose_ FILE *file = NULL;
+        char r;
+        bool need_nl;
+        char name[] = "/tmp/test-read_one_char.XXXXXX";
+        int fd;
+
+        fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+        assert_se(fd >= 0);
+        file = fdopen(fd, "r+");
+        assert_se(file);
+        assert_se(fputs("c\n", file) >= 0);
+        rewind(file);
+
+        assert_se(read_one_char(file, &r, 1000000, &need_nl) >= 0);
+        assert_se(!need_nl);
+        assert_se(r == 'c');
+        assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
+
+        rewind(file);
+        assert_se(fputs("foobar\n", file) >= 0);
+        rewind(file);
+        assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
+
+        rewind(file);
+        assert_se(fputs("\n", file) >= 0);
+        rewind(file);
+        assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
+
+        unlink(name);
+}
+
+int main(int argc, char *argv[]) {
+        log_parse_environment();
+        log_open();
+
+        test_default_term_for_tty();
+        test_read_one_char();
+
+        return 0;
+}
index bfd4df9..fdb772d 100644 (file)
@@ -522,21 +522,6 @@ static void test_foreach_word_quoted(void) {
               true);
 }
 
-static void test_default_term_for_tty(void) {
-        puts(default_term_for_tty("/dev/tty23"));
-        puts(default_term_for_tty("/dev/ttyS23"));
-        puts(default_term_for_tty("/dev/tty0"));
-        puts(default_term_for_tty("/dev/pty0"));
-        puts(default_term_for_tty("/dev/pts/0"));
-        puts(default_term_for_tty("/dev/console"));
-        puts(default_term_for_tty("tty23"));
-        puts(default_term_for_tty("ttyS23"));
-        puts(default_term_for_tty("tty0"));
-        puts(default_term_for_tty("pty0"));
-        puts(default_term_for_tty("pts/0"));
-        puts(default_term_for_tty("console"));
-}
-
 static void test_memdup_multiply(void) {
         int org[] = {1, 2, 3};
         int *dup;
@@ -981,38 +966,6 @@ static void test_readlink_and_make_absolute(void) {
         assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
 }
 
-static void test_read_one_char(void) {
-        _cleanup_fclose_ FILE *file = NULL;
-        char r;
-        bool need_nl;
-        char name[] = "/tmp/test-read_one_char.XXXXXX";
-        int fd;
-
-        fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
-        assert_se(fd >= 0);
-        file = fdopen(fd, "r+");
-        assert_se(file);
-        assert_se(fputs("c\n", file) >= 0);
-        rewind(file);
-
-        assert_se(read_one_char(file, &r, 1000000, &need_nl) >= 0);
-        assert_se(!need_nl);
-        assert_se(r == 'c');
-        assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
-
-        rewind(file);
-        assert_se(fputs("foobar\n", file) >= 0);
-        rewind(file);
-        assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
-
-        rewind(file);
-        assert_se(fputs("\n", file) >= 0);
-        rewind(file);
-        assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
-
-        unlink(name);
-}
-
 static void test_ignore_signals(void) {
         assert_se(ignore_signals(SIGINT, -1) >= 0);
         assert_se(kill(getpid(), SIGINT) >= 0);
@@ -1525,7 +1478,6 @@ int main(int argc, char *argv[]) {
         test_cunescape();
         test_foreach_word();
         test_foreach_word_quoted();
-        test_default_term_for_tty();
         test_memdup_multiply();
         test_hostname_is_valid();
         test_u64log2();
@@ -1552,7 +1504,6 @@ int main(int argc, char *argv[]) {
         test_close_nointr();
         test_unlink_noerrno();
         test_readlink_and_make_absolute();
-        test_read_one_char();
         test_ignore_signals();
         test_strshorten();
         test_strjoina();
index 0a41f05..61b6e76 100644 (file)
@@ -33,6 +33,7 @@
 #include "build.h"
 #include "strv.h"
 #include "pager.h"
+#include "terminal-util.h"
 
 static bool arg_no_pager = false;
 static bool arg_ask_password = true;
index 8f4031a..8cd6cab 100644 (file)
@@ -43,6 +43,7 @@
 #include "build.h"
 #include "def.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 static enum {
         ACTION_LIST,
index 3f93524..6c782b3 100644 (file)
@@ -36,6 +36,7 @@
 #include "virt.h"
 #include "fileio.h"
 #include "process-util.h"
+#include "terminal-util.h"
 
 static bool is_vconsole(int fd) {
         unsigned char data[1];