aboutsummaryrefslogtreecommitdiff
path: root/rtty.c
blob: 6f820c6ff83aa02a1bb3db3a21339016373deeb0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <unistd.h>

#define INIT "export TERM=tty43 EDITOR=ed PAGER='pr -pl25'\n"
#define MAXBUF 2048

int
main(int argc, char *argv[])
{
	char bufin[MAXBUF], bufout[MAXBUF], *bi, *bo, in[30], **nargv, out[30];
	fd_set rfds0, rfds1;
	int fdin, fdout, i, n;
	struct timeval tv;

	/* Create named pipes. */
	sprintf(in, "/var/tmp/rtty.in.%d", getpid());
	sprintf(out, "/var/tmp/rtty.out.%d", getpid());
	if(mkfifo(in, 0644) == -1 || mkfifo(out, 0664) == -1)
		if(errno != EEXIST)
			err(1, "mkfifo");

	if(fork() == 0){
		/* Redirect standard in, out. */
		if(!(fdin = open(in, O_RDONLY)))
			err(1, "open");
		if(!(fdout = open(out, O_WRONLY)))
			err(1, "open");
		dup2(fdin, 0);
		dup2(fdout, 1);

		/* Create new argument vector. */
		if(!(nargv = malloc(sizeof(char *)*(argc+1))))
			err(1, "malloc");
		nargv[0] = "ssh";
		nargv[1] = "-tt";
		for(i = 1; i < argc; i++)
			nargv[i+1] = argv[i];
		nargv[argc+1] = NULL;

		/* Exec into ssh. */
		execvp("ssh", nargv);
		err(1, "execvp");
	}

	if(!(fdin = open(in, O_WRONLY)))
		err(1, "open");
	if(!(fdout = open(out, O_RDONLY)))
		err(1, "open");

	dprintf(fdin, INIT);

	FD_ZERO(&rfds0);
	FD_ZERO(&rfds1);

	tv.tv_sec = 0;
	tv.tv_usec = 1;

	for(;;){
		/*
		 * User input is read from standard in and copied the
		 * input pipe. It is saved in bufin for later use.
		 */
		FD_SET(0, &rfds0);
		if(select(0+1, &rfds0, NULL, NULL, &tv) > 0){
			n = read(0, bufin, MAXBUF);
			bufin[n] = 0;
			dprintf(fdin, "%s", bufin);
			fflush(stdout);
		}

		/*
		 * System output is read from the output pipe and copied
		 * to standard out for the user to see.
		 */
		FD_SET(fdout, &rfds1);
		if(select(fdout+1, &rfds1, NULL, NULL, &tv) > 0){
			n = read(fdout, bufout, MAXBUF);
			if(!n) continue;
			bufout[n] = 0;

			/*
			 * Bufin and bufout are copied to the temporary
			 * pointers bi and bo. Bo is incremented in order
			 * to skip any potential repetition of the command
			 * given by the user on standard in. (It is assumed
			 * that the typed command fits in bufin, i.e. is
			 * not larger than MAXBUF.)
			 */
			bi = bufin;
			bo = bufout;
			for(;;){
				if(*bo == '\n'){
					bo++;
					break;
				}
				if(*bo == 13){
					bo++;
					continue;
				}
				if(*bi != *bo){
					bo = bufout;
					break;
				}
				bi++; bo++;
			}

			/*
			 * Bo is printed and bufin is cleared, so as not
			 * to perform the skip again, incorrectly.
			 */
			printf("%s", bo);
			fflush(stdout);
			bufin[0] = 0;
		}
	}

}