/* * Main program. */ #include #include #include #include #include #include #include #include #include #include #include "sel.h" #include "pty.h" #include "telnet.h" int signalpipe[2]; sel *asel; sel_rfd *netr, *ptyr, *sigr; int ptyfd; sel_wfd *netw, *ptyw; Telnet telnet; #define BUF 65536 void sigchld(int signum) { write(signalpipe[1], "C", 1); } void fatal(const char *fmt, ...) { va_list ap; fprintf(stderr, "FIXME: "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); exit(1); } void net_readdata(sel_rfd *rfd, void *data, size_t len) { if (len == 0) exit(0); /* EOF on network - client went away */ telnet_from_net(telnet, data, len); if (sel_write(netw, NULL, 0) > BUF) sel_rfd_freeze(ptyr); if (sel_write(ptyw, NULL, 0) > BUF) sel_rfd_freeze(netr); } void net_readerr(sel_rfd *rfd, int error) { fprintf(stderr, "standard input: read: %s\n", strerror(errno)); exit(1); } void net_written(sel_wfd *wfd, size_t bufsize) { if (bufsize < BUF) sel_rfd_unfreeze(ptyr); } void net_writeerr(sel_wfd *wfd, int error) { fprintf(stderr, "standard input: write: %s\n", strerror(errno)); exit(1); } void pty_readdata(sel_rfd *rfd, void *data, size_t len) { if (len == 0) exit(0); /* EOF on pty */ telnet_from_pty(telnet, data, len); if (sel_write(netw, NULL, 0) > BUF) sel_rfd_freeze(ptyr); if (sel_write(ptyw, NULL, 0) > BUF) sel_rfd_freeze(netr); } void pty_readerr(sel_rfd *rfd, int error) { if (error == EIO) /* means EOF, on a pty */ exit(0); fprintf(stderr, "pty: read: %s\n", strerror(errno)); exit(1); } void pty_written(sel_wfd *wfd, size_t bufsize) { if (bufsize < BUF) sel_rfd_unfreeze(netr); } void pty_writeerr(sel_wfd *wfd, int error) { fprintf(stderr, "pty: write: %s\n", strerror(errno)); exit(1); } void sig_readdata(sel_rfd *rfd, void *data, size_t len) { char *p = data; while (len > 0) { if (*p == 'C') { int status; waitpid(-1, &status, WNOHANG); if (WIFEXITED(status) || WIFSIGNALED(status)) exit(0); /* child process vanished */ } } } void sig_readerr(sel_rfd *rfd, int error) { fprintf(stderr, "signal pipe: read: %s\n", strerror(errno)); exit(1); } int main(int argc, char **argv) { int ret; int shell_started = 0; char *directory = NULL; char **program_args = NULL; if (argc > 1 && argv[1][0]) { directory = argv[1]; argc--, argv++; } if (argc > 1) { program_args = argv + 1; } pty_preinit(); asel = sel_new(NULL); netr = sel_rfd_add(asel, 0, net_readdata, net_readerr, NULL); netw = sel_wfd_add(asel, 1, net_written, net_writeerr, NULL); ptyr = sel_rfd_add(asel, -1, pty_readdata, pty_readerr, NULL); ptyw = sel_wfd_add(asel, -1, pty_written, pty_writeerr, NULL); telnet = telnet_new(netw, ptyw); if (pipe(signalpipe) < 0) { perror("pipe"); return 1; } sigr = sel_rfd_add(asel, signalpipe[0], sig_readdata, sig_readerr, NULL); signal(SIGCHLD, sigchld); do { struct shell_data shdata; ret = sel_iterate(asel, -1); if (!shell_started && telnet_shell_ok(telnet, &shdata)) { ptyfd = run_program_in_pty(&shdata, directory, program_args); sel_rfd_setfd(ptyr, ptyfd); sel_wfd_setfd(ptyw, ptyfd); shell_started = 1; } } while (ret == 0); return 0; }