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)
/* 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);
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
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);
.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;
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,},
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);
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;
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);