parent
baae1fc84f
commit
de0064af47
@ -41,7 +41,7 @@ static int write_blocking(int fd, char *buf, ssize_t bufsz) {
|
|||||||
* Pump data from input FD to output FD. If close_output is
|
* Pump data from input FD to output FD. If close_output is
|
||||||
* true, then close the output FD when we're done.
|
* true, then close the output FD when we're done.
|
||||||
*/
|
*/
|
||||||
static void pump_ex(int input, int output, int close_output) {
|
static void pump(int input, int output, bool close_output = true) {
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
int len;
|
int len;
|
||||||
while ((len = read(input, buf, 4096)) > 0) {
|
while ((len = read(input, buf, 4096)) > 0) {
|
||||||
@ -51,32 +51,19 @@ static void pump_ex(int input, int output, int close_output) {
|
|||||||
if (close_output) close(output);
|
if (close_output) close(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Pump data from input FD to output FD. Will close the
|
|
||||||
* output FD when done.
|
|
||||||
*/
|
|
||||||
static void pump(int input, int output) {
|
|
||||||
pump_ex(input, output, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void* pump_thread(void* data) {
|
static void* pump_thread(void* data) {
|
||||||
int* files = (int*)data;
|
int *fds = (int*) data;
|
||||||
int input = files[0];
|
pump(fds[0], fds[1]);
|
||||||
int output = files[1];
|
delete[] fds;
|
||||||
pump(input, output);
|
return nullptr;
|
||||||
free(data);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pump_async(int input, int output) {
|
static void pump_async(int input, int output) {
|
||||||
pthread_t writer;
|
pthread_t writer;
|
||||||
int* files = (int*)malloc(sizeof(int) * 2);
|
int *fds = new int[2];
|
||||||
if (files == NULL) {
|
fds[0] = input;
|
||||||
exit(-1);
|
fds[1] = output;
|
||||||
}
|
pthread_create(&writer, nullptr, pump_thread, fds);
|
||||||
files[0] = input;
|
|
||||||
files[1] = output;
|
|
||||||
pthread_create(&writer, NULL, pump_thread, files);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -190,7 +177,7 @@ int restore_stdin(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flag indicating whether the sigwinch watcher should terminate.
|
// Flag indicating whether the sigwinch watcher should terminate.
|
||||||
static volatile int closing_time = 0;
|
static volatile bool close_sigwinch_watcher = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread process. Wait for a SIGWINCH to be received, then update
|
* Thread process. Wait for a SIGWINCH to be received, then update
|
||||||
@ -198,29 +185,29 @@ static volatile int closing_time = 0;
|
|||||||
*/
|
*/
|
||||||
static void *watch_sigwinch(void *data) {
|
static void *watch_sigwinch(void *data) {
|
||||||
sigset_t winch;
|
sigset_t winch;
|
||||||
|
int *fds = (int *)data;
|
||||||
int sig;
|
int sig;
|
||||||
int master = ((int *)data)[0];
|
|
||||||
int slave = ((int *)data)[1];
|
|
||||||
|
|
||||||
sigemptyset(&winch);
|
sigemptyset(&winch);
|
||||||
sigaddset(&winch, SIGWINCH);
|
sigaddset(&winch, SIGWINCH);
|
||||||
|
pthread_sigmask(SIG_UNBLOCK, &winch, nullptr);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (closing_time) break;
|
if (close_sigwinch_watcher)
|
||||||
|
break;
|
||||||
|
|
||||||
// Get the new terminal size
|
// Get the new terminal size
|
||||||
struct winsize w;
|
struct winsize w;
|
||||||
if (ioctl(master, TIOCGWINSZ, &w) == -1) {
|
if (ioctl(fds[0], TIOCGWINSZ, &w) == -1)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// Set the new terminal size
|
// Set the new terminal size
|
||||||
ioctl(slave, TIOCSWINSZ, &w);
|
ioctl(fds[1], TIOCSWINSZ, &w);
|
||||||
|
|
||||||
} while (sigwait(&winch, &sig) == 0);
|
} while (sigwait(&winch, &sig) == 0);
|
||||||
|
delete[] fds;
|
||||||
|
|
||||||
free(data);
|
return nullptr;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -247,27 +234,24 @@ static void *watch_sigwinch(void *data) {
|
|||||||
*/
|
*/
|
||||||
int watch_sigwinch_async(int master, int slave) {
|
int watch_sigwinch_async(int master, int slave) {
|
||||||
pthread_t watcher;
|
pthread_t watcher;
|
||||||
int *files = (int *) malloc(sizeof(int) * 2);
|
int *fds = new int[2];
|
||||||
if (files == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Block SIGWINCH so sigwait can later receive it
|
// Block SIGWINCH so sigwait can later receive it
|
||||||
sigset_t winch;
|
sigset_t winch;
|
||||||
sigemptyset(&winch);
|
sigemptyset(&winch);
|
||||||
sigaddset(&winch, SIGWINCH);
|
sigaddset(&winch, SIGWINCH);
|
||||||
if (sigprocmask(SIG_BLOCK, &winch, NULL) == -1) {
|
if (pthread_sigmask(SIG_BLOCK, &winch, nullptr) == -1) {
|
||||||
free(files);
|
delete[] fds;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize some variables, then start the thread
|
// Initialize some variables, then start the thread
|
||||||
closing_time = 0;
|
close_sigwinch_watcher = 0;
|
||||||
files[0] = master;
|
fds[0] = master;
|
||||||
files[1] = slave;
|
fds[1] = slave;
|
||||||
int ret = pthread_create(&watcher, NULL, &watch_sigwinch, files);
|
int ret = pthread_create(&watcher, nullptr, &watch_sigwinch, fds);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
free(files);
|
delete[] fds;
|
||||||
errno = ret;
|
errno = ret;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -275,16 +259,6 @@ int watch_sigwinch_async(int master, int slave) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* watch_sigwinch_cleanup
|
|
||||||
*
|
|
||||||
* Cause the SIGWINCH watcher thread to terminate
|
|
||||||
*/
|
|
||||||
void watch_sigwinch_cleanup(void) {
|
|
||||||
closing_time = 1;
|
|
||||||
raise(SIGWINCH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pump_stdin_async
|
* pump_stdin_async
|
||||||
*
|
*
|
||||||
@ -309,9 +283,10 @@ void pump_stdin_async(int outfd) {
|
|||||||
*/
|
*/
|
||||||
void pump_stdout_blocking(int infd) {
|
void pump_stdout_blocking(int infd) {
|
||||||
// Pump data from stdout to PTY
|
// Pump data from stdout to PTY
|
||||||
pump_ex(infd, STDOUT_FILENO, 0 /* Don't close output when done */);
|
pump(infd, STDOUT_FILENO, false /* Don't close output when done */);
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
restore_stdin();
|
restore_stdin();
|
||||||
watch_sigwinch_cleanup();
|
close_sigwinch_watcher = true;
|
||||||
|
raise(SIGWINCH);
|
||||||
}
|
}
|
||||||
|
@ -78,13 +78,6 @@ int restore_stdin(void);
|
|||||||
*/
|
*/
|
||||||
int watch_sigwinch_async(int master, int slave);
|
int watch_sigwinch_async(int master, int slave);
|
||||||
|
|
||||||
/**
|
|
||||||
* watch_sigwinch_cleanup
|
|
||||||
*
|
|
||||||
* Cause the SIGWINCH watcher thread to terminate
|
|
||||||
*/
|
|
||||||
void watch_sigwinch_cleanup(void);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pump_stdin_async
|
* pump_stdin_async
|
||||||
*
|
*
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
#include "pts.h"
|
#include "pts.h"
|
||||||
#include "flags.h"
|
#include "flags.h"
|
||||||
|
|
||||||
#define quit_signals ((int []) { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 })
|
int quit_signals[] = { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 };
|
||||||
|
|
||||||
static void usage(int status) {
|
static void usage(int status) {
|
||||||
FILE *stream = (status == EXIT_SUCCESS) ? stdout : stderr;
|
FILE *stream = (status == EXIT_SUCCESS) ? stdout : stderr;
|
||||||
@ -224,13 +224,10 @@ int su_client_main(int argc, char *argv[]) {
|
|||||||
// Send stderr
|
// Send stderr
|
||||||
send_fd(fd, (atty & ATTY_ERR) ? -1 : STDERR_FILENO);
|
send_fd(fd, (atty & ATTY_ERR) ? -1 : STDERR_FILENO);
|
||||||
|
|
||||||
if (atty & ATTY_IN) {
|
if (atty) {
|
||||||
setup_sighandlers(sighandler);
|
setup_sighandlers(sighandler);
|
||||||
pump_stdin_async(ptmx);
|
|
||||||
}
|
|
||||||
if (atty & ATTY_OUT) {
|
|
||||||
// Forward SIGWINCH
|
|
||||||
watch_sigwinch_async(STDOUT_FILENO, ptmx);
|
watch_sigwinch_async(STDOUT_FILENO, ptmx);
|
||||||
|
pump_stdin_async(ptmx);
|
||||||
pump_stdout_blocking(ptmx);
|
pump_stdout_blocking(ptmx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user