mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 18:07:59 +00:00
b642aa086a
hacky helper program to let PuTTY act as a local pterm-oid on Cygwin-enabled Windows systems. [originally from svn r9191]
175 lines
3.5 KiB
C
175 lines
3.5 KiB
C
/*
|
|
* Main program.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <stdarg.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
|
|
#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;
|
|
pid_t pid = 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;
|
|
}
|