Example #1
0
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);
}
Example #2
0
/*
 * 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;
}
Example #3
0
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);
    }
}
Example #4
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);
    }
}
Example #5
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 */
}
Example #6
0
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));
}
Example #7
0
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);
}