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

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 12 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.