Missing assert.
[sgt/putty] / contrib / cygtermd / main.c
1 /*
2 * Main program.
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stddef.h>
8 #include <stdarg.h>
9 #include <signal.h>
10 #include <string.h>
11 #include <errno.h>
12
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16
17 #include "sel.h"
18 #include "pty.h"
19 #include "telnet.h"
20
21 int signalpipe[2];
22
23 sel *asel;
24 sel_rfd *netr, *ptyr, *sigr;
25 int ptyfd;
26 sel_wfd *netw, *ptyw;
27 Telnet telnet;
28
29 #define BUF 65536
30
31 void sigchld(int signum)
32 {
33 write(signalpipe[1], "C", 1);
34 }
35
36 void fatal(const char *fmt, ...)
37 {
38 va_list ap;
39 fprintf(stderr, "FIXME: ");
40 va_start(ap, fmt);
41 vfprintf(stderr, fmt, ap);
42 va_end(ap);
43 fprintf(stderr, "\n");
44 exit(1);
45 }
46
47 void net_readdata(sel_rfd *rfd, void *data, size_t len)
48 {
49 if (len == 0)
50 exit(0); /* EOF on network - client went away */
51 telnet_from_net(telnet, data, len);
52 if (sel_write(netw, NULL, 0) > BUF)
53 sel_rfd_freeze(ptyr);
54 if (sel_write(ptyw, NULL, 0) > BUF)
55 sel_rfd_freeze(netr);
56 }
57
58 void net_readerr(sel_rfd *rfd, int error)
59 {
60 fprintf(stderr, "standard input: read: %s\n", strerror(errno));
61 exit(1);
62 }
63
64 void net_written(sel_wfd *wfd, size_t bufsize)
65 {
66 if (bufsize < BUF)
67 sel_rfd_unfreeze(ptyr);
68 }
69
70 void net_writeerr(sel_wfd *wfd, int error)
71 {
72 fprintf(stderr, "standard input: write: %s\n", strerror(errno));
73 exit(1);
74 }
75
76 void pty_readdata(sel_rfd *rfd, void *data, size_t len)
77 {
78 if (len == 0)
79 exit(0); /* EOF on pty */
80 telnet_from_pty(telnet, data, len);
81 if (sel_write(netw, NULL, 0) > BUF)
82 sel_rfd_freeze(ptyr);
83 if (sel_write(ptyw, NULL, 0) > BUF)
84 sel_rfd_freeze(netr);
85 }
86
87 void pty_readerr(sel_rfd *rfd, int error)
88 {
89 if (error == EIO) /* means EOF, on a pty */
90 exit(0);
91 fprintf(stderr, "pty: read: %s\n", strerror(errno));
92 exit(1);
93 }
94
95 void pty_written(sel_wfd *wfd, size_t bufsize)
96 {
97 if (bufsize < BUF)
98 sel_rfd_unfreeze(netr);
99 }
100
101 void pty_writeerr(sel_wfd *wfd, int error)
102 {
103 fprintf(stderr, "pty: write: %s\n", strerror(errno));
104 exit(1);
105 }
106
107 void sig_readdata(sel_rfd *rfd, void *data, size_t len)
108 {
109 char *p = data;
110
111 while (len > 0) {
112 if (*p == 'C') {
113 int status;
114 pid_t pid = waitpid(-1, &status, WNOHANG);
115 if (WIFEXITED(status) || WIFSIGNALED(status))
116 exit(0); /* child process vanished */
117 }
118 }
119 }
120
121 void sig_readerr(sel_rfd *rfd, int error)
122 {
123 fprintf(stderr, "signal pipe: read: %s\n", strerror(errno));
124 exit(1);
125 }
126
127 int main(int argc, char **argv)
128 {
129 int ret;
130 int shell_started = 0;
131 char *directory = NULL;
132 char **program_args = NULL;
133
134 if (argc > 1 && argv[1][0]) {
135 directory = argv[1];
136 argc--, argv++;
137 }
138 if (argc > 1) {
139 program_args = argv + 1;
140 }
141
142 pty_preinit();
143
144 asel = sel_new(NULL);
145 netr = sel_rfd_add(asel, 0, net_readdata, net_readerr, NULL);
146 netw = sel_wfd_add(asel, 1, net_written, net_writeerr, NULL);
147 ptyr = sel_rfd_add(asel, -1, pty_readdata, pty_readerr, NULL);
148 ptyw = sel_wfd_add(asel, -1, pty_written, pty_writeerr, NULL);
149
150 telnet = telnet_new(netw, ptyw);
151
152 if (pipe(signalpipe) < 0) {
153 perror("pipe");
154 return 1;
155 }
156 sigr = sel_rfd_add(asel, signalpipe[0], sig_readdata,
157 sig_readerr, NULL);
158
159 signal(SIGCHLD, sigchld);
160
161 do {
162 struct shell_data shdata;
163
164 ret = sel_iterate(asel, -1);
165 if (!shell_started && telnet_shell_ok(telnet, &shdata)) {
166 ptyfd = run_program_in_pty(&shdata, directory, program_args);
167 sel_rfd_setfd(ptyr, ptyfd);
168 sel_wfd_setfd(ptyw, ptyfd);
169 shell_started = 1;
170 }
171 } while (ret == 0);
172
173 return 0;
174 }