[lxc-devel] [PATCH] extend command processor to handle generic data

Dwight Engen dwight.engen at oracle.com
Fri May 17 22:29:12 UTC 2013


Motivation for this change is to have the ability to get the run-time
configuration items from a container, which may differ from its current
on disk configuration, or might not be available any other way (for
example lxc.network.0.veth.pair). In adding this ability it seemed there
was room for refactoring improvements.

Genericize the command infrastructure so that both command requests and
responses can have arbitrary data. Consolidate all commands into command.c
and name them consistently. This allows all the callback routines to be
made static, reducing exposure.

Return the actual allocated tty for the console command. Don't print the
init pid in lxc_info if the container isn't actually running. Command
processing was made more thread safe by removing the static buffer from
receive_answer(). Refactored command response code to a common routine.

Signed-off-by: Dwight Engen <dwight.engen at oracle.com>
---
 src/lxc/Makefile.am    |   1 -
 src/lxc/cgroup.c       |  70 ++----
 src/lxc/cgroup.h       |   1 -
 src/lxc/commands.c     | 648 +++++++++++++++++++++++++++++++++++++++++--------
 src/lxc/commands.h     |  75 +++---
 src/lxc/console.c      |  84 -------
 src/lxc/lxc.h          |   8 -
 src/lxc/lxc_attach.c   |   4 +-
 src/lxc/lxc_console.c  |   8 +-
 src/lxc/lxc_info.c     |  10 +-
 src/lxc/lxc_kill.c     |   2 +-
 src/lxc/lxc_stop.c     |   3 +-
 src/lxc/lxccontainer.c |   4 +-
 src/lxc/start.c        |  88 +------
 src/lxc/state.c        |  63 +----
 src/lxc/stop.c         | 115 ---------
 src/tests/cgpath.c     |   5 +-
 17 files changed, 633 insertions(+), 556 deletions(-)
 delete mode 100644 src/lxc/stop.c

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 4a19061..f8eb41b 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -40,7 +40,6 @@ liblxc_so_SOURCES = \
 	bdev.c bdev.h \
 	commands.c commands.h \
 	start.c start.h \
-	stop.c \
 	execute.c \
 	monitor.c monitor.h \
 	console.c \
diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
index a8ae8c1..a3fa2c6 100644
--- a/src/lxc/cgroup.c
+++ b/src/lxc/cgroup.c
@@ -120,7 +120,7 @@ static int get_cgroup_mount(const char *subsystem, char *mnt)
 	while ((getmntent_r(file, &mntent_r, buf, sizeof(buf)))) {
 		if (strcmp(mntent_r.mnt_type, "cgroup") != 0)
 			continue;
-		
+
 		if (subsystem) {
 			if (!hasmntopt(&mntent_r, subsystem))
 				continue;
@@ -215,55 +215,9 @@ fail:
 }
 
 /*
- * Calculate a container's cgroup path for a particular subsystem.  This
- * is the cgroup path relative to the root of the cgroup filesystem.
- * @path: A char ** into which we copy the char* containing the answer
- * @subsystem: the cgroup subsystem of interest (i.e. freezer)
- * @name: container name
- * @lxcpath: the lxcpath in which the container is running.
- *
- * Returns 0 on success, -1 on error.
- *
- * Note that the char* copied into *path is a static char[MAXPATHLEN] in
- * commands.c:receive_answer().  It should not be freed.
- */
-extern int lxc_get_cgpath(const char **path, const char *subsystem, const char *name, const char *lxcpath)
-{
-	struct lxc_command command = {
-		.request = { .type = LXC_COMMAND_CGROUP },
-	};
-
-	int ret, stopped = 0;
-
-	ret = lxc_command(name, &command, &stopped, lxcpath);
-	if (ret < 0) {
-		if (!stopped)
-			ERROR("failed to send command");
-		return -1;
-	}
-
-	if (!ret) {
-		WARN("'%s' has stopped before sending its state", name);
-		return -1;
-	}
-
-	if (command.answer.ret < 0 || command.answer.pathlen < 0) {
-		ERROR("failed to get state for '%s': %s",
-			name, strerror(-command.answer.ret));
-		return -1;
-	}
-
-	*path = command.answer.path;
-
-	return 0;
-}
-
-/*
  * lxc_cgroup_path_get: determine full pathname for a cgroup
  * file for a specific container.
- * @path: char ** used to return the answer.  The char * will point
- * into the static char* retuf from cgroup_path_get() (so no need
- * to free it).
+ * @path: char ** used to return the answer.
  * @subsystem: cgroup subsystem (i.e. "freezer") for which to
  * return an answer.  If NULL, then the first cgroup entry in
  * mtab will be used.
@@ -275,12 +229,16 @@ extern int lxc_get_cgpath(const char **path, const char *subsystem, const char *
  */
 int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name, const char *lxcpath)
 {
-	const char *cgpath;
+	int ret;
+	char *cgpath;
 
-	if (lxc_get_cgpath(&cgpath, subsystem, name, lxcpath) < 0)
+	cgpath = lxc_cmd_get_cgroup_path(subsystem, name, lxcpath);
+	if (!cgpath)
 		return -1;
 
-	return cgroup_path_get(path, subsystem, cgpath);
+	ret = cgroup_path_get(path, subsystem, cgpath);
+	free(cgpath);
+	return ret;
 }
 
 /*
@@ -917,13 +875,17 @@ int lxc_cgroup_destroy(const char *cgpath)
 
 int lxc_cgroup_attach(pid_t pid, const char *name, const char *lxcpath)
 {
-	const char *dirpath;
+	int ret;
+	char *dirpath;
 
-	if (lxc_get_cgpath(&dirpath, NULL, name, lxcpath) < 0) {
+	dirpath = lxc_cmd_get_cgroup_path(NULL, name, lxcpath);
+	if (!dirpath) {
 		ERROR("Error getting cgroup for container %s: %s", lxcpath, name);
 		return -1;
 	}
 	INFO("joining pid %d to cgroup %s", pid, dirpath);
 
-	return lxc_cgroup_enter(dirpath, pid);
+	ret = lxc_cgroup_enter(dirpath, pid);
+	free(dirpath);
+	return ret;
 }
diff --git a/src/lxc/cgroup.h b/src/lxc/cgroup.h
index 937b9c9..971311e 100644
--- a/src/lxc/cgroup.h
+++ b/src/lxc/cgroup.h
@@ -34,5 +34,4 @@ extern char *lxc_cgroup_path_create(const char *lxcgroup, const char *name);
 extern int lxc_cgroup_enter(const char *cgpath, pid_t pid);
 extern int lxc_cgroup_attach(pid_t pid, const char *name, const char *lxcpath);
 extern int cgroup_path_get(char **path, const char *subsystem, const char *cgpath);
-extern int lxc_get_cgpath(const char **path, const char *subsystem, const char *name, const char *lxcpath);
 #endif
diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index d45ae21..3f21488 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -34,27 +34,30 @@
 #include <stdlib.h>
 
 #include <lxc/log.h>
+#include <lxc/lxc.h>
 #include <lxc/conf.h>
 #include <lxc/start.h>	/* for struct lxc_handler */
 #include <lxc/utils.h>
 
 #include "commands.h"
+#include "confile.h"
 #include "mainloop.h"
 #include "af_unix.h"
 #include "config.h"
 
 /*
- * This file provides the different functions to have the client
- * and the server to communicate
+ * This file provides the different functions for clients to
+ * query/command the server. The client is typically some lxc
+ * tool and the server is typically the container (ie. lxc-start).
  *
- * Each command is transactional, the client send a request to
- * the server and the server answer the request with a message
+ * Each command is transactional, the clients send a request to
+ * the server and the server answers the request with a message
  * giving the request's status (zero or a negative errno value).
+ * Both the request and response may contain addtional data.
  *
  * Each command is wrapped in a ancillary message in order to pass
  * a credential making possible to the server to check if the client
  * is allowed to ask for this command or not.
- *
  */
 
 lxc_log_define(lxc_commands, lxc);
@@ -81,66 +84,183 @@ static int fill_sock_name(char *path, int len, const char *name,
 	return 0;
 }
 
-static int receive_answer(int sock, struct lxc_answer *answer)
+static const char *lxc_cmd_str(lxc_cmd_t cmd)
 {
-	int ret;
-	static char answerpath[MAXPATHLEN];
+	static const char *cmdname[LXC_CMD_MAX] = {
+		[LXC_CMD_CONSOLE]         = "console",
+		[LXC_CMD_STOP]            = "stop",
+		[LXC_CMD_GET_STATE]       = "get_state",
+		[LXC_CMD_GET_INIT_PID]    = "get_init_pid",
+		[LXC_CMD_GET_CLONE_FLAGS] = "get_clone_flags",
+		[LXC_CMD_GET_CGROUP]      = "get_cgroup",
+		[LXC_CMD_GET_CONFIG_ITEM] = "get_config_item",
+	};
 
-	ret = lxc_af_unix_recv_fd(sock, &answer->fd, answer, sizeof(*answer));
-	if (ret < 0)
-		ERROR("failed to receive answer for the command");
-	if (answer->pathlen == 0)
+	if (cmd < 0 || cmd >= LXC_CMD_MAX)
+		return "Unknown cmd";
+	return cmdname[cmd];
+}
+
+/*
+ * lxc_cmd_rsp_recv: Receive a response to a command
+ *
+ * @sock  : the socket connected to the container
+ * @cmd   : command to put response in
+ *
+ * Returns the size of the response message or < 0 on failure
+ *
+ * Note that if the command response datalen > 0, then data is
+ * a malloc()ed buffer and should be free()ed by the caller. If
+ * the response data is <= a void * worth of data, it will be
+ * stored directly in data and datalen will be 0.
+ *
+ * As a special case, the response for LXC_CMD_CONSOLE is created
+ * here as it contains an fd passed through the unix socket.
+ */
+static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
+{
+	int ret,rspfd;
+	struct lxc_cmd_rsp *rsp = &cmd->rsp;
+
+	ret = lxc_af_unix_recv_fd(sock, &rspfd, rsp, sizeof(*rsp));
+	if (ret < 0) {
+		ERROR("command %s failed to receive response",
+		      lxc_cmd_str(cmd->req.cmd));
+		return -1;
+	}
+
+	if (cmd->req.cmd == LXC_CMD_CONSOLE) {
+		struct lxc_cmd_console_rsp_data *rspdata;
+
+		rspdata = malloc(sizeof(*rspdata));
+		if (!rspdata) {
+			ERROR("command %s couldn't allocate response buffer",
+			      lxc_cmd_str(cmd->req.cmd));
+			return -1;
+		}
+		rspdata->fd = rspfd;
+		rspdata->ttynum = PTR_TO_INT(rsp->data);
+		rsp->data = rspdata;
+	}
+
+	if (rsp->datalen == 0)
 		return ret;
-	if (answer->pathlen >= MAXPATHLEN) {
-		ERROR("cgroup path was too long");
+	if (rsp->datalen > LXC_CMD_DATA_MAX) {
+		ERROR("command %s response data %d too long",
+		      lxc_cmd_str(cmd->req.cmd), rsp->datalen);
+		errno = EFBIG;
 		return -1;
 	}
-	ret = recv(sock, answerpath, answer->pathlen, 0);
-	if (ret != answer->pathlen) {
-		ERROR("failed to receive answer for the command");
-		ret = 0;
-	} else
-		answer->path = answerpath;
+
+	rsp->data = malloc(rsp->datalen);
+	if (!rsp->data) {
+		ERROR("command %s unable to allocate response buffer",
+		      lxc_cmd_str(cmd->req.cmd));
+		return -1;
+	}
+	ret = recv(sock, rsp->data, rsp->datalen, 0);
+	if (ret != rsp->datalen) {
+		ERROR("command %s failed to receive response data",
+		      lxc_cmd_str(cmd->req.cmd));
+		if (ret >= 0)
+			ret = -1;
+	}
 
 	return ret;
 }
 
-static int __lxc_command(const char *name, struct lxc_command *command,
-			 int *stopped, int stay_connected, const char *lxcpath)
+/*
+ * lxc_cmd_rsp_send: Send a command response
+ *
+ * @fd   : file descriptor of socket to send response on
+ * @rsp  : response to send
+ *
+ * Returns 0 on success, < 0 on failure
+ */
+static int lxc_cmd_rsp_send(int fd, struct lxc_cmd_rsp *rsp)
+{
+	int ret;
+
+	ret = send(fd, rsp, sizeof(*rsp), 0);
+	if (ret != sizeof(*rsp)) {
+		ERROR("failed to send command response %d %s", ret,
+		      strerror(errno));
+		return -1;
+	}
+
+	if (rsp->datalen > 0) {
+		ret = send(fd, rsp->data, rsp->datalen, 0);
+		if (ret != rsp->datalen) {
+			WARN("failed to send command response data %d %s", ret,
+			      strerror(errno));
+			return -1;
+		}
+	}
+	return 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 reqest 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 in its mainloop select and then free the slot with
+ * lxc_cmd_fd_cleanup().
+ */
+static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
+		   const char *lxcpath)
 {
 	int sock, ret = -1;
 	char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
 	char *offset = &path[1];
 	int len;
+	int stay_connected = cmd->req.cmd == LXC_CMD_CONSOLE;
 
 	len = sizeof(path)-1;
 	if (fill_sock_name(offset, len, name, lxcpath))
 		return -1;
 
 	sock = lxc_af_unix_connect(path);
-	if (sock < 0 && errno == ECONNREFUSED) {
-		*stopped = 1;
-		return -1;
-	}
-
 	if (sock < 0) {
-		SYSERROR("failed to connect to '@%s'", offset);
+		if (errno == ECONNREFUSED)
+			*stopped = 1;
+		else
+			SYSERROR("command %s failed to connect to '@%s'",
+				 lxc_cmd_str(cmd->req.cmd), offset);
 		return -1;
 	}
 
-	ret = lxc_af_unix_send_credential(sock, &command->request,
-					sizeof(command->request));
-	if (ret < 0) {
-		SYSERROR("failed to send request to '@%s'", offset);
+	ret = lxc_af_unix_send_credential(sock, &cmd->req, sizeof(cmd->req));
+	if (ret != sizeof(cmd->req)) {
+		SYSERROR("command %s failed to send req to '@%s' %d",
+			 lxc_cmd_str(cmd->req.cmd), offset, ret);
+		if (ret >=0)
+			ret = -1;
 		goto out;
 	}
 
-	if (ret != sizeof(command->request)) {
-		SYSERROR("message partially sent to '@%s'", offset);
-		goto out;
+	if (cmd->req.datalen > 0) {
+		ret = send(sock, cmd->req.data, cmd->req.datalen, 0);
+		if (ret != cmd->req.datalen) {
+			SYSERROR("command %s failed to send request data to '@%s' %d",
+				 lxc_cmd_str(cmd->req.cmd), offset, ret);
+			if (ret >=0)
+				ret = -1;
+			goto out;
+		}
 	}
 
-	ret = receive_answer(sock, &command->answer);
+	ret = lxc_cmd_rsp_recv(sock, cmd);
 out:
 	if (!stay_connected || ret < 0)
 		close(sock);
@@ -148,114 +268,418 @@ out:
 	return ret;
 }
 
-extern int lxc_command(const char *name,
-		       struct lxc_command *command, int *stopped,
-		       const char *lxcpath)
+/* Implentations of the commands and their callbacks */
+
+/*
+ * lxc_cmd_get_init_pid: Get pid of the container's init process
+ *
+ * @name      : name of container to connect to
+ * @lxcpath   : the lxcpath in which the container is running
+ *
+ * Returns the pid on success, < 0 on failure
+ */
+pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath)
 {
-	return __lxc_command(name, command, stopped, 0, lxcpath);
+	int ret, stopped = 0;
+	struct lxc_cmd_rr cmd = {
+		.req = { .cmd = LXC_CMD_GET_INIT_PID },
+	};
+
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
+	if (ret < 0)
+		return ret;
+
+	return PTR_TO_INT(cmd.rsp.data);
 }
 
-extern int lxc_command_connected(const char *name,
-				 struct lxc_command *command, int *stopped,
-				 const char *lxcpath)
+static int lxc_cmd_get_init_pid_callback(int fd, struct lxc_cmd_req *req,
+					 struct lxc_handler *handler)
 {
-	return __lxc_command(name, command, stopped, 1, lxcpath);
+	struct lxc_cmd_rsp rsp = { .data = INT_TO_PTR(handler->pid) };
+
+	return lxc_cmd_rsp_send(fd, &rsp);
 }
 
+/*
+ * lxc_cmd_get_clone_flags: Get clone flags container was spawned with
+ *
+ * @name      : name of container to connect to
+ * @lxcpath   : the lxcpath in which the container is running
+ *
+ * Returns the clone flags on success, < 0 on failure
+ */
+int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath)
+{
+	int ret, stopped = 0;
+	struct lxc_cmd_rr cmd = {
+		.req = { .cmd = LXC_CMD_GET_CLONE_FLAGS },
+	};
+
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
+	if (ret < 0)
+		return ret;
 
-pid_t get_init_pid(const char *name, const char *lxcpath)
+	return PTR_TO_INT(cmd.rsp.data);
+}
+
+static int lxc_cmd_get_clone_flags_callback(int fd, struct lxc_cmd_req *req,
+					    struct lxc_handler *handler)
 {
-	struct lxc_command command = {
-		.request = { .type = LXC_COMMAND_PID },
+	struct lxc_cmd_rsp rsp = { .data = INT_TO_PTR(handler->clone_flags) };
+
+	return lxc_cmd_rsp_send(fd, &rsp);
+}
+
+/*
+ * lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a
+ * particular subsystem. This is the cgroup path relative to the root
+ * of the cgroup filesystem.
+ *
+ * @subsystem : the cgroup subsystem of interest (i.e. freezer)
+ * @name      : name of container to connect to
+ * @lxcpath   : the lxcpath in which the container is running
+ *
+ * Returns the path on success, NULL on failure. The caller must free() the
+ * returned path.
+ */
+char *lxc_cmd_get_cgroup_path(const char *subsystem, const char *name,
+			      const char *lxcpath)
+{
+	int ret, stopped = 0;
+	struct lxc_cmd_rr cmd = {
+		.req = { .cmd = LXC_CMD_GET_CGROUP },
 	};
 
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
+	if (ret < 0)
+		return NULL;
+
+	if (!ret) {
+		WARN("'%s' has stopped before sending its state", name);
+		return NULL;
+	}
+
+	if (cmd.rsp.ret < 0 || cmd.rsp.datalen < 0) {
+		ERROR("command %s failed for '%s': %s",
+		      lxc_cmd_str(cmd.req.cmd), name,
+		      strerror(-cmd.rsp.ret));
+		return NULL;
+	}
+
+	return cmd.rsp.data;
+}
+
+static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
+				       struct lxc_handler *handler)
+{
+	struct lxc_cmd_rsp rsp = {
+		.datalen = strlen(handler->cgroup) + 1,
+		.data = handler->cgroup,
+	};
+
+	return lxc_cmd_rsp_send(fd, &rsp);
+}
+
+/*
+ * lxc_cmd_get_config_item: Get config item the running container
+ *
+ * @name     : name of container to connect to
+ * @item     : the configuration item to retrieve (ex: lxc.network.0.veth.pair)
+ * @lxcpath  : the lxcpath in which the container is running
+ *
+ * Returns the item on success, NULL on failure. The caller must free() the
+ * returned item.
+ */
+char *lxc_cmd_get_config_item(const char *name, const char *item,
+			      const char *lxcpath)
+{
+	int ret, stopped = 0;
+	struct lxc_cmd_rr cmd = {
+		.req = { .cmd = LXC_CMD_GET_CONFIG_ITEM,
+			 .data = item,
+			 .datalen = strlen(item)+1,
+		       },
+	};
+
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
+	if (ret < 0)
+		return NULL;
+
+	if (cmd.rsp.ret == 0)
+		return cmd.rsp.data;
+	return NULL;
+}
+
+static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req,
+					    struct lxc_handler *handler)
+{
+	int cilen;
+	struct lxc_cmd_rsp rsp;
+	char *cidata;
+
+	memset(&rsp, 0, sizeof(rsp));
+	cilen = lxc_get_config_item(handler->conf, req->data, NULL, 0);
+	if (cilen <= 0)
+		goto err1;
+
+	cidata = alloca(cilen + 1);
+	if (lxc_get_config_item(handler->conf, req->data, cidata, cilen + 1) != cilen)
+		goto err1;
+	cidata[cilen] = '\0';
+	rsp.data = cidata;
+	rsp.datalen = cilen + 1;
+	rsp.ret = 0;
+	goto out;
+
+err1:
+	rsp.ret = -1;
+out:
+	return lxc_cmd_rsp_send(fd, &rsp);
+}
+
+/*
+ * lxc_cmd_get_state: Get current state of the container
+ *
+ * @name      : name of container to connect to
+ * @lxcpath   : the lxcpath in which the container is running
+ *
+ * Returns the state on success, < 0 on failure
+ */
+lxc_state_t lxc_cmd_get_state(const char *name, const char *lxcpath)
+{
 	int ret, stopped = 0;
+	struct lxc_cmd_rr cmd = {
+		.req = { .cmd = LXC_CMD_GET_STATE }
+	};
 
-	ret = lxc_command(name, &command, &stopped, lxcpath);
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
 	if (ret < 0 && stopped)
+		return STOPPED;
+
+	if (ret < 0)
 		return -1;
 
+	if (!ret) {
+		WARN("'%s' has stopped before sending its state", name);
+		return -1;
+	}
+
+	DEBUG("'%s' is in '%s' state", name,
+	      lxc_state2str(PTR_TO_INT(cmd.rsp.data)));
+	return PTR_TO_INT(cmd.rsp.data);
+}
+
+static int lxc_cmd_get_state_callback(int fd, struct lxc_cmd_req *req,
+				      struct lxc_handler *handler)
+{
+	struct lxc_cmd_rsp rsp = { .data = INT_TO_PTR(handler->state) };
+
+	return lxc_cmd_rsp_send(fd, &rsp);
+}
+
+/*
+ * lxc_cmd_stop: Stop the container previously started with lxc_start. All
+ * the processes running inside this container will be killed.
+ *
+ * @name     : name of container to connect to
+ * @lxcpath  : the lxcpath in which the container is running
+ *
+ * Returns 0 on success, < 0 on failure
+ */
+int lxc_cmd_stop(const char *name, const char *lxcpath)
+{
+	int ret, stopped = 0;
+	struct lxc_cmd_rr cmd = {
+		.req = { .cmd = LXC_CMD_STOP },
+	};
+
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
 	if (ret < 0) {
-		ERROR("failed to send command");
+		if (stopped) {
+			INFO("'%s' is already stopped", name);
+			return 0;
+		}
 		return -1;
 	}
 
-	if (command.answer.ret) {
-		ERROR("failed to retrieve the init pid: %s",
-		      strerror(-command.answer.ret));
+	/* we do not expect any answer, because we wait for the connection to be
+	 * closed
+	 */
+	if (ret > 0) {
+		ERROR("failed to stop '%s': %s", name, strerror(-cmd.rsp.ret));
 		return -1;
 	}
 
-	return command.answer.pid;
+	INFO("'%s' has stopped", name);
+	return 0;
 }
 
-int lxc_get_clone_flags(const char *name, const char *lxcpath)
+static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
+				 struct lxc_handler *handler)
 {
-	struct lxc_command command = {
-		.request = { .type = LXC_COMMAND_CLONE_FLAGS },
-	};
+	struct lxc_cmd_rsp rsp;
+	int ret;
+	int stopsignal = SIGKILL;
+
+	if (handler->conf->stopsignal)
+		stopsignal = handler->conf->stopsignal;
+	memset(&rsp, 0, sizeof(rsp));
+	rsp.ret = kill(handler->pid, stopsignal);
+	if (!rsp.ret) {
+		ret = lxc_unfreeze_bypath(handler->cgroup);
+		if (!ret)
+			return 0;
+
+		ERROR("failed to unfreeze container");
+		rsp.ret = ret;
+	}
+
+	return lxc_cmd_rsp_send(fd, &rsp);
+}
 
+/*
+ * lxc_cmd_console: Open an fd to a tty in the container
+ *
+ * @name           : name of container to connect to
+ * @ttynum         : in:  the tty to open or -1 for next available
+ *                 : out: the tty allocated
+ * @fd             : out: file descriptor for master side of pty
+ * @lxcpath        : the lxcpath in which the container is running
+ *
+ * Returns 0 on success, < 0 on failure
+ */
+int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath)
+{
 	int ret, stopped = 0;
+	struct lxc_cmd_console_rsp_data *rspdata;
+	struct lxc_cmd_rr cmd = {
+		.req = { .cmd = LXC_CMD_CONSOLE, .data = INT_TO_PTR(*ttynum) },
+	};
 
-	ret = lxc_command(name, &command, &stopped, lxcpath);
-	if (ret < 0 && stopped)
-		return -1;
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath);
+	if (ret < 0)
+		return ret;
+	if (ret == 0) {
+		ERROR("console %d invalid or all consoles busy", *ttynum);
+		ret = -1;
+		goto out;
+	}
 
-	if (ret < 0) {
-		ERROR("failed to send command");
-		return -1;
+	ret = -1;
+	#if 1 /* FIXME: how can this happen? */
+	if (cmd.rsp.ret) {
+		ERROR("console access denied: %s",
+			strerror(-cmd.rsp.ret));
+		goto out;
+	}
+	#endif
+
+	rspdata = cmd.rsp.data;
+	if (rspdata->fd < 0) {
+		ERROR("unable to allocate fd for tty %d", rspdata->ttynum);
+		goto out;
+	}
+
+	ret = 0;
+	*fd = rspdata->fd;
+	*ttynum = rspdata->ttynum;
+	INFO("tty %d allocated", rspdata->ttynum);
+out:
+	free(cmd.rsp.data);
+	return ret;
+}
+
+static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
+				    struct lxc_handler *handler)
+{
+	int ttynum = PTR_TO_INT(req->data);
+	struct lxc_tty_info *tty_info = &handler->conf->tty_info;
+	struct lxc_cmd_rsp rsp;
+
+	if (ttynum > 0) {
+		if (ttynum > tty_info->nbtty)
+			goto out_close;
+
+		if (tty_info->pty_info[ttynum - 1].busy)
+			goto out_close;
+
+		/* the requested tty is available */
+		goto out_send;
 	}
 
-	return command.answer.ret;
+	/* search for next available tty, fixup index tty1 => [0] */
+	for (ttynum = 1;
+	     ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
+	     ttynum++);
+
+	/* we didn't find any available slot for tty */
+	if (ttynum > tty_info->nbtty)
+		goto out_close;
+
+out_send:
+	memset(&rsp, 0, sizeof(rsp));
+	rsp.data = INT_TO_PTR(ttynum);
+	if (lxc_af_unix_send_fd(fd, tty_info->pty_info[ttynum - 1].master,
+				&rsp, sizeof(rsp)) < 0) {
+		ERROR("failed to send tty to client");
+		goto out_close;
+	}
+
+	tty_info->pty_info[ttynum - 1].busy = fd;
+	return 0;
+
+out_close:
+	/* special indicator to lxc_cmd_handler() to close the fd and do
+	 * related cleanup
+	 */
+	return 1;
 }
 
-extern void lxc_console_remove_fd(int, struct lxc_tty_info *);
-extern int  lxc_console_callback(int, struct lxc_request *, struct lxc_handler *);
-extern int  lxc_stop_callback(int, struct lxc_request *, struct lxc_handler *);
-extern int  lxc_state_callback(int, struct lxc_request *, struct lxc_handler *);
-extern int  lxc_pid_callback(int, struct lxc_request *, struct lxc_handler *);
-extern int  lxc_clone_flags_callback(int, struct lxc_request *, struct lxc_handler *);
-extern int lxc_cgroup_callback(int, struct lxc_request *, struct lxc_handler *);
 
-static int trigger_command(int fd, struct lxc_request *request,
+
+static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
 			   struct lxc_handler *handler)
 {
-	typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
-
-	callback cb[LXC_COMMAND_MAX] = {
-		[LXC_COMMAND_TTY]         = lxc_console_callback,
-		[LXC_COMMAND_STOP]        = lxc_stop_callback,
-		[LXC_COMMAND_STATE]       = lxc_state_callback,
-		[LXC_COMMAND_PID]         = lxc_pid_callback,
-		[LXC_COMMAND_CLONE_FLAGS] = lxc_clone_flags_callback,
-		[LXC_COMMAND_CGROUP]      = lxc_cgroup_callback,
+	typedef int (*callback)(int, struct lxc_cmd_req *, struct lxc_handler *);
+
+	callback cb[LXC_CMD_MAX] = {
+		[LXC_CMD_CONSOLE]         = lxc_cmd_console_callback,
+		[LXC_CMD_STOP]            = lxc_cmd_stop_callback,
+		[LXC_CMD_GET_STATE]       = lxc_cmd_get_state_callback,
+		[LXC_CMD_GET_INIT_PID]    = lxc_cmd_get_init_pid_callback,
+		[LXC_CMD_GET_CLONE_FLAGS] = lxc_cmd_get_clone_flags_callback,
+		[LXC_CMD_GET_CGROUP]      = lxc_cmd_get_cgroup_callback,
+		[LXC_CMD_GET_CONFIG_ITEM] = lxc_cmd_get_config_item_callback,
 	};
 
-	if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
+	if (req->cmd < 0 || req->cmd >= LXC_CMD_MAX) {
+		ERROR("bad cmd %d recieved", req->cmd);
 		return -1;
-
-	return cb[request->type](fd, request, handler);
+	}
+	return cb[req->cmd](fd, req, handler);
 }
 
-static void command_fd_cleanup(int fd, struct lxc_handler *handler,
+static void lxc_cmd_fd_cleanup(int fd, struct lxc_handler *handler,
 			       struct lxc_epoll_descr *descr)
 {
+	extern void lxc_console_remove_fd(int, struct lxc_tty_info *);
 	lxc_console_remove_fd(fd, &handler->conf->tty_info);
 	lxc_mainloop_del_handler(descr, fd);
 	close(fd);
 }
 
-static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
+static int lxc_cmd_handler(int fd, void *data, struct lxc_epoll_descr *descr)
 {
 	int ret;
-	struct lxc_request request;
+	struct lxc_cmd_req req;
 	struct lxc_handler *handler = data;
 
-	ret = lxc_af_unix_rcv_credential(fd, &request, sizeof(request));
+	ret = lxc_af_unix_rcv_credential(fd, &req, sizeof(req));
 	if (ret == -EACCES) {
 		/* we don't care for the peer, just send and close */
-		struct lxc_answer answer = { .ret = ret };
-		send(fd, &answer, sizeof(answer), 0);
+		struct lxc_cmd_rsp rsp = { .ret = ret };
+
+		lxc_cmd_rsp_send(fd, &rsp);
 		goto out_close;
 	}
 
@@ -269,12 +693,32 @@ static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
 		goto out_close;
 	}
 
-	if (ret != sizeof(request)) {
+	if (ret != sizeof(req)) {
 		WARN("partial request, ignored");
+		ret = -1;
+		goto out_close;
+	}
+
+	if (req.datalen > LXC_CMD_DATA_MAX) {
+		ERROR("cmd data length %d too large", req.datalen);
+		ret = -1;
 		goto out_close;
 	}
 
-	ret = trigger_command(fd, &request, handler);
+	if (req.datalen > 0) {
+		void *reqdata;
+
+		reqdata = alloca(req.datalen);
+		ret = recv(fd, reqdata, req.datalen, 0);
+		if (ret != req.datalen) {
+			WARN("partial request, ignored");
+			ret = -1;
+			goto out_close;
+		}
+		req.data = reqdata;
+	}
+
+	ret = lxc_cmd_process(fd, &req, handler);
 	if (ret) {
 		/* this is not an error, but only a request to close fd */
 		ret = 0;
@@ -284,12 +728,11 @@ static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
 out:
 	return ret;
 out_close:
-	command_fd_cleanup(fd, handler, descr);
+	lxc_cmd_fd_cleanup(fd, handler, descr);
 	goto out;
 }
 
-static int incoming_command_handler(int fd, void *data,
-				    struct lxc_epoll_descr *descr)
+static int lxc_cmd_accept(int fd, void *data, struct lxc_epoll_descr *descr)
 {
 	int opt = 1, ret = -1, connection;
 
@@ -310,7 +753,7 @@ static int incoming_command_handler(int fd, void *data,
 		goto out_close;
 	}
 
-	ret = lxc_mainloop_add_handler(descr, connection, command_handler, data);
+	ret = lxc_mainloop_add_handler(descr, connection, lxc_cmd_handler, data);
 	if (ret) {
 		ERROR("failed to add handler");
 		goto out_close;
@@ -324,8 +767,8 @@ out_close:
 	goto out;
 }
 
-extern int lxc_command_init(const char *name, struct lxc_handler *handler,
-			    const char *lxcpath)
+int lxc_cmd_init(const char *name, struct lxc_handler *handler,
+		 const char *lxcpath)
 {
 	int fd;
 	char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
@@ -357,14 +800,13 @@ extern int lxc_command_init(const char *name, struct lxc_handler *handler,
 	return 0;
 }
 
-extern int lxc_command_mainloop_add(const char *name,
-				    struct lxc_epoll_descr *descr,
-				    struct lxc_handler *handler)
+int lxc_cmd_mainloop_add(const char *name,
+			 struct lxc_epoll_descr *descr,
+			 struct lxc_handler *handler)
 {
 	int ret, fd = handler->conf->maincmd_fd;
 
-	ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler,
-				       handler);
+	ret = lxc_mainloop_add_handler(descr, fd, lxc_cmd_accept, handler);
 	if (ret) {
 		ERROR("failed to add handler for command socket");
 		close(fd);
diff --git a/src/lxc/commands.h b/src/lxc/commands.h
index 3b725fb..b5b4788 100644
--- a/src/lxc/commands.h
+++ b/src/lxc/commands.h
@@ -20,52 +20,67 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
+
 #ifndef __commands_h
 #define __commands_h
 
-enum {
-	LXC_COMMAND_TTY,
-	LXC_COMMAND_STOP,
-	LXC_COMMAND_STATE,
-	LXC_COMMAND_PID,
-	LXC_COMMAND_CLONE_FLAGS,
-	LXC_COMMAND_CGROUP,
-	LXC_COMMAND_MAX,
-};
+#include "state.h"
+
+#define LXC_CMD_DATA_MAX (MAXPATHLEN*2)
+
+/* https://developer.gnome.org/glib/2.28/glib-Type-Conversion-Macros.html */
+#define INT_TO_PTR(n) ((void *) (long) (n))
+#define PTR_TO_INT(p) ((int) (long) (p))
+
+typedef enum {
+	LXC_CMD_CONSOLE,
+	LXC_CMD_STOP,
+	LXC_CMD_GET_STATE,
+	LXC_CMD_GET_INIT_PID,
+	LXC_CMD_GET_CLONE_FLAGS,
+	LXC_CMD_GET_CGROUP,
+	LXC_CMD_GET_CONFIG_ITEM,
+	LXC_CMD_MAX,
+} lxc_cmd_t;
 
-struct lxc_request {
-	int type;
-	int data;
+struct lxc_cmd_req {
+	lxc_cmd_t cmd;
+	int datalen;
+	const void *data;
 };
 
-struct lxc_answer {
-	int fd;
+struct lxc_cmd_rsp {
 	int ret; /* 0 on success, -errno on failure */
-	pid_t pid;
-	int pathlen;
-	const char *path;
+	int datalen;
+	void *data;
 };
 
-struct lxc_command {
-	struct lxc_request request;
-	struct lxc_answer answer;
+struct lxc_cmd_rr {
+	struct lxc_cmd_req req;
+	struct lxc_cmd_rsp rsp;
 };
 
-extern pid_t get_init_pid(const char *name, const char *lxcpath);
-extern int lxc_get_clone_flags(const char *name, const char *lxcpath);
-
-extern int lxc_command(const char *name, struct lxc_command *command,
-			int *stopped, const char *lxcpath);
+struct lxc_cmd_console_rsp_data {
+	int fd;
+	int ttynum;
+};
 
-extern int lxc_command_connected(const char *name, struct lxc_command *command,
-				 int *stopped, const char *lxcpath);
+extern int lxc_cmd_console(const char *name, int *ttynum, int *fd,
+			   const char *lxcpath);
+extern char *lxc_cmd_get_cgroup_path(const char *subsystem,
+				     const char *name, const char *lxcpath);
+extern int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath);
+extern char *lxc_cmd_get_config_item(const char *name, const char *item, const char *lxcpath);
+extern pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath);
+extern lxc_state_t lxc_cmd_get_state(const char *name, const char *lxcpath);
+extern int lxc_cmd_stop(const char *name, const char *lxcpath);
 
 struct lxc_epoll_descr;
 struct lxc_handler;
 
-extern int lxc_command_init(const char *name, struct lxc_handler *handler,
+extern int lxc_cmd_init(const char *name, struct lxc_handler *handler,
 			    const char *lxcpath);
-extern int lxc_command_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
+extern int lxc_cmd_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
 				    struct lxc_handler *handler);
 
-#endif
+#endif /* __commands_h */
diff --git a/src/lxc/console.c b/src/lxc/console.c
index 9ef62c1..93c16b5 100644
--- a/src/lxc/console.c
+++ b/src/lxc/console.c
@@ -46,49 +46,6 @@
 
 lxc_log_define(lxc_console, lxc);
 
-extern int lxc_console(const char *name, int ttynum, int *fd, const char *lxcpath)
-{
-	int ret, stopped = 0;
-	struct lxc_command command = {
-		.request = { .type = LXC_COMMAND_TTY, .data = ttynum },
-	};
-
-	ret = lxc_command_connected(name, &command, &stopped, lxcpath);
-	if (ret < 0 && stopped) {
-		ERROR("'%s' is stopped", name);
-		return -1;
-	}
-
-	if (ret < 0) {
-		ERROR("failed to send command");
-		return -1;
-	}
-
-	if (!ret) {
-		ERROR("console denied by '%s'", name);
-		return -1;
-	}
-
-	if (command.answer.ret) {
-		ERROR("console access denied: %s",
-			strerror(-command.answer.ret));
-		return -1;
-	}
-
-	*fd = command.answer.fd;
-	if (*fd <0) {
-		ERROR("unable to allocate fd for tty %d", ttynum);
-		return -1;
-	}
-
-	INFO("tty %d allocated", ttynum);
-	return 0;
-}
-
-/*----------------------------------------------------------------------------
- * functions used by lxc-start mainloop
- * to handle above command request.
- *--------------------------------------------------------------------------*/
 extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info)
 {
 	int i;
@@ -104,47 +61,6 @@ extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info)
 	return;
 }
 
-extern int lxc_console_callback(int fd, struct lxc_request *request,
-				struct lxc_handler *handler)
-{
-	int ttynum = request->data;
-	struct lxc_tty_info *tty_info = &handler->conf->tty_info;
-
-	if (ttynum > 0) {
-		if (ttynum > tty_info->nbtty)
-			goto out_close;
-
-		if (tty_info->pty_info[ttynum - 1].busy)
-			goto out_close;
-
-		goto out_send;
-	}
-
-	/* fixup index tty1 => [0] */
-	for (ttynum = 1;
-	     ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
-	     ttynum++);
-
-	/* we didn't find any available slot for tty */
-	if (ttynum > tty_info->nbtty)
-		goto out_close;
-
-out_send:
-	if (lxc_af_unix_send_fd(fd, tty_info->pty_info[ttynum - 1].master,
-				&ttynum, sizeof(ttynum)) < 0) {
-		ERROR("failed to send tty to client");
-		goto out_close;
-	}
-
-	tty_info->pty_info[ttynum - 1].busy = fd;
-
-	return 0;
-
-out_close:
-	/* the close fd and related cleanup will be done by caller */
-	return 1;
-}
-
 static int get_default_console(char **console)
 {
 	int fd;
diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h
index 9057757..8491ff3 100644
--- a/src/lxc/lxc.h
+++ b/src/lxc/lxc.h
@@ -52,14 +52,6 @@ extern int lxc_start(const char *name, char *const argv[], struct lxc_conf *conf
 		     const char *lxcpath);
 
 /*
- * Stop the container previously started with lxc_start, all
- * the processes running inside this container will be killed.
- * @name : the name of the container
- * Returns 0 on success, < 0 otherwise
- */
-extern int lxc_stop(const char *name, const char *lxcpath);
-
-/*
  * Start the specified command inside an application container
  * @name     : the name of the container
  * @argv     : an array of char * corresponding to the commande line
diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c
index e0c253b..efa7d89 100644
--- a/src/lxc/lxc_attach.c
+++ b/src/lxc/lxc_attach.c
@@ -296,7 +296,7 @@ int main(int argc, char *argv[])
 	if (ret)
 		return ret;
 
-	init_pid = get_init_pid(my_args.name, my_args.lxcpath[0]);
+	init_pid = lxc_cmd_get_init_pid(my_args.name, my_args.lxcpath[0]);
 	if (init_pid < 0) {
 		ERROR("failed to get the init pid");
 		return -1;
@@ -314,7 +314,7 @@ int main(int argc, char *argv[])
 	 * by asking lxc-start
 	 */
 	if (namespace_flags == -1) {
-		namespace_flags = lxc_get_clone_flags(my_args.name, my_args.lxcpath[0]);
+		namespace_flags = lxc_cmd_get_clone_flags(my_args.name, my_args.lxcpath[0]);
 		/* call failed */
 		if (namespace_flags == -1) {
 			ERROR("failed to automatically determine the "
diff --git a/src/lxc/lxc_console.c b/src/lxc/lxc_console.c
index 795b54c..820794a 100644
--- a/src/lxc/lxc_console.c
+++ b/src/lxc/lxc_console.c
@@ -43,6 +43,7 @@
 #include "log.h"
 #include "mainloop.h"
 #include "arguments.h"
+#include "commands.h"
 
 lxc_log_define(lxc_console_ui, lxc_console);
 
@@ -202,13 +203,14 @@ int main(int argc, char *argv[])
 		return -1;
 	}
 
-	err = lxc_console(my_args.name, my_args.ttynum, &master, my_args.lxcpath[0]);
+	err = lxc_cmd_console(my_args.name, &my_args.ttynum, &master, my_args.lxcpath[0]);
 	if (err)
 		goto out;
 
 	fprintf(stderr, "\n\
-Type <Ctrl+%1$c q> to exit the console, \
-<Ctrl+%1$c Ctrl+%1$c> to enter Ctrl+%1$c itself\n",
+Connected to tty %1$d\n\
+Type <Ctrl+%2$c q> to exit the console, \
+<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n", my_args.ttynum,
                 'a' + my_args.escape - 1);
 
 	err = setsid();
diff --git a/src/lxc/lxc_info.c b/src/lxc/lxc_info.c
index f815b0f..f86626d 100644
--- a/src/lxc/lxc_info.c
+++ b/src/lxc/lxc_info.c
@@ -22,6 +22,7 @@
  */
 #include <stdio.h>
 #include <stdbool.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <libgen.h>
 #include <sys/types.h>
@@ -96,8 +97,13 @@ int main(int argc, char *argv[])
 		printf("state:%10s\n", lxc_state2str(ret));
 	}
 
-	if (pid)
-		printf("pid:%10d\n", get_init_pid(my_args.name, my_args.lxcpath[0]));
+	if (pid) {
+		pid_t initpid;
+
+		initpid = lxc_cmd_get_init_pid(my_args.name, my_args.lxcpath[0]);
+		if (initpid >= 0)
+			printf("pid:%10d\n", initpid);
+	}
 
 	return 0;
 }
diff --git a/src/lxc/lxc_kill.c b/src/lxc/lxc_kill.c
index 9a24209..1fedf1d 100644
--- a/src/lxc/lxc_kill.c
+++ b/src/lxc/lxc_kill.c
@@ -76,7 +76,7 @@ int main(int argc, char *argv[], char *envp[])
 	} else
 		sig=SIGKILL;
 
-	pid = get_init_pid(my_args.name, my_args.lxcpath[0]);
+	pid = lxc_cmd_get_init_pid(my_args.name, my_args.lxcpath[0]);
 	if (pid < 0) {
 		ERROR("failed to get the init pid");
 		return -1;
diff --git a/src/lxc/lxc_stop.c b/src/lxc/lxc_stop.c
index d7c7283..0ed8ca0 100644
--- a/src/lxc/lxc_stop.c
+++ b/src/lxc/lxc_stop.c
@@ -29,6 +29,7 @@
 #include <lxc/log.h>
 
 #include "arguments.h"
+#include "commands.h"
 #include "utils.h"
 
 static const struct option my_longopts[] = {
@@ -58,5 +59,5 @@ int main(int argc, char *argv[])
 			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
 		return -1;
 
-	return lxc_stop(my_args.name, my_args.lxcpath[0]);
+	return lxc_cmd_stop(my_args.name, my_args.lxcpath[0]);
 }
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 23db6f2..01501e7 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -279,7 +279,7 @@ static pid_t lxcapi_init_pid(struct lxc_container *c)
 
 	if (lxclock(c->slock, 0))
 		return -1;
-	ret = get_init_pid(c->name, c->config_path);
+	ret = lxc_cmd_get_init_pid(c->name, c->config_path);
 	lxcunlock(c->slock);
 	return ret;
 }
@@ -517,7 +517,7 @@ static bool lxcapi_stop(struct lxc_container *c)
 	if (!c)
 		return false;
 
-	ret = lxc_stop(c->name, c->config_path);
+	ret = lxc_cmd_stop(c->name, c->config_path);
 
 	return ret == 0;
 }
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 692de44..d43d580 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -262,90 +262,6 @@ static int signal_handler(int fd, void *data,
 	return 1;
 }
 
-int lxc_pid_callback(int fd, struct lxc_request *request,
-		     struct lxc_handler *handler)
-{
-	struct lxc_answer answer;
-	int ret;
-
-	memset(&answer, 0, sizeof(answer));
-	answer.pid = handler->pid;
-	answer.ret = 0;
-
-	ret = send(fd, &answer, sizeof(answer), 0);
-	if (ret < 0) {
-		WARN("failed to send answer to the peer");
-		return -1;
-	}
-
-	if (ret != sizeof(answer)) {
-		ERROR("partial answer sent");
-		return -1;
-	}
-
-	return 0;
-}
-
-int lxc_cgroup_callback(int fd, struct lxc_request *request,
-		     struct lxc_handler *handler)
-{
-	struct lxc_answer answer;
-	int ret;
-
-	memset(&answer, 0, sizeof(answer));
-	answer.pathlen = strlen(handler->cgroup) + 1;
-	answer.path = handler->cgroup;
-	answer.ret = 0;
-
-	ret = send(fd, &answer, sizeof(answer), 0);
-	if (ret < 0) {
-		WARN("failed to send answer to the peer");
-		return -1;
-	}
-
-	if (ret != sizeof(answer)) {
-		ERROR("partial answer sent");
-		return -1;
-	}
-
-	ret = send(fd, answer.path, answer.pathlen, 0);
-	if (ret < 0) {
-		WARN("failed to send answer to the peer");
-		return -1;
-	}
-
-	if (ret != answer.pathlen) {
-		ERROR("partial answer sent");
-		return -1;
-	}
-
-	return 0;
-}
-
-int lxc_clone_flags_callback(int fd, struct lxc_request *request,
-			     struct lxc_handler *handler)
-{
-	struct lxc_answer answer;
-	int ret;
-
-	memset(&answer, 0, sizeof(answer));
-	answer.pid = 0;
-	answer.ret = handler->clone_flags;
-
-	ret = send(fd, &answer, sizeof(answer), 0);
-	if (ret < 0) {
-		WARN("failed to send answer to the peer");
-		return -1;
-	}
-
-	if (ret != sizeof(answer)) {
-		ERROR("partial answer sent");
-		return -1;
-	}
-
-	return 0;
-}
-
 int lxc_set_state(const char *name, struct lxc_handler *handler, lxc_state_t state)
 {
 	handler->state = state;
@@ -374,7 +290,7 @@ int lxc_poll(const char *name, struct lxc_handler *handler)
 		goto out_mainloop_open;
 	}
 
-	if (lxc_command_mainloop_add(name, &descr, handler)) {
+	if (lxc_cmd_mainloop_add(name, &descr, handler)) {
 		ERROR("failed to add command handler to mainloop");
 		goto out_mainloop_open;
 	}
@@ -426,7 +342,7 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf, const char
 		goto out_free;
 	}
 
-	if (lxc_command_init(name, handler, lxcpath))
+	if (lxc_cmd_init(name, handler, lxcpath))
 		goto out_free_name;
 
 	if (lxc_read_seccomp_config(conf) != 0) {
diff --git a/src/lxc/state.c b/src/lxc/state.c
index 68ec00b..ed59535 100644
--- a/src/lxc/state.c
+++ b/src/lxc/state.c
@@ -103,75 +103,14 @@ fail:
 	return -1;
 }
 
-static lxc_state_t __lxc_getstate(const char *name, const char *lxcpath)
-{
-	struct lxc_command command = {
-		.request = { .type = LXC_COMMAND_STATE },
-	};
-
-	int ret, stopped = 0;
-
-	ret = lxc_command(name, &command, &stopped, lxcpath);
-	if (ret < 0 && stopped)
-		return STOPPED;
-
-	if (ret < 0) {
-		ERROR("failed to send command");
-		return -1;
-	}
-
-	if (!ret) {
-		WARN("'%s' has stopped before sending its state", name);
-		return -1;
-	}
-
-	if (command.answer.ret < 0) {
-		ERROR("failed to get state for '%s': %s",
-			name, strerror(-command.answer.ret));
-		return -1;
-	}
-
-	DEBUG("'%s' is in '%s' state", name, lxc_state2str(command.answer.ret));
-
-	return command.answer.ret;
-}
-
 lxc_state_t lxc_getstate(const char *name, const char *lxcpath)
 {
 	lxc_state_t state = freezer_state(name, lxcpath);
 	if (state != FROZEN && state != FREEZING)
-		state = __lxc_getstate(name, lxcpath);
+		state = lxc_cmd_get_state(name, lxcpath);
 	return state;
 }
 
-/*----------------------------------------------------------------------------
- * functions used by lxc-start mainloop
- * to handle above command request.
- *--------------------------------------------------------------------------*/
-extern int lxc_state_callback(int fd, struct lxc_request *request,
-			struct lxc_handler *handler)
-{
-	struct lxc_answer answer;
-	int ret;
-
-	memset(&answer, 0, sizeof(answer));
-	answer.ret = handler->state;
-
-	ret = send(fd, &answer, sizeof(answer), 0);
-	if (ret < 0) {
-		WARN("failed to send answer to the peer");
-		goto out;
-	}
-
-	if (ret != sizeof(answer)) {
-		ERROR("partial answer sent");
-		goto out;
-	}
-
-out:
-	return ret;
-}
-
 static int fillwaitedstates(const char *strstates, int *states)
 {
 	char *token, *saveptr = NULL;
diff --git a/src/lxc/stop.c b/src/lxc/stop.c
deleted file mode 100644
index 4fb4480..0000000
--- a/src/lxc/stop.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/param.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <fcntl.h>
-
-#include <lxc/log.h>
-#include <lxc/start.h>
-#include <lxc/conf.h>
-
-#include "lxc.h"
-#include "commands.h"
-
-lxc_log_define(lxc_stop, lxc);
-
-int lxc_stop(const char *name, const char *lxcpath)
-{
-	struct lxc_command command = {
-		.request = { .type = LXC_COMMAND_STOP },
-	};
-
-	int ret, stopped = 0;
-
-	ret = lxc_command(name, &command,&stopped, lxcpath);
-	if (ret < 0 && stopped) {
-		INFO("'%s' is already stopped", name);
-		return 0;
-	}
-
-	if (ret < 0) {
-		ERROR("failed to send command");
-		return -1;
-	}
-
-	/* we do not expect any answer, because we wait for the connection to be
-	 * closed
-	 */
-	if (ret > 0) {
-		ERROR("failed to stop '%s': %s",
-			name, strerror(-command.answer.ret));
-		return -1;
-	}
-
-	INFO("'%s' has stopped", name);
-
-	return 0;
-}
-
-/*----------------------------------------------------------------------------
- * functions used by lxc-start mainloop
- * to handle above command request.
- *--------------------------------------------------------------------------*/
-extern int lxc_stop_callback(int fd, struct lxc_request *request,
-			struct lxc_handler *handler)
-{
-	struct lxc_answer answer;
-	int ret;
-	int stopsignal = SIGKILL;
-
-	if (handler->conf->stopsignal)
-		stopsignal = handler->conf->stopsignal;
-	memset(&answer, 0, sizeof(answer));
-	answer.ret = kill(handler->pid, stopsignal);
-	if (!answer.ret) {
-		ret = lxc_unfreeze_bypath(handler->cgroup);
-		if (!ret)
-			return 0;
-
-		ERROR("failed to unfreeze container");
-		answer.ret = ret;
-	}
-
-	ret = send(fd, &answer, sizeof(answer), 0);
-	if (ret < 0) {
-		WARN("failed to send answer to the peer");
-		goto out;
-	}
-
-	if (ret != sizeof(answer)) {
-		ERROR("partial answer sent");
-		goto out;
-	}
-
-out:
-	return -1;
-}
-
diff --git a/src/tests/cgpath.c b/src/tests/cgpath.c
index d8c3624..b7f0885 100644
--- a/src/tests/cgpath.c
+++ b/src/tests/cgpath.c
@@ -137,7 +137,8 @@ int main()
 	}
 
 	const char *dirpath;
-	if (lxc_get_cgpath(&dirpath, NULL, c2->name, c2->config_path) < 0) {
+	dirpath = lxc_cmd_get_cgroup_path(NULL, c2->name, c2->config_path);
+	if (!dirpath) {
 		TSTERR("getting second container's cgpath");
 		goto out;
 	}
@@ -150,6 +151,8 @@ int main()
 
 	retv = 0;
 out:
+	if (dirpath)
+		free(dirpath);
 	if (c2) {
 		c2->stop(c2);
 		c2->destroy(c2);
-- 
1.8.1.4





More information about the lxc-devel mailing list