terminal-util: excorcise fgets()
authorLennart Poettering <lennart@poettering.net>
Thu, 18 Oct 2018 11:32:05 +0000 (13:32 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 18 Oct 2018 11:32:05 +0000 (13:32 +0200)
src/basic/terminal-util.c

index c2aa75c..ba3b952 100644 (file)
@@ -81,14 +81,16 @@ int chvt(int vt) {
 }
 
 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];
+        _cleanup_free_ char *line = NULL;
+        struct termios old_termios;
+        int r;
 
         assert(f);
         assert(ret);
 
+        /* If this is a terminal, then switch canonical mode off, so that we can read a single character */
         if (tcgetattr(fileno(f), &old_termios) >= 0) {
-                new_termios = old_termios;
+                struct termios new_termios = old_termios;
 
                 new_termios.c_lflag &= ~ICANON;
                 new_termios.c_cc[VMIN] = 1;
@@ -124,11 +126,13 @@ int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) {
                         return -ETIMEDOUT;
         }
 
-        errno = 0;
-        if (!fgets(line, sizeof(line), f))
-                return errno > 0 ? -errno : -EIO;
+        /* If this is not a terminal, then read a full line instead */
 
-        truncate_nl(line);
+        r = read_line(f, 16, &line); /* longer than necessary, to eat up UTF-8 chars/vt100 key sequences */
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EIO;
 
         if (strlen(line) != 1)
                 return -EBADMSG;
@@ -196,11 +200,13 @@ int ask_char(char *ret, const char *replies, const char *fmt, ...) {
 }
 
 int ask_string(char **ret, const char *text, ...) {
+        int r;
+
         assert(ret);
         assert(text);
 
         for (;;) {
-                char line[LINE_MAX];
+                _cleanup_free_ char *line = NULL;
                 va_list ap;
 
                 if (colors_enabled())
@@ -215,24 +221,14 @@ int ask_string(char **ret, const char *text, ...) {
 
                 fflush(stdout);
 
-                errno = 0;
-                if (!fgets(line, sizeof(line), stdin))
-                        return errno > 0 ? -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;
+                r = read_line(stdin, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return -EIO;
 
-                        *ret = s;
+                if (!isempty(line)) {
+                        *ret = TAKE_PTR(line);
                         return 0;
                 }
         }