source: MondoRescue/branches/stable/mindi-busybox/networking/telnetd.c@ 1842

Last change on this file since 1842 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 14.5 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Simple telnet server
4 * Bjorn Wesen, Axis Communications AB (bjornw@axis.com)
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7 *
8 * ---------------------------------------------------------------------------
9 * (C) Copyright 2000, Axis Communications AB, LUND, SWEDEN
10 ****************************************************************************
11 *
12 * The telnetd manpage says it all:
13 *
14 * Telnetd operates by allocating a pseudo-terminal device (see pty(4)) for
15 * a client, then creating a login process which has the slave side of the
16 * pseudo-terminal as stdin, stdout, and stderr. Telnetd manipulates the
17 * master side of the pseudo-terminal, implementing the telnet protocol and
18 * passing characters between the remote client and the login process.
19 *
20 * Vladimir Oleynik <dzo@simtreas.ru> 2001
21 * Set process group corrections, initial busybox port
22 */
23
24#define DEBUG 0
25
26#include "libbb.h"
27
28#if DEBUG
29#define TELCMDS
30#define TELOPTS
31#endif
32#include <arpa/telnet.h>
33#include <sys/syslog.h>
34
35
36#if ENABLE_LOGIN
37static const char *loginpath = "/bin/login";
38#else
39static const char *loginpath = DEFAULT_SHELL;
40#endif
41
42static const char *issuefile = "/etc/issue.net";
43
44/* structure that describes a session */
45
46struct tsession {
47 struct tsession *next;
48 int sockfd_read, sockfd_write, ptyfd;
49 int shell_pid;
50 /* two circular buffers */
51 char *buf1, *buf2;
52 int rdidx1, wridx1, size1;
53 int rdidx2, wridx2, size2;
54};
55
56/* Two buffers are directly after tsession in malloced memory.
57 * Make whole thing fit in 4k */
58enum { BUFSIZE = (4*1024 - sizeof(struct tsession)) / 2 };
59
60/*
61 This is how the buffers are used. The arrows indicate the movement
62 of data.
63
64 +-------+ wridx1++ +------+ rdidx1++ +----------+
65 | | <-------------- | buf1 | <-------------- | |
66 | | size1-- +------+ size1++ | |
67 | pty | | socket |
68 | | rdidx2++ +------+ wridx2++ | |
69 | | --------------> | buf2 | --------------> | |
70 +-------+ size2++ +------+ size2-- +----------+
71
72 Each session has got two buffers.
73*/
74
75static int maxfd;
76
77static struct tsession *sessions;
78
79
80/*
81 Remove all IAC's from the buffer pointed to by bf (received IACs are ignored
82 and must be removed so as to not be interpreted by the terminal). Make an
83 uninterrupted string of characters fit for the terminal. Do this by packing
84 all characters meant for the terminal sequentially towards the end of bf.
85
86 Return a pointer to the beginning of the characters meant for the terminal.
87 and make *num_totty the number of characters that should be sent to
88 the terminal.
89
90 Note - If an IAC (3 byte quantity) starts before (bf + len) but extends
91 past (bf + len) then that IAC will be left unprocessed and *processed will be
92 less than len.
93
94 FIXME - if we mean to send 0xFF to the terminal then it will be escaped,
95 what is the escape character? We aren't handling that situation here.
96
97 CR-LF ->'s CR mapping is also done here, for convenience
98 */
99static char *
100remove_iacs(struct tsession *ts, int *pnum_totty)
101{
102 unsigned char *ptr0 = (unsigned char *)ts->buf1 + ts->wridx1;
103 unsigned char *ptr = ptr0;
104 unsigned char *totty = ptr;
105 unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
106 int processed;
107 int num_totty;
108
109 while (ptr < end) {
110 if (*ptr != IAC) {
111 int c = *ptr;
112 *totty++ = *ptr++;
113 /* We now map \r\n ==> \r for pragmatic reasons.
114 * Many client implementations send \r\n when
115 * the user hits the CarriageReturn key.
116 */
117 if (c == '\r' && (*ptr == '\n' || *ptr == 0) && ptr < end)
118 ptr++;
119 } else {
120 /*
121 * TELOPT_NAWS support!
122 */
123 if ((ptr+2) >= end) {
124 /* only the beginning of the IAC is in the
125 buffer we were asked to process, we can't
126 process this char. */
127 break;
128 }
129
130 /*
131 * IAC -> SB -> TELOPT_NAWS -> 4-byte -> IAC -> SE
132 */
133 else if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
134 struct winsize ws;
135 if ((ptr+8) >= end)
136 break; /* incomplete, can't process */
137 ws.ws_col = (ptr[3] << 8) | ptr[4];
138 ws.ws_row = (ptr[5] << 8) | ptr[6];
139 ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
140 ptr += 9;
141 } else {
142 /* skip 3-byte IAC non-SB cmd */
143#if DEBUG
144 fprintf(stderr, "Ignoring IAC %s,%s\n",
145 TELCMD(ptr[1]), TELOPT(ptr[2]));
146#endif
147 ptr += 3;
148 }
149 }
150 }
151
152 processed = ptr - ptr0;
153 num_totty = totty - ptr0;
154 /* the difference between processed and num_to tty
155 is all the iacs we removed from the stream.
156 Adjust buf1 accordingly. */
157 ts->wridx1 += processed - num_totty;
158 ts->size1 -= processed - num_totty;
159 *pnum_totty = num_totty;
160 /* move the chars meant for the terminal towards the end of the
161 buffer. */
162 return memmove(ptr - num_totty, ptr0, num_totty);
163}
164
165
166static int
167getpty(char *line, int size)
168{
169 int p;
170#if ENABLE_FEATURE_DEVPTS
171 p = open("/dev/ptmx", O_RDWR);
172 if (p > 0) {
173 const char *name;
174 grantpt(p);
175 unlockpt(p);
176 name = ptsname(p);
177 if (!name) {
178 bb_perror_msg("ptsname error (is /dev/pts mounted?)");
179 return -1;
180 }
181 safe_strncpy(line, name, size);
182 return p;
183 }
184#else
185 struct stat stb;
186 int i;
187 int j;
188
189 strcpy(line, "/dev/ptyXX");
190
191 for (i = 0; i < 16; i++) {
192 line[8] = "pqrstuvwxyzabcde"[i];
193 line[9] = '0';
194 if (stat(line, &stb) < 0) {
195 continue;
196 }
197 for (j = 0; j < 16; j++) {
198 line[9] = j < 10 ? j + '0' : j - 10 + 'a';
199 if (DEBUG)
200 fprintf(stderr, "Trying to open device: %s\n", line);
201 p = open(line, O_RDWR | O_NOCTTY);
202 if (p >= 0) {
203 line[5] = 't';
204 return p;
205 }
206 }
207 }
208#endif /* FEATURE_DEVPTS */
209 return -1;
210}
211
212
213static void
214send_iac(struct tsession *ts, unsigned char command, int option)
215{
216 /* We rely on that there is space in the buffer for now. */
217 char *b = ts->buf2 + ts->rdidx2;
218 *b++ = IAC;
219 *b++ = command;
220 *b++ = option;
221 ts->rdidx2 += 3;
222 ts->size2 += 3;
223}
224
225
226static struct tsession *
227make_new_session(
228 USE_FEATURE_TELNETD_STANDALONE(int sock_r, int sock_w)
229 SKIP_FEATURE_TELNETD_STANDALONE(void)
230) {
231 const char *login_argv[2];
232 struct termios termbuf;
233 int fd, pid;
234 char tty_name[32];
235 struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
236
237 ts->buf1 = (char *)(&ts[1]);
238 ts->buf2 = ts->buf1 + BUFSIZE;
239
240 /* Got a new connection, set up a tty. */
241 fd = getpty(tty_name, 32);
242 if (fd < 0) {
243 bb_error_msg("all terminals in use");
244 return NULL;
245 }
246 if (fd > maxfd) maxfd = fd;
247 ndelay_on(ts->ptyfd = fd);
248#if ENABLE_FEATURE_TELNETD_STANDALONE
249 if (sock_w > maxfd) maxfd = sock_w;
250 if (sock_r > maxfd) maxfd = sock_r;
251 ndelay_on(ts->sockfd_write = sock_w);
252 ndelay_on(ts->sockfd_read = sock_r);
253#else
254 ts->sockfd_write = 1;
255 /* xzalloc: ts->sockfd_read = 0; */
256 ndelay_on(0);
257 ndelay_on(1);
258#endif
259 /* Make the telnet client understand we will echo characters so it
260 * should not do it locally. We don't tell the client to run linemode,
261 * because we want to handle line editing and tab completion and other
262 * stuff that requires char-by-char support. */
263 send_iac(ts, DO, TELOPT_ECHO);
264 send_iac(ts, DO, TELOPT_NAWS);
265 send_iac(ts, DO, TELOPT_LFLOW);
266 send_iac(ts, WILL, TELOPT_ECHO);
267 send_iac(ts, WILL, TELOPT_SGA);
268
269 pid = fork();
270 if (pid < 0) {
271 free(ts);
272 close(fd);
273 bb_perror_msg("fork");
274 return NULL;
275 }
276 if (pid > 0) {
277 /* parent */
278 ts->shell_pid = pid;
279 return ts;
280 }
281
282 /* child */
283
284 /* make new session and process group */
285 setsid();
286
287 /* open the child's side of the tty. */
288 /* NB: setsid() disconnects from any previous ctty's. Therefore
289 * we must open child's side of the tty AFTER setsid! */
290 fd = xopen(tty_name, O_RDWR); /* becomes our ctty */
291 dup2(fd, 0);
292 dup2(fd, 1);
293 dup2(fd, 2);
294 while (fd > 2) close(fd--);
295 tcsetpgrp(0, getpid()); /* switch this tty's process group to us */
296
297 /* The pseudo-terminal allocated to the client is configured to operate in
298 * cooked mode, and with XTABS CRMOD enabled (see tty(4)). */
299 tcgetattr(0, &termbuf);
300 termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
301 termbuf.c_oflag |= ONLCR|XTABS;
302 termbuf.c_iflag |= ICRNL;
303 termbuf.c_iflag &= ~IXOFF;
304 /*termbuf.c_lflag &= ~ICANON;*/
305 tcsetattr(0, TCSANOW, &termbuf);
306
307 print_login_issue(issuefile, NULL);
308
309 /* exec shell / login /whatever */
310 login_argv[0] = loginpath;
311 login_argv[1] = NULL;
312 execv(loginpath, (char **)login_argv);
313 /* Hmmm... this gets sent to the client thru fd#2! Is it ok?? */
314 bb_perror_msg_and_die("execv %s", loginpath);
315}
316
317#if ENABLE_FEATURE_TELNETD_STANDALONE
318
319static void
320free_session(struct tsession *ts)
321{
322 struct tsession *t = sessions;
323
324 /* unlink this telnet session from the session list */
325 if (t == ts)
326 sessions = ts->next;
327 else {
328 while (t->next != ts)
329 t = t->next;
330 t->next = ts->next;
331 }
332
333 kill(ts->shell_pid, SIGKILL);
334 wait4(ts->shell_pid, NULL, 0, NULL);
335 close(ts->ptyfd);
336 close(ts->sockfd_read);
337 /* error if ts->sockfd_read == ts->sockfd_write. So what? ;) */
338 close(ts->sockfd_write);
339 free(ts);
340
341 /* scan all sessions and find new maxfd */
342 ts = sessions;
343 maxfd = 0;
344 while (ts) {
345 if (maxfd < ts->ptyfd)
346 maxfd = ts->ptyfd;
347 if (maxfd < ts->sockfd_read)
348 maxfd = ts->sockfd_read;
349 if (maxfd < ts->sockfd_write)
350 maxfd = ts->sockfd_write;
351 ts = ts->next;
352 }
353}
354
355#else /* !FEATURE_TELNETD_STANDALONE */
356
357/* Never actually called */
358void free_session(struct tsession *ts);
359
360#endif
361
362
363int telnetd_main(int argc, char **argv);
364int telnetd_main(int argc, char **argv)
365{
366 fd_set rdfdset, wrfdset;
367 unsigned opt;
368 int selret, maxlen, w, r;
369 struct tsession *ts;
370#if ENABLE_FEATURE_TELNETD_STANDALONE
371#define IS_INETD (opt & OPT_INETD)
372 int master_fd = -1; /* be happy, gcc */
373 unsigned portnbr = 23;
374 char *opt_bindaddr = NULL;
375 char *opt_portnbr;
376#else
377 enum {
378 IS_INETD = 1,
379 master_fd = -1,
380 portnbr = 23,
381 };
382#endif
383 enum {
384 OPT_PORT = 4 * ENABLE_FEATURE_TELNETD_STANDALONE,
385 OPT_FOREGROUND = 0x10 * ENABLE_FEATURE_TELNETD_STANDALONE,
386 OPT_INETD = 0x20 * ENABLE_FEATURE_TELNETD_STANDALONE,
387 };
388
389 opt = getopt32(argv, "f:l:" USE_FEATURE_TELNETD_STANDALONE("p:b:Fi"),
390 &issuefile, &loginpath
391 USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
392 /* Redirect log to syslog early, if needed */
393 if (IS_INETD || !(opt & OPT_FOREGROUND)) {
394 openlog(applet_name, 0, LOG_USER);
395 logmode = LOGMODE_SYSLOG;
396 }
397 //if (opt & 1) // -f
398 //if (opt & 2) // -l
399 USE_FEATURE_TELNETD_STANDALONE(
400 if (opt & OPT_PORT) // -p
401 portnbr = xatou16(opt_portnbr);
402 //if (opt & 8) // -b
403 //if (opt & 0x10) // -F
404 //if (opt & 0x20) // -i
405 );
406
407 /* Used to check access(loginpath, X_OK) here. Pointless.
408 * exec will do this for us for free later. */
409
410#if ENABLE_FEATURE_TELNETD_STANDALONE
411 if (IS_INETD) {
412 sessions = make_new_session(0, 1);
413 } else {
414 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
415 xlisten(master_fd, 1);
416 if (!(opt & OPT_FOREGROUND))
417 bb_daemonize(DAEMON_CHDIR_ROOT);
418 }
419#else
420 sessions = make_new_session();
421#endif
422
423 /* We don't want to die if just one session is broken */
424 signal(SIGPIPE, SIG_IGN);
425
426 again:
427 FD_ZERO(&rdfdset);
428 FD_ZERO(&wrfdset);
429 if (!IS_INETD) {
430 FD_SET(master_fd, &rdfdset);
431 /* This is needed because free_session() does not
432 * take into account master_fd when it finds new
433 * maxfd among remaining fd's: */
434 if (master_fd > maxfd)
435 maxfd = master_fd;
436 }
437
438 /* select on the master socket, all telnet sockets and their
439 * ptys if there is room in their session buffers. */
440 ts = sessions;
441 while (ts) {
442 /* buf1 is used from socket to pty
443 * buf2 is used from pty to socket */
444 if (ts->size1 > 0) /* can write to pty */
445 FD_SET(ts->ptyfd, &wrfdset);
446 if (ts->size1 < BUFSIZE) /* can read from socket */
447 FD_SET(ts->sockfd_read, &rdfdset);
448 if (ts->size2 > 0) /* can write to socket */
449 FD_SET(ts->sockfd_write, &wrfdset);
450 if (ts->size2 < BUFSIZE) /* can read from pty */
451 FD_SET(ts->ptyfd, &rdfdset);
452 ts = ts->next;
453 }
454
455 selret = select(maxfd + 1, &rdfdset, &wrfdset, 0, 0);
456 if (!selret)
457 return 0;
458
459#if ENABLE_FEATURE_TELNETD_STANDALONE
460 /* First check for and accept new sessions. */
461 if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
462 int fd;
463 struct tsession *new_ts;
464
465 fd = accept(master_fd, NULL, 0);
466 if (fd < 0)
467 goto again;
468 /* Create a new session and link it into our active list */
469 new_ts = make_new_session(fd, fd);
470 if (new_ts) {
471 new_ts->next = sessions;
472 sessions = new_ts;
473 } else {
474 close(fd);
475 }
476 }
477#endif
478
479 /* Then check for data tunneling. */
480 ts = sessions;
481 while (ts) { /* For all sessions... */
482 struct tsession *next = ts->next; /* in case we free ts. */
483
484 if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) {
485 int num_totty;
486 char *ptr;
487 /* Write to pty from buffer 1. */
488 ptr = remove_iacs(ts, &num_totty);
489 w = safe_write(ts->ptyfd, ptr, num_totty);
490 /* needed? if (w < 0 && errno == EAGAIN) continue; */
491 if (w < 0) {
492 if (IS_INETD)
493 return 0;
494 free_session(ts);
495 ts = next;
496 continue;
497 }
498 ts->wridx1 += w;
499 ts->size1 -= w;
500 if (ts->wridx1 == BUFSIZE)
501 ts->wridx1 = 0;
502 }
503
504 if (ts->size2 && FD_ISSET(ts->sockfd_write, &wrfdset)) {
505 /* Write to socket from buffer 2. */
506 maxlen = MIN(BUFSIZE - ts->wridx2, ts->size2);
507 w = safe_write(ts->sockfd_write, ts->buf2 + ts->wridx2, maxlen);
508 /* needed? if (w < 0 && errno == EAGAIN) continue; */
509 if (w < 0) {
510 if (IS_INETD)
511 return 0;
512 free_session(ts);
513 ts = next;
514 continue;
515 }
516 ts->wridx2 += w;
517 ts->size2 -= w;
518 if (ts->wridx2 == BUFSIZE)
519 ts->wridx2 = 0;
520 }
521
522 if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd_read, &rdfdset)) {
523 /* Read from socket to buffer 1. */
524 maxlen = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
525 r = safe_read(ts->sockfd_read, ts->buf1 + ts->rdidx1, maxlen);
526 if (r < 0 && errno == EAGAIN) continue;
527 if (r <= 0) {
528 if (IS_INETD)
529 return 0;
530 free_session(ts);
531 ts = next;
532 continue;
533 }
534 if (!ts->buf1[ts->rdidx1 + r - 1])
535 if (!--r)
536 continue;
537 ts->rdidx1 += r;
538 ts->size1 += r;
539 if (ts->rdidx1 == BUFSIZE)
540 ts->rdidx1 = 0;
541 }
542
543 if (ts->size2 < BUFSIZE && FD_ISSET(ts->ptyfd, &rdfdset)) {
544 /* Read from pty to buffer 2. */
545 maxlen = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
546 r = safe_read(ts->ptyfd, ts->buf2 + ts->rdidx2, maxlen);
547 if (r < 0 && errno == EAGAIN) continue;
548 if (r <= 0) {
549 if (IS_INETD)
550 return 0;
551 free_session(ts);
552 ts = next;
553 continue;
554 }
555 ts->rdidx2 += r;
556 ts->size2 += r;
557 if (ts->rdidx2 == BUFSIZE)
558 ts->rdidx2 = 0;
559 }
560
561 if (ts->size1 == 0) {
562 ts->rdidx1 = 0;
563 ts->wridx1 = 0;
564 }
565 if (ts->size2 == 0) {
566 ts->rdidx2 = 0;
567 ts->wridx2 = 0;
568 }
569 ts = next;
570 }
571 goto again;
572}
Note: See TracBrowser for help on using the repository browser.