diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 4a1906101..f8eb41b8d 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 c2f0a2da4..44266de62 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; @@ -214,56 +214,10 @@ fail: return -1; } -/* - * 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 937b9c92f..971311ece 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 d45ae2112..3f2148858 100644 --- a/src/lxc/commands.c +++ b/src/lxc/commands.c @@ -34,27 +34,30 @@ #include #include +#include #include #include /* for struct lxc_handler */ #include #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) - return ret; - if (answer->pathlen >= MAXPATHLEN) { - ERROR("cgroup path was too long"); + 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; } - 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; + + 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 (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; + } + + 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) -{ - return __lxc_command(name, command, stopped, 0, lxcpath); -} +/* Implentations of the commands and their callbacks */ -extern int lxc_command_connected(const char *name, - struct lxc_command *command, int *stopped, - const char *lxcpath) +/* + * 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, 1, lxcpath); -} - - -pid_t get_init_pid(const char *name, const char *lxcpath) -{ - struct lxc_command command = { - .request = { .type = LXC_COMMAND_PID }, + int ret, stopped = 0; + struct lxc_cmd_rr cmd = { + .req = { .cmd = LXC_CMD_GET_INIT_PID }, }; - int ret, stopped = 0; + ret = lxc_cmd(name, &cmd, &stopped, lxcpath); + if (ret < 0) + return ret; - ret = lxc_command(name, &command, &stopped, lxcpath); - if (ret < 0 && stopped) - return -1; - - if (ret < 0) { - ERROR("failed to send command"); - return -1; - } - - if (command.answer.ret) { - ERROR("failed to retrieve the init pid: %s", - strerror(-command.answer.ret)); - return -1; - } - - return command.answer.pid; + return PTR_TO_INT(cmd.rsp.data); } -int lxc_get_clone_flags(const char *name, const char *lxcpath) +static int lxc_cmd_get_init_pid_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 = { .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 }, }; - int ret, stopped = 0; + ret = lxc_cmd(name, &cmd, &stopped, lxcpath); + if (ret < 0) + return ret; - ret = lxc_command(name, &command, &stopped, 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_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_cmd(name, &cmd, &stopped, lxcpath); if (ret < 0 && stopped) + return STOPPED; + + if (ret < 0) return -1; - if (ret < 0) { - ERROR("failed to send command"); + if (!ret) { + WARN("'%s' has stopped before sending its state", name); return -1; } - return command.answer.ret; + DEBUG("'%s' is in '%s' state", name, + lxc_state2str(PTR_TO_INT(cmd.rsp.data))); + return PTR_TO_INT(cmd.rsp.data); } -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 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) }; -static int trigger_command(int fd, struct lxc_request *request, + 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) { + if (stopped) { + INFO("'%s' is already stopped", name); + return 0; + } + 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(-cmd.rsp.ret)); + return -1; + } + + INFO("'%s' has stopped", name); + return 0; +} + +static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req, + struct lxc_handler *handler) +{ + 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_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; + } + + 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; + } + + /* 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; +} + + + +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 *); + typedef int (*callback)(int, struct lxc_cmd_req *, 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, + 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; } - ret = trigger_command(fd, &request, handler); + if (req.datalen > LXC_CMD_DATA_MAX) { + ERROR("cmd data length %d too large", req.datalen); + ret = -1; + goto out_close; + } + + 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 3b725fbbf..b5b478878 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_cmd_req { + lxc_cmd_t cmd; + int datalen; + const void *data; }; -struct lxc_request { - int type; - int 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); +struct lxc_cmd_console_rsp_data { + int fd; + int ttynum; +}; -extern int lxc_command(const char *name, struct lxc_command *command, - int *stopped, const char *lxcpath); - -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 9ef62c102..93c16b5fa 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 9057757c5..8491ff3da 100644 --- a/src/lxc/lxc.h +++ b/src/lxc/lxc.h @@ -51,14 +51,6 @@ struct lxc_arguments; 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 diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c index e0c253b4b..efa7d89da 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 795b54c24..820794ab9 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 to exit the console, \ - to enter Ctrl+%1$c itself\n", +Connected to tty %1$d\n\ +Type to exit the console, \ + 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 f815b0f47..f86626d97 100644 --- a/src/lxc/lxc_info.c +++ b/src/lxc/lxc_info.c @@ -22,6 +22,7 @@ */ #include #include +#include #include #include #include @@ -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 9a24209dd..1fedf1d08 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 d7c728373..0ed8ca066 100644 --- a/src/lxc/lxc_stop.c +++ b/src/lxc/lxc_stop.c @@ -29,6 +29,7 @@ #include #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 4a6f774b2..7ce25c6d8 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -283,7 +283,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; } @@ -521,7 +521,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 692de4459..d43d58073 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 68ec00ba0..ed5953511 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 4fb4480f8..000000000 --- a/src/lxc/stop.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * lxc: linux Container library - * - * (C) Copyright IBM Corp. 2007, 2008 - * - * Authors: - * Daniel Lezcano - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#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 d8c36248e..b7f088563 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);