No need to use pseudo-cbreak mode now that we use pipes when stdout is

not a tty.  Instead, check whether stdin is a tty and if not, delay
setting the tty to raw mode until the command tries to access it itself
(and receives SIGTTIN or SIGTTOU).
This commit is contained in:
Todd C. Miller
2010-05-10 17:23:35 -04:00
parent cbb3010d73
commit c2d0888bf9
4 changed files with 27 additions and 26 deletions

View File

@@ -150,7 +150,7 @@ static int stack_top;
extern time_t get_date(char *); extern time_t get_date(char *);
extern char *get_timestr(time_t, int); extern char *get_timestr(time_t, int);
extern int term_raw(int, int, int); extern int term_raw(int, int);
extern int term_restore(int, int); extern int term_restore(int, int);
extern void zero_bytes(volatile void *, size_t); extern void zero_bytes(volatile void *, size_t);
void cleanup(int); void cleanup(int);
@@ -297,7 +297,7 @@ main(int argc, char *argv[])
ch = fcntl(STDIN_FILENO, F_GETFL, 0); ch = fcntl(STDIN_FILENO, F_GETFL, 0);
if (ch != -1) if (ch != -1)
(void) fcntl(STDIN_FILENO, F_SETFL, ch | O_NONBLOCK); (void) fcntl(STDIN_FILENO, F_SETFL, ch | O_NONBLOCK);
if (!term_raw(STDIN_FILENO, 0, 1)) if (!term_raw(STDIN_FILENO, 1))
error(1, "cannot set tty to raw mode"); error(1, "cannot set tty to raw mode");
} }
fdsr = (fd_set *)emalloc2(howmany(STDOUT_FILENO + 1, NFDBITS), fdsr = (fd_set *)emalloc2(howmany(STDOUT_FILENO + 1, NFDBITS),

View File

@@ -87,8 +87,7 @@
#define SFD_USERTTY 5 #define SFD_USERTTY 5
#define TERM_COOKED 0 #define TERM_COOKED 0
#define TERM_CBREAK 1 #define TERM_RAW 1
#define TERM_RAW 2
#if !defined(TIOCGSIZE) && defined(TIOCGWINSZ) #if !defined(TIOCGSIZE) && defined(TIOCGWINSZ)
# define TIOCGSIZE TIOCGWINSZ # define TIOCGSIZE TIOCGWINSZ
@@ -108,7 +107,7 @@ struct io_buffer {
}; };
static int script_fds[6] = { -1, -1, -1, -1, -1, -1}; static int script_fds[6] = { -1, -1, -1, -1, -1, -1};
static int ttyout = TRUE; static int ttyin = TRUE;
static sig_atomic_t recvsig[NSIG]; static sig_atomic_t recvsig[NSIG];
static sig_atomic_t ttymode = TERM_COOKED; static sig_atomic_t ttymode = TERM_COOKED;
@@ -296,7 +295,7 @@ suspend_parent(int signo, int fd, struct io_buffer *iobufs)
if (foreground) { if (foreground) {
if (ttymode != TERM_RAW) { if (ttymode != TERM_RAW) {
do { do {
n = term_raw(script_fds[SFD_USERTTY], !ttyout, 0); n = term_raw(script_fds[SFD_USERTTY], 0);
} while (!n && errno == EINTR); } while (!n && errno == EINTR);
ttymode = TERM_RAW; ttymode = TERM_RAW;
} }
@@ -335,10 +334,9 @@ suspend_parent(int signo, int fd, struct io_buffer *iobufs)
if (ttymode != TERM_COOKED) { if (ttymode != TERM_COOKED) {
if (foreground) { if (foreground) {
/* Set raw/cbreak mode. */ /* Set raw mode. */
do { do {
n = term_raw(script_fds[SFD_USERTTY], !ttyout, n = term_raw(script_fds[SFD_USERTTY], 0);
ttymode == TERM_CBREAK);
} while (!n && errno == EINTR); } while (!n && errno == EINTR);
} else { } else {
/* Background process, no access to tty. */ /* Background process, no access to tty. */
@@ -565,6 +563,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
*/ */
memset(io_pipe, 0, sizeof(io_pipe)); memset(io_pipe, 0, sizeof(io_pipe));
if (!isatty(STDIN_FILENO)) { if (!isatty(STDIN_FILENO)) {
ttyin = FALSE;
if (pipe(io_pipe[STDIN_FILENO]) != 0) if (pipe(io_pipe[STDIN_FILENO]) != 0)
error(1, "unable to create pipe"); error(1, "unable to create pipe");
iobufs = io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1], iobufs = io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1],
@@ -572,7 +571,6 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
script_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0]; script_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0];
} }
if (!isatty(STDOUT_FILENO)) { if (!isatty(STDOUT_FILENO)) {
ttyout = FALSE;
if (pipe(io_pipe[STDOUT_FILENO]) != 0) if (pipe(io_pipe[STDOUT_FILENO]) != 0)
error(1, "unable to create pipe"); error(1, "unable to create pipe");
iobufs = io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO, iobufs = io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO,
@@ -603,14 +601,15 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
sync_ttysize(script_fds[SFD_USERTTY], script_fds[SFD_SLAVE]); sync_ttysize(script_fds[SFD_USERTTY], script_fds[SFD_SLAVE]);
} }
/* Start out in raw mode is stdout is a tty. */ /* Start out in raw mode is stdin is a tty. */
ttymode = ttyout ? TERM_RAW : TERM_CBREAK; if (ttyin) {
do { ttymode = TERM_RAW;
n = term_raw(script_fds[SFD_USERTTY], !ttyout, do {
ttymode == TERM_CBREAK); n = term_raw(script_fds[SFD_USERTTY], 0);
} while (!n && errno == EINTR); } while (!n && errno == EINTR);
if (!n) if (!n)
error(1, "Can't set terminal to raw mode"); error(1, "Can't set terminal to raw mode");
}
} }
} }
@@ -738,7 +737,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
FD_SET(iob->rfd, fdsr); FD_SET(iob->rfd, fdsr);
} }
if (iob->wfd != -1 && if (iob->wfd != -1 &&
(ttymode == TERM_RAW || iob->wfd != script_fds[SFD_USERTTY])) { (foreground || iob->wfd != script_fds[SFD_USERTTY])) {
if (iob->len > iob->off) if (iob->len > iob->off)
FD_SET(iob->wfd, fdsw); FD_SET(iob->wfd, fdsw);
} }
@@ -971,7 +970,13 @@ script_child(const char *path, char *argv[], char *envp[], int backchannel, int
close(n); close(n);
#endif #endif
if (foreground && !ttyout) /*
* If stdin is not a tty, start command in the background since
* it might be part of a pipeline that reads from /dev/tty.
* In this case, we rely on the command receiving SIGTTOU or SIGTTIN
* when it needs access to the controlling tty.
*/
if (foreground && !ttyin)
foreground = 0; foreground = 0;
/* Start command and wait for it to stop or exit */ /* Start command and wait for it to stop or exit */
@@ -1012,7 +1017,6 @@ script_child(const char *path, char *argv[], char *envp[], int backchannel, int
close(errpipe[1]); close(errpipe[1]);
/* If any of stdin/stdout/stderr are pipes, close them in parent. */ /* If any of stdin/stdout/stderr are pipes, close them in parent. */
/* XXX - close other end too */
if (script_fds[SFD_STDIN] != script_fds[SFD_SLAVE]) if (script_fds[SFD_STDIN] != script_fds[SFD_SLAVE])
close(script_fds[SFD_STDIN]); close(script_fds[SFD_STDIN]);
if (script_fds[SFD_STDOUT] != script_fds[SFD_SLAVE]) if (script_fds[SFD_STDOUT] != script_fds[SFD_SLAVE])

View File

@@ -178,7 +178,7 @@ void script_setup(uid_t);
int term_cbreak(int); int term_cbreak(int);
int term_copy(int, int); int term_copy(int, int);
int term_noecho(int); int term_noecho(int);
int term_raw(int, int, int); int term_raw(int, int);
int term_restore(int, int); int term_restore(int, int);
/* fmt_string.h */ /* fmt_string.h */

View File

@@ -116,7 +116,7 @@ term_noecho(int fd)
} }
int int
term_raw(int fd, int opost, int isig) term_raw(int fd, int isig)
{ {
struct termios term; struct termios term;
@@ -130,9 +130,6 @@ term_raw(int fd, int opost, int isig)
if (isig) if (isig)
SET(term.c_lflag, ISIG); SET(term.c_lflag, ISIG);
CLR(term.c_iflag, ICRNL | IGNCR | INLCR | IUCLC | IXON); CLR(term.c_iflag, ICRNL | IGNCR | INLCR | IUCLC | IXON);
/* Only retain output post-processing opost flag set. */
if (!opost)
CLR(term.c_oflag, OPOST);
if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
changed = 1; changed = 1;
return(1); return(1);