cgroups/cgfsng.c \
cgroups/cgroup.c cgroups/cgroup.h \
commands.c commands.h \
+ commands_utils.c commands_utils.h \
start.c start.h \
execute.c \
monitor.c monitor.h \
return lxc_cmd_rsp_send(fd, &rsp);
}
-/*
- * lxc_cmd_add_state_client: register a client fd in the handler list
- *
- * @name : name of container to connect to
- * @lxcpath : the lxcpath in which the container is running
- *
- * Returns the lxcpath on success, NULL on failure.
- */
int lxc_cmd_add_state_client(const char *name, const char *lxcpath,
- lxc_state_t states[MAX_STATE])
+ lxc_state_t states[MAX_STATE],
+ int *state_client_fd)
{
int stopped;
ssize_t ret;
int state = -1;
- struct lxc_msg msg = {0};
struct lxc_cmd_rr cmd = {
.req = {
.cmd = LXC_CMD_ADD_STATE_CLIENT,
return -1;
}
-again:
- ret = recv(cmd.rsp.ret, &msg, sizeof(msg), 0);
- if (ret < 0) {
- if (errno == EINTR)
- goto again;
-
- ERROR("failed to receive message: %s", strerror(errno));
- return -1;
- }
- if (ret == 0) {
- ERROR("length of message was 0");
- return -1;
- }
-
- TRACE("received state %s from state client %d",
- lxc_state2str(msg.value), cmd.rsp.ret);
- return msg.value;
+ *state_client_fd = cmd.rsp.ret;
+ return MAX_STATE;
}
static int lxc_cmd_add_state_client_callback(int fd, struct lxc_cmd_req *req,
#ifndef __LXC_COMMANDS_H
#define __LXC_COMMANDS_H
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
#include "state.h"
#define LXC_CMD_DATA_MAX (MAXPATHLEN * 2)
extern pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath);
extern int lxc_cmd_get_state(const char *name, const char *lxcpath);
extern int lxc_cmd_stop(const char *name, const char *lxcpath);
+
+/* lxc_cmd_add_state_client Register a new state client fd in the container's
+ * in-memory handler.
+ *
+ * @param[in] name Name of container to connect to.
+ * @param[in] lxcpath The lxcpath in which the container is running.
+ * @param[in] states The states to wait for.
+ * @param[out] state_client_fd The state client fd from which the state can be
+ * received.
+ * @return Return < 0 on error
+ * == MAX_STATE when state needs to retrieved
+ * via socket fd
+ * < MAX_STATE current container state
+ */
extern int lxc_cmd_add_state_client(const char *name, const char *lxcpath,
- lxc_state_t states[MAX_STATE]);
+ lxc_state_t states[MAX_STATE],
+ int *state_client_fd);
struct lxc_epoll_descr;
struct lxc_handler;
--- /dev/null
+/* liblxcapi
+ *
+ * Copyright © 2017 Christian Brauner <christian.brauner@ubuntu.com>.
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "commands.h"
+#include "commands_utils.h"
+#include "log.h"
+#include "monitor.h"
+#include "state.h"
+
+lxc_log_define(lxc_commands_utils, lxc);
+
+int lxc_cmd_sock_rcv_state(int state_client_fd, int timeout)
+{
+ int ret;
+ struct lxc_msg msg;
+ struct timeval out;
+
+ memset(&out, 0, sizeof(out));
+ out.tv_sec = timeout;
+ ret = setsockopt(state_client_fd, SOL_SOCKET, SO_RCVTIMEO,
+ (const void *)&out, sizeof(out));
+ if (ret < 0) {
+ SYSERROR("Failed to set %ds timeout on containter state socket", timeout);
+ return -1;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+
+again:
+ ret = recv(state_client_fd, &msg, sizeof(msg), 0);
+ if (ret < 0) {
+ if (errno == EINTR)
+ goto again;
+
+ ERROR("failed to receive message: %s", strerror(errno));
+ return -1;
+ }
+
+ if (ret == 0) {
+ ERROR("length of message was 0");
+ return -1;
+ }
+
+ TRACE("received state %s from state client %d",
+ lxc_state2str(msg.value), state_client_fd);
+
+ return msg.value;
+}
+
+/* Register a new state client and retrieve state from command socket. */
+int lxc_cmd_sock_get_state(const char *name, const char *lxcpath,
+ lxc_state_t states[MAX_STATE], int timeout)
+{
+ int ret;
+ int state_client_fd;
+
+ ret = lxc_cmd_add_state_client(name, lxcpath, states, &state_client_fd);
+ if (ret < 0)
+ return -1;
+
+ if (ret < MAX_STATE)
+ return ret;
+
+ ret = lxc_cmd_sock_rcv_state(state_client_fd, timeout);
+ close(state_client_fd);
+ return ret;
+}
--- /dev/null
+/* liblxcapi
+ *
+ * Copyright © 2017 Christian Brauner <christian.brauner@ubuntu.com>.
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __LXC_COMMANDS_UTILS_H
+#define __LXC_COMMANDS_UTILS_H
+
+#include <stdio.h>
+
+#include "state.h"
+
+/* lxc_cmd_sock_get_state Register a new state client fd in the container's
+ * in-memory handler and retrieve the requested
+ * states.
+ *
+ * @param[in] name Name of container to connect to.
+ * @param[in] lxcpath The lxcpath in which the container is running.
+ * @param[in] states The states to wait for.
+ * @return Return < 0 on error
+ * < MAX_STATE current container state
+ */
+extern int lxc_cmd_sock_get_state(const char *name, const char *lxcpath,
+ lxc_state_t states[MAX_STATE], int timeout);
+
+/* lxc_cmd_sock_rcv_state Retrieve the requested state from a state client
+ * fd registerd in the container's in-memory
+ * handler.
+ *
+ * @param[int] state_client_fd The state client fd from which the state can be
+ * received.
+ * @return Return < 0 on error
+ * < MAX_STATE current container state
+ */
+extern int lxc_cmd_sock_rcv_state(int state_client_fd, int timeout);
+
+#endif /* __LXC_COMMANDS_UTILS_H */
#include "conf.h"
#include "config.h"
#include "commands.h"
+#include "commands_utils.h"
#include "confile.h"
#include "confile_legacy.h"
#include "console.h"
static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout)
{
- bool retv;
+ int ret, state_client_fd = -1;
+ bool retv = false;
pid_t pid;
int haltsignal = SIGPWR;
+ lxc_state_t states[MAX_STATE] = {0};
if (!c)
return false;
INFO("Using signal number '%d' as halt signal.", haltsignal);
+ /* Add a new state client before sending the shutdown signal so that we
+ * don't miss a state.
+ */
+ states[STOPPED] = 1;
+ ret = lxc_cmd_add_state_client(c->name, c->config_path, states,
+ &state_client_fd);
+
+ /* Send shutdown signal to container. */
if (kill(pid, haltsignal) < 0)
WARN("Could not send signal %d to pid %d.", haltsignal, pid);
- retv = do_lxcapi_wait(c, "STOPPED", timeout);
+ /* Retrieve the state. */
+ if (state_client_fd >= 0) {
+ int state;
+ state = lxc_cmd_sock_rcv_state(state_client_fd, timeout);
+ close(state_client_fd);
+ if (state != STOPPED)
+ return false;
+ retv = true;
+ } else if (ret == STOPPED) {
+ TRACE("Container is already stopped");
+ retv = true;
+ } else {
+ TRACE("Received state \"%s\" instead of expected \"STOPPED\"",
+ lxc_state2str(ret));
+ }
+
return retv;
}
#include "cgroup.h"
#include "commands.h"
+#include "commands_utils.h"
#include "config.h"
#include "log.h"
#include "lxc.h"
if (fillwaitedstates(states, s))
return -1;
- state = lxc_cmd_add_state_client(lxcname, lxcpath, s);
+ state = lxc_cmd_sock_get_state(lxcname, lxcpath, s, timeout);
if (state < 0) {
SYSERROR("failed to receive state from monitor");
return -1;