From: Karel Zak Date: Mon, 25 Nov 2019 11:39:52 +0000 (+0100) Subject: script: add --echo X-Git-Tag: v2.35-rc1~43 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1eee1acb245a8b724e441778dfa9b858465bf7e5;p=thirdparty%2Futil-linux.git script: add --echo 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 --- diff --git a/include/pty-session.h b/include/pty-session.h index 798f606b82..9681bcc779 100644 --- a/include/pty-session.h +++ b/include/pty-session.h @@ -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); diff --git a/lib/pty-session.c b/lib/pty-session.c index 8017d9f4d5..b668e953fc 100644 --- a/lib/pty-session.c +++ b/lib/pty-session.c @@ -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); diff --git a/term-utils/script.1 b/term-utils/script.1 index e7195d65ff..2da845fc71 100644 --- a/term-utils/script.1 +++ b/term-utils/script.1 @@ -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 diff --git a/term-utils/script.c b/term-utils/script.c index f9494fd507..d5a3836320 100644 --- a/term-utils/script.c +++ b/term-utils/script.c @@ -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 echo input (auto, always or never)\n"), out); fputs(_(" -o, --output-limit 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); diff --git a/term-utils/scriptlive.c b/term-utils/scriptlive.c index 899871574b..6d263296bf 100644 --- a/term-utils/scriptlive.c +++ b/term-utils/scriptlive.c @@ -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"));