static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd, const char *lxcpath, const char *hashed_sock_name) { __do_close_prot_errno int client_fd = -EBADF; ssize_t ret = -1; client_fd = lxc_cmd_connect(name, lxcpath, hashed_sock_name, "command"); if (client_fd < 0) return -1; ret = lxc_abstract_unix_send_credential(client_fd, &cmd->req, sizeof(cmd->req)); if (ret < 0 || (size_t)ret != sizeof(cmd->req)) return -1; if (cmd->req.datalen <= 0) return move_fd(client_fd); errno = EMSGSIZE; ret = lxc_send_nointr(client_fd, (void *)cmd->req.data, cmd->req.datalen, MSG_NOSIGNAL); if (ret < 0 || ret != (ssize_t)cmd->req.datalen) return -1; return move_fd(client_fd); }
/* * lxc_cmd: Connect to the specified running container, send it a command * request and collect the response * * @name : name of container to connect to * @cmd : command with initialized request to send * @stopped : output indicator if the container was not running * @lxcpath : the lxcpath in which the container is running * * Returns the size of the response message on success, < 0 on failure * * Note that there is a special case for LXC_CMD_CONSOLE. For this command * the fd cannot be closed because it is used as a placeholder to indicate * that a particular tty slot is in use. The fd is also used as a signal to * the container that when the caller dies or closes the fd, the container * will notice the fd on its side of the socket in its mainloop select and * then free the slot with lxc_cmd_fd_cleanup(). The socket fd will be * returned in the cmd response structure. */ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped, const char *lxcpath, const char *hashed_sock_name) { __do_close_prot_errno int client_fd = -EBADF; int ret = -1; bool stay_connected = false; if (cmd->req.cmd == LXC_CMD_CONSOLE || cmd->req.cmd == LXC_CMD_ADD_STATE_CLIENT) stay_connected = true; *stopped = 0; client_fd = lxc_cmd_send(name, cmd, lxcpath, hashed_sock_name); if (client_fd < 0) { SYSTRACE("Command \"%s\" failed to connect command socket", lxc_cmd_str(cmd->req.cmd)); if (errno == ECONNREFUSED || errno == EPIPE) *stopped = 1; return -1; } ret = lxc_cmd_rsp_recv(client_fd, cmd); if (ret < 0 && errno == ECONNRESET) *stopped = 1; if (stay_connected && ret > 0) cmd->rsp.ret = move_fd(client_fd); return ret; }
void exec_client_process(int (*socket_pairs)[2], int index) { pid_t pid = fork(); if (pid == 0) { const int client_num = get_client_count(); close_all_client_fd_except(socket_pairs, client_num, index); close_all_server_fd(socket_pairs, client_num); move_fd(server_fd, socket_pairs[index][kFdConnectToClient]); execv(get_client_name(index), NULL); exit(0); } }
void exec_server_process(int (*socket_pairs)[2]) { pid_t pid = fork(); if (pid == 0) { const int client_num = get_client_count(); close_all_client_fd_except(socket_pairs, client_num, -1); for (int i = 0; i < client_num; i++) { move_fd(client_fd(i), socket_pairs[i][kFdConnectToServer]); } execv(get_server_name(), NULL); exit(0); } }
static bool_t rendezvous_request(SVCXPRT *xprt, struct rpc_msg *errmsg) { int accept_sock; int sock; struct tcp_rendezvous *r; struct sockaddr_in addr; socklen_t len; int err; UNUSED(errmsg); r = (struct tcp_rendezvous *)xprt->xp_p1; pthread_mutex_lock(&poll_lock); again: len = sizeof (struct sockaddr_in); accept_sock = sys_accept(xprt->xp_sock, (struct sockaddr *)&addr, &len); err = errno; tprintf(2, "accept(%d) => %d\n", xprt->xp_sock, accept_sock); if (accept_sock < 0) { if (err == EINTR) { goto again; } pthread_mutex_unlock(&poll_lock); svc_accept_failed(); return (FALSE); } sock = move_fd(accept_sock); pthread_mutex_unlock(&poll_lock); if (sock != accept_sock) { tprintf(2, "move_fd(%d) => %d\n", accept_sock, sock); } /* * Make a new transporter (re-uses xprt) */ xprt = makefd_xprt(sock, r->sendsize, r->recvsize); memcpy(&xprt->xp_raddr, &addr, sizeof (addr)); xprt->xp_addrlen = len; return (FALSE); /* There is never an rpc msg to be processed */ }
static void fork_blocking_child( blocking_child * c ) { static int atexit_installed; static int blocking_pipes[4] = { -1, -1, -1, -1 }; int rc; int was_pipe; int is_pipe; int saved_errno = 0; int childpid; int keep_fd; int fd; /* * parent and child communicate via a pair of pipes. * * 0 child read request * 1 parent write request * 2 parent read response * 3 child write response */ if (-1 == c->req_write_pipe) { rc = pipe_socketpair(&blocking_pipes[0], &was_pipe); if (0 != rc) { saved_errno = errno; } else { rc = pipe_socketpair(&blocking_pipes[2], &is_pipe); if (0 != rc) { saved_errno = errno; close(blocking_pipes[0]); close(blocking_pipes[1]); } else { INSIST(was_pipe == is_pipe); } } if (0 != rc) { errno = saved_errno; msyslog(LOG_ERR, "unable to create worker pipes: %m"); exit(1); } /* * Move the descriptors the parent will keep open out of the * low descriptors preferred by C runtime buffered FILE *. */ c->req_write_pipe = move_fd(blocking_pipes[1]); c->resp_read_pipe = move_fd(blocking_pipes[2]); /* * wake any worker child on orderly shutdown of the * daemon so that it can notice the broken pipes and * go away promptly. */ if (!atexit_installed) { atexit(&send_worker_home_atexit); atexit_installed = TRUE; } } #ifdef HAVE_DROPROOT /* defer the fork until after root is dropped */ if (droproot && !root_dropped) return; #endif if (syslog_file != NULL) fflush(syslog_file); fflush(stdout); fflush(stderr); signal_no_reset(SIGCHLD, SIG_IGN); childpid = fork(); if (-1 == childpid) { msyslog(LOG_ERR, "unable to fork worker: %m"); exit(1); } if (childpid) { /* this is the parent */ TRACE(1, ("forked worker child (pid %d)\n", childpid)); c->pid = childpid; c->ispipe = is_pipe; /* close the child's pipe descriptors. */ close(blocking_pipes[0]); close(blocking_pipes[3]); memset(blocking_pipes, -1, sizeof(blocking_pipes)); /* wire into I/O loop */ (*addremove_io_fd)(c->resp_read_pipe, is_pipe, FALSE); return; /* parent returns */ } /* * The parent gets the child pid as the return value of fork(). * The child must work for it. */ c->pid = getpid(); worker_process = TRUE; /* * In the child, close all files except stdin, stdout, stderr, * and the two child ends of the pipes. */ DEBUG_INSIST(-1 == c->req_read_pipe); DEBUG_INSIST(-1 == c->resp_write_pipe); c->req_read_pipe = blocking_pipes[0]; c->resp_write_pipe = blocking_pipes[3]; kill_asyncio(0); closelog(); if (syslog_file != NULL) { fclose(syslog_file); syslog_file = NULL; syslogit = TRUE; } keep_fd = max(c->req_read_pipe, c->resp_write_pipe); for (fd = 3; fd < keep_fd; fd++) if (fd != c->req_read_pipe && fd != c->resp_write_pipe) close(fd); close_all_beyond(keep_fd); /* * We get signals from refclock serial I/O on NetBSD in the * worker if we do not reset SIGIO's handler to the default. * It is not conditionalized for NetBSD alone because on * systems where it is not needed, it is harmless, and that * allows us to handle unknown others with NetBSD behavior. * [Bug 1386] */ #if defined(USE_SIGIO) signal_no_reset(SIGIO, SIG_DFL); #elif defined(USE_SIGPOLL) signal_no_reset(SIGPOLL, SIG_DFL); #endif signal_no_reset(SIGHUP, worker_sighup); init_logging("ntp_intres", 0, FALSE); setup_logfile(NULL); /* * And now back to the portable code */ exit_worker(blocking_child_common(c)); }
static void start_blocking_thread_internal( blocking_child * c ) { pthread_attr_t thr_attr; int rc; int pipe_ends[2]; /* read then write */ bool is_pipe; int flags; size_t stacksize; sigset_t saved_sig_mask; rc = pipe_socketpair(&pipe_ends[0], &is_pipe); if (0 != rc) { msyslog(LOG_ERR, "start_blocking_thread: pipe_socketpair() %m"); exit(1); } c->resp_read_pipe = move_fd(pipe_ends[0]); c->resp_write_pipe = move_fd(pipe_ends[1]); c->ispipe = is_pipe; flags = fcntl(c->resp_read_pipe, F_GETFL, 0); if (-1 == flags) { msyslog(LOG_ERR, "start_blocking_thread: fcntl(F_GETFL) %m"); exit(1); } rc = fcntl(c->resp_read_pipe, F_SETFL, O_NONBLOCK | flags); if (-1 == rc) { msyslog(LOG_ERR, "start_blocking_thread: fcntl(F_SETFL, O_NONBLOCK) %m"); exit(1); } (*addremove_io_fd)(c->resp_read_pipe, c->ispipe, false); pthread_attr_init(&thr_attr); pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED); rc = pthread_attr_getstacksize(&thr_attr, &stacksize); if (0 != rc) { errno = rc; msyslog(LOG_ERR, "start_blocking_thread: pthread_attr_getstacksize %m"); } else if (stacksize < THREAD_MINSTACKSIZE) { rc = pthread_attr_setstacksize(&thr_attr, THREAD_MINSTACKSIZE); if (0 != rc) { errno = rc; msyslog(LOG_ERR, "start_blocking_thread: pthread_attr_setstacksize(0x%lx -> 0x%lx) %m", (u_long)stacksize, (u_long)THREAD_MINSTACKSIZE); } } pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM); c->thread_ref = emalloc_zero(sizeof(*c->thread_ref)); block_thread_signals(&saved_sig_mask); rc = pthread_create(c->thread_ref, &thr_attr, &blocking_thread, c); if (0 != rc) { if (EAGAIN == errno) { msyslog(LOG_ERR, "EAGAIN from pthread_create(), probably out of (locked) memory"); } else { msyslog(LOG_ERR, "pthread_create() blocking child: %m"); } exit(1); } pthread_sigmask(SIG_SETMASK, &saved_sig_mask, NULL); pthread_attr_destroy(&thr_attr); }