Use pipes to the sudo process if stdout or stderr is not a tty.
Still needs some polishing and a decision as to whether it is desirable to add additonal entry points for logging stdout/stderr/stdin when they are not ttys. That would allow a replay program to keep things separate and to know whether the terminal needs to be in raw mode at replay time.
This commit is contained in:
314
src/script.c
314
src/script.c
@@ -79,9 +79,12 @@
|
|||||||
#include "sudo_plugin.h"
|
#include "sudo_plugin.h"
|
||||||
#include "sudo_plugin_int.h"
|
#include "sudo_plugin_int.h"
|
||||||
|
|
||||||
#define SFD_MASTER 0
|
#define SFD_STDIN 0
|
||||||
#define SFD_SLAVE 1
|
#define SFD_STDOUT 1
|
||||||
#define SFD_USERTTY 2
|
#define SFD_STDERR 2
|
||||||
|
#define SFD_MASTER 3
|
||||||
|
#define SFD_SLAVE 4
|
||||||
|
#define SFD_USERTTY 5
|
||||||
|
|
||||||
#define TERM_COOKED 0
|
#define TERM_COOKED 0
|
||||||
#define TERM_CBREAK 1
|
#define TERM_CBREAK 1
|
||||||
@@ -94,14 +97,18 @@
|
|||||||
# define ts_cols ws_col
|
# define ts_cols ws_col
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct script_buf {
|
struct io_buffer {
|
||||||
int len; /* buffer length (how much read in) */
|
struct io_buffer *next;
|
||||||
|
int len; /* buffer length (how much produced) */
|
||||||
int off; /* write position (how much already consumed) */
|
int off; /* write position (how much already consumed) */
|
||||||
|
int rfd; /* reader (producer) */
|
||||||
|
int wfd; /* writer (consumer) */
|
||||||
|
int (*action)(char *buf, unsigned int len);
|
||||||
char buf[16 * 1024];
|
char buf[16 * 1024];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int script_fds[3] = { -1, -1, -1 };
|
static int script_fds[6] = { -1, -1, -1, -1, -1, -1};
|
||||||
static int ttyout;
|
static int ttyout = 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;
|
||||||
@@ -115,8 +122,8 @@ static int foreground;
|
|||||||
|
|
||||||
static char slavename[PATH_MAX];
|
static char slavename[PATH_MAX];
|
||||||
|
|
||||||
static int suspend_parent(int signo, struct script_buf *output);
|
static int suspend_parent(int signo, int fd, struct io_buffer *output);
|
||||||
static void flush_output(struct script_buf *output);
|
static void flush_output(struct io_buffer *iobufs);
|
||||||
static void handler(int s);
|
static void handler(int s);
|
||||||
static int script_child(const char *path, char *argv[], char *envp[], int, int);
|
static int script_child(const char *path, char *argv[], char *envp[], int, int);
|
||||||
static void script_run(const char *path, char *argv[], char *envp[], int);
|
static void script_run(const char *path, char *argv[], char *envp[], int);
|
||||||
@@ -202,7 +209,7 @@ check_foreground(void)
|
|||||||
* Returns SIGUSR1 if the child should be resume in foreground else SIGUSR2.
|
* Returns SIGUSR1 if the child should be resume in foreground else SIGUSR2.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
suspend_parent(int signo, struct script_buf *output)
|
suspend_parent(int signo, int fd, struct io_buffer *iobufs)
|
||||||
{
|
{
|
||||||
sigaction_t sa, osa;
|
sigaction_t sa, osa;
|
||||||
int n, oldmode = ttymode, rval = 0;
|
int n, oldmode = ttymode, rval = 0;
|
||||||
@@ -230,8 +237,8 @@ suspend_parent(int signo, struct script_buf *output)
|
|||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case SIGSTOP:
|
case SIGSTOP:
|
||||||
case SIGTSTP:
|
case SIGTSTP:
|
||||||
/* Flush any remaining output to master tty. */
|
/* Flush any remaining output before suspending. */
|
||||||
flush_output(output);
|
flush_output(iobufs);
|
||||||
|
|
||||||
/* Restore original tty mode before suspending. */
|
/* Restore original tty mode before suspending. */
|
||||||
if (oldmode != TERM_COOKED) {
|
if (oldmode != TERM_COOKED) {
|
||||||
@@ -264,7 +271,7 @@ suspend_parent(int signo, struct script_buf *output)
|
|||||||
ttymode == TERM_CBREAK);
|
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. */
|
||||||
ttymode = TERM_COOKED;
|
ttymode = TERM_COOKED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,6 +327,21 @@ terminate_child(pid_t pid, int use_pgrp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct io_buffer *
|
||||||
|
io_buf_new(int rfd, int wfd, int (*action)(char *, unsigned int),
|
||||||
|
struct io_buffer *head)
|
||||||
|
{
|
||||||
|
struct io_buffer *iob;
|
||||||
|
|
||||||
|
iob = emalloc(sizeof(*iob));
|
||||||
|
zero_bytes(iob, sizeof(*iob));
|
||||||
|
iob->rfd = rfd;
|
||||||
|
iob->wfd = wfd;
|
||||||
|
iob->action = action;
|
||||||
|
iob->next = head;
|
||||||
|
return iob;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a little bit tricky due to how POSIX job control works and
|
* This is a little bit tricky due to how POSIX job control works and
|
||||||
* we fact that we have two different controlling terminals to deal with.
|
* we fact that we have two different controlling terminals to deal with.
|
||||||
@@ -339,9 +361,9 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
struct command_status *cstat)
|
struct command_status *cstat)
|
||||||
{
|
{
|
||||||
sigaction_t sa;
|
sigaction_t sa;
|
||||||
struct script_buf input, output;
|
struct io_buffer *iob, *iobufs = NULL;
|
||||||
int n, nready;
|
int n, nready;
|
||||||
int sv[2];
|
int pv[2], sv[2];
|
||||||
fd_set *fdsr, *fdsw;
|
fd_set *fdsr, *fdsw;
|
||||||
int rbac_enabled = 0;
|
int rbac_enabled = 0;
|
||||||
int log_io, maxfd;
|
int log_io, maxfd;
|
||||||
@@ -376,7 +398,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
zero_bytes(&sa, sizeof(sa));
|
zero_bytes(&sa, sizeof(sa));
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
|
|
||||||
/* Ignore SIGPIPE from other end of socketpair. */
|
/* Ignore SIGPIPE, check errno instead... */
|
||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
sigaction(SIGPIPE, &sa, NULL);
|
sigaction(SIGPIPE, &sa, NULL);
|
||||||
@@ -407,8 +429,41 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
/* Are we the foreground process? */
|
/* Are we the foreground process? */
|
||||||
foreground = tcgetpgrp(script_fds[SFD_USERTTY]) == ppgrp;
|
foreground = tcgetpgrp(script_fds[SFD_USERTTY]) == ppgrp;
|
||||||
|
|
||||||
/* If stdout is not a tty we handle post-processing differently. */
|
/*
|
||||||
ttyout = isatty(STDOUT_FILENO);
|
* Setup stdin/stdout/stderr for child, to be duped after forking.
|
||||||
|
*/
|
||||||
|
/* XXX - use a pipe for stdin if not a tty? */
|
||||||
|
script_fds[SFD_STDIN] = isatty(STDIN_FILENO) ?
|
||||||
|
script_fds[SFD_SLAVE] : STDIN_FILENO;
|
||||||
|
script_fds[SFD_STDOUT] = script_fds[SFD_SLAVE];
|
||||||
|
script_fds[SFD_STDERR] = script_fds[SFD_SLAVE];
|
||||||
|
|
||||||
|
/* Copy /dev/tty -> pty master */
|
||||||
|
iobufs = io_buf_new(script_fds[SFD_USERTTY], script_fds[SFD_MASTER],
|
||||||
|
log_input, iobufs);
|
||||||
|
|
||||||
|
/* Copy pty master -> /dev/tty */
|
||||||
|
iobufs = io_buf_new(script_fds[SFD_MASTER], script_fds[SFD_USERTTY],
|
||||||
|
log_output, iobufs);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If either stdout or stderr is not a tty we use a pipe
|
||||||
|
* to interpose ourselves instead of duping the pty fd.
|
||||||
|
* NOTE: we don't currently log tty/stdout/stderr separately.
|
||||||
|
*/
|
||||||
|
if (!isatty(STDOUT_FILENO)) {
|
||||||
|
ttyout = FALSE;
|
||||||
|
if (pipe(pv) != 0)
|
||||||
|
error(1, "unable to create pipe");
|
||||||
|
iobufs = io_buf_new(pv[0], STDOUT_FILENO, log_output, iobufs);
|
||||||
|
script_fds[SFD_STDOUT] = pv[1];
|
||||||
|
}
|
||||||
|
if (!isatty(STDERR_FILENO)) {
|
||||||
|
if (pipe(pv) != 0)
|
||||||
|
error(1, "unable to create pipe");
|
||||||
|
iobufs = io_buf_new(pv[0], STDERR_FILENO, log_output, iobufs);
|
||||||
|
script_fds[SFD_STDERR] = pv[1];
|
||||||
|
}
|
||||||
|
|
||||||
/* Job control signals to relay from parent to child. */
|
/* Job control signals to relay from parent to child. */
|
||||||
sa.sa_flags = 0; /* do not restart syscalls */
|
sa.sa_flags = 0; /* do not restart syscalls */
|
||||||
@@ -478,25 +533,26 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
maxfd = sv[0];
|
maxfd = sv[0];
|
||||||
|
|
||||||
if (log_io) {
|
if (log_io) {
|
||||||
if (maxfd < script_fds[SFD_MASTER])
|
/* Close the writer end of the stdout/stderr pipes. */
|
||||||
maxfd = script_fds[SFD_MASTER];
|
if (script_fds[SFD_STDOUT] != script_fds[SFD_SLAVE])
|
||||||
if (maxfd < script_fds[SFD_USERTTY])
|
close(script_fds[SFD_STDOUT]);
|
||||||
maxfd = script_fds[SFD_USERTTY];
|
if (script_fds[SFD_STDERR] != script_fds[SFD_SLAVE])
|
||||||
|
close(script_fds[SFD_STDERR]);
|
||||||
|
|
||||||
n = fcntl(script_fds[SFD_MASTER], F_GETFL, 0);
|
for (iob = iobufs; iob; iob = iob->next) {
|
||||||
if (n != -1) {
|
/* Determine maxfd */
|
||||||
n |= O_NONBLOCK;
|
if (iob->rfd > maxfd)
|
||||||
(void) fcntl(script_fds[SFD_MASTER], F_SETFL, n);
|
maxfd = iob->rfd;
|
||||||
}
|
if (iob->wfd > maxfd)
|
||||||
n = fcntl(script_fds[SFD_USERTTY], F_GETFL, 0);
|
maxfd = iob->wfd;
|
||||||
if (n != -1) {
|
|
||||||
n |= O_NONBLOCK;
|
/* Set non-blocking mode. */
|
||||||
(void) fcntl(script_fds[SFD_USERTTY], F_SETFL, n);
|
n = fcntl(iob->rfd, F_GETFL, 0);
|
||||||
}
|
if (n != -1 && !ISSET(n, O_NONBLOCK))
|
||||||
n = fcntl(STDOUT_FILENO, F_GETFL, 0);
|
(void) fcntl(iob->rfd, F_SETFL, n | O_NONBLOCK);
|
||||||
if (n != -1) {
|
n = fcntl(iob->wfd, F_GETFL, 0);
|
||||||
n |= O_NONBLOCK;
|
if (n != -1 && !ISSET(n, O_NONBLOCK))
|
||||||
(void) fcntl(STDOUT_FILENO, F_SETFL, n);
|
(void) fcntl(iob->wfd, F_SETFL, n | O_NONBLOCK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,8 +562,6 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
*/
|
*/
|
||||||
fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
|
fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
|
||||||
fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
|
fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
|
||||||
zero_bytes(&input, sizeof(input));
|
|
||||||
zero_bytes(&output, sizeof(output));
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (recvsig[SIGCHLD]) {
|
if (recvsig[SIGCHLD]) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
@@ -533,22 +587,20 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
zero_bytes(fdsw, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
|
zero_bytes(fdsw, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
|
||||||
zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
|
zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
|
||||||
|
|
||||||
if (log_io) {
|
|
||||||
if (input.off == input.len)
|
|
||||||
input.off = input.len = 0;
|
|
||||||
if (output.off == output.len)
|
|
||||||
output.off = output.len = 0;
|
|
||||||
|
|
||||||
if (ttymode == TERM_RAW && input.len != sizeof(input.buf))
|
|
||||||
FD_SET(script_fds[SFD_USERTTY], fdsr);
|
|
||||||
if (output.len != sizeof(output.buf))
|
|
||||||
FD_SET(script_fds[SFD_MASTER], fdsr);
|
|
||||||
if (output.len > output.off)
|
|
||||||
FD_SET(STDOUT_FILENO, fdsw);
|
|
||||||
if (input.len > input.off)
|
|
||||||
FD_SET(script_fds[SFD_MASTER], fdsw);
|
|
||||||
}
|
|
||||||
FD_SET(sv[0], fdsr);
|
FD_SET(sv[0], fdsr);
|
||||||
|
for (iob = iobufs; iob; iob = iob->next) {
|
||||||
|
if (iob->off == iob->len)
|
||||||
|
iob->off = iob->len = 0;
|
||||||
|
/* Don't read/write /dev/tty if we are not in the foreground. */
|
||||||
|
if (ttymode == TERM_RAW || iob->rfd != script_fds[SFD_USERTTY]) {
|
||||||
|
if (iob->len != sizeof(iob->buf))
|
||||||
|
FD_SET(iob->rfd, fdsr);
|
||||||
|
}
|
||||||
|
if (ttymode == TERM_RAW || iob->wfd != script_fds[SFD_USERTTY]) {
|
||||||
|
if (iob->len > iob->off)
|
||||||
|
FD_SET(iob->wfd, fdsw);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (n = 0; n < NSIG; n++) {
|
for (n = 0; n < NSIG; n++) {
|
||||||
if (recvsig[n] && n != SIGCHLD) {
|
if (recvsig[n] && n != SIGCHLD) {
|
||||||
if (log_io) {
|
if (log_io) {
|
||||||
@@ -587,7 +639,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
if (WIFSTOPPED(cstat->val)) {
|
if (WIFSTOPPED(cstat->val)) {
|
||||||
/* Suspend parent and tell child how to resume on return. */
|
/* Suspend parent and tell child how to resume on return. */
|
||||||
sudo_debug(8, "child stopped, suspending parent");
|
sudo_debug(8, "child stopped, suspending parent");
|
||||||
n = suspend_parent(WSTOPSIG(cstat->val), &output);
|
n = suspend_parent(WSTOPSIG(cstat->val), script_fds[SFD_USERTTY], iobufs);
|
||||||
recvsig[n] = TRUE;
|
recvsig[n] = TRUE;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
@@ -599,8 +651,6 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!log_io)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (FD_ISSET(sv[0], fdsw)) {
|
if (FD_ISSET(sv[0], fdsw)) {
|
||||||
for (n = 0; n < NSIG; n++) {
|
for (n = 0; n < NSIG; n++) {
|
||||||
@@ -619,72 +669,49 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (FD_ISSET(script_fds[SFD_USERTTY], fdsr)) {
|
|
||||||
n = read(script_fds[SFD_USERTTY], input.buf + input.len,
|
for (iob = iobufs; iob; iob = iob->next) {
|
||||||
sizeof(input.buf) - input.len);
|
if (FD_ISSET(iob->rfd, fdsr)) {
|
||||||
if (n == -1) {
|
n = read(iob->rfd, iob->buf + iob->len,
|
||||||
if (errno == EINTR)
|
sizeof(iob->buf) - iob->len);
|
||||||
continue;
|
if (n == -1) {
|
||||||
if (errno != EAGAIN)
|
if (errno == EINTR)
|
||||||
break;
|
continue;
|
||||||
} else {
|
if (errno != EAGAIN)
|
||||||
if (n == 0)
|
break;
|
||||||
break; /* got EOF */
|
} else {
|
||||||
if (!log_input(input.buf + input.len, n))
|
if (n == 0)
|
||||||
terminate_child(child, TRUE);
|
break; /* got EOF */
|
||||||
input.len += n;
|
if (!iob->action(iob->buf + iob->len, n))
|
||||||
|
terminate_child(child, TRUE);
|
||||||
|
iob->len += n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (FD_ISSET(iob->wfd, fdsw)) {
|
||||||
if (FD_ISSET(script_fds[SFD_MASTER], fdsw)) {
|
n = write(iob->wfd, iob->buf + iob->off,
|
||||||
n = write(script_fds[SFD_MASTER], input.buf + input.off,
|
iob->len - iob->off);
|
||||||
input.len - input.off);
|
if (n == -1) {
|
||||||
if (n == -1) {
|
if (errno == EINTR)
|
||||||
if (errno == EINTR)
|
continue;
|
||||||
continue;
|
if (errno != EAGAIN)
|
||||||
if (errno != EAGAIN)
|
break;
|
||||||
break;
|
} else {
|
||||||
} else {
|
iob->off += n;
|
||||||
input.off += n;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
if (FD_ISSET(script_fds[SFD_MASTER], fdsr)) {
|
|
||||||
n = read(script_fds[SFD_MASTER], output.buf + output.len,
|
|
||||||
sizeof(output.buf) - output.len);
|
|
||||||
if (n == -1) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
if (errno != EAGAIN)
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (n == 0)
|
|
||||||
break; /* got EOF */
|
|
||||||
if (!log_output(output.buf + output.len, n))
|
|
||||||
terminate_child(child, TRUE);
|
|
||||||
output.len += n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (FD_ISSET(STDOUT_FILENO, fdsw)) {
|
|
||||||
n = write(STDOUT_FILENO, output.buf + output.off,
|
|
||||||
output.len - output.off);
|
|
||||||
if (n == -1) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
if (errno != EAGAIN)
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
output.off += n;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_io) {
|
if (log_io) {
|
||||||
/* Flush any remaining output to stdout (plugin already got it) */
|
/* Flush any remaining output (the plugin already got it) */
|
||||||
n = fcntl(STDOUT_FILENO, F_GETFL, 0);
|
for (iob = iobufs; iob; iob = iob->next) {
|
||||||
if (n != -1) {
|
n = fcntl(iob->wfd, F_GETFL, 0);
|
||||||
n &= ~O_NONBLOCK;
|
if (n != -1 && ISSET(n, O_NONBLOCK)) {
|
||||||
(void) fcntl(STDOUT_FILENO, F_SETFL, n);
|
CLR(n, O_NONBLOCK);
|
||||||
|
(void) fcntl(iob->wfd, F_SETFL, n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
flush_output(&output);
|
flush_output(iobufs);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
n = term_restore(script_fds[SFD_USERTTY], 0);
|
n = term_restore(script_fds[SFD_USERTTY], 0);
|
||||||
@@ -694,10 +721,10 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
int signo = WTERMSIG(cstat->val);
|
int signo = WTERMSIG(cstat->val);
|
||||||
if (signo && signo != SIGINT && signo != SIGPIPE) {
|
if (signo && signo != SIGINT && signo != SIGPIPE) {
|
||||||
char *reason = strsignal(signo);
|
char *reason = strsignal(signo);
|
||||||
write(STDOUT_FILENO, reason, strlen(reason));
|
write(script_fds[SFD_USERTTY], reason, strlen(reason));
|
||||||
if (WCOREDUMP(cstat->val))
|
if (WCOREDUMP(cstat->val))
|
||||||
write(STDOUT_FILENO, " (core dumped)", 14);
|
write(script_fds[SFD_USERTTY], " (core dumped)", 14);
|
||||||
write(STDOUT_FILENO, "\n", 1);
|
write(script_fds[SFD_USERTTY], "\n", 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -979,34 +1006,38 @@ bad:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
flush_output(struct script_buf *output)
|
flush_output(struct io_buffer *iobufs)
|
||||||
{
|
{
|
||||||
|
struct io_buffer *iob, output;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
while (output->len > output->off) {
|
/* XXX - really only want to flush output buffers, does it matter? */
|
||||||
n = write(STDOUT_FILENO, output->buf + output->off,
|
for (iob = iobufs; iob; iob = iob->next) {
|
||||||
output->len - output->off);
|
while (iob->len > iob->off) {
|
||||||
if (n <= 0)
|
n = write(iob->wfd, iob->buf + iob->off, iob->len - iob->off);
|
||||||
break;
|
if (n <= 0)
|
||||||
output->off += n;
|
break;
|
||||||
|
iob->off += n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure there is no output remaining on the master pty. */
|
/* Make sure there is no output remaining on the master pty. */
|
||||||
|
/* XXX - pipes too? */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
n = read(script_fds[SFD_MASTER], output->buf, sizeof(output->buf));
|
n = read(script_fds[SFD_MASTER], output.buf, sizeof(output.buf));
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
break;
|
break;
|
||||||
/* XXX */
|
/* XXX */
|
||||||
log_output(output->buf, n);
|
log_output(output.buf, n);
|
||||||
output->off = 0;
|
output.off = 0;
|
||||||
output->len = n;
|
output.len = n;
|
||||||
do {
|
do {
|
||||||
n = write(STDOUT_FILENO, output->buf + output->off,
|
n = write(script_fds[SFD_USERTTY], output.buf + output.off,
|
||||||
output->len - output->off);
|
output.len - output.off);
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
break;
|
break;
|
||||||
output->off += n;
|
output.off += n;
|
||||||
} while (output->len > output->off);
|
} while (output.len > output.off);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1018,21 +1049,20 @@ script_run(const char *path, char *argv[], char *envp[], int rbac_enabled)
|
|||||||
/* Set child process group here too to avoid a race. */
|
/* Set child process group here too to avoid a race. */
|
||||||
setpgid(0, self);
|
setpgid(0, self);
|
||||||
|
|
||||||
/*
|
/* Wire up standard fds, note that stdout/stderr may be pipes. */
|
||||||
* We have guaranteed that the slave fd > 3
|
dup2(script_fds[SFD_STDIN], STDIN_FILENO);
|
||||||
*/
|
dup2(script_fds[SFD_STDOUT], STDOUT_FILENO);
|
||||||
if (isatty(STDIN_FILENO))
|
dup2(script_fds[SFD_STDERR], STDERR_FILENO);
|
||||||
dup2(script_fds[SFD_SLAVE], STDIN_FILENO);
|
|
||||||
dup2(script_fds[SFD_SLAVE], STDOUT_FILENO);
|
|
||||||
dup2(script_fds[SFD_SLAVE], STDERR_FILENO);
|
|
||||||
close(script_fds[SFD_SLAVE]);
|
|
||||||
|
|
||||||
/* Wait for parent to grant us the tty if we are foreground. */
|
/* Wait for parent to grant us the tty if we are foreground. */
|
||||||
if (foreground) {
|
if (foreground) {
|
||||||
while (tcgetpgrp(STDOUT_FILENO) != self)
|
while (tcgetpgrp(script_fds[SFD_SLAVE]) != self)
|
||||||
; /* spin */
|
; /* spin */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We have guaranteed that the slave fd > 3 */
|
||||||
|
close(script_fds[SFD_SLAVE]);
|
||||||
|
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
if (rbac_enabled)
|
if (rbac_enabled)
|
||||||
selinux_execve(path, argv, envp);
|
selinux_execve(path, argv, envp);
|
||||||
|
Reference in New Issue
Block a user