]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
script: add --echo
authorKarel Zak <kzak@redhat.com>
Mon, 25 Nov 2019 11:39:52 +0000 (12:39 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 25 Nov 2019 11:39:52 +0000 (12:39 +0100)
It some cases it makes sense to disable ECHO flag also when script
used in pipe. This new option allows to keep full control in user's
hands.

Signed-off-by: Karel Zak <kzak@redhat.com>
include/pty-session.h
lib/pty-session.c
term-utils/script.1
term-utils/script.c
term-utils/scriptlive.c

index 798f606b82055d82b82d403c581447170bdf348c..9681bcc7793a22a5821abaf2f1a8c74e26b03e6f 100644 (file)
@@ -76,14 +76,14 @@ struct ul_pty {
        struct timeval  next_callback_time;
 
        unsigned int isterm:1,          /* is stdin terminal? */
-                    keep_slave_echo:1; /* keep ECHO on stdin */
+                    slave_echo:1;      /* keep ECHO on stdin */
 };
 
 void ul_pty_init_debug(int mask);
 struct ul_pty *ul_new_pty(int is_stdin_tty);
 void ul_free_pty(struct ul_pty *pty);
 
-void ul_pty_keep_slave_echo(struct ul_pty *pty, int enable);
+void ul_pty_slave_echo(struct ul_pty *pty, int enable);
 int ul_pty_get_delivered_signal(struct ul_pty *pty);
 
 void ul_pty_set_callback_data(struct ul_pty *pty, void *data);
index 8017d9f4d5461d9d03f4e4236541b4347b74eba7..b668e953fc96bf11f91027b3919a211a0d19d0c9 100644 (file)
@@ -71,10 +71,10 @@ void ul_free_pty(struct ul_pty *pty)
        free(pty);
 }
 
-void ul_pty_keep_slave_echo(struct ul_pty *pty, int enable)
+void ul_pty_slave_echo(struct ul_pty *pty, int enable)
 {
        assert(pty);
-       pty->keep_slave_echo = enable ? 1 : 0;
+       pty->slave_echo = enable ? 1 : 0;
 }
 
 int ul_pty_get_delivered_signal(struct ul_pty *pty)
@@ -172,20 +172,28 @@ int ul_pty_setup(struct ul_pty *pty)
                /* set the current terminal to raw mode; pty_cleanup() reverses this change on exit */
                slave_attrs = pty->stdin_attrs;
                cfmakeraw(&slave_attrs);
-               slave_attrs.c_lflag &= ~ECHO;
+
+               if (pty->slave_echo)
+                       slave_attrs.c_lflag |= ECHO;
+               else
+                       slave_attrs.c_lflag &= ~ECHO;
+
                tcsetattr(STDIN_FILENO, TCSANOW, &slave_attrs);
        } else {
                DBG(SETUP, ul_debugobj(pty, "create for non-terminal"));
-               rc = openpty(&pty->master, &pty->slave, NULL, NULL, NULL);
 
-               if (!rc) {
-                       tcgetattr(pty->slave, &slave_attrs);
-                       if (!pty->keep_slave_echo) {
-                               slave_attrs.c_lflag &= ~ECHO;
-                               tcsetattr(pty->slave, TCSANOW, &slave_attrs);
-                       }
-               } else
+               rc = openpty(&pty->master, &pty->slave, NULL, NULL, NULL);
+               if (rc)
                        goto done;
+
+               tcgetattr(pty->slave, &slave_attrs);
+
+               if (pty->slave_echo)
+                       slave_attrs.c_lflag |= ECHO;
+               else
+                       slave_attrs.c_lflag &= ~ECHO;
+
+               tcsetattr(pty->slave, TCSANOW, &slave_attrs);
        }
 
        sigfillset(&ourset);
index e7195d65ff438d749b2de0159380c368e3bd1ab1..2da845fc716adc63e8018a111abe8fcf7fb3a2b6 100644 (file)
@@ -88,6 +88,13 @@ rather than an interactive shell.  This makes it easy for a script to capture
 the output of a program that behaves differently when its stdout is not a
 tty.
 .TP
+\fB\-E\fR, \fB\-\-echo\fR \fIwhen\fR
+This option controls the ECHO flag for pseudoterminal within the session. The
+supported modes are always, never, or auto. The default is "auto" -- in this
+case, ECHO is disabled if the current standard input is a terminal to avoid
+double-echo, and enabled if standard input is not terminal (for example pipe:
+"echo date | script") to avoid missing input in the session log.
+.TP
 \fB\-e\fR, \fB\-\-return\fR
 Return the exit code of the child process.  Uses the same format as bash
 termination on signal termination exit code is 128+n.  The exit code of
index f9494fd507ee33f269d1b2509994d60bbc6e50b9..d5a3836320ba1382688a5f0ed15c28920fbb75f1 100644 (file)
@@ -208,6 +208,7 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -e, --return                  return exit code of the child process\n"), out);
        fputs(_(" -f, --flush                   run flush after each write\n"), out);
        fputs(_("     --force                   use output file even when it is a link\n"), out);
+       fputs(_(" -E, --echo <when>             echo input (auto, always or never)\n"), out);
        fputs(_(" -o, --output-limit <size>     terminate if output files exceed size\n"), out);
        fputs(_(" -q, --quiet                   be quiet\n"), out);
 
@@ -720,7 +721,7 @@ int main(int argc, char **argv)
                .in  = { .ident = 'I' },
        };
        struct ul_pty_callbacks *cb;
-       int ch, format = 0, caught_signal = 0, rc = 0;
+       int ch, format = 0, caught_signal = 0, rc = 0, echo = 0;
        const char *outfile = NULL, *infile = NULL;
        const char *timingfile = NULL, *shell = NULL, *command = NULL;
 
@@ -729,6 +730,7 @@ int main(int argc, char **argv)
        static const struct option longopts[] = {
                {"append", no_argument, NULL, 'a'},
                {"command", required_argument, NULL, 'c'},
+               {"echo", required_argument, NULL, 'E'},
                {"return", no_argument, NULL, 'e'},
                {"flush", no_argument, NULL, 'f'},
                {"force", no_argument, NULL, FORCE_OPTION,},
@@ -765,7 +767,14 @@ int main(int argc, char **argv)
        script_init_debug();
        ON_DBG(PTY, ul_pty_init_debug(0xFFFF));
 
-       while ((ch = getopt_long(argc, argv, "aB:c:efI:O:o:qm:T:t::Vh", longopts, NULL)) != -1) {
+       /* The default is to keep ECHO flag when stdin is not terminal. We need
+        * it to make stdin (in case of "echo foo | script") log-able and
+        * visiable on terminal, and for backward compatibility.
+        */
+       ctl.isterm = isatty(STDIN_FILENO);
+       echo = ctl.isterm ? 0 : 1;
+
+       while ((ch = getopt_long(argc, argv, "aB:c:eE:fI:O:o:qm:T:t::Vh", longopts, NULL)) != -1) {
 
                err_exclusive_options(ch, longopts, excl, excl_st);
 
@@ -776,6 +785,16 @@ int main(int argc, char **argv)
                case 'c':
                        command = optarg;
                        break;
+               case 'E':
+                       if (strcmp(optarg, "auto") == 0)
+                               ; /* keep default */
+                       else if (strcmp(optarg, "never") == 0)
+                               echo = 0;
+                       else if (strcmp(optarg, "always") == 0)
+                               echo = 1;
+                       else
+                               errx(EXIT_FAILURE, _("unssuported echo mode: '%s'"), optarg);
+                       break;
                case 'e':
                        ctl.rc_wanted = 1;
                        break;
@@ -870,17 +889,11 @@ int main(int argc, char **argv)
        if (!shell)
                shell = _PATH_BSHELL;
 
-       ctl.isterm = isatty(STDIN_FILENO);
        ctl.pty = ul_new_pty(ctl.isterm);
        if (!ctl.pty)
                err(EXIT_FAILURE, "failed to allocate PTY handler");
 
-       if (!ctl.isterm)
-               /* We keep ECHO flag for 'echo "date" | script' otherwise the
-                * input is no visible (output is completely comtroled by
-                * shell/command, we do not write anything there).
-                */
-               ul_pty_keep_slave_echo(ctl.pty, 1);
+       ul_pty_slave_echo(ctl.pty, echo);
 
        ul_pty_set_callback_data(ctl.pty, (void *) &ctl);
        cb = ul_pty_get_callbacks(ctl.pty);
index 899871574b7d85974284995b8935441de850697b..6d263296bf62a5f119baf7f447685a16715eb643 100644 (file)
@@ -291,7 +291,7 @@ main(int argc, char *argv[])
 
        if (!isatty(STDIN_FILENO))
                /* We keep ECHO flag for compatibility with script(1) */
-               ul_pty_keep_slave_echo(ss.pty, 1);
+               ul_pty_slave_echo(ss.pty, 1);
 
        if (ul_pty_setup(ss.pty))
                err(EXIT_FAILURE, _("failed to create pseudo-terminal"));