示例#1
0
static void
child_died(int unused)
{
    int saved_errno;
    DEBUG_RANDOM_SLEEP;
    zero_select_timeout();
    saved_errno = errno;
    DPRINTF0(DEBUG_SIGNALS, "Caught SIGCHLD");

    if(command_pid && waitpid(command_pid, &commands_exit_status, WNOHANG)) {
        DPRINTF2(DEBUG_SIGNALS, "child (pid %d) has died, exit status: %x", command_pid, commands_exit_status);
        command_is_dead = TRUE;
        command_pid = 0;            /* thus we know that there is no child anymore to pass signals to */
    } else if (filter_pid && waitpid(filter_pid, &filters_exit_status, WNOHANG)) {
        DPRINTF2(DEBUG_SIGNALS, "filter (pid %d) has died, exit status: %x", filter_pid, filters_exit_status);
        filter_is_dead = TRUE;
        filter_pid = 0;
    } else  {
        DPRINTF0(DEBUG_ALL, "Whoa, got a SIGCHLD, but not from slave command or filter! I must have children I don't know about (blush...)!");
        /* ignore */
    }

    errno = saved_errno;
    return;   /* allow remaining output from child to be processed in main loop */
    /* (so that we will see childs good-bye talk)                     */
    /* this will then clean up and terminate                          */

}
示例#2
0
void
restore_rl_state()
{
  
  char *newprompt;


  move_cursor_to_start_of_prompt(impatient_prompt ? ERASE : DONT_ERASE);

  cook_prompt_if_necessary();
  newprompt =  mark_invisible(saved_rl_state.cooked_prompt); /* bracket (colour) control sequences with \001 and \002 */  
  rl_expand_prompt(newprompt);
  mirror_slaves_echo_mode();    /* don't show passwords etc */
  
  DPRINTF1(DEBUG_READLINE,"newprompt now %s", mangle_string_for_debug_log(newprompt,MANGLE_LENGTH));
  rl_callback_handler_install(newprompt, &line_handler);
  DPRINTF0(DEBUG_AD_HOC, "freeing newprompt");
  free(newprompt);             /* readline docs don't say it, but we can free newprompt now (readline apparently
                                  uses its own copy) */
  rl_insert_text(saved_rl_state.input_buffer);
  rl_point = saved_rl_state.point;
  saved_rl_state.already_saved = 0;
  DPRINTF0(DEBUG_AD_HOC, "Starting redisplay");
  rl_redisplay(); 
  rl_prep_terminal(1);
  prompt_is_still_uncooked =  FALSE; /* has been done right now */
}
示例#3
0
void
fwtcp_del(struct fwspec *fwspec)
{
    struct fwtcp *fwtcp;
    struct fwtcp **pprev;

    for (pprev = &fwtcp_list; (fwtcp = *pprev) != NULL; pprev = &fwtcp->next) {
        if (fwspec_equal(&fwtcp->fwspec, fwspec)) {
            *pprev = fwtcp->next;
            fwtcp->next = NULL;
            break;
        }
    }

    if (fwtcp == NULL) {
        DPRINTF0(("%s: not found\n", __func__));
        return;
    }

    DPRINTF0(("%s\n", __func__));

    pollmgr_del_slot(fwtcp->pmhdl.slot);
    fwtcp->pmhdl.slot = -1;

    closesocket(fwtcp->sock);
    fwtcp->sock = -1;

    /* let pending msg_connect be processed before we delete fwtcp */
    proxy_lwip_post(&fwtcp->msg_delete);
}
示例#4
0
文件: rtmon_bsd.c 项目: jeppeter/vbox
/**
 * Query IPv6 routing table - BSD routing sockets version.
 *
 * We don't actually monitor the routing socket for updates, and
 * instead query the kernel each time.
 *
 * We take a shortcut and don't read the reply to our RTM_GET - if
 * there's no default IPv6 route, write(2) will fail with ESRCH
 * synchronously.  In theory it may fail asynchronously and we should
 * wait for the RTM_GET reply and check rt_msghdr::rtm_errno.
 *
 * KAME code in *BSD maintains internally a list of default routers
 * that it learned from RAs, and installs only one of them into the
 * routing table (actually, I'm not sure if BSD routing table can
 * handle multiple routes to the same destination).  One side-effect
 * of this is that when manually configured route (e.g. teredo) is
 * deleted, the system will lose its default route even when KAME IPv6
 * has default router(s) in its internal list.  Next RA will force the
 * update, though.
 *
 * Solaris does expose multiple routes in the routing table and
 * replies to RTM_GET with "default default".
 */
int
rtmon_get_defaults(void)
{
    int rtsock;
    struct req {
        struct rt_msghdr rtm;
        struct sockaddr_in6 dst;
        struct sockaddr_in6 mask;
        struct sockaddr_dl ifp;
    } req;
    ssize_t nsent;

    rtsock = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
    if (rtsock < 0) {
        DPRINTF0(("rtmon: failed to create routing socket\n"));
        return -1;
    }

    memset(&req, 0, sizeof(req));

    req.rtm.rtm_type = RTM_GET;
    req.rtm.rtm_version = RTM_VERSION;
    req.rtm.rtm_msglen = sizeof(req);
    req.rtm.rtm_seq = 0x12345;

    req.rtm.rtm_flags = RTF_UP;
    req.rtm.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_IFP;

    req.dst.sin6_family = AF_INET6;
#if HAVE_SA_LEN
    req.dst.sin6_len = sizeof(req.dst);
#endif

    req.mask.sin6_family = AF_INET6;
#if HAVE_SA_LEN
    req.mask.sin6_len = sizeof(req.mask);
#endif

    req.ifp.sdl_family = AF_LINK;
#if HAVE_SA_LEN
    req.ifp.sdl_len = sizeof(req.ifp);
#endif

    nsent = write(rtsock, &req, req.rtm.rtm_msglen);
    if (nsent < 0) {
        if (errno == ESRCH) {
            /* there's no default route */
            return 0;
        }
        else {
            DPRINTF0(("rtmon: failed to send RTM_GET\n"));
            return -1;
        }
    }

    return 1;
}
示例#5
0
void
fwtcp_add(struct fwspec *fwspec)
{
    struct fwtcp *fwtcp;

    fwtcp = fwtcp_create(fwspec);
    if (fwtcp == NULL) {
        DPRINTF0(("%s: failed to add rule for TCP ...\n", __func__));
        return;
    }

    DPRINTF0(("%s\n", __func__));
    /* fwtcp_create has put fwtcp on the linked list */
}
示例#6
0
void
handle_sigALRM(int signo) {
    received_sigALRM = TRUE;
    assert(myalarm_was_set); /* cry wolf if sigALRM is caught when none was requested by myalarm */
    myalarm_was_set= FALSE;
    DPRINTF0(DEBUG_SIGNALS, "got sigALRM");
}
示例#7
0
static void
handle_sigTSTP(int signo)
{
    sigset_t all_signals;
    int error, saved_errno = errno;

    DEBUG_RANDOM_SLEEP;
    sigfillset(&all_signals);

    DPRINTF2(DEBUG_SIGNALS, "got %s, sending it to pgid %d", signal_name(signo), command_pid);
    zero_select_timeout();
    /* Hand the SIGTSTP down to command and its process group */
    if (command_pid && (error = kill(-command_pid, SIGTSTP))) {
        myerror(FATAL|USE_ERRNO, "Failed to deliver SIGTSTP");
    }

    if (within_line_edit)
        save_rl_state();


    mysignal(SIGTSTP, SIG_DFL);   /* reset disposition to default (i.e. suspend) */
    sigprocmask(SIG_UNBLOCK, &all_signals, NULL); /* respond to sleep- and wake-up signals  */
    kill(getpid(), SIGTSTP); /* suspend */
    /* keyboard gathers dust, kingdoms crumble,.... */

    /* .... */

    /* Beautiful princess types "fg", (or her father tries to kill us...) and we wake up HERE: */
    sigprocmask(SIG_BLOCK, &all_signals, NULL);
    mysignal(SIGTSTP, &handle_sigTSTP);
    DPRINTF0(DEBUG_SIGNALS, "woken up");

    /* On most systems, command's process group will have been woken up by the handler of
       the signal that woke us up. This doesn't seem to happen for SIGCONT on QNX, so here goes: */

#ifdef __QNX__
    if (command_pid && (error = kill(-command_pid, SIGCONT))) {
        myerror(FATAL|USE_ERRNO, "Failed to deliver SIGCONT");
    }
#endif

    if (within_line_edit) {
        restore_rl_state();
    } else {
        set_echo(FALSE);
        cr();
        if (skip_rlwrap())
            return;
        move_cursor_to_start_of_prompt(ERASE);
        cook_prompt_if_necessary();
        my_putstr(saved_rl_state.cooked_prompt);
    }
    adapt_tty_winsize(STDIN_FILENO, master_pty_fd);       /* just in case */
    errno = saved_errno;
    sigprocmask(SIG_UNBLOCK, &all_signals, NULL);
}
示例#8
0
文件: main.c 项目: albfan/rlwrap
void
cleanup_rlwrap_and_exit(int status)
{
  unblock_all_signals();
  DPRINTF0(DEBUG_TERMIO, "Cleaning up");

  if (write_histfile && (histsize==0 ||  history_total_bytes() > 0)) /* avoid creating empty .speling_eror_history file after typo */
    write_history(history_filename);	/* ignore errors */

  close_logfile();

  DPRINTF4(DEBUG_SIGNALS, "command_pid: %d, commands_exit_status: %x, filter_pid: %d, filters_exit_status: %x",
           command_pid, commands_exit_status, filter_pid, filters_exit_status);
  mymicrosleep(10); /* we may have got an EOF or EPIPE because the filter or command died, but this doesn't mean that
                       SIGCHLD has been caught already. Taking a little nap now improves the chance that we will catch it
                       (no grave problem if we miss it, but diagnostics, exit status and transparent signal handling depend on it) */
  if (filter_pid) 
    kill_filter();
  else if (filter_is_dead) {
    int filters_killer = killed_by(filters_exit_status);
    errno = 0;
    mywarn((filters_killer ? "filter was killed by signal %d (%s)": WEXITSTATUS(filters_exit_status) ? "filter died" : "filter exited"), filters_killer, signal_name(filters_killer));
  }     
  if (debug) 
    debug_postmortem();
  
  if (terminal_settings_saved)
    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_terminal_settings) < 0)  /* ignore errors (almost dead anyway) */ 
      ; /* fprintf(stderr, "Arggh\n"); don't use myerror!!*/

  if (!newline_came_last) /* print concluding newline, if necessary */
    my_putstr("\n");
     

  if (status != EXIT_SUCCESS)  /* rlwrap itself has failed, rather than the wrapped command */
    exit(status);              
  else {                      
    int commands_killer = killed_by(commands_exit_status);
    if (commands_killer)
      suicide_by(commands_killer, commands_exit_status); /* command terminated by signal, make rlwrap's
                                                            parent believe rlwrap was killed by it */ 
    else
      exit(WEXITSTATUS(commands_exit_status));           /* propagate command's exit status */
  }
}
static void
pollmgr_loop(void)
{
    int nready;
    SOCKET delfirst;
    SOCKET *pdelprev;
    int i;

    for (;;) {
#ifndef RT_OS_WINDOWS
        nready = poll(pollmgr.fds, pollmgr.nfds, -1);
#else
        int rc = RTWinPoll(pollmgr.fds, pollmgr.nfds,RT_INDEFINITE_WAIT, &nready);
        if (RT_FAILURE(rc)) {
            err(EXIT_FAILURE, "poll"); /* XXX: what to do on error? */
            /* NOTREACHED*/
        }
#endif

	DPRINTF2(("%s: ready %d fd%s\n",
                  __func__, nready, (nready == 1 ? "" : "s")));

        if (nready < 0) {
            if (errno == EINTR) {
                continue;
            }

            err(EXIT_FAILURE, "poll"); /* XXX: what to do on error? */
            /* NOTREACHED*/
        }
        else if (nready == 0) { /* cannot happen, we wait forever (-1) */
            continue;           /* - but be defensive */
        }


        delfirst = INVALID_SOCKET;
        pdelprev = &delfirst;

        for (i = 0; (nfds_t)i < pollmgr.nfds && nready > 0; ++i) {
            struct pollmgr_handler *handler;
            SOCKET fd; 
            int revents, nevents;

	    fd = pollmgr.fds[i].fd;
	    revents = pollmgr.fds[i].revents;

            /*
             * Channel handlers can request deletion of dynamic slots
             * by calling pollmgr_del_slot() that clobbers slot's fd.
             */
            if (fd == INVALID_SOCKET && i >= POLLMGR_SLOT_FIRST_DYNAMIC) {
                /* adjust count if events were pending for that slot */
                if (revents != 0) {
                    --nready;
                }

                /* pretend that slot handler requested deletion */
                nevents = -1;
                goto update_events;
            }

            if (revents == 0) {
                continue; /* next fd */
            }
            --nready;

            handler = pollmgr.handlers[i];

            if (handler != NULL && handler->callback != NULL) {
#if LWIP_PROXY_DEBUG /* DEBUG */
                if (i < POLLMGR_SLOT_FIRST_DYNAMIC) {
                    if (revents == POLLIN) {
                        DPRINTF2(("%s: ch %d\n", __func__, i));
                    }
                    else {
                        DPRINTF2(("%s: ch %d @ revents 0x%x!\n",
                                  __func__, i, revents));
                    }
                }
                else {
                    DPRINTF2(("%s: fd %d @ revents 0x%x\n",
                              __func__, fd, revents));
                }
#endif /* DEBUG */
                nevents = (*handler->callback)(handler, fd, revents);
            }
            else {
                DPRINTF0(("%s: invalid handler for fd %d: ", __func__, fd));
                if (handler == NULL) {
                    DPRINTF0(("NULL\n"));
                }
                else {
                    DPRINTF0(("%p (callback = NULL)\n", (void *)handler));
                }
                nevents = -1;   /* delete it */
            }

          update_events:
            if (nevents >= 0) {
                if (nevents != pollmgr.fds[i].events) {
                    DPRINTF2(("%s: fd %d ! nevents 0x%x\n",
                              __func__, fd, nevents));
                }
                pollmgr.fds[i].events = nevents;
            }
	    else if (i < POLLMGR_SLOT_FIRST_DYNAMIC) {
                /* Don't garbage-collect channels. */
                DPRINTF2(("%s: fd %d ! DELETED (channel %d)\n",
                          __func__, fd, i));
                pollmgr.fds[i].fd = INVALID_SOCKET;
                pollmgr.fds[i].events = 0;
                pollmgr.fds[i].revents = 0;
                pollmgr.handlers[i] = NULL;
            }
            else {
                DPRINTF2(("%s: fd %d ! DELETED\n", __func__, fd));

                /* schedule for deletion (see g/c loop for details) */
                *pdelprev = i;	/* make previous entry point to us */
                pdelprev = &pollmgr.fds[i].fd;

                pollmgr.fds[i].fd = INVALID_SOCKET; /* end of list (for now) */
                pollmgr.fds[i].events = POLLMGR_GARBAGE;
                pollmgr.fds[i].revents = 0;
                pollmgr.handlers[i] = NULL;
            }
        } /* processing loop */


        /*
	 * Garbage collect and compact the array.
         *
         * We overload pollfd::fd of garbage entries to store the
         * index of the next garbage entry.  The garbage list is
         * co-directional with the fds array.  The index of the first
         * entry is in "delfirst", the last entry "points to"
         * INVALID_SOCKET.
         *
         * See update_events code for nevents < 0 at the end of the
         * processing loop above.
	 */
        while (delfirst != INVALID_SOCKET) {
            const int last = pollmgr.nfds - 1;

            /*
             * We want a live entry in the last slot to swap into the
             * freed slot, so make sure we have one.
             */
            if (pollmgr.fds[last].events == POLLMGR_GARBAGE /* garbage */
                || pollmgr.fds[last].fd == INVALID_SOCKET)  /* or killed */
            {
                /* drop garbage entry at the end of the array */
                --pollmgr.nfds;

                if (delfirst == last) {
                    /* congruent to delnext >= pollmgr.nfds test below */
                    delfirst = INVALID_SOCKET; /* done */
                }
            }
            else {
                const SOCKET delnext = pollmgr.fds[delfirst].fd;

                /* copy live entry at the end to the first slot being freed */
                pollmgr.fds[delfirst] = pollmgr.fds[last]; /* struct copy */
                pollmgr.handlers[delfirst] = pollmgr.handlers[last];
                pollmgr.handlers[delfirst]->slot = (int)delfirst;
                --pollmgr.nfds;

                if ((nfds_t)delnext >= pollmgr.nfds) {
                    delfirst = INVALID_SOCKET; /* done */
                }
                else {
                    delfirst = delnext;
                }
            }

            pollmgr.fds[last].fd = INVALID_SOCKET;
            pollmgr.fds[last].events = 0;
            pollmgr.fds[last].revents = 0;
            pollmgr.handlers[last] = NULL;
        }
    } /* poll loop */
}
/**
 * Initialize DHCP6 server.
 *
 * Join DHCP6 multicast groups.
 * Create and bind server pcb.
 * Prebuild fixed parts of reply.
 */
err_t
dhcp6ds_init(struct netif *proxy_netif)
{
    ip6_addr_t *pxaddr, *pxaddr_nonlocal;
    int i;
    err_t error;

    LWIP_ASSERT1(proxy_netif != NULL);
    LWIP_ASSERT1(proxy_netif->hwaddr_len == 6); /* ethernet */

    pxaddr = netif_ip6_addr(proxy_netif, 0); /* link local */

    /*
     * XXX: TODO: This is a leftover from testing with IPv6 mapped
     * loopback with a special IPv6->IPv4 mapping hack in pxudp.c
     */
    /* advertise ourself as DNS resolver - will be proxied to host */
    pxaddr_nonlocal = NULL;
    for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
        if (ip6_addr_ispreferred(netif_ip6_addr_state(proxy_netif, i))
            && !ip6_addr_islinklocal(netif_ip6_addr(proxy_netif, i)))
        {
            pxaddr_nonlocal = netif_ip6_addr(proxy_netif, i);
            break;
        }
    }
    LWIP_ASSERT1(pxaddr_nonlocal != NULL); /* must be configured on the netif */


    error = mld6_joingroup(pxaddr, &all_dhcp_relays_and_servers);
    if (error != ERR_OK) {
        DPRINTF0(("%s: failed to join All_DHCP_Relay_Agents_and_Servers: %s\n",
                  __func__, proxy_lwip_strerr(error)));
        goto err;
    }

    error = mld6_joingroup(pxaddr, &all_dhcp_servers);
    if (error != ERR_OK) {
        DPRINTF0(("%s: failed to join All_DHCP_Servers: %s\n",
                  __func__, proxy_lwip_strerr(error)));
        goto err1;
    }


    dhcp6ds_pcb = udp_new_ip6();
    if (dhcp6ds_pcb == NULL) {
        DPRINTF0(("%s: failed to allocate PCB\n", __func__));
        error = ERR_MEM;
        goto err2;
    }

    udp_recv_ip6(dhcp6ds_pcb, dhcp6ds_recv, NULL);

    error = udp_bind_ip6(dhcp6ds_pcb, pxaddr, DHCP6_SERVER_PORT);
    if (error != ERR_OK) {
        DPRINTF0(("%s: failed to bind PCB\n", __func__));
        goto err3;
    }


#define OPT_SET(buf, off, c) do {                       \
        u16_t _s = PP_HTONS(c);                         \
        memcpy(&(buf)[off], &_s, sizeof(u16_t));        \
    } while (0)

#define SERVERID_SET(off, c)    OPT_SET(dhcp6ds_serverid, (off), (c))
#define DNSSRV_SET(off, c)      OPT_SET(dhcp6ds_dns, (off), (c))

    SERVERID_SET(0, DHCP6_OPTION_SERVERID);
    SERVERID_SET(2, DUID_LL_LEN);
    SERVERID_SET(4, DHCP6_DUID_LL);
    SERVERID_SET(6, ARES_HRD_ETHERNET);
    memcpy(&dhcp6ds_serverid[8], proxy_netif->hwaddr, 6);

    DNSSRV_SET(0, DHCP6_OPTION_DNS_SERVERS);
    DNSSRV_SET(2, 16);          /* one IPv6 address */
    /*
     * XXX: TODO: This is a leftover from testing with IPv6 mapped
     * loopback with a special IPv6->IPv4 mapping hack in pxudp.c
     */
    memcpy(&dhcp6ds_dns[4], pxaddr_nonlocal, sizeof(ip6_addr_t));

#undef SERVERID_SET
#undef DNSSRV_SET

    return ERR_OK;


  err3:
    udp_remove(dhcp6ds_pcb);
    dhcp6ds_pcb = NULL;
  err2:
    mld6_leavegroup(pxaddr, &all_dhcp_servers);
  err1:
    mld6_leavegroup(pxaddr, &all_dhcp_relays_and_servers);
  err:
    return error;
}
示例#11
0
/**
 * Read IPv6 routing table - Linux rtnetlink version.
 *
 * XXX: TODO: To avoid re-reading the table we should subscribe to
 * updates by binding a monitoring NETLINK_ROUTE socket to
 * sockaddr_nl::nl_groups = RTMGRP_IPV6_ROUTE.
 *
 * But that will provide updates only.  Documentation is scarce, but
 * from what I've seen it seems that to get accurate routing info the
 * monitoring socket needs to be created first, then full routing
 * table requested (easier to do via spearate socket), then monitoring
 * socket polled for input.  The first update(s) of the monitoring
 * socket may happen before full table is returned, so we can't just
 * count the defaults, we need to keep track of their { oif, gw } to
 * correctly ignore updates that are reported via monitoring socket,
 * but that are already reflected in the full routing table returned
 * in response to our request.
 */
int
rtmon_get_defaults(void)
{
    int rtsock;
    ssize_t nsent, ssize;
    int ndefrts;

    char *buf = NULL;
    size_t bufsize;

    struct {
        struct nlmsghdr nh;
        struct rtmsg rtm;
        char attrbuf[512];
    } rtreq;

    memset(&rtreq, 0, sizeof(rtreq));
    rtreq.nh.nlmsg_type = RTM_GETROUTE;
    rtreq.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
    rtreq.rtm.rtm_family = AF_INET6;
    rtreq.rtm.rtm_table = RT_TABLE_MAIN;
    rtreq.rtm.rtm_protocol = RTPROT_UNSPEC;

    rtreq.nh.nlmsg_len = NLMSG_SPACE(sizeof(rtreq.rtm));

    bufsize = 1024;
    ssize = bufsize;
    for (;;) {
        char *newbuf;
        int recverr;

        newbuf = (char *)realloc(buf, ssize);
        if (newbuf == NULL) {
            DPRINTF0(("rtmon: failed to %sallocate buffer\n",
                      buf == NULL ? "" : "re"));
            free(buf);
            return -1;
        }

        buf = newbuf;
        bufsize = ssize;

        /* it's easier to reopen than to flush */
        rtsock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        if (rtsock < 0) {
            DPRINTF0(("rtmon: failed to create netlink socket: %s", strerror(errno)));
            free(buf);
            return -1;
        }

        nsent = send(rtsock, &rtreq, rtreq.nh.nlmsg_len, 0);
        if (nsent < 0) {
            DPRINTF0(("rtmon: RTM_GETROUTE failed: %s", strerror(errno)));
            close (rtsock);
            free(buf);
            return -1;
        }

        ssize = recv(rtsock, buf, bufsize, MSG_TRUNC);
        recverr = errno;
        close (rtsock);

        if (ssize < 0) {
            DPRINTF(("rtmon: failed to read RTM_GETROUTE response: %s",
                     strerror(recverr)));
            free(buf);
            return -1;
        }

        if ((size_t)ssize <= bufsize) {
            DPRINTF2(("rtmon: RTM_GETROUTE: %lu bytes\n",
                      (unsigned long)ssize));
            break;
        }

        DPRINTF2(("rtmon: RTM_GETROUTE: truncated %lu to %lu bytes, retrying\n",
                  (unsigned long)ssize, (unsigned long)bufsize));
        /* try again with larger buffer */
    }

    ndefrts = rtmon_check_defaults(buf, (size_t)ssize);
    free(buf);

    if (ndefrts == 0) {
        DPRINTF(("rtmon: no IPv6 default routes found\n"));
    }
    else {
        DPRINTF(("rtmon: %d IPv6 default route%s found\n",
                 ndefrts,
                 ndefrts == 1 || ndefrts == -1 ? "" : "s"));
    }

    return ndefrts;
}
示例#12
0
static void
my_homegrown_redisplay(int hide_passwords)
{
  static int line_start = 0;    /* at which position of prompt_plus_line does the printed line start? */
  static int line_extends_right = 0;
  static int line_extends_left = 0;
  static char *previous_line = NULL;
  
  
  int width = winsize.ws_col;
  int skip = max(1, min(width / 5, 10));        /* jumpscroll this many positions when cursor reaches edge of terminal */
  
  char *prompt_without_ignore_markers;
  int colourless_promptlen = colourless_strlen(rl_prompt, &prompt_without_ignore_markers);
  int promptlen = strlen(prompt_without_ignore_markers);
  int invisible_chars_in_prompt = promptlen - colourless_promptlen;
  char *prompt_plus_line = add2strings(prompt_without_ignore_markers, rl_line_buffer);
  char *new_line;
  int total_length = strlen(prompt_plus_line);
  int curpos = promptlen + rl_point; /* cursor position within prompt_plus_line */
  int i, printed_length,
    new_curpos,                    /* cursor position on screen */
    keep_old_line, vlinestart, printwidth, last_column;
  DPRINTF3(DEBUG_AD_HOC,"rl_prompt: <%s>, prompt_without_ignore_markers: <%s>,  prompt_plus_line: <%s>", rl_prompt, prompt_without_ignore_markers, prompt_plus_line);   

  /* In order to handle prompt with colour we either print the whole prompt, or start past it:
     starting in the middle is too difficult (i.e. I am too lazy) to get it right.
     We use a "virtual line start" vlinestart, which is the number of invisible chars in prompt in the former case, or
     linestart in the latter (which then must be >= strlen(prompt))

     At all times (before redisplay and after) the following is true:
     - the cursor is at column (curpos - vlinestart) (may be < 0 or > width)
     - the character under the cursor is prompt_plus_line[curpos]
     - the character at column 0 is prompt_plus_line[linestart]
     - the last column is at <number of printed visible or invisible chars> - vlinestart
     
     the goal of this function is to display (part of) prompt_plus_line such
     that the cursor is visible again */
     
  
  if (hide_passwords)
    for (i = promptlen; i < total_length; i++)
      prompt_plus_line[i] = '*';        /* hide a pasword by making user input unreadable  */


  if (rl_point == 0)            /* (re)set  at program start and after accept_line (where rl_point is zeroed) */
    line_start = 0;
  assert(line_start == 0 || line_start >= promptlen); /* the line *never* starts in the middle of the prompt (too complicated to handle)*/
  vlinestart = (line_start > promptlen ? line_start : invisible_chars_in_prompt); 
  

  if (curpos - vlinestart > width - line_extends_right) /* cursor falls off right edge ?   */
    vlinestart = (curpos - width + line_extends_right) + skip;  /* jumpscroll left                 */

  else if (curpos < vlinestart + line_extends_left) {   /* cursor falls off left edge ?    */
    if (curpos == total_length) /* .. but still at end of line?    */
      vlinestart = max(0, total_length - width);        /* .. try to display entire line   */
    else                        /* in not at end of line ..        */
      vlinestart = curpos - line_extends_left - skip; /* ... jumpscroll right ..         */
  }     
  if (vlinestart <= invisible_chars_in_prompt) {
    line_start = 0;             /* ... but not past start of line! */
    vlinestart = invisible_chars_in_prompt;
  } else if (vlinestart > invisible_chars_in_prompt && vlinestart <= promptlen) {
    line_start = vlinestart = promptlen;
  } else {
    line_start = vlinestart;
  }

  printwidth = (line_start > 0 ? width : width + invisible_chars_in_prompt);
  printed_length = min(printwidth, total_length - line_start);  /* never print more than width     */
  last_column = printed_length - vlinestart;


  /* some invariants :     0 <= line_start <= curpos <= line_start + printed_length <= total_length */
  /* these are interesting:   ^                                                      ^              */

  assert(0 <= line_start);
  assert(line_start <= curpos);
  assert(curpos <= line_start + printed_length);        /* <=, rather than <, as cursor may be past eol   */
  assert(line_start + printed_length <= total_length);


  new_line = prompt_plus_line + line_start;
  new_line[printed_length] = '\0';
  new_curpos = curpos - vlinestart;

  /* indicate whether line extends past right or left edge  (i.e. whether the "interesting
     inequalities marked ^ above are really unequal) */

  line_extends_left = (line_start > 0 ? 1 : 0);
  line_extends_right = (total_length - vlinestart > width ? 1 : 0);
  if (line_extends_left)
    new_line[0] = '<';
  if (line_extends_right)
    new_line[printwidth - 1] = '>';

  DPRINTF0(DEBUG_AD_HOC, "In the middle...");

  keep_old_line = FALSE;
  if (term_cursor_hpos) {
    if (previous_line && strcmp(new_line, previous_line) == 0) {
      keep_old_line = TRUE;
    } else {
      if (previous_line)
        free(previous_line);
      previous_line = mysavestring(new_line);
    }
  }


  if (!keep_old_line) {
    clear_line();
    cr();
    write_patiently(STDOUT_FILENO, new_line, printed_length, "to stdout");
  }
  
  assert(term_cursor_hpos || !keep_old_line);   /* if we cannot position cursor, we must have reprinted ... */

  if (term_cursor_hpos)
    cursor_hpos(new_curpos);
  else                          /* ... so we know we're 1 past last position on line */
    backspace(last_column - new_curpos);
  free(prompt_plus_line);
  free(prompt_without_ignore_markers);
}
示例#13
0
文件: pxdns.c 项目: bayasist/vbox
static int
pxdns_pmgr_pump(struct pollmgr_handler *handler, SOCKET fd, int revents)
{
    struct pxdns *pxdns;
    struct request *req;
    ssize_t nread;
    err_t error;
    u16_t id;

    pxdns = (struct pxdns *)handler->data;
    LWIP_ASSERT1(handler == &pxdns->pmhdl4 || handler == &pxdns->pmhdl6);
    LWIP_ASSERT1(fd == (handler == &pxdns->pmhdl4 ? pxdns->sock4 : pxdns->sock6));

    if (revents & ~(POLLIN|POLLERR)) {
        DPRINTF0(("%s: unexpected revents 0x%x\n", __func__, revents));
        return POLLIN;
    }

    if (revents & POLLERR) {
        int sockerr = -1;
        socklen_t optlen = (socklen_t)sizeof(sockerr);
        int status;

        status = getsockopt(fd, SOL_SOCKET,
                            SO_ERROR, (char *)&sockerr, &optlen);
        if (status < 0) {
            DPRINTF(("%s: sock %d: SO_ERROR failed: %R[sockerr]\n",
                     __func__, fd, SOCKERRNO()));
        }
        else {
            DPRINTF(("%s: sock %d: %R[sockerr]\n",
                     __func__, fd, sockerr));
        }
    }

    if ((revents & POLLIN) == 0) {
        return POLLIN;
    }


    nread = recv(fd, pollmgr_udpbuf, sizeof(pollmgr_udpbuf), 0);
    if (nread < 0) {
        DPRINTF(("%s: %R[sockerr]\n", __func__, SOCKERRNO()));
        return POLLIN;
    }

    /* check for minimum dns packet length */
    if (nread < 12) {
        DPRINTF2(("%s: short reply %lu bytes\n",
                  __func__, (unsigned long)nread));
        return POLLIN;
    }

    /* XXX: shall we proxy back RCODE=Refused responses? */

    memcpy(&id, pollmgr_udpbuf, sizeof(id));
    req = pxdns_request_find(pxdns, id);
    if (req == NULL) {
        DPRINTF2(("%s: orphaned reply for %d\n", __func__, id));
        ++pxdns->late_answers;
        return POLLIN;
    }

    DPRINTF2(("%s: reply for req=%p: id %d -> client id %d\n",
              __func__, (void *)req, req->id, req->client_id));

    req->reply = pbuf_alloc(PBUF_RAW, nread, PBUF_RAM);
    if (req->reply == NULL) {
        DPRINTF(("%s: pbuf_alloc(%d) failed\n", __func__, (int)nread));
        pxdns_request_free(req);
        return POLLIN;
    }

    memcpy(pollmgr_udpbuf, &req->client_id, sizeof(req->client_id));
    error = pbuf_take(req->reply, pollmgr_udpbuf, nread);
    if (error != ERR_OK) {
        DPRINTF(("%s: pbuf_take(%d) failed\n", __func__, (int)nread));
        pxdns_request_free(req);
        return POLLIN;
    }

    proxy_lwip_post(&req->msg_reply);
    return POLLIN;
}
示例#14
0
文件: main.c 项目: albfan/rlwrap
/* Read history and completion word lists */
void
init_rlwrap()
{

  char *homedir, *histdir, *homedir_prefix, *hostname;
  time_t now;
  
  /* open debug file if necessary */

  if (debug) {    
    debug_fp = fopen(DEBUG_FILENAME, "w");
    if (!debug_fp)
      myerror("Couldn't open debug file %s", DEBUG_FILENAME);
    setbuf(debug_fp, NULL); /* always write debug messages to disk at once */
  }
  hostname = getenv("HOSTNAME") ? getenv("HOSTNAME") : "?";
  now = time(NULL);
  DPRINTF0(DEBUG_ALL, "-*- mode: grep -*-");
  DPRINTF3(DEBUG_ALL, "rlwrap version %s, host: %s, time: %s", VERSION, hostname, ctime(&now));
  init_terminal();

  
  
  /* Determine rlwrap home dir and prefix for default history and completion filenames */
  homedir = (getenv("RLWRAP_HOME") ? getenv("RLWRAP_HOME") : getenv("HOME"));
  homedir_prefix = (getenv("RLWRAP_HOME") ?                    /* is RLWRAP_HOME set?                */
		    add2strings(getenv("RLWRAP_HOME"), "/") :  /* use $RLWRAP_HOME/<command>_history */
		    add2strings(getenv("HOME"), "/."));	       /* if not, use ~/.<command>_history   */

  /* Determine history file name and check its existence and permissions */

  if (history_filename) {
    histdir = mydirname(history_filename);
  } else {
    histdir = homedir;
    history_filename = add3strings(homedir_prefix, command_name, "_history");
  }
  
  if (write_histfile) {
    if (access(history_filename, F_OK) == 0) {	/* already exists, can we read/write it? */
      if (access(history_filename, R_OK | W_OK) != 0) {
	myerror("cannot read and write %s", history_filename);
      }
    } else {			        /* doesn't exist, can we create it? */
      if(access(histdir, W_OK) != 0) {
        if (errno == ENOENT) {
          mode_t oldmask = umask(0);
          if (mkdir(histdir, 0700))       /* rwx------ */
            myerror("cannot create directory %s", histdir);
          umask(oldmask);
        } else {
          myerror("cannot create history file in %s", histdir);
        }
      }
    }
  } else {			/* ! write_histfile */
    if (access(history_filename, R_OK) != 0) {
      myerror("cannot read %s", history_filename);
    }
  }

  /* Initialize history */
  using_history();
  stifle_history(histsize);
  read_history(history_filename);	/* ignore errors here: history file may not yet exist, but will be created on exit */

  if (feed_history_into_completion_list)
    feed_file_into_completion_list(history_filename);
  /* Determine completion file name (completion files are never written to,
     and ignored when unreadable or non-existent) */

  completion_filename =
    add3strings(homedir_prefix, command_name, "_completions");
  default_completion_filename =
    add3strings(DATADIR, "/rlwrap/completions/", command_name);

  rl_readline_name = command_name;

  /* Initialise completion list (if <completion_filename> is readable) */
  if (access(completion_filename, R_OK) == 0) {
    feed_file_into_completion_list(completion_filename);
  } else if (access(default_completion_filename, R_OK) == 0) {
    feed_file_into_completion_list(default_completion_filename);
  }

  
}
示例#15
0
文件: main.c 项目: albfan/rlwrap
/*
 * main loop: listen on stdin (for user input) and master pty (for command output),
 * and try to write output_queue to master_pty (if it is not empty)
 * This function never returns.
 */
void
main_loop()
{				
  int nfds;			
  fd_set readfds;	
  fd_set writefds;
  int nread;		
  char buf[BUFFSIZE], *timeoutstr, *old_raw_prompt, *new_output_minus_prompt;
  int promptlen = 0;
  int leave_prompt_alone;
  sigset_t no_signals_blocked;
   
  struct timespec         select_timeout, *select_timeoutptr;
  struct timespec immediately = { 0, 0 }; /* zero timeout when child is dead */
  struct timespec  wait_a_little = {0, 0xBadf00d }; /* tv_usec field will be filled in when initialising */
  struct timespec  *forever = NULL;
  wait_a_little.tv_nsec = 1000 * 1000 * wait_before_prompt;

  
  
  sigemptyset(&no_signals_blocked);
  

  init_readline("");
  last_minute_checks();
  pass_through_filter(TAG_OUTPUT,""); /* If something is wrong with filter, get the error NOW */
  set_echo(FALSE);		/* This will also put the terminal in CBREAK mode */
	test_main(); 
  
  /* ------------------------------  main loop  -------------------------------*/
  while (TRUE) {
    /* listen on both stdin and pty_fd */
    FD_ZERO(&readfds);
    FD_SET(STDIN_FILENO, &readfds);
    FD_SET(master_pty_fd, &readfds);

    /* try to write output_queue to master_pty (but only if it is nonempty) */
    FD_ZERO(&writefds);
    if (output_queue_is_nonempty())
      FD_SET(master_pty_fd, &writefds);



    DPRINTF1(DEBUG_AD_HOC, "prompt_is_still_uncooked =  %d", prompt_is_still_uncooked);
    if (command_is_dead || ignore_queued_input) {
      select_timeout = immediately;
      select_timeoutptr = &select_timeout;
      timeoutstr = "immediately";
    } else if (prompt_is_still_uncooked) {
      select_timeout = wait_a_little;
      select_timeoutptr = &select_timeout;
      timeoutstr = "wait_a_little";
    } else {
      select_timeoutptr = forever; /* NULL */
      timeoutstr = "forever";
    }
     
    DPRINTF1(DEBUG_TERMIO, "calling select() with timeout %s",  timeoutstr);
    

    nfds = my_pselect(1 + master_pty_fd, &readfds, &writefds, NULL, select_timeoutptr, &no_signals_blocked);

    DPRINTF3(DEBUG_TERMIO, "select() returned  %d (stdin|pty in|pty out = %03d), within_line_edit=%d", nfds,
	     100*(FD_ISSET(STDIN_FILENO, &readfds)?1:0) + 10*(FD_ISSET(master_pty_fd, &readfds)?1:0) + (FD_ISSET(master_pty_fd, &writefds)?1:0), 
	     within_line_edit);

    assert(!filter_pid || filter_is_dead || kill(filter_pid,0) == 0); 
    assert(command_is_dead || kill(command_pid,0) == 0);
    
    /* check flags that may have been set by signal handlers */
    if (filter_is_dead) 
      filters_last_words(); /* will call myerror with last words */
      	
    if (received_WINCH) {  /* received_WINCH flag means we've had a WINCH while within_line_edit was FALSE */
      DPRINTF0(DEBUG_READLINE, "Starting line edit as a result of WINCH ");
      within_line_edit = TRUE;
      restore_rl_state();
      received_WINCH = FALSE;
      continue;
    }	
    
    if (nfds < 0) {		/* exception  */	
      if (errno == EINTR) {	/* interrupted by signal */
	continue;
      }	else
	myerror("select received exception");
    } else if (nfds == 0) {
      
      /* timeout, which can only happen when .. */
      if (ignore_queued_input) {       /* ... we have read all the input keystrokes that should
					  be ignored (i.e. those that accumulated on stdin while we
				          were calling an external editor) */
	ignore_queued_input = FALSE;
	continue;
      } else if (command_is_dead) {                         /* ... or else, if child is dead, ... */
	DPRINTF2(DEBUG_SIGNALS,
		 "select returned 0, command_is_dead=%d, commands_exit_status=%d",
		 command_is_dead, commands_exit_status);
	cleanup_rlwrap_and_exit(EXIT_SUCCESS);
      }	else if (prompt_is_still_uncooked) { /* cooking time? */
	if (we_just_got_a_signal_or_EOF) {
	  we_just_got_a_signal_or_EOF = FALSE;              /* 1. If we got a signal/EOF before cooking time, we don't need special action
                                                                  to preserve the cooked prompt.
							       2. Reset we_just_got_a_signal_or_EOF  after a signal or EOF that didn't kill command */
          continue;
	}	
	if (!skip_rlwrap()) {                        /* ... or else, it is time to cook the prompt */
	  if (pre_given && accepted_lines == 0) {
	    saved_rl_state.input_buffer = mysavestring(pre_given); /* stuff pre-given text into edit buffer */
	    saved_rl_state.point =  strlen(pre_given);
	    DPRINTF0(DEBUG_READLINE, "Starting line edit (because of -P option)");
	    within_line_edit = TRUE;
	    restore_rl_state();

	    continue;
	  }
	  
	  if (accepted_lines == 1 && one_shot_rlwrap) 
	    cleanup_rlwrap_and_exit(EXIT_SUCCESS);

			  
	  move_cursor_to_start_of_prompt(ERASE); /* cooked prompt may be shorter than raw prompt, hence the ERASE */
	  /* move and erase before cooking, as we need to move/erase according
	     to the raw prompt */
          cook_prompt_if_necessary();
	  DPRINTF2(DEBUG_READLINE,"After cooking, raw_prompt=%s, cooked=%s",
                   mangle_string_for_debug_log(saved_rl_state.raw_prompt, MANGLE_LENGTH),
                   mangle_string_for_debug_log(saved_rl_state.cooked_prompt, MANGLE_LENGTH));
	  my_putstr(saved_rl_state.cooked_prompt);
	  rlwrap_already_prompted = TRUE;
	}
	prompt_is_still_uncooked = FALSE;
      } else {
	myerror("unexpected select() timeout");
      }
    } else if (nfds > 0) {	/* Hah! something to read or write */ 

      /* -------------------------- read pty --------------------------------- */
      if (FD_ISSET(master_pty_fd, &readfds)) { /* there is something to read on master pty: */
	if ((nread = read(master_pty_fd, buf, BUFFSIZE - 1)) <= 0) { /* read it */
	 
	  if (command_is_dead || nread == 0) { /*  child is dead or has closed its stdout */
	    if (promptlen > 0)	/* commands dying words were not terminated by \n ... */
	      my_putchar('\n');	/* provide the missing \n */
	    cleanup_rlwrap_and_exit(EXIT_SUCCESS);
	  } else  if (errno == EINTR)	/* interrupted by signal ...*/	                     
	    continue;                   /* ... don't worry */
	  else
	    myerror("read error on master pty");
	}
	  
	completely_mirror_slaves_output_settings(); /* some programs (e.g. joe) need this. Gasp!! */	
        
	
        if (skip_rlwrap()) { /* Race condition here! The client may just have finished an emacs session and
			        returned to cooked mode, while its ncurses-riddled output is stil waiting for us to be processed. */
	  write_patiently(STDOUT_FILENO, buf, nread, "to stdout");

	  DPRINTF2(DEBUG_TERMIO, "read from pty and wrote to stdout  %d  bytes in direct mode  <%s>",
                   nread, mangle_string_for_debug_log((buf[nread]='\0', buf), MANGLE_LENGTH));
	  yield();
	  continue;
	}

	DPRINTF2(DEBUG_TERMIO, "read %d bytes from pty into buffer: %s", nread,  mangle_string_for_debug_log((buf[nread]='\0', buf), MANGLE_LENGTH));
        
        remove_padding_and_terminate(buf, nread);
        
	write_logfile(buf);
	if (within_line_edit)	/* client output arrives while we're editing keyboard input:  */
	  save_rl_state();      /* temporarily disable readline and restore the screen state before readline was called */
  

	assert(saved_rl_state.raw_prompt != NULL);


        /* We *always* compute the printable part and the new raw prompt, and *always* print the printable part
           There are four possibilities:
           1. impatient before cooking.         The raw prompt has been printed,  write the new output after it
           2. patient before cooking            No raw prompt has been printed yet, don't print anything
           3. impatient after cooking
             3a  no current prompt              print the new output
             3b  some current prompt            erase it, replace by current raw prompt and print new output
           4. patient after cooking             don't print anything
        */
        
        /* sometimes we want to leave the prompt standing, e.g. after accepting a line, or when a signal arrived */
	leave_prompt_alone =
	     *saved_rl_state.raw_prompt == '\0' /* saved_rl_state.raw_prompt = "" in two distinct cases: when there is actually no prompt,
						   or just after accepting a line, when the cursor is at the end of the prompt. In both
						   cases, we dont't want to move the cursor */
          || prompt_is_still_uncooked /* in this case no prompt has been displayed yet */
          || command_is_dead                    
          || (we_just_got_a_signal_or_EOF && strrchr(buf, '\n')); /* a signal followed by output with a newline in it: treat it as
                                                                     response to user input, so leave the prompt alone */

        DPRINTF3(DEBUG_READLINE, "leave_prompt_alone: %s (raw prompt: %s, prompt_is_still_uncooked: %d)",
                 (leave_prompt_alone? "yes" : "no"), mangle_string_for_debug_log(saved_rl_state.raw_prompt, MANGLE_LENGTH), prompt_is_still_uncooked);
	
        if (!leave_prompt_alone) /* && (!impatient_prompt || !saved_rl_state.cooked_prompt)) */
	  move_cursor_to_start_of_prompt(ERASE);  
	else if (we_just_got_a_signal_or_EOF) {
	  free (saved_rl_state.raw_prompt);
	  saved_rl_state.raw_prompt =  mysavestring(""); /* prevent reprinting the prompt */
	}	

        if (impatient_prompt && !leave_prompt_alone)
          old_raw_prompt =  mysavestring(saved_rl_state.raw_prompt);

        new_output_minus_prompt = process_new_output(buf, &saved_rl_state);	/* chop off the part after the last newline and put this in
										   saved_rl_state.raw_prompt (or append buf if  no newline found)*/

	if (impatient_prompt) {   /* in impatient mode, ALL command output is passed through the OUTPUT filter, including the prompt The
				     prompt, however, is filtered separately at cooking time and then displayed */
	  char *filtered = pass_through_filter(TAG_OUTPUT, buf);
          if(!leave_prompt_alone) {
            my_putstr(old_raw_prompt);
            free(old_raw_prompt);
          }
	  my_putstr(filtered);
	  free (filtered);
	  rlwrap_already_prompted = TRUE;
	} else {
	  my_putstr(new_output_minus_prompt);
	  rlwrap_already_prompted = FALSE;
	}	
	   
	free(new_output_minus_prompt);	

		    
	prompt_is_still_uncooked = TRUE; 
       

	if (within_line_edit)
	  restore_rl_state();

	yield();  /* wait for what client has to say .... */ 
	continue; /* ... and don't attempt to process keyboard input as long as it is talking ,
		     in order to avoid re-printing the current prompt (i.e. unfinished output line) */
      }

      
      /* ----------------------------- key pressed: read stdin -------------------------*/
      if (FD_ISSET(STDIN_FILENO, &readfds)) {	/* key pressed */
	unsigned char byte_read;                /* the readline function names and documentation talk about "characters" and "keys",
						   but we're reading bytes (i.e. unsigned chars) here, and those may very well be
						   part of a multi-byte character. Example: hebrew "aleph" in utf-8 is 0xd790; pressing this key
						   will make us read 2 bytes 0x90 and then 0xd7, (or maybe the other way round depending on endianness??)
						   The readline library hides all this complexity and allows one to just "pass the bytes around" */
	nread = read(STDIN_FILENO, &byte_read, 1);  /* read next byte of input   */
	assert(sizeof(unsigned char) == 1);      /* gets optimised away */

	if (nread <= 0) 
	  DPRINTF1(DEBUG_TERMIO, "read from stdin returned %d", nread); 
	if (nread < 0)
	  if (errno == EINTR)
	    continue;
	  else
	    myerror("Unexpected error");
	else if (nread == 0)	/* EOF on stdin */
	  cleanup_rlwrap_and_exit(EXIT_SUCCESS);
        else if (ignore_queued_input)
	  continue;             /* do nothing with it*/
	assert(nread == 1);
	DPRINTF2(DEBUG_TERMIO, "read from stdin: byte 0x%02x (%s)", byte_read, mangle_char_for_debug_log(byte_read, TRUE)); 
	if (skip_rlwrap()) {	/* direct mode, just pass it on */
	                        /* remote possibility of a race condition here: when the first half of a multi-byte char is read in
				   direct mode and the second half in readline mode. Oh well... */
	  DPRINTF0(DEBUG_TERMIO, "passing it on (in transparent mode)");	
	  completely_mirror_slaves_terminal_settings(); /* this is of course 1 keypress too late: we should
							   mirror the terminal settings *before* the user presses a key.
							   (maybe using rl_event_hook??)   @@@FIXME  @@@ HOW?*/
          write_patiently(master_pty_fd, &byte_read, 1, "to master pty");
	} else {		/* hand it over to readline */
	  if (!within_line_edit) {	/* start a new line edit    */
	    DPRINTF0(DEBUG_READLINE, "Starting line edit");
	    within_line_edit = TRUE;
	    restore_rl_state();
	  } 
	                                        
	  
	  

	  if (term_eof && byte_read == term_eof && strlen(rl_line_buffer) == 0) {	/* hand a term_eof (usually CTRL-D) directly to command */ 
	    char *sent_EOF = mysavestring("?");
	    *sent_EOF = term_eof;
	    put_in_output_queue(sent_EOF);
	    we_just_got_a_signal_or_EOF = TRUE;
	    free(sent_EOF);
	  }	
	  else {
	    rl_stuff_char(byte_read);  /* stuff it back in readline's input queue */
	    DPRINTF0(DEBUG_TERMIO, "passing it to readline");	
	    DPRINTF2(DEBUG_READLINE, "rl_callback_read_char() (_rl_eof_char=%d, term_eof=%d)", _rl_eof_char, term_eof);
	    rl_callback_read_char();
	  }
	}
      }
    
      /* -------------------------- write pty --------------------------------- */
      if (FD_ISSET(master_pty_fd, &writefds)) {
	flush_output_queue();
	yield(); /*  give  slave command time to respond. If we don't do this,
		     nothing bad will happen, but the "dialogue" on screen will be
		     out of order   */
      }
    }				/* if (ndfs > 0)         */
  }				/* while (1)             */
}				/* void main_loop()      */