Skip to content
This repository has been archived by the owner on Apr 19, 2024. It is now read-only.

Commit

Permalink
Add a directory 'contrib/cygtermd', containing the source code for my
Browse files Browse the repository at this point in the history
hacky helper program to let PuTTY act as a local pterm-oid on
Cygwin-enabled Windows systems.

[originally from svn r9191]
  • Loading branch information
sgtatham committed Jul 10, 2011
1 parent c8f2b65 commit b642aa0
Show file tree
Hide file tree
Showing 11 changed files with 1,660 additions and 0 deletions.
2 changes: 2 additions & 0 deletions contrib/cygtermd/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cygtermd.exe: main.c sel.c telnet.c pty.c malloc.c
gcc -o cygtermd.exe main.c sel.c telnet.c pty.c malloc.c
11 changes: 11 additions & 0 deletions contrib/cygtermd/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
This directory contains 'cygtermd', a small and specialist Telnet
server designed to act as middleware between PuTTY and a Cygwin shell
session running on the same machine, so that PuTTY can act as an
xterm-alike for Cygwin.

To install it, you must compile it from source using Cygwin gcc,
install it in Cygwin's /bin, and configure PuTTY to use it as a local
proxy process. For detailed instructions, see the PuTTY Wishlist page
at

http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/cygwin-terminal-window.html
174 changes: 174 additions & 0 deletions contrib/cygtermd/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* 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;
}
43 changes: 43 additions & 0 deletions contrib/cygtermd/malloc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* malloc.c: implementation of malloc.h
*/

#include <stdlib.h>
#include <string.h>

#include "malloc.h"

extern void fatal(const char *, ...);

void *smalloc(size_t size) {
void *p;
p = malloc(size);
if (!p) {
fatal("out of memory");
}
return p;
}

void sfree(void *p) {
if (p) {
free(p);
}
}

void *srealloc(void *p, size_t size) {
void *q;
if (p) {
q = realloc(p, size);
} else {
q = malloc(size);
}
if (!q)
fatal("out of memory");
return q;
}

char *dupstr(const char *s) {
char *r = smalloc(1+strlen(s));
strcpy(r,s);
return r;
}
56 changes: 56 additions & 0 deletions contrib/cygtermd/malloc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* malloc.h: safe wrappers around malloc, realloc, free, strdup
*/

#ifndef UMLWRAP_MALLOC_H
#define UMLWRAP_MALLOC_H

#include <stddef.h>

/*
* smalloc should guarantee to return a useful pointer - Halibut
* can do nothing except die when it's out of memory anyway.
*/
void *smalloc(size_t size);

/*
* srealloc should guaranteeably be able to realloc NULL
*/
void *srealloc(void *p, size_t size);

/*
* sfree should guaranteeably deal gracefully with freeing NULL
*/
void sfree(void *p);

/*
* dupstr is like strdup, but with the never-return-NULL property
* of smalloc (and also reliably defined in all environments :-)
*/
char *dupstr(const char *s);

/*
* snew allocates one instance of a given type, and casts the
* result so as to type-check that you're assigning it to the
* right kind of pointer. Protects against allocation bugs
* involving allocating the wrong size of thing.
*/
#define snew(type) \
( (type *) smalloc (sizeof (type)) )

/*
* snewn allocates n instances of a given type, for arrays.
*/
#define snewn(number, type) \
( (type *) smalloc ((number) * sizeof (type)) )

/*
* sresize wraps realloc so that you specify the new number of
* elements and the type of the element, with the same type-
* checking advantages. Also type-checks the input pointer.
*/
#define sresize(array, number, type) \
( (void)sizeof((array)-(type *)0), \
(type *) srealloc ((array), (number) * sizeof (type)) )

#endif /* UMLWRAP_MALLOC_H */
Loading

0 comments on commit b642aa0

Please sign in to comment.