diff options
author | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2002-09-30 20:52:10 +0000 |
---|---|---|
committer | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2002-09-30 20:52:10 +0000 |
commit | 297d987034a23511a748b4c9aa9093590584a37e (patch) | |
tree | baa06980ecaf8a8cedb27887f6da8b6d47e9f8c6 /networking | |
parent | 613d1366341793b382f63572d472016c1ad7b5a0 (diff) | |
download | busybox-w32-297d987034a23511a748b4c9aa9093590584a37e.tar.gz busybox-w32-297d987034a23511a748b4c9aa9093590584a37e.tar.bz2 busybox-w32-297d987034a23511a748b4c9aa9093590584a37e.zip |
last_patch58 from vodz:
Ok. I generate patch for include to busybox-devel my work with
top (original author give me maintaining) and telnetd (my
support and unofficial maintaining) applets. Docs changes
also: added awk, netstat, time applets to list ;)
git-svn-id: svn://busybox.net/trunk/busybox@5614 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'networking')
-rw-r--r-- | networking/Makefile.in | 1 | ||||
-rw-r--r-- | networking/config.in | 1 | ||||
-rw-r--r-- | networking/telnetd.c | 538 |
3 files changed, 540 insertions, 0 deletions
diff --git a/networking/Makefile.in b/networking/Makefile.in index 425b5d3d9..510c8119d 100644 --- a/networking/Makefile.in +++ b/networking/Makefile.in | |||
@@ -32,6 +32,7 @@ NETWORKING-$(CONFIG_PING) += ping.o | |||
32 | NETWORKING-$(CONFIG_PING6) += ping6.o | 32 | NETWORKING-$(CONFIG_PING6) += ping6.o |
33 | NETWORKING-$(CONFIG_ROUTE) += route.o | 33 | NETWORKING-$(CONFIG_ROUTE) += route.o |
34 | NETWORKING-$(CONFIG_TELNET) += telnet.o | 34 | NETWORKING-$(CONFIG_TELNET) += telnet.o |
35 | NETWORKING-$(CONFIG_TELNETD) += telnetd.o | ||
35 | NETWORKING-$(CONFIG_TFTP) += tftp.o | 36 | NETWORKING-$(CONFIG_TFTP) += tftp.o |
36 | NETWORKING-$(CONFIG_TRACEROUTE) += traceroute.o | 37 | NETWORKING-$(CONFIG_TRACEROUTE) += traceroute.o |
37 | NETWORKING-$(CONFIG_UDHCPC) += udhcpc.o | 38 | NETWORKING-$(CONFIG_UDHCPC) += udhcpc.o |
diff --git a/networking/config.in b/networking/config.in index bc11d83a7..4438a8c6c 100644 --- a/networking/config.in +++ b/networking/config.in | |||
@@ -34,6 +34,7 @@ bool 'telnet' CONFIG_TELNET | |||
34 | if [ "$CONFIG_TELNET" = "y" ]; then | 34 | if [ "$CONFIG_TELNET" = "y" ]; then |
35 | bool ' Pass TERM type to remote host' CONFIG_FEATURE_TELNET_TTYPE | 35 | bool ' Pass TERM type to remote host' CONFIG_FEATURE_TELNET_TTYPE |
36 | fi | 36 | fi |
37 | bool 'telnetd' CONFIG_TELNETD | ||
37 | bool 'tftp' CONFIG_TFTP | 38 | bool 'tftp' CONFIG_TFTP |
38 | if [ "$CONFIG_TFTP" = "y" ]; then | 39 | if [ "$CONFIG_TFTP" = "y" ]; then |
39 | bool ' Enable "get" command' CONFIG_FEATURE_TFTP_GET | 40 | bool ' Enable "get" command' CONFIG_FEATURE_TFTP_GET |
diff --git a/networking/telnetd.c b/networking/telnetd.c new file mode 100644 index 000000000..edc018a2a --- /dev/null +++ b/networking/telnetd.c | |||
@@ -0,0 +1,538 @@ | |||
1 | /* $Id: telnetd.c,v 1.1 2002/09/30 20:52:04 andersen Exp $ | ||
2 | * | ||
3 | * Simple telnet server | ||
4 | * Bjorn Wesen, Axis Communications AB (bjornw@axis.com) | ||
5 | * | ||
6 | * This file is distributed under the Gnu Public License (GPL), | ||
7 | * please see the file LICENSE for further information. | ||
8 | * | ||
9 | * --------------------------------------------------------------------------- | ||
10 | * (C) Copyright 2000, Axis Communications AB, LUND, SWEDEN | ||
11 | **************************************************************************** | ||
12 | * | ||
13 | * The telnetd manpage says it all: | ||
14 | * | ||
15 | * Telnetd operates by allocating a pseudo-terminal device (see pty(4)) for | ||
16 | * a client, then creating a login process which has the slave side of the | ||
17 | * pseudo-terminal as stdin, stdout, and stderr. Telnetd manipulates the | ||
18 | * master side of the pseudo-terminal, implementing the telnet protocol and | ||
19 | * passing characters between the remote client and the login process. | ||
20 | * | ||
21 | * Vladimir Oleynik <dzo@simtreas.ru> 2001 | ||
22 | * Set process group corrections, initial busybox port | ||
23 | */ | ||
24 | |||
25 | /*#define DEBUG 1 */ | ||
26 | |||
27 | #include <sys/time.h> | ||
28 | #include <sys/socket.h> | ||
29 | #include <sys/wait.h> | ||
30 | #include <string.h> | ||
31 | #include <stdlib.h> | ||
32 | #include <unistd.h> | ||
33 | #include <errno.h> | ||
34 | #include <netinet/in.h> | ||
35 | #include <fcntl.h> | ||
36 | #include <stdio.h> | ||
37 | #include <signal.h> | ||
38 | #include <termios.h> | ||
39 | #ifdef DEBUG | ||
40 | #define TELCMDS | ||
41 | #define TELOPTS | ||
42 | #endif | ||
43 | #include <arpa/telnet.h> | ||
44 | #include <ctype.h> | ||
45 | #include <sys/syslog.h> | ||
46 | |||
47 | #include "busybox.h" | ||
48 | |||
49 | #define BUFSIZE 4000 | ||
50 | |||
51 | static const char *loginpath = "/bin/sh"; | ||
52 | |||
53 | /* shell name and arguments */ | ||
54 | |||
55 | static const char *argv_init[] = {NULL, NULL}; | ||
56 | |||
57 | /* structure that describes a session */ | ||
58 | |||
59 | struct tsession { | ||
60 | struct tsession *next; | ||
61 | int sockfd, ptyfd; | ||
62 | int shell_pid; | ||
63 | /* two circular buffers */ | ||
64 | char *buf1, *buf2; | ||
65 | int rdidx1, wridx1, size1; | ||
66 | int rdidx2, wridx2, size2; | ||
67 | }; | ||
68 | |||
69 | /* | ||
70 | |||
71 | This is how the buffers are used. The arrows indicate the movement | ||
72 | of data. | ||
73 | |||
74 | +-------+ wridx1++ +------+ rdidx1++ +----------+ | ||
75 | | | <-------------- | buf1 | <-------------- | | | ||
76 | | | size1-- +------+ size1++ | | | ||
77 | | pty | | socket | | ||
78 | | | rdidx2++ +------+ wridx2++ | | | ||
79 | | | --------------> | buf2 | --------------> | | | ||
80 | +-------+ size2++ +------+ size2-- +----------+ | ||
81 | |||
82 | Each session has got two buffers. | ||
83 | |||
84 | */ | ||
85 | |||
86 | static int maxfd; | ||
87 | |||
88 | static struct tsession *sessions; | ||
89 | |||
90 | |||
91 | /* | ||
92 | |||
93 | Remove all IAC's from the buffer pointed to by bf (recieved IACs are ignored | ||
94 | and must be removed so as to not be interpreted by the terminal). Make an | ||
95 | uninterrupted string of characters fit for the terminal. Do this by packing | ||
96 | all characters meant for the terminal sequentially towards the end of bf. | ||
97 | |||
98 | Return a pointer to the beginning of the characters meant for the terminal. | ||
99 | and make *num_totty the number of characters that should be sent to | ||
100 | the terminal. | ||
101 | |||
102 | Note - If an IAC (3 byte quantity) starts before (bf + len) but extends | ||
103 | past (bf + len) then that IAC will be left unprocessed and *processed will be | ||
104 | less than len. | ||
105 | |||
106 | FIXME - if we mean to send 0xFF to the terminal then it will be escaped, | ||
107 | what is the escape character? We aren't handling that situation here. | ||
108 | |||
109 | */ | ||
110 | static char * | ||
111 | remove_iacs(struct tsession *ts, int *pnum_totty) { | ||
112 | unsigned char *ptr0 = ts->buf1 + ts->wridx1; | ||
113 | unsigned char *ptr = ptr0; | ||
114 | unsigned char *totty = ptr; | ||
115 | unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1); | ||
116 | int processed; | ||
117 | int num_totty; | ||
118 | |||
119 | while (ptr < end) { | ||
120 | if (*ptr != IAC) { | ||
121 | *totty++ = *ptr++; | ||
122 | } | ||
123 | else { | ||
124 | if ((ptr+2) < end) { | ||
125 | /* the entire IAC is contained in the buffer | ||
126 | we were asked to process. */ | ||
127 | #ifdef DEBUG | ||
128 | fprintf(stderr, "Ignoring IAC %s,%s\n", | ||
129 | *ptr, TELCMD(*(ptr+1)), TELOPT(*(ptr+2))); | ||
130 | #endif | ||
131 | ptr += 3; | ||
132 | } else { | ||
133 | /* only the beginning of the IAC is in the | ||
134 | buffer we were asked to process, we can't | ||
135 | process this char. */ | ||
136 | break; | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | |||
141 | processed = ptr - ptr0; | ||
142 | num_totty = totty - ptr0; | ||
143 | /* the difference between processed and num_to tty | ||
144 | is all the iacs we removed from the stream. | ||
145 | Adjust buf1 accordingly. */ | ||
146 | ts->wridx1 += processed - num_totty; | ||
147 | ts->size1 -= processed - num_totty; | ||
148 | *pnum_totty = num_totty; | ||
149 | /* move the chars meant for the terminal towards the end of the | ||
150 | buffer. */ | ||
151 | return memmove(ptr - num_totty, ptr0, num_totty); | ||
152 | } | ||
153 | |||
154 | |||
155 | static int | ||
156 | getpty(char *line) | ||
157 | { | ||
158 | int p; | ||
159 | #ifdef HAVE_DEVPTS_FS | ||
160 | p = open("/dev/ptmx", 2); | ||
161 | if (p > 0) { | ||
162 | grantpt(p); | ||
163 | unlockpt(p); | ||
164 | strcpy(line, ptsname(p)); | ||
165 | return(p); | ||
166 | } | ||
167 | #else | ||
168 | struct stat stb; | ||
169 | int i; | ||
170 | int j; | ||
171 | |||
172 | strcpy(line, "/dev/ptyXX"); | ||
173 | |||
174 | for (i = 0; i < 16; i++) { | ||
175 | line[8] = "pqrstuvwxyzabcde"[i]; | ||
176 | line[9] = '0'; | ||
177 | if (stat(line, &stb) < 0) { | ||
178 | continue; | ||
179 | } | ||
180 | for (j = 0; j < 16; j++) { | ||
181 | line[9] = j < 10 ? j + '0' : j - 10 + 'a'; | ||
182 | if ((p = open(line, O_RDWR | O_NOCTTY)) >= 0) { | ||
183 | line[5] = 't'; | ||
184 | return p; | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | #endif /* HAVE_DEVPTS_FS */ | ||
189 | return -1; | ||
190 | } | ||
191 | |||
192 | |||
193 | static void | ||
194 | send_iac(struct tsession *ts, unsigned char command, int option) | ||
195 | { | ||
196 | /* We rely on that there is space in the buffer for now. */ | ||
197 | char *b = ts->buf2 + ts->rdidx2; | ||
198 | *b++ = IAC; | ||
199 | *b++ = command; | ||
200 | *b++ = option; | ||
201 | ts->rdidx2 += 3; | ||
202 | ts->size2 += 3; | ||
203 | } | ||
204 | |||
205 | |||
206 | static struct tsession * | ||
207 | make_new_session(int sockfd) | ||
208 | { | ||
209 | struct termios termbuf; | ||
210 | int pty, pid; | ||
211 | char tty_name[32]; | ||
212 | struct tsession *ts = malloc(sizeof(struct tsession) + BUFSIZE * 2); | ||
213 | |||
214 | ts->buf1 = (char *)(&ts[1]); | ||
215 | ts->buf2 = ts->buf1 + BUFSIZE; | ||
216 | |||
217 | ts->sockfd = sockfd; | ||
218 | |||
219 | ts->rdidx1 = ts->wridx1 = ts->size1 = 0; | ||
220 | ts->rdidx2 = ts->wridx2 = ts->size2 = 0; | ||
221 | |||
222 | /* Got a new connection, set up a tty and spawn a shell. */ | ||
223 | |||
224 | pty = getpty(tty_name); | ||
225 | |||
226 | if (pty < 0) { | ||
227 | syslog_msg(LOG_USER, LOG_ERR, "All network ports in use!"); | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | if (pty > maxfd) | ||
232 | maxfd = pty; | ||
233 | |||
234 | ts->ptyfd = pty; | ||
235 | |||
236 | /* Make the telnet client understand we will echo characters so it | ||
237 | * should not do it locally. We don't tell the client to run linemode, | ||
238 | * because we want to handle line editing and tab completion and other | ||
239 | * stuff that requires char-by-char support. | ||
240 | */ | ||
241 | |||
242 | send_iac(ts, DO, TELOPT_ECHO); | ||
243 | send_iac(ts, DO, TELOPT_LFLOW); | ||
244 | send_iac(ts, WILL, TELOPT_ECHO); | ||
245 | send_iac(ts, WILL, TELOPT_SGA); | ||
246 | |||
247 | |||
248 | if ((pid = fork()) < 0) { | ||
249 | syslog_msg(LOG_USER, LOG_ERR, "Can`t forking"); | ||
250 | } | ||
251 | if (pid == 0) { | ||
252 | /* In child, open the child's side of the tty. */ | ||
253 | int i; | ||
254 | |||
255 | for(i = 0; i <= maxfd; i++) | ||
256 | close(i); | ||
257 | /* make new process group */ | ||
258 | setsid(); | ||
259 | |||
260 | if (open(tty_name, O_RDWR /*| O_NOCTTY*/) < 0) { | ||
261 | syslog_msg(LOG_USER, LOG_ERR, "Could not open tty"); | ||
262 | exit(1); | ||
263 | } | ||
264 | dup(0); | ||
265 | dup(0); | ||
266 | |||
267 | tcsetpgrp(0, getpid()); | ||
268 | |||
269 | /* The pseudo-terminal allocated to the client is configured to operate in | ||
270 | * cooked mode, and with XTABS CRMOD enabled (see tty(4)). | ||
271 | */ | ||
272 | |||
273 | tcgetattr(0, &termbuf); | ||
274 | termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */ | ||
275 | termbuf.c_oflag |= ONLCR|XTABS; | ||
276 | termbuf.c_iflag |= ICRNL; | ||
277 | termbuf.c_iflag &= ~IXOFF; | ||
278 | /*termbuf.c_lflag &= ~ICANON;*/ | ||
279 | tcsetattr(0, TCSANOW, &termbuf); | ||
280 | |||
281 | /* exec shell, with correct argv and env */ | ||
282 | execv(loginpath, (char *const *)argv_init); | ||
283 | |||
284 | /* NOT REACHED */ | ||
285 | syslog_msg(LOG_USER, LOG_ERR, "execv error"); | ||
286 | exit(1); | ||
287 | } | ||
288 | |||
289 | ts->shell_pid = pid; | ||
290 | |||
291 | return ts; | ||
292 | } | ||
293 | |||
294 | static void | ||
295 | free_session(struct tsession *ts) | ||
296 | { | ||
297 | struct tsession *t = sessions; | ||
298 | |||
299 | /* Unlink this telnet session from the session list. */ | ||
300 | if(t == ts) | ||
301 | sessions = ts->next; | ||
302 | else { | ||
303 | while(t->next != ts) | ||
304 | t = t->next; | ||
305 | t->next = ts->next; | ||
306 | } | ||
307 | |||
308 | kill(ts->shell_pid, SIGKILL); | ||
309 | |||
310 | wait4(ts->shell_pid, NULL, 0, NULL); | ||
311 | |||
312 | close(ts->ptyfd); | ||
313 | close(ts->sockfd); | ||
314 | |||
315 | if(ts->ptyfd == maxfd || ts->sockfd == maxfd) | ||
316 | maxfd--; | ||
317 | if(ts->ptyfd == maxfd || ts->sockfd == maxfd) | ||
318 | maxfd--; | ||
319 | |||
320 | free(ts); | ||
321 | } | ||
322 | |||
323 | int | ||
324 | telnetd_main(int argc, char **argv) | ||
325 | { | ||
326 | struct sockaddr_in sa; | ||
327 | int master_fd; | ||
328 | fd_set rdfdset, wrfdset; | ||
329 | int selret; | ||
330 | int on = 1; | ||
331 | int portnbr = 23; | ||
332 | int c; | ||
333 | |||
334 | /* check if user supplied a port number */ | ||
335 | |||
336 | for (;;) { | ||
337 | c = getopt( argc, argv, "p:l:"); | ||
338 | if (c == EOF) break; | ||
339 | switch (c) { | ||
340 | case 'p': | ||
341 | portnbr = atoi(optarg); | ||
342 | break; | ||
343 | case 'l': | ||
344 | loginpath = strdup (optarg); | ||
345 | break; | ||
346 | default: | ||
347 | show_usage(); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | if (access(loginpath, X_OK) < 0) { | ||
352 | error_msg_and_die ("'%s' unavailable.", loginpath); | ||
353 | } | ||
354 | |||
355 | argv_init[0] = loginpath; | ||
356 | sessions = 0; | ||
357 | |||
358 | /* Grab a TCP socket. */ | ||
359 | |||
360 | master_fd = socket(AF_INET, SOCK_STREAM, 0); | ||
361 | if (master_fd < 0) { | ||
362 | perror_msg_and_die("socket"); | ||
363 | } | ||
364 | (void)setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); | ||
365 | |||
366 | /* Set it to listen to specified port. */ | ||
367 | |||
368 | memset((void *)&sa, 0, sizeof(sa)); | ||
369 | sa.sin_family = AF_INET; | ||
370 | sa.sin_port = htons(portnbr); | ||
371 | |||
372 | if (bind(master_fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { | ||
373 | perror_msg_and_die("bind"); | ||
374 | } | ||
375 | |||
376 | if (listen(master_fd, 1) < 0) { | ||
377 | perror_msg_and_die("listen"); | ||
378 | } | ||
379 | |||
380 | if (daemon(0, 0) < 0) | ||
381 | perror_msg_and_die("daemon"); | ||
382 | |||
383 | |||
384 | maxfd = master_fd; | ||
385 | |||
386 | do { | ||
387 | struct tsession *ts; | ||
388 | |||
389 | FD_ZERO(&rdfdset); | ||
390 | FD_ZERO(&wrfdset); | ||
391 | |||
392 | /* select on the master socket, all telnet sockets and their | ||
393 | * ptys if there is room in their respective session buffers. | ||
394 | */ | ||
395 | |||
396 | FD_SET(master_fd, &rdfdset); | ||
397 | |||
398 | ts = sessions; | ||
399 | while (ts) { | ||
400 | /* buf1 is used from socket to pty | ||
401 | * buf2 is used from pty to socket | ||
402 | */ | ||
403 | if (ts->size1 > 0) { | ||
404 | FD_SET(ts->ptyfd, &wrfdset); /* can write to pty */ | ||
405 | } | ||
406 | if (ts->size1 < BUFSIZE) { | ||
407 | FD_SET(ts->sockfd, &rdfdset); /* can read from socket */ | ||
408 | } | ||
409 | if (ts->size2 > 0) { | ||
410 | FD_SET(ts->sockfd, &wrfdset); /* can write to socket */ | ||
411 | } | ||
412 | if (ts->size2 < BUFSIZE) { | ||
413 | FD_SET(ts->ptyfd, &rdfdset); /* can read from pty */ | ||
414 | } | ||
415 | ts = ts->next; | ||
416 | } | ||
417 | |||
418 | selret = select(maxfd + 1, &rdfdset, &wrfdset, 0, 0); | ||
419 | |||
420 | if (!selret) | ||
421 | break; | ||
422 | |||
423 | /* First check for and accept new sessions. */ | ||
424 | if (FD_ISSET(master_fd, &rdfdset)) { | ||
425 | int fd, salen; | ||
426 | |||
427 | salen = sizeof(sa); | ||
428 | if ((fd = accept(master_fd, (struct sockaddr *)&sa, | ||
429 | &salen)) < 0) { | ||
430 | continue; | ||
431 | } else { | ||
432 | /* Create a new session and link it into | ||
433 | our active list. */ | ||
434 | struct tsession *new_ts = make_new_session(fd); | ||
435 | if (new_ts) { | ||
436 | new_ts->next = sessions; | ||
437 | sessions = new_ts; | ||
438 | if (fd > maxfd) | ||
439 | maxfd = fd; | ||
440 | } else { | ||
441 | close(fd); | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | |||
446 | /* Then check for data tunneling. */ | ||
447 | |||
448 | ts = sessions; | ||
449 | while (ts) { /* For all sessions... */ | ||
450 | int maxlen, w, r; | ||
451 | struct tsession *next = ts->next; /* in case we free ts. */ | ||
452 | |||
453 | if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) { | ||
454 | int num_totty; | ||
455 | char *ptr; | ||
456 | /* Write to pty from buffer 1. */ | ||
457 | |||
458 | ptr = remove_iacs(ts, &num_totty); | ||
459 | |||
460 | w = write(ts->ptyfd, ptr, num_totty); | ||
461 | if (w < 0) { | ||
462 | free_session(ts); | ||
463 | ts = next; | ||
464 | continue; | ||
465 | } | ||
466 | ts->wridx1 += w; | ||
467 | ts->size1 -= w; | ||
468 | if (ts->wridx1 == BUFSIZE) | ||
469 | ts->wridx1 = 0; | ||
470 | } | ||
471 | |||
472 | if (ts->size2 && FD_ISSET(ts->sockfd, &wrfdset)) { | ||
473 | /* Write to socket from buffer 2. */ | ||
474 | maxlen = MIN(BUFSIZE - ts->wridx2, ts->size2); | ||
475 | w = write(ts->sockfd, ts->buf2 + ts->wridx2, maxlen); | ||
476 | if (w < 0) { | ||
477 | free_session(ts); | ||
478 | ts = next; | ||
479 | continue; | ||
480 | } | ||
481 | ts->wridx2 += w; | ||
482 | ts->size2 -= w; | ||
483 | if (ts->wridx2 == BUFSIZE) | ||
484 | ts->wridx2 = 0; | ||
485 | } | ||
486 | |||
487 | if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd, &rdfdset)) { | ||
488 | /* Read from socket to buffer 1. */ | ||
489 | maxlen = MIN(BUFSIZE - ts->rdidx1, | ||
490 | BUFSIZE - ts->size1); | ||
491 | r = read(ts->sockfd, ts->buf1 + ts->rdidx1, maxlen); | ||
492 | if (!r || (r < 0 && errno != EINTR)) { | ||
493 | free_session(ts); | ||
494 | ts = next; | ||
495 | continue; | ||
496 | } | ||
497 | if(!*(ts->buf1 + ts->rdidx1 + r - 1)) { | ||
498 | r--; | ||
499 | if(!r) | ||
500 | continue; | ||
501 | } | ||
502 | ts->rdidx1 += r; | ||
503 | ts->size1 += r; | ||
504 | if (ts->rdidx1 == BUFSIZE) | ||
505 | ts->rdidx1 = 0; | ||
506 | } | ||
507 | |||
508 | if (ts->size2 < BUFSIZE && FD_ISSET(ts->ptyfd, &rdfdset)) { | ||
509 | /* Read from pty to buffer 2. */ | ||
510 | maxlen = MIN(BUFSIZE - ts->rdidx2, | ||
511 | BUFSIZE - ts->size2); | ||
512 | r = read(ts->ptyfd, ts->buf2 + ts->rdidx2, maxlen); | ||
513 | if (!r || (r < 0 && errno != EINTR)) { | ||
514 | free_session(ts); | ||
515 | ts = next; | ||
516 | continue; | ||
517 | } | ||
518 | ts->rdidx2 += r; | ||
519 | ts->size2 += r; | ||
520 | if (ts->rdidx2 == BUFSIZE) | ||
521 | ts->rdidx2 = 0; | ||
522 | } | ||
523 | |||
524 | if (ts->size1 == 0) { | ||
525 | ts->rdidx1 = 0; | ||
526 | ts->wridx1 = 0; | ||
527 | } | ||
528 | if (ts->size2 == 0) { | ||
529 | ts->rdidx2 = 0; | ||
530 | ts->wridx2 = 0; | ||
531 | } | ||
532 | ts = next; | ||
533 | } | ||
534 | |||
535 | } while (1); | ||
536 | |||
537 | return 0; | ||
538 | } | ||