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 <kzak@redhat.com>
This commit is contained in:
parent
a06b278bd3
commit
1eee1acb24
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"));
|
||||
|
|
Loading…
Reference in New Issue