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

Dwight Engen dwight.engen at oracle.com
Tue May 21 14:44:31 UTC 2013


On Tue, 21 May 2013 08:18:01 -0500
Serge Hallyn <serge.hallyn at ubuntu.com> wrote:

> 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')

Creating a container using the API/bindings creates a new c, and
c->lxc_conf contains a parse of the on-disk configuration as it
exists at the time of the lxcContainer() call but may not reflect an
already running c1. I specifically wanted to know the veth pair name of
an already running container, and I think it may be useful to know other
configuration items of a running container which may differ from what
is currently on disk.

> > ---
> >  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