예제 #1
0
topic_monitor_t::topic_monitor_t() {
    // Set up our pipes. Assert it succeeds.
    auto pipes = make_autoclose_pipes({});
    assert(pipes.has_value() && "Failed to make pubsub pipes");
    pipes_ = pipes.acquire();

    // Make sure that our write side doesn't block, else we risk hanging in a signal handler.
    // The read end must block to avoid spinning in await.
    DIE_ON_FAILURE(make_fd_nonblocking(pipes_.write.fd()));

#if TOPIC_MONITOR_TSAN_WORKAROUND
    DIE_ON_FAILURE(make_fd_nonblocking(pipes_.read.fd()));
#endif
}
예제 #2
0
파일: io.cpp 프로젝트: Aulos/fish-shell
io_buffer_t *io_buffer_t::create(int fd)
{
    bool success = true;
    assert(fd >= 0);
    io_buffer_t *buffer_redirect = new io_buffer_t(fd);

    if (exec_pipe(buffer_redirect->pipe_fd) == -1)
    {
        debug(1, PIPE_ERROR);
        wperror(L"pipe");
        success = false;
    }
    else if (make_fd_nonblocking(buffer_redirect->pipe_fd[0]) != 0)
    {
        debug(1, PIPE_ERROR);
        wperror(L"fcntl");
        success = false;
    }

    if (! success)
    {
        delete buffer_redirect;
        buffer_redirect = NULL;
    }
    else
    {
        //fprintf(stderr, "Created pipes {%d, %d} for %p\n", buffer_redirect->pipe_fd[0], buffer_redirect->pipe_fd[1], buffer_redirect);
    }

    return buffer_redirect;
}
예제 #3
0
shared_ptr<io_bufferfill_t> io_bufferfill_t::create(const io_chain_t &conflicts,
                                                    size_t buffer_limit) {
    // Construct our pipes.
    auto pipes = make_autoclose_pipes(conflicts);
    if (!pipes) {
        return nullptr;
    }
    // Our buffer will read from the read end of the pipe. This end must be non-blocking. This is
    // because our fillthread needs to poll to decide if it should shut down, and also accept input
    // from direct buffer transfers.
    if (make_fd_nonblocking(pipes->read.fd())) {
        debug(1, PIPE_ERROR);
        wperror(L"fcntl");
        return nullptr;
    }
    // Our fillthread gets the read end of the pipe; out_pipe gets the write end.
    auto buffer = std::make_shared<io_buffer_t>(buffer_limit);
    buffer->begin_background_fillthread(std::move(pipes->read));
    return std::make_shared<io_bufferfill_t>(std::move(pipes->write), buffer);
}
예제 #4
0
파일: io.cpp 프로젝트: elnappo/fish-shell
shared_ptr<io_buffer_t> io_buffer_t::create(int fd, const io_chain_t &conflicts,
                                            size_t buffer_limit) {
    bool success = true;
    assert(fd >= 0);
    shared_ptr<io_buffer_t> buffer_redirect(new io_buffer_t(fd, buffer_limit));

    if (exec_pipe(buffer_redirect->pipe_fd) == -1) {
        debug(1, PIPE_ERROR);
        wperror(L"pipe");
        success = false;
    } else if (!buffer_redirect->avoid_conflicts_with_io_chain(conflicts)) {
        // The above call closes the fds on error.
        success = false;
    } else if (make_fd_nonblocking(buffer_redirect->pipe_fd[0]) != 0) {
        debug(1, PIPE_ERROR);
        wperror(L"fcntl");
        success = false;
    }

    if (!success) {
        buffer_redirect.reset();
    }
    return buffer_redirect;
}
예제 #5
0
파일: io.cpp 프로젝트: haarts/fish-shell
io_buffer_t *io_buffer_t::create(int fd, const io_chain_t &conflicts) {
    bool success = true;
    assert(fd >= 0);
    io_buffer_t *buffer_redirect = new io_buffer_t(fd);

    if (exec_pipe(buffer_redirect->pipe_fd) == -1) {
        debug(1, PIPE_ERROR);
        wperror(L"pipe");
        success = false;
    } else if (!buffer_redirect->avoid_conflicts_with_io_chain(conflicts)) {
        // The above call closes the fds on error.
        success = false;
    } else if (make_fd_nonblocking(buffer_redirect->pipe_fd[0]) != 0) {
        debug(1, PIPE_ERROR);
        wperror(L"fcntl");
        success = false;
    }

    if (!success) {
        delete buffer_redirect;
        buffer_redirect = NULL;
    }
    return buffer_redirect;
}
예제 #6
0
/**
   Main function for fishd
*/
int main(int argc, char ** argv)
{
    int child_socket;
    struct sockaddr_un remote;
    socklen_t t;
    uid_t sock_euid;
    gid_t sock_egid;
    int max_fd;
    int update_count=0;

    fd_set read_fd, write_fd;

    set_main_thread();
    setup_fork_guards();

    program_name=L"fishd";
    wsetlocale(LC_ALL, L"");

    /*
      Parse options
    */
    while (1)
    {
        static struct option
                long_options[] =
        {
            {
                "help", no_argument, 0, 'h'
            }
            ,
            {
                "version", no_argument, 0, 'v'
            }
            ,
            {
                0, 0, 0, 0
            }
        }
        ;

        int opt_index = 0;

        int opt = getopt_long(argc,
                              argv,
                              GETOPT_STRING,
                              long_options,
                              &opt_index);

        if (opt == -1)
            break;

        switch (opt)
        {
            case 0:
                break;

            case 'h':
                print_help(argv[0], 1);
                exit(0);

            case 'v':
                debug(0, L"%ls, version %s\n", program_name, FISH_BUILD_VERSION);
                exit(0);

            case '?':
                return 1;

        }
    }

    init();
    while (1)
    {
        int res;

        t = sizeof(remote);

        FD_ZERO(&read_fd);
        FD_ZERO(&write_fd);
        FD_SET(sock, &read_fd);
        max_fd = sock+1;
        for (connection_list_t::const_iterator iter = connections.begin(); iter != connections.end(); ++iter)
        {
            const connection_t &c = *iter;
            FD_SET(c.fd, &read_fd);
            max_fd = maxi(max_fd, c.fd+1);

            if (! c.unsent.empty())
            {
                FD_SET(c.fd, &write_fd);
            }
        }

        while (1)
        {
            res=select(max_fd, &read_fd, &write_fd, 0, 0);

            if (quit)
            {
                save();
                exit(0);
            }

            if (res != -1)
                break;

            if (errno != EINTR)
            {
                wperror(L"select");
                exit(1);
            }
        }

        if (FD_ISSET(sock, &read_fd))
        {
            if ((child_socket =
                        accept(sock,
                               (struct sockaddr *)&remote,
                               &t)) == -1)
            {
                wperror(L"accept");
                exit(1);
            }
            else
            {
                debug(4, L"Connected with new child on fd %d", child_socket);

                if (((getpeereid(child_socket, &sock_euid, &sock_egid) != 0) || sock_euid != geteuid()))
                {
                    debug(1, L"Wrong credentials for child on fd %d", child_socket);
                    close(child_socket);
                }
                else if (make_fd_nonblocking(child_socket) != 0)
                {
                    wperror(L"fcntl");
                    close(child_socket);
                }
                else
                {
                    connections.push_front(connection_t(child_socket));
                    connection_t &newc = connections.front();
                    send(newc.fd, GREETING, strlen(GREETING), MSG_DONTWAIT);
                    enqueue_all(&newc);
                }
            }
        }

        for (connection_list_t::iterator iter = connections.begin(); iter != connections.end(); ++iter)
        {
            if (FD_ISSET(iter->fd, &write_fd))
            {
                try_send_all(&*iter);
            }
        }

        for (connection_list_t::iterator iter = connections.begin(); iter != connections.end(); ++iter)
        {
            if (FD_ISSET(iter->fd, &read_fd))
            {
                read_message(&*iter);

                /*
                  Occasionally we save during normal use, so that we
                  won't lose everything on a system crash
                */
                update_count++;
                if (update_count >= 64)
                {
                    save();
                    update_count = 0;
                }
            }
        }

        for (connection_list_t::iterator iter = connections.begin(); iter != connections.end();)
        {
            if (iter->killme)
            {
                debug(4, L"Close connection %d", iter->fd);

                while (! iter->unsent.empty())
                {
                    message_t *msg = iter->unsent.front();
                    iter->unsent.pop();
                    msg->count--;
                    if (! msg->count)
                        free(msg);
                }

                connection_destroy(&*iter);
                iter = connections.erase(iter);
            }
            else
            {
                ++iter;
            }
        }

        if (connections.empty())
        {
            debug(0, L"No more clients. Quitting");
            save();
            break;
        }

    }
}
예제 #7
0
/**
   Connects to the fish socket and starts listening for connections
*/
static int get_socket(void)
{
    // Cygwin has random problems involving sockets. When using Cygwin,
    // allow 20 attempts at making socket correctly.
#ifdef __CYGWIN__
    int attempts = 0;
repeat:
    attempts += 1;
#endif

    int s, len, doexit = 0;
    int exitcode = EXIT_FAILURE;
    struct sockaddr_un local;
    const std::string sock_name = get_socket_filename();

    /*
       Start critical section protected by lock
    */
    std::string lockfile;
    if (! acquire_socket_lock(sock_name, &lockfile))
    {
        debug(0, L"Unable to obtain lock on socket, exiting");
        exit(EXIT_FAILURE);
    }
    debug(4, L"Acquired lockfile: %s", lockfile.c_str());

    local.sun_family = AF_UNIX;
    strcpy(local.sun_path, sock_name.c_str());
    len = sizeof(local);

    debug(1, L"Connect to socket at %s", sock_name.c_str());

    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
    {
        wperror(L"socket");
        doexit = 1;
        goto unlock;
    }

    /*
       First check whether the socket has been opened by another fishd;
       if so, exit with success status
    */
    if (connect(s, (struct sockaddr *)&local, len) == 0)
    {
        debug(1, L"Socket already exists, exiting");
        doexit = 1;
        exitcode = 0;
        goto unlock;
    }

    unlink(local.sun_path);
    if (bind(s, (struct sockaddr *)&local, len) == -1)
    {
        wperror(L"bind");
        doexit = 1;
        goto unlock;
    }

    if (make_fd_nonblocking(s) != 0)
    {
        wperror(L"fcntl");
        close(s);
        doexit = 1;
    }
    else if (listen(s, 64) == -1)
    {
        wperror(L"listen");
        doexit = 1;
    }

unlock:
    (void)unlink(lockfile.c_str());
    debug(4, L"Released lockfile: %s", lockfile.c_str());
    /*
       End critical section protected by lock
    */

    if (doexit)
    {
        // If Cygwin, only allow normal quit when made lots of attempts.
#ifdef __CYGWIN__
        if (exitcode && attempts < 20) goto repeat;
#endif
        exit_without_destructors(exitcode);
    }

    return s;
}
예제 #8
0
static int try_get_socket_once(void)
{
    int s;

    wchar_t *wdir;
    wchar_t *wuname;
    char *dir = 0;

    wdir = path;
    wuname = user;

    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
    {
        wperror(L"socket");
        return -1;
    }

    if (wdir)
        dir = wcs2str(wdir);
    else
        dir = strdup("/tmp");

    std::string uname;
    if (wuname)
    {
        uname = wcs2string(wuname);
    }
    else
    {
        struct passwd *pw = getpwuid(getuid());
        if (pw && pw->pw_name)
        {
            uname = pw->pw_name;
        }
    }

    std::string name;
    name.reserve(strlen(dir) + uname.size() + strlen(SOCK_FILENAME) + 2);
    name.append(dir);
    name.append("/");
    name.append(SOCK_FILENAME);
    name.append(uname);

    free(dir);

    debug(3, L"Connect to socket %s at fd %d", name.c_str(), s);

    struct sockaddr_un local = {};
    local.sun_family = AF_UNIX;
    strncpy(local.sun_path, name.c_str(), (sizeof local.sun_path) - 1);

    if (connect(s, (struct sockaddr *)&local, sizeof local) == -1)
    {
        close(s);

        /* If it fails on first try, it's probably no serious error, but fishd hasn't been launched yet.
         This happens (at least) on the first concurrent session. */
        if (get_socket_count > 1)
            wperror(L"connect");

        return -1;
    }

    if ((make_fd_nonblocking(s) != 0) || (fcntl(s, F_SETFD, FD_CLOEXEC) != 0))
    {
        wperror(L"fcntl");
        close(s);

        return -1;
    }

    debug(3, L"Connected to fd %d", s);

    return s;
}