Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (16 years ago)
Author:
Bruno Cornec
Message:
  • 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:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/stable/mindi-busybox/networking/telnetd.c

    r821 r1770  
    2222 */
    2323
    24 /*#define DEBUG 1 */
    25 #undef DEBUG
    26 
    27 #include <sys/socket.h>
    28 #include <sys/wait.h>
    29 #include <sys/ioctl.h>
    30 #include <string.h>
    31 #include <stdlib.h>
    32 #include <unistd.h>
    33 #include <errno.h>
    34 #include <netinet/in.h>
    35 #include <arpa/inet.h>
    36 #include <fcntl.h>
    37 #include <stdio.h>
    38 #include <signal.h>
    39 #include <termios.h>
    40 #ifdef DEBUG
     24#define DEBUG 0
     25
     26#include "libbb.h"
     27
     28#if DEBUG
    4129#define TELCMDS
    4230#define TELOPTS
    4331#endif
    4432#include <arpa/telnet.h>
    45 #include <ctype.h>
    4633#include <sys/syslog.h>
    4734
    48 #include "busybox.h"
    49 
    50 #define BUFSIZE 4000
    51 
    52 #ifdef CONFIG_FEATURE_IPV6
    53 #define SOCKET_TYPE AF_INET6
    54 typedef struct sockaddr_in6 sockaddr_type;
    55 #else
    56 #define SOCKET_TYPE AF_INET
    57 typedef struct sockaddr_in sockaddr_type;
    58 #endif
    59 
    60 
    61 #ifdef CONFIG_LOGIN
     35
     36#if ENABLE_LOGIN
    6237static const char *loginpath = "/bin/login";
    6338#else
    64 static const char *loginpath;
    65 #endif
     39static const char *loginpath = DEFAULT_SHELL;
     40#endif
     41
    6642static const char *issuefile = "/etc/issue.net";
    6743
    68 /* shell name and arguments */
    69 
    70 static const char *argv_init[] = {NULL, NULL};
    71 
    7244/* structure that describes a session */
    7345
    7446struct tsession {
    75 #ifdef CONFIG_FEATURE_TELNETD_INETD
     47    struct tsession *next;
    7648    int sockfd_read, sockfd_write, ptyfd;
    77 #else /* CONFIG_FEATURE_TELNETD_INETD */
    78     struct tsession *next;
    79     int sockfd, ptyfd;
    80 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    8149    int shell_pid;
    8250    /* two circular buffers */
     
    8654};
    8755
     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
    8860/*
    89 
    9061   This is how the buffers are used. The arrows indicate the movement
    9162   of data.
     
    10071
    10172   Each session has got two buffers.
    102 
    10373*/
    10474
     
    10979
    11080/*
    111 
    11281   Remove all IAC's from the buffer pointed to by bf (received IACs are ignored
    11382   and must be removed so as to not be interpreted by the terminal).  Make an
     
    12796
    12897   CR-LF ->'s CR mapping is also done here, for convenience
    129 
    130   */
     98 */
    13199static char *
    132 remove_iacs(struct tsession *ts, int *pnum_totty) {
     100remove_iacs(struct tsession *ts, int *pnum_totty)
     101{
    133102    unsigned char *ptr0 = (unsigned char *)ts->buf1 + ts->wridx1;
    134103    unsigned char *ptr = ptr0;
     
    148117            if (c == '\r' && (*ptr == '\n' || *ptr == 0) && ptr < end)
    149118                ptr++;
    150         }
    151         else {
     119        } else {
    152120            /*
    153121             * TELOPT_NAWS support!
     
    169137                ws.ws_col = (ptr[3] << 8) | ptr[4];
    170138                ws.ws_row = (ptr[5] << 8) | ptr[6];
    171                 (void) ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
     139                ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
    172140                ptr += 9;
    173             }
    174             else {
     141            } else {
    175142                /* skip 3-byte IAC non-SB cmd */
    176 #ifdef DEBUG
     143#if DEBUG
    177144                fprintf(stderr, "Ignoring IAC %s,%s\n",
    178                     TELCMD(*(ptr+1)), TELOPT(*(ptr+2)));
     145                    TELCMD(ptr[1]), TELOPT(ptr[2]));
    179146#endif
    180147                ptr += 3;
     
    198165
    199166static int
    200 getpty(char *line)
     167getpty(char *line, int size)
    201168{
    202169    int p;
    203 #ifdef CONFIG_FEATURE_DEVPTS
    204     p = open("/dev/ptmx", 2);
     170#if ENABLE_FEATURE_DEVPTS
     171    p = open("/dev/ptmx", O_RDWR);
    205172    if (p > 0) {
     173        const char *name;
    206174        grantpt(p);
    207175        unlockpt(p);
    208         strcpy(line, ptsname(p));
    209         return(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;
    210183    }
    211184#else
     
    224197        for (j = 0; j < 16; j++) {
    225198            line[9] = j < 10 ? j + '0' : j - 10 + 'a';
    226 #ifdef DEBUG
    227             fprintf(stderr, "Trying to open device: %s\n", line);
    228 #endif
    229             if ((p = open(line, O_RDWR | O_NOCTTY)) >= 0) {
     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) {
    230203                line[5] = 't';
    231204                return p;
     
    233206        }
    234207    }
    235 #endif /* CONFIG_FEATURE_DEVPTS */
     208#endif /* FEATURE_DEVPTS */
    236209    return -1;
    237210}
     
    241214send_iac(struct tsession *ts, unsigned char command, int option)
    242215{
    243     /* We rely on that there is space in the buffer for now.  */
     216    /* We rely on that there is space in the buffer for now. */
    244217    char *b = ts->buf2 + ts->rdidx2;
    245218    *b++ = IAC;
     
    252225
    253226static struct tsession *
    254 #ifdef CONFIG_FEATURE_TELNETD_INETD
    255 make_new_session(void)
    256 #else /* CONFIG_FEATURE_TELNETD_INETD */
    257 make_new_session(int sockfd)
    258 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    259 {
     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];
    260232    struct termios termbuf;
    261     int pty, pid;
     233    int fd, pid;
    262234    char tty_name[32];
    263235    struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
     
    266238    ts->buf2 = ts->buf1 + BUFSIZE;
    267239
    268 #ifdef CONFIG_FEATURE_TELNETD_INETD
     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
    269254    ts->sockfd_write = 1;
    270 #else /* CONFIG_FEATURE_TELNETD_INETD */
    271     ts->sockfd = sockfd;
    272 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    273 
    274     /* Got a new connection, set up a tty and spawn a shell.  */
    275 
    276     pty = getpty(tty_name);
    277 
    278     if (pty < 0) {
    279         syslog(LOG_ERR, "All terminals in use!");
    280         return 0;
    281     }
    282 
    283     if (pty > maxfd)
    284         maxfd = pty;
    285 
    286     ts->ptyfd = pty;
    287 
     255    /* xzalloc: ts->sockfd_read = 0; */
     256    ndelay_on(0);
     257    ndelay_on(1);
     258#endif
    288259    /* Make the telnet client understand we will echo characters so it
    289260     * should not do it locally. We don't tell the client to run linemode,
    290261     * because we want to handle line editing and tab completion and other
    291      * stuff that requires char-by-char support.
    292      */
    293 
     262     * stuff that requires char-by-char support. */
    294263    send_iac(ts, DO, TELOPT_ECHO);
    295264    send_iac(ts, DO, TELOPT_NAWS);
     
    298267    send_iac(ts, WILL, TELOPT_SGA);
    299268
    300     if ((pid = fork()) < 0) {
    301         syslog(LOG_ERR, "Could not fork");
    302     }
    303     if (pid == 0) {
    304         /* In child, open the child's side of the tty.  */
    305         int i;
    306 
    307         for(i = 0; i <= maxfd; i++)
    308             close(i);
    309         /* make new process group */
    310         setsid();
    311 
    312         if (open(tty_name, O_RDWR /*| O_NOCTTY*/) < 0) {
    313             syslog(LOG_ERR, "Could not open tty");
    314             exit(1);
    315         }
    316         dup(0);
    317         dup(0);
    318 
    319         tcsetpgrp(0, getpid());
    320 
    321         /* The pseudo-terminal allocated to the client is configured to operate in
    322          * cooked mode, and with XTABS CRMOD enabled (see tty(4)).
    323          */
    324 
    325         tcgetattr(0, &termbuf);
    326         termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */
    327         termbuf.c_oflag |= ONLCR|XTABS;
    328         termbuf.c_iflag |= ICRNL;
    329         termbuf.c_iflag &= ~IXOFF;
    330         /*termbuf.c_lflag &= ~ICANON;*/
    331         tcsetattr(0, TCSANOW, &termbuf);
    332 
    333         print_login_issue(issuefile, NULL);
    334 
    335         /* exec shell, with correct argv and env */
    336         execv(loginpath, (char *const *)argv_init);
    337 
    338         /* NOT REACHED */
    339         syslog(LOG_ERR, "execv error");
    340         exit(1);
    341     }
    342 
    343     ts->shell_pid = pid;
    344 
    345     return ts;
     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);
    346315}
    347316
    348 #ifndef CONFIG_FEATURE_TELNETD_INETD
     317#if ENABLE_FEATURE_TELNETD_STANDALONE
     318
    349319static void
    350320free_session(struct tsession *ts)
     
    352322    struct tsession *t = sessions;
    353323
    354     /* Unlink this telnet session from the session list. */
     324    /* unlink this telnet session from the session list */
    355325    if (t == ts)
    356326        sessions = ts->next;
    357327    else {
    358         while(t->next != ts)
     328        while (t->next != ts)
    359329            t = t->next;
    360330        t->next = ts->next;
     
    362332
    363333    kill(ts->shell_pid, SIGKILL);
    364 
    365334    wait4(ts->shell_pid, NULL, 0, NULL);
    366 
    367335    close(ts->ptyfd);
    368     close(ts->sockfd);
    369 
    370     if (ts->ptyfd == maxfd || ts->sockfd == maxfd)
    371         maxfd--;
    372     if (ts->ptyfd == maxfd || ts->sockfd == maxfd)
    373         maxfd--;
    374 
     336    close(ts->sockfd_read);
     337    /* error if ts->sockfd_read == ts->sockfd_write. So what? ;) */
     338    close(ts->sockfd_write);
    375339    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    }
    376353}
    377 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    378 
    379 int
    380 telnetd_main(int argc, char **argv)
     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)
    381365{
    382 #ifndef CONFIG_FEATURE_TELNETD_INETD
    383     sockaddr_type sa;
    384     int master_fd;
    385 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    386366    fd_set rdfdset, wrfdset;
    387     int selret;
    388 #ifndef CONFIG_FEATURE_TELNETD_INETD
    389     int on = 1;
    390     int portnbr = 23;
    391     struct in_addr bind_addr = { .s_addr = 0x0 };
    392 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    393     int c;
    394     static const char options[] =
    395 #ifdef CONFIG_FEATURE_TELNETD_INETD
    396         "f:l:";
    397 #else /* CONFIG_EATURE_TELNETD_INETD */
    398         "f:l:p:b:";
    399 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    400     int maxlen, w, r;
    401 
    402 #ifndef CONFIG_LOGIN
    403     loginpath = DEFAULT_SHELL;
    404 #endif
    405 
    406     for (;;) {
    407         c = getopt( argc, argv, options);
    408         if (c == EOF) break;
    409         switch (c) {
    410             case 'f':
    411                 issuefile = optarg;
    412                 break;
    413             case 'l':
    414                 loginpath = optarg;
    415                 break;
    416 #ifndef CONFIG_FEATURE_TELNETD_INETD
    417             case 'p':
    418                 portnbr = atoi(optarg);
    419                 break;
    420             case 'b':
    421                 if (inet_aton(optarg, &bind_addr) == 0)
    422                     bb_show_usage();
    423                 break;
    424 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    425             default:
    426                 bb_show_usage();
    427         }
    428     }
    429 
    430     if (access(loginpath, X_OK) < 0) {
    431         bb_error_msg_and_die ("'%s' unavailable.", loginpath);
    432     }
    433 
    434     argv_init[0] = loginpath;
    435 
    436     openlog(bb_applet_name, 0, LOG_USER);
    437 
    438 #ifdef CONFIG_FEATURE_TELNETD_INETD
    439     maxfd = 1;
     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
    440420    sessions = make_new_session();
    441 #else /* CONFIG_EATURE_TELNETD_INETD */
    442     sessions = 0;
    443 
    444     /* Grab a TCP socket.  */
    445 
    446     master_fd = bb_xsocket(SOCKET_TYPE, SOCK_STREAM, 0);
    447     (void)setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    448 
    449     /* Set it to listen to specified port.  */
    450 
    451     memset((void *)&sa, 0, sizeof(sa));
    452 #ifdef CONFIG_FEATURE_IPV6
    453     sa.sin6_family = AF_INET6;
    454     sa.sin6_port = htons(portnbr);
    455     /* sa.sin6_addr = bind_addr6; */
    456 #else
    457     sa.sin_family = AF_INET;
    458     sa.sin_port = htons(portnbr);
    459     sa.sin_addr = bind_addr;
    460 #endif
    461 
    462     bb_xbind(master_fd, (struct sockaddr *) &sa, sizeof(sa));
    463     bb_xlisten(master_fd, 1);
    464     bb_xdaemon(0, 0);
    465 
    466     maxfd = master_fd;
    467 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    468 
    469     do {
    470         struct tsession *ts;
    471 
    472         FD_ZERO(&rdfdset);
    473         FD_ZERO(&wrfdset);
    474 
    475         /* select on the master socket, all telnet sockets and their
    476          * ptys if there is room in their respective session buffers.
    477          */
    478 
    479 #ifndef CONFIG_FEATURE_TELNETD_INETD
     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) {
    480430        FD_SET(master_fd, &rdfdset);
    481 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    482 
    483         ts = sessions;
    484 #ifndef CONFIG_FEATURE_TELNETD_INETD
    485         while (ts) {
    486 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    487             /* buf1 is used from socket to pty
    488              * buf2 is used from pty to socket
    489              */
    490             if (ts->size1 > 0) {
    491                 FD_SET(ts->ptyfd, &wrfdset);  /* can write to pty */
    492             }
    493             if (ts->size1 < BUFSIZE) {
    494 #ifdef CONFIG_FEATURE_TELNETD_INETD
    495                 FD_SET(ts->sockfd_read, &rdfdset); /* can read from socket */
    496 #else /* CONFIG_FEATURE_TELNETD_INETD */
    497                 FD_SET(ts->sockfd, &rdfdset); /* can read from socket */
    498 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    499             }
    500             if (ts->size2 > 0) {
    501 #ifdef CONFIG_FEATURE_TELNETD_INETD
    502                 FD_SET(ts->sockfd_write, &wrfdset); /* can write to socket */
    503 #else /* CONFIG_FEATURE_TELNETD_INETD */
    504                 FD_SET(ts->sockfd, &wrfdset); /* can write to socket */
    505 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    506             }
    507             if (ts->size2 < BUFSIZE) {
    508                 FD_SET(ts->ptyfd, &rdfdset);  /* can read from pty */
    509             }
    510 #ifndef CONFIG_FEATURE_TELNETD_INETD
    511             ts = ts->next;
    512         }
    513 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    514 
    515         selret = select(maxfd + 1, &rdfdset, &wrfdset, 0, 0);
    516 
    517         if (!selret)
    518             break;
    519 
    520 #ifndef CONFIG_FEATURE_TELNETD_INETD
    521         /* First check for and accept new sessions.  */
    522         if (FD_ISSET(master_fd, &rdfdset)) {
    523             int fd;
    524             socklen_t salen;
    525 
    526             salen = sizeof(sa);
    527             if ((fd = accept(master_fd, (struct sockaddr *)&sa,
    528                         &salen)) < 0) {
     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;
    529496                continue;
    530             } else {
    531                 /* Create a new session and link it into
    532                     our active list.  */
    533                 struct tsession *new_ts = make_new_session(fd);
    534                 if (new_ts) {
    535                     new_ts->next = sessions;
    536                     sessions = new_ts;
    537                     if (fd > maxfd)
    538                         maxfd = fd;
    539                 } else {
    540                     close(fd);
    541                 }
    542             }
    543         }
    544 
    545         /* Then check for data tunneling.  */
    546 
    547         ts = sessions;
    548         while (ts) { /* For all sessions...  */
    549 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    550 #ifndef CONFIG_FEATURE_TELNETD_INETD
    551             struct tsession *next = ts->next; /* in case we free ts. */
    552 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    553 
    554             if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) {
    555                 int num_totty;
    556                 char *ptr;
    557                 /* Write to pty from buffer 1.  */
    558 
    559                 ptr = remove_iacs(ts, &num_totty);
    560 
    561                 w = write(ts->ptyfd, ptr, num_totty);
    562                 if (w < 0) {
    563 #ifdef CONFIG_FEATURE_TELNETD_INETD
    564                     exit(0);
    565 #else /* CONFIG_FEATURE_TELNETD_INETD */
    566                     free_session(ts);
    567                     ts = next;
     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)
    568536                    continue;
    569 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    570                 }
    571                 ts->wridx1 += w;
    572                 ts->size1 -= w;
    573                 if (ts->wridx1 == BUFSIZE)
    574                     ts->wridx1 = 0;
    575             }
    576 
    577 #ifdef CONFIG_FEATURE_TELNETD_INETD
    578             if (ts->size2 && FD_ISSET(ts->sockfd_write, &wrfdset)) {
    579 #else /* CONFIG_FEATURE_TELNETD_INETD */
    580             if (ts->size2 && FD_ISSET(ts->sockfd, &wrfdset)) {
    581 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    582                 /* Write to socket from buffer 2.  */
    583                 maxlen = MIN(BUFSIZE - ts->wridx2, ts->size2);
    584 #ifdef CONFIG_FEATURE_TELNETD_INETD
    585                 w = write(ts->sockfd_write, ts->buf2 + ts->wridx2, maxlen);
    586                 if (w < 0)
    587                     exit(0);
    588 #else /* CONFIG_FEATURE_TELNETD_INETD */
    589                 w = write(ts->sockfd, ts->buf2 + ts->wridx2, maxlen);
    590                 if (w < 0) {
    591                     free_session(ts);
    592                     ts = next;
    593                     continue;
    594                 }
    595 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    596                 ts->wridx2 += w;
    597                 ts->size2 -= w;
    598                 if (ts->wridx2 == BUFSIZE)
    599                     ts->wridx2 = 0;
    600             }
    601 
    602 #ifdef CONFIG_FEATURE_TELNETD_INETD
    603             if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd_read, &rdfdset)) {
    604 #else /* CONFIG_FEATURE_TELNETD_INETD */
    605             if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd, &rdfdset)) {
    606 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    607                 /* Read from socket to buffer 1. */
    608                 maxlen = MIN(BUFSIZE - ts->rdidx1,
    609                         BUFSIZE - ts->size1);
    610 #ifdef CONFIG_FEATURE_TELNETD_INETD
    611                 r = read(ts->sockfd_read, ts->buf1 + ts->rdidx1, maxlen);
    612                 if (!r || (r < 0 && errno != EINTR))
    613                     exit(0);
    614 #else /* CONFIG_FEATURE_TELNETD_INETD */
    615                 r = read(ts->sockfd, ts->buf1 + ts->rdidx1, maxlen);
    616                 if (!r || (r < 0 && errno != EINTR)) {
    617                     free_session(ts);
    618                     ts = next;
    619                     continue;
    620                 }
    621 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    622                 if (!*(ts->buf1 + ts->rdidx1 + r - 1)) {
    623                     r--;
    624                     if (!r)
    625                         continue;
    626                 }
    627                 ts->rdidx1 += r;
    628                 ts->size1 += r;
    629                 if (ts->rdidx1 == BUFSIZE)
    630                     ts->rdidx1 = 0;
    631             }
    632 
    633             if (ts->size2 < BUFSIZE && FD_ISSET(ts->ptyfd, &rdfdset)) {
    634                 /* Read from pty to buffer 2.  */
    635                 maxlen = MIN(BUFSIZE - ts->rdidx2,
    636                         BUFSIZE - ts->size2);
    637                 r = read(ts->ptyfd, ts->buf2 + ts->rdidx2, maxlen);
    638                 if (!r || (r < 0 && errno != EINTR)) {
    639 #ifdef CONFIG_FEATURE_TELNETD_INETD
    640                     exit(0);
    641 #else /* CONFIG_FEATURE_TELNETD_INETD */
    642                     free_session(ts);
    643                     ts = next;
    644                     continue;
    645 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    646                 }
    647                 ts->rdidx2 += r;
    648                 ts->size2 += r;
    649                 if (ts->rdidx2 == BUFSIZE)
    650                     ts->rdidx2 = 0;
    651             }
    652 
    653             if (ts->size1 == 0) {
     537            ts->rdidx1 += r;
     538            ts->size1 += r;
     539            if (ts->rdidx1 == BUFSIZE)
    654540                ts->rdidx1 = 0;
    655                 ts->wridx1 = 0;
    656             }
    657             if (ts->size2 == 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)
    658558                ts->rdidx2 = 0;
    659                 ts->wridx2 = 0;
    660             }
    661 #ifndef CONFIG_FEATURE_TELNETD_INETD
    662             ts = next;
    663         }
    664 #endif /* CONFIG_FEATURE_TELNETD_INETD */
    665 
    666     } while (1);
    667 
    668     return 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;
    669572}
Note: See TracChangeset for help on using the changeset viewer.