diff options
Diffstat (limited to 'src/tty.c')
-rw-r--r-- | src/tty.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/src/tty.c b/src/tty.c new file mode 100644 index 0000000..a3c460e --- /dev/null +++ b/src/tty.c @@ -0,0 +1,137 @@ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <setjmp.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "config.h" + +static int setup_slave(int fd) +{ + struct termios tio; + + tcgetattr(fd, &tio); + + /* disable "\n" -> "\r\n" */ + tio.c_oflag &= ~ONLCR; + + return tcsetattr(fd, TCSANOW, &tio); +} + +int tty_master(struct lt_config_app *cfg) +{ + int mfd; + + if ((mfd = getpt()) < 0) { + perror("getpt failed"); + return -1; + } + + if (unlockpt(mfd)) { + perror("unlockpt failed"); + return -1; + } + + PRINT_VERBOSE(cfg, 1, "pty master opened succesfully\n"); + return mfd; +} + +int tty_init(struct lt_config_app *cfg, int master) +{ + int i, slave, num_files = getdtablesize(); + char *sname; + jmp_buf env; + + if (setjmp(env)) { + tty_restore(cfg); + return -1; + } + + sname = (char*) ptsname(master); + if (!sname) + longjmp(env, 1); + + PRINT_VERBOSE(cfg, 1, "closing all opened descriptors\n"); + for(i = 0; i < num_files; i++) + close(i); + + /* get new session before we open new controling tty */ + if (-1 == setsid()) { + perror("setsid failed"); + return -1; + } + + slave = open(sname, O_RDWR); + if (slave != 0) + longjmp(env, 1); + + /* set controling tty */ + if (ioctl(0, TIOCSCTTY, 1)) + longjmp(env, 1); + + if (setup_slave(0)) + longjmp(env, 1); + + dup(0); + dup(0); + return 0; +} + +int tty_restore(struct lt_config_app *cfg) +{ + int i, num_files = getdtablesize(); + + for(i = 0; i < num_files; i++) + close(i); + + open("/dev/tty", O_RDWR); + dup(0); + dup(0); + + return 0; +} + +int tty_process(struct lt_config_app *cfg, int master) +{ +#define BUFSIZE 4096 + char buf[BUFSIZE]; + ssize_t ret; + static int fd = 0; + + if (!fd) { + fd = open(cfg->output_tty_file, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (fd < 0) { + perror("failed to open OUTPUT_TTY file," + " output is not logged"); + return -1; + } + PRINT_VERBOSE(cfg, 1, "opened tty output file %s\n", + cfg->output_tty_file); + } + + ret = read(master, buf, BUFSIZE); + /* Most likely the other side closed */ + if (ret <= 0) { + PRINT_VERBOSE(cfg, 1, + "failed to read tty, closing [ errno %d '%s']\n", + errno, strerror(errno)); + return -1; + } + + if (fd < 0) + return -1; + + if (write(fd, buf, ret) <= 0) { + perror("failed to write to OUTPUT_TTY file"); + return -1; + } + + return 0; +} |