NOEXPORT SOCKET connect_local(CLI *c) { /* spawn local process */
    int fd[2], pid;
    char **env;
#ifdef HAVE_PTHREAD_SIGMASK
    sigset_t newmask;
#endif

    if(c->opt->option.pty) {
        char tty[64];

        if(pty_allocate(fd, fd+1, tty))
            throw_exception(c, 1);
        s_log(LOG_DEBUG, "TTY=%s allocated", tty);
    } else
        if(make_sockets(fd))
            throw_exception(c, 1);
    set_nonblock(fd[1], 0); /* switch back to the blocking mode */

    env=env_alloc(c);
    pid=fork();
    c->pid=(unsigned long)pid;
    switch(pid) {
    case -1:    /* error */
        closesocket(fd[0]);
        closesocket(fd[1]);
        env_free(env);
        ioerror("fork");
        throw_exception(c, 1);
    case  0:    /* child */
        /* the child is not allowed to play with thread-local storage */
        /* see http://linux.die.net/man/3/pthread_atfork for details */
        closesocket(fd[0]);
        /* dup2() does not copy FD_CLOEXEC flag */
        dup2(fd[1], 0);
        dup2(fd[1], 1);
        if(!c->opt->option.log_stderr)
            dup2(fd[1], 2);
        closesocket(fd[1]); /* not really needed due to FD_CLOEXEC */
#ifdef HAVE_PTHREAD_SIGMASK
        sigemptyset(&newmask);
        sigprocmask(SIG_SETMASK, &newmask, NULL);
#endif
        signal(SIGCHLD, SIG_DFL);
        signal(SIGHUP, SIG_DFL);
        signal(SIGUSR1, SIG_DFL);
        signal(SIGUSR2, SIG_DFL);
        signal(SIGPIPE, SIG_DFL);
        signal(SIGTERM, SIG_DFL);
        signal(SIGQUIT, SIG_DFL);
        signal(SIGINT, SIG_DFL);
        execve(c->opt->exec_name, c->opt->exec_args, env);
        _exit(1); /* failed, but there is no way to report an error here */
    default: /* parent */
        closesocket(fd[1]);
        env_free(env);
        s_log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid);
        return fd[0];
    }
}
NOEXPORT SOCKET connect_local(CLI *c) {  
    int fd[2], pid;
    char **env;
#ifdef HAVE_PTHREAD_SIGMASK
    sigset_t newmask;
#endif

    if(c->opt->option.pty) {
        char tty[64];

        if(pty_allocate(fd, fd+1, tty))
            throw_exception(c, 1);
        s_log(LOG_DEBUG, "TTY=%s allocated", tty);
    } else
        if(make_sockets(fd))
            throw_exception(c, 1);
    set_nonblock(fd[1], 0);  

    env=env_alloc(c);
    pid=fork();
    c->pid=(unsigned long)pid;
    switch(pid) {
    case -1:     
        closesocket(fd[0]);
        closesocket(fd[1]);
        env_free(env);
        ioerror("fork");
        throw_exception(c, 1);
    case  0:     
         
         
        closesocket(fd[0]);
         
        dup2(fd[1], 0);
        dup2(fd[1], 1);
        if(!c->opt->option.log_stderr)
            dup2(fd[1], 2);
        closesocket(fd[1]);  
#ifdef HAVE_PTHREAD_SIGMASK
        sigemptyset(&newmask);
        sigprocmask(SIG_SETMASK, &newmask, NULL);
#endif
        signal(SIGCHLD, SIG_DFL);
        signal(SIGHUP, SIG_DFL);
        signal(SIGUSR1, SIG_DFL);
        signal(SIGUSR2, SIG_DFL);
        signal(SIGPIPE, SIG_DFL);
        signal(SIGTERM, SIG_DFL);
        signal(SIGQUIT, SIG_DFL);
        signal(SIGINT, SIG_DFL);
        execve(c->opt->exec_name, c->opt->exec_args, env);
        _exit(1);  
    default:  
        closesocket(fd[1]);
        env_free(env);
        s_log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid);
        return fd[0];
    }
}