]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/terminal-util.c
terminal-util: introduce openpt_allocate()
[thirdparty/systemd.git] / src / basic / terminal-util.c
index 4702e917324a80fc26b1c3beeffdd82855e4e7ce..aa69bede6f5fb63e133f6c38ae22c73d46c7ce6f 100644 (file)
@@ -891,50 +891,39 @@ bool on_tty(void) {
 }
 
 int getttyname_malloc(int fd, char **ret) {
-        size_t l = 100;
+        char path[PATH_MAX], *c; /* PATH_MAX is counted *with* the trailing NUL byte */
         int r;
 
         assert(fd >= 0);
         assert(ret);
 
-        for (;;) {
-                char path[l];
-
-                r = ttyname_r(fd, path, sizeof(path));
-                if (r == 0) {
-                        char *c;
-
-                        c = strdup(skip_dev_prefix(path));
-                        if (!c)
-                                return -ENOMEM;
-
-                        *ret = c;
-                        return 0;
-                }
-
-                if (r != ERANGE)
-                        return -r;
+        r = ttyname_r(fd, path, sizeof path); /* positive error */
+        assert(r >= 0);
+        if (r == ERANGE)
+                return -ENAMETOOLONG;
+        if (r > 0)
+                return -r;
 
-                l *= 2;
-        }
+        c = strdup(skip_dev_prefix(path));
+        if (!c)
+                return -ENOMEM;
 
+        *ret = c;
         return 0;
 }
 
-int getttyname_harder(int fd, char **r) {
-        int k;
-        char *s = NULL;
+int getttyname_harder(int fd, char **ret) {
+        _cleanup_free_ char *s = NULL;
+        int r;
 
-        k = getttyname_malloc(fd, &s);
-        if (k < 0)
-                return k;
+        r = getttyname_malloc(fd, &s);
+        if (r < 0)
+                return r;
 
-        if (streq(s, "tty")) {
-                free(s);
-                return get_ctty(0, NULL, r);
-        }
+        if (streq(s, "tty"))
+                return get_ctty(0, NULL, ret);
 
-        *r = s;
+        *ret = TAKE_PTR(s);
         return 0;
 }
 
@@ -1052,11 +1041,42 @@ int ptsname_malloc(int fd, char **ret) {
                 }
 
                 free(c);
+
+                if (l > SIZE_MAX / 2)
+                        return -ENOMEM;
+
                 l *= 2;
         }
 }
 
-int ptsname_namespace(int pty, char **ret) {
+int openpt_allocate(int flags, char **ret_slave) {
+        _cleanup_close_ int fd = -1;
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        fd = posix_openpt(flags|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        if (ret_slave) {
+                r = ptsname_malloc(fd, &p);
+                if (r < 0)
+                        return r;
+
+                if (!path_startswith(p, "/dev/pts/"))
+                        return -EINVAL;
+        }
+
+        if (unlockpt(fd) < 0)
+                return -errno;
+
+        if (ret_slave)
+                *ret_slave = TAKE_PTR(p);
+
+        return TAKE_FD(fd);
+}
+
+static int ptsname_namespace(int pty, char **ret) {
         int no = -1, r;
 
         /* Like ptsname(), but doesn't assume that the path is
@@ -1075,8 +1095,8 @@ 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;
+int openpt_allocate_in_namespace(pid_t pid, int flags, char **ret_slave) {
+        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1, fd = -1;
         _cleanup_close_pair_ int pair[2] = { -1, -1 };
         pid_t child;
         int r;
@@ -1095,18 +1115,13 @@ int openpt_in_namespace(pid_t pid, int flags) {
         if (r < 0)
                 return r;
         if (r == 0) {
-                int master;
-
                 pair[0] = safe_close(pair[0]);
 
-                master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC);
-                if (master < 0)
-                        _exit(EXIT_FAILURE);
-
-                if (unlockpt(master) < 0)
+                fd = openpt_allocate(flags, NULL);
+                if (fd < 0)
                         _exit(EXIT_FAILURE);
 
-                if (send_one_fd(pair[1], master, 0) < 0)
+                if (send_one_fd(pair[1], fd, 0) < 0)
                         _exit(EXIT_FAILURE);
 
                 _exit(EXIT_SUCCESS);
@@ -1120,7 +1135,17 @@ int openpt_in_namespace(pid_t pid, int flags) {
         if (r != EXIT_SUCCESS)
                 return -EIO;
 
-        return receive_one_fd(pair[0], 0);
+        fd = receive_one_fd(pair[0], 0);
+        if (fd < 0)
+                return fd;
+
+        if (ret_slave) {
+                r = ptsname_namespace(fd, ret_slave);
+                if (r < 0)
+                        return r;
+        }
+
+        return TAKE_FD(fd);
 }
 
 int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
@@ -1189,7 +1214,7 @@ bool colors_enabled(void) {
          * (which is the explicit way to turn colors on/off). If that didn't work we turn colors off unless we are on a
          * TTY. And if we are on a TTY we turn it off if $TERM is set to "dumb". There's one special tweak though: if
          * we are PID 1 then we do not check whether we are connected to a TTY, because we don't keep /dev/console open
-         * continously due to fear of SAK, and hence things are a bit weird. */
+         * continuously due to fear of SAK, and hence things are a bit weird. */
 
         if (cached_colors_enabled < 0) {
                 int val;
@@ -1256,12 +1281,36 @@ int vt_default_utf8(void) {
         return parse_boolean(b);
 }
 
+int vt_verify_kbmode(int fd) {
+        int curr_mode;
+
+        /*
+         * Make sure we only adjust consoles in K_XLATE or K_UNICODE mode.
+         * Otherwise we would (likely) interfere with X11's processing of the
+         * key events.
+         *
+         * http://lists.freedesktop.org/archives/systemd-devel/2013-February/008573.html
+         */
+
+        if (ioctl(fd, KDGKBMODE, &curr_mode) < 0)
+                return -errno;
+
+        return IN_SET(curr_mode, K_XLATE, K_UNICODE) ? 0 : -EBUSY;
+}
+
 int vt_reset_keyboard(int fd) {
-        int kb;
+        int kb, r;
 
         /* If we can't read the default, then default to unicode. It's 2017 after all. */
         kb = vt_default_utf8() != 0 ? K_UNICODE : K_XLATE;
 
+        r = vt_verify_kbmode(fd);
+        if (r == -EBUSY) {
+                log_debug_errno(r, "Keyboard is not in XLATE or UNICODE mode, not resetting: %m");
+                return 0;
+        } else if (r < 0)
+                return r;
+
         if (ioctl(fd, KDSKBMODE, kb) < 0)
                 return -errno;
 
@@ -1274,8 +1323,7 @@ int vt_restore(int fd) {
         };
         int r, q = 0;
 
-        r = ioctl(fd, KDSETMODE, KD_TEXT);
-        if (r < 0)
+        if (ioctl(fd, KDSETMODE, KD_TEXT) < 0)
                 q = log_debug_errno(errno, "Failed to set VT in text mode, ignoring: %m");
 
         r = vt_reset_keyboard(fd);
@@ -1285,18 +1333,17 @@ int vt_restore(int fd) {
                         q = r;
         }
 
-        r = ioctl(fd, VT_SETMODE, &mode);
-        if (r < 0) {
+        if (ioctl(fd, VT_SETMODE, &mode) < 0) {
                 log_debug_errno(errno, "Failed to set VT_AUTO mode, ignoring: %m");
                 if (q >= 0)
                         q = -errno;
         }
 
-        r = fchown(fd, 0, (gid_t) -1);
+        r = fchmod_and_chown(fd, TTY_MODE, 0, (gid_t) -1);
         if (r < 0) {
-                log_debug_errno(errno, "Failed to chown VT, ignoring: %m");
+                log_debug_errno(r, "Failed to chmod()/chown() VT, ignoring: %m");
                 if (q >= 0)
-                        q = -errno;
+                        q = r;
         }
 
         return q;
@@ -1317,3 +1364,41 @@ int vt_release(int fd, bool restore) {
 
         return 0;
 }
+
+void get_log_colors(int priority, const char **on, const char **off, const char **highlight) {
+        /* Note that this will initialize output variables only when there's something to output.
+         * The caller must pre-initalize to "" or NULL as appropriate. */
+
+        if (priority <= LOG_ERR) {
+                if (on)
+                        *on = ANSI_HIGHLIGHT_RED;
+                if (off)
+                        *off = ANSI_NORMAL;
+                if (highlight)
+                        *highlight = ANSI_HIGHLIGHT;
+
+        } else if (priority <= LOG_WARNING) {
+                if (on)
+                        *on = ANSI_HIGHLIGHT_YELLOW;
+                if (off)
+                        *off = ANSI_NORMAL;
+                if (highlight)
+                        *highlight = ANSI_HIGHLIGHT;
+
+        } else if (priority <= LOG_NOTICE) {
+                if (on)
+                        *on = ANSI_HIGHLIGHT;
+                if (off)
+                        *off = ANSI_NORMAL;
+                if (highlight)
+                        *highlight = ANSI_HIGHLIGHT_RED;
+
+        } else if (priority >= LOG_DEBUG) {
+                if (on)
+                        *on = ANSI_GREY;
+                if (off)
+                        *off = ANSI_NORMAL;
+                if (highlight)
+                        *highlight = ANSI_HIGHLIGHT_RED;
+        }
+}