#include "caps.h"
#include "cgroup.h"
#include "commands.h"
+#include "commands_utils.h"
#include "conf.h"
#include "console.h"
#include "error.h"
#include "log.h"
+#include "lxccontainer.h"
#include "lxclock.h"
#include "lxcseccomp.h"
#include "lxcutmp.h"
#include "monitor.h"
#include "namespace.h"
#include "start.h"
+#include "storage_utils.h"
#include "sync.h"
#include "utils.h"
#include "lsm/lsm.h"
return (fd == 0 || fd == 1 || fd == 2);
}
-/* Check for any fds we need to close.
- * - If fd_to_ignore != -1, then if we find that fd open we will ignore it.
- * - By default we warn about open fds we find.
- * - If closeall is true, we will close open fds.
- * - If lxc-start was passed "-C", then conf->close_all_fds will be true, in
- * which case we also close all open fds.
- * - A daemonized container will always pass closeall=true.
- */
-int lxc_check_inherited(struct lxc_conf *conf, bool closeall, int fd_to_ignore)
+int lxc_check_inherited(struct lxc_conf *conf, bool closeall,
+ int *fds_to_ignore, size_t len_fds)
{
struct dirent *direntp;
int fd, fddir;
+ size_t i;
DIR *dir;
if (conf && conf->close_all_fds)
continue;
}
- if (fd == fddir || fd == lxc_log_fd || fd == fd_to_ignore)
+ for (i = 0; i < len_fds; i++)
+ if (fds_to_ignore[i] == fd)
+ break;
+
+ if (fd == fddir || fd == lxc_log_fd ||
+ (i < len_fds && fd == fds_to_ignore[i]))
continue;
if (current_config && fd == current_config->logfd)
return 1;
}
-int lxc_set_state(const char *name, struct lxc_handler *handler,
- lxc_state_t state)
+static int lxc_serve_state_clients(const char *name,
+ struct lxc_handler *handler,
+ lxc_state_t state)
{
ssize_t ret;
struct lxc_list *cur, *next;
struct lxc_msg msg = {.type = lxc_msg_state, .value = state};
process_lock();
+
/* Only set state under process lock held so that we don't cause
- * lxc_cmd_state_server() to miss a state.
+ * lxc_cmd_add_state_client() to miss a state.
*/
handler->state = state;
TRACE("set container state to %s", lxc_state2str(state));
if (lxc_list_empty(&handler->state_clients)) {
TRACE("no state clients registered");
process_unlock();
+ lxc_monitor_send_state(name, state, handler->lxcpath);
return 0;
}
}
process_unlock();
+ return 0;
+}
+
+static int lxc_serve_state_socket_pair(const char *name,
+ struct lxc_handler *handler,
+ lxc_state_t state)
+{
+ ssize_t ret;
+
+ if (!handler->backgrounded ||
+ handler->state_socket_pair[1] < 0 ||
+ state == STARTING)
+ return 0;
+
+ /* Close read end of the socket pair. */
+ close(handler->state_socket_pair[0]);
+ handler->state_socket_pair[0] = -1;
+
+ ret = lxc_abstract_unix_send_credential(handler->state_socket_pair[1],
+ &(int){state}, sizeof(int));
+ if (ret != sizeof(int))
+ SYSERROR("Failed to send state to %d",
+ handler->state_socket_pair[1]);
+
+ TRACE("Sent container state \"%s\" to %d", lxc_state2str(state),
+ handler->state_socket_pair[1]);
+
+ /* Close write end of the socket pair. */
+ close(handler->state_socket_pair[1]);
+ handler->state_socket_pair[1] = -1;
+
+ return 0;
+}
+
+int lxc_set_state(const char *name, struct lxc_handler *handler,
+ lxc_state_t state)
+{
+ int ret;
+
+ ret = lxc_serve_state_socket_pair(name, handler, state);
+ if (ret < 0) {
+ ERROR("Failed to synchronize via anonymous pair of unix sockets");
+ return -1;
+ }
+
+ ret = lxc_serve_state_clients(name, handler, state);
+ if (ret < 0)
+ return -1;
+
/* This function will try to connect to the legacy lxc-monitord state
* server and only exists for backwards compatibility.
*/
if (handler->conf && handler->conf->maincmd_fd)
close(handler->conf->maincmd_fd);
+ if (handler->state_socket_pair[0] >= 0)
+ close(handler->state_socket_pair[0]);
+
+ if (handler->state_socket_pair[1] >= 0)
+ close(handler->state_socket_pair[1]);
+
if (handler->name)
free(handler->name);
}
struct lxc_handler *lxc_init_handler(const char *name, struct lxc_conf *conf,
- const char *lxcpath)
+ const char *lxcpath, bool daemonize)
{
- int i;
+ int i, ret;
struct lxc_handler *handler;
handler = malloc(sizeof(*handler));
handler->conf = conf;
handler->lxcpath = lxcpath;
handler->pinfd = -1;
+ handler->state_socket_pair[0] = handler->state_socket_pair[1] = -1;
lxc_list_init(&handler->state_clients);
for (i = 0; i < LXC_NS_MAX; i++)
goto on_error;
}
+ if (daemonize && !handler->conf->reboot) {
+ /* Create socketpair() to synchronize on daemonized startup.
+ * When the container reboots we don't need to synchronize again
+ * currently so don't open another socketpair().
+ */
+ ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
+ handler->state_socket_pair);
+ if (ret < 0) {
+ ERROR("Failed to create anonymous pair of unix sockets");
+ goto on_error;
+ }
+ TRACE("Created anonymous pair {%d,%d} of unix sockets",
+ handler->state_socket_pair[0],
+ handler->state_socket_pair[1]);
+ }
+
if (lxc_cmd_init(name, handler, lxcpath)) {
ERROR("failed to set up command socket");
goto on_error;