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

Serge Hallyn serge.hallyn at ubuntu.com
Tue May 21 13:18:01 UTC 2013


Quoting Dwight Engen (dwight.engen at oracle.com):
> 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>

Working great on my box - thanks.

Acked-by: Serge E. Hallyn <serge.hallyn at ubuntu.com>

It seems like a general cleanup, but I'm wondering what your motivation
was for the get-config command?  Programs using the struct
lxc_container API or lua/python3 bindings can after all just do

	import lxc
	c = lxcContainer('c1', NULL);
	c.get_config_item('lxc.rootfs')

> ---
>  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
> 
> 
> ------------------------------------------------------------------------------
> AlienVault Unified Security Management (USM) platform delivers complete
> security visibility with the essential security capabilities. Easily and
> efficiently configure, manage, and operate all of your security controls
> from a single console and one unified framework. Download a free trial.
> http://p.sf.net/sfu/alienvault_d2d
> _______________________________________________
> Lxc-devel mailing list
> Lxc-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel




More information about the lxc-devel mailing list