From 29c845fe630204d35b300241a47ccd4525d315f9 Mon Sep 17 00:00:00 2001 From: LiFeng Date: Fri, 29 Nov 2019 22:12:10 -0500 Subject: [PATCH 138/139] resize: implement resize function in exec/start Signed-off-by: LiFeng --- src/lxc/Makefile.am | 1 + src/lxc/attach.c | 45 ++++- src/lxc/attach.h | 2 +- src/lxc/commands.c | 44 +++++ src/lxc/commands.h | 9 + src/lxc/exec_commands.c | 416 +++++++++++++++++++++++++++++++++++++++++++++ src/lxc/exec_commands.h | 73 ++++++++ src/lxc/lxccontainer.c | 64 ++++++- src/lxc/lxccontainer.h | 15 +- src/lxc/terminal.c | 26 +++ src/lxc/terminal.h | 1 + src/lxc/tools/arguments.h | 3 +- src/lxc/tools/lxc_attach.c | 20 ++- src/lxc/tools/lxc_copy.c | 2 +- src/lxc/tools/lxc_ls.c | 2 +- 15 files changed, 698 insertions(+), 25 deletions(-) create mode 100644 src/lxc/exec_commands.c create mode 100644 src/lxc/exec_commands.h diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 27240cc..c21eb85 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -101,6 +101,7 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \ cgroups/cgroup_utils.c cgroups/cgroup_utils.h \ compiler.h \ commands.c commands.h \ + exec_commands.c exec_commands.h \ commands_utils.c commands_utils.h \ conf.c conf.h \ confile.c confile.h \ diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 1f14eb4..03a7646 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -64,6 +64,7 @@ #include "syscall_wrappers.h" #include "terminal.h" #include "utils.h" +#include "exec_commands.h" #if HAVE_SYS_PERSONALITY_H #include @@ -1208,7 +1209,7 @@ out: return ret; } -int lxc_attach(const char *name, const char *lxcpath, +int lxc_attach(const char *name, const char *lxcpath, const char *suffix, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process, char **err_msg) { @@ -1221,6 +1222,10 @@ int lxc_attach(const char *name, const char *lxcpath, struct lxc_terminal terminal; struct lxc_conf *conf; struct attach_clone_payload payload = {0}; + struct lxc_exec_command_handler exec_command; + + exec_command.maincmd_fd = -1; + exec_command.terminal = &terminal; ret = access("/proc/self/ns", X_OK); if (ret) { @@ -1354,6 +1359,10 @@ int lxc_attach(const char *name, const char *lxcpath, } terminal.log_fd = options->log_fd; + if (suffix != NULL) { + exec_command.maincmd_fd = lxc_exec_cmd_init(name, lxcpath, suffix); + exec_command.terminal = &terminal; + } } else { lxc_terminal_init(&terminal); } @@ -1394,15 +1403,30 @@ int lxc_attach(const char *name, const char *lxcpath, ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); if (ret < 0) { SYSERROR("Could not set up required IPC mechanism for attaching"); + if (options->attach_flags & LXC_ATTACH_TERMINAL) { + lxc_terminal_delete(&terminal); + lxc_terminal_conf_free(&terminal); + if (exec_command.maincmd_fd != -1) { + close(exec_command.maincmd_fd); + } + } free(cwd); lxc_proc_put_context_info(init_ctx); return -1; } - /* isulad: pipdfd for get error message of child or grandchild process. */ if (pipe2(conf->errpipe, O_CLOEXEC) != 0) { SYSERROR("Failed to init errpipe"); + if (options->attach_flags & LXC_ATTACH_TERMINAL) { + lxc_terminal_delete(&terminal); + lxc_terminal_conf_free(&terminal); + if (exec_command.maincmd_fd != -1) { + close(exec_command.maincmd_fd); + } + } + close(ipc_sockets[0]); + close(ipc_sockets[1]); free(cwd); lxc_proc_put_context_info(init_ctx); return -1; @@ -1418,6 +1442,15 @@ int lxc_attach(const char *name, const char *lxcpath, pid = fork(); if (pid < 0) { SYSERROR("Failed to create first subprocess"); + if (options->attach_flags & LXC_ATTACH_TERMINAL) { + lxc_terminal_delete(&terminal); + lxc_terminal_conf_free(&terminal); + if (exec_command.maincmd_fd != -1) { + close(exec_command.maincmd_fd); + } + } + close(ipc_sockets[0]); + close(ipc_sockets[1]); free(cwd); lxc_proc_put_context_info(init_ctx); return -1; @@ -1474,6 +1507,8 @@ int lxc_attach(const char *name, const char *lxcpath, if (ret < 0) goto on_error; + (void)lxc_exec_cmd_mainloop_add(&descr, &exec_command); + TRACE("Initialized terminal mainloop"); } @@ -1597,6 +1632,9 @@ int lxc_attach(const char *name, const char *lxcpath, if (options->attach_flags & LXC_ATTACH_TERMINAL) { lxc_terminal_delete(&terminal); lxc_terminal_conf_free(&terminal); + if (exec_command.maincmd_fd != -1) { + close(exec_command.maincmd_fd); + } } lxc_proc_put_context_info(init_ctx); @@ -1615,6 +1653,9 @@ int lxc_attach(const char *name, const char *lxcpath, lxc_attach_terminal_close_master(&terminal); lxc_attach_terminal_close_peer(&terminal); lxc_attach_terminal_close_log(&terminal); + if (exec_command.maincmd_fd != -1) { + close(exec_command.maincmd_fd); + } } /* Wait for the parent to have setup cgroups. */ diff --git a/src/lxc/attach.h b/src/lxc/attach.h index e62b98b..8626a8e 100644 --- a/src/lxc/attach.h +++ b/src/lxc/attach.h @@ -41,7 +41,7 @@ struct lxc_proc_context_info { int ns_fd[LXC_NS_MAX]; }; -extern int lxc_attach(const char *name, const char *lxcpath, +extern int lxc_attach(const char *name, const char *lxcpath, const char *suffix, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process, char **err_msg); diff --git a/src/lxc/commands.c b/src/lxc/commands.c index b70564f..8fd929d 100644 --- a/src/lxc/commands.c +++ b/src/lxc/commands.c @@ -97,6 +97,7 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd) [LXC_CMD_CONSOLE_LOG] = "console_log", [LXC_CMD_SERVE_STATE_CLIENTS] = "serve_state_clients", [LXC_CMD_SET_TERMINAL_FIFOS] = "set_terminal_fifos", + [LXC_CMD_SET_TERMINAL_WINCH] = "set_terminal_winch", }; if (cmd >= LXC_CMD_MAX) @@ -1126,6 +1127,48 @@ static int lxc_cmd_set_terminal_fifos_callback(int fd, struct lxc_cmd_req *req, } +int lxc_cmd_set_terminal_winch(const char *name, const char *lxcpath, unsigned int height, unsigned int width) +{ + int ret = 0, stopped = 0; + struct lxc_cmd_set_terminal_winch_request data = { 0 }; + + data.height = height; + data.width = width; + + struct lxc_cmd_rr cmd = { + .req = { + .cmd = LXC_CMD_SET_TERMINAL_WINCH, + .datalen = sizeof(struct lxc_cmd_set_terminal_winch_request), + .data = &data, + }, + }; + + ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); + if (ret < 0) { + ERROR("Failed to send command to container"); + return -1; + } + + if (cmd.rsp.ret != 0) { + ERROR("Command response error:%d", cmd.rsp.ret); + return -1; + } + return 0; +} + +static int lxc_cmd_set_terminal_winch_callback(int fd, struct lxc_cmd_req *req, + struct lxc_handler *handler) +{ + struct lxc_cmd_rsp rsp; + struct lxc_cmd_set_terminal_winch_request *data = (struct lxc_cmd_set_terminal_winch_request *)(req->data); + memset(&rsp, 0, sizeof(rsp)); + + rsp.ret = lxc_set_terminal_winsz(&handler->conf->console, data->height, data->width);; + + return lxc_cmd_rsp_send(fd, &rsp); + +} + static int lxc_cmd_process(int fd, struct lxc_cmd_req *req, struct lxc_handler *handler) { @@ -1146,6 +1189,7 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req, [LXC_CMD_CONSOLE_LOG] = lxc_cmd_console_log_callback, [LXC_CMD_SERVE_STATE_CLIENTS] = lxc_cmd_serve_state_clients_callback, [LXC_CMD_SET_TERMINAL_FIFOS] = lxc_cmd_set_terminal_fifos_callback, + [LXC_CMD_SET_TERMINAL_WINCH] = lxc_cmd_set_terminal_winch_callback, }; if (req->cmd >= LXC_CMD_MAX) { diff --git a/src/lxc/commands.h b/src/lxc/commands.h index 6b64849..c8cc8cd 100644 --- a/src/lxc/commands.h +++ b/src/lxc/commands.h @@ -47,6 +47,7 @@ typedef enum { LXC_CMD_CONSOLE_LOG, LXC_CMD_SERVE_STATE_CLIENTS, LXC_CMD_SET_TERMINAL_FIFOS, + LXC_CMD_SET_TERMINAL_WINCH, LXC_CMD_MAX, } lxc_cmd_t; @@ -80,6 +81,11 @@ struct lxc_cmd_console_log { }; +struct lxc_cmd_set_terminal_winch_request { + unsigned int height; + unsigned int width; +}; + extern int lxc_cmd_terminal_winch(const char *name, const char *lxcpath); extern int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath); @@ -129,4 +135,7 @@ extern int lxc_cmd_console_log(const char *name, const char *lxcpath, extern int lxc_cmd_set_terminal_fifos(const char *name, const char *lxcpath, const char *in_fifo, const char *out_fifo, const char *err_fifo); +extern int lxc_cmd_set_terminal_winch(const char *name, const char *lxcpath, unsigned int height, unsigned int width); + + #endif /* __commands_h */ diff --git a/src/lxc/exec_commands.c b/src/lxc/exec_commands.c new file mode 100644 index 0000000..00129cb --- /dev/null +++ b/src/lxc/exec_commands.c @@ -0,0 +1,416 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved. + * Author: lifeng + * Create: 2019-12-08 + * Description: provide container definition + * lxc: linux Container library + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + ******************************************************************************/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "af_unix.h" +#include "cgroup.h" +#include "exec_commands.h" +#include "commands_utils.h" +#include "conf.h" +#include "config.h" +#include "confile.h" +#include "log.h" +#include "lxc.h" +#include "lxclock.h" +#include "mainloop.h" +#include "monitor.h" +#include "terminal.h" +#include "utils.h" + +lxc_log_define(commands_exec, lxc); + +static const char *lxc_exec_cmd_str(lxc_exec_cmd_t cmd) +{ + static const char *const cmdname[LXC_EXEC_CMD_MAX] = { + [LXC_EXEC_CMD_SET_TERMINAL_WINCH] = "set_exec_terminal_winch", + }; + + if (cmd >= LXC_EXEC_CMD_MAX) + return "Invalid request"; + + return cmdname[cmd]; +} + +static int lxc_exec_cmd_rsp_recv(int sock, struct lxc_exec_cmd_rr *cmd) +{ + int ret, rspfd; + struct lxc_exec_cmd_rsp *rsp = &cmd->rsp; + + ret = lxc_abstract_unix_recv_fds_timeout(sock, &rspfd, 1, rsp, sizeof(*rsp), 1000 * 1000); + if (ret < 0) { + SYSERROR("Failed to receive response for command \"%s\"", + lxc_exec_cmd_str(cmd->req.cmd)); + + if (errno == ECONNRESET || errno == EAGAIN || errno == EWOULDBLOCK) { + errno = ECONNRESET; /*isulad set errno ECONNRESET when timeout */ + return -1; + } + + return -1; + } + TRACE("Command \"%s\" received response", lxc_exec_cmd_str(cmd->req.cmd)); + + if (rsp->datalen == 0) { + DEBUG("Response data length for command \"%s\" is 0", + lxc_exec_cmd_str(cmd->req.cmd)); + return ret; + } + + if (rsp->datalen > LXC_CMD_DATA_MAX) { + ERROR("Response data for command \"%s\" is too long: %d bytes > %d", + lxc_exec_cmd_str(cmd->req.cmd), rsp->datalen, LXC_CMD_DATA_MAX); + return -1; + } + + rsp->data = malloc(rsp->datalen); + if (!rsp->data) { + errno = ENOMEM; + ERROR("Failed to allocate response buffer for command \"%s\"", + lxc_exec_cmd_str(cmd->req.cmd)); + return -1; + } + + ret = lxc_recv_nointr(sock, rsp->data, rsp->datalen, 0); + if (ret != rsp->datalen) { + SYSERROR("Failed to receive response data for command \"%s\"", + lxc_exec_cmd_str(cmd->req.cmd)); + return -1; + } + + return ret; +} + +static int lxc_exec_cmd_rsp_send(int fd, struct lxc_exec_cmd_rsp *rsp) +{ + ssize_t ret; + + errno = EMSGSIZE; + ret = lxc_send_nointr(fd, rsp, sizeof(*rsp), MSG_NOSIGNAL); + if (ret < 0 || (size_t)ret != sizeof(*rsp)) { + SYSERROR("Failed to send command response %zd", ret); + return -1; + } + + if (!rsp->data || rsp->datalen <= 0) + return 0; + + errno = EMSGSIZE; + ret = lxc_send_nointr(fd, rsp->data, rsp->datalen, MSG_NOSIGNAL); + if (ret < 0 || ret != (ssize_t)rsp->datalen) { + SYSWARN("Failed to send command response data %zd", ret); + return -1; + } + + return 0; +} + +static int lxc_exec_cmd_send(const char *name, struct lxc_exec_cmd_rr *cmd, + const char *lxcpath, const char *hashed_sock_name, const char *suffix) +{ + int client_fd, saved_errno; + ssize_t ret = -1; + + client_fd = lxc_cmd_connect(name, lxcpath, hashed_sock_name, suffix); + if (client_fd < 0) + return -1; + + ret = lxc_abstract_unix_send_credential(client_fd, &cmd->req, + sizeof(cmd->req)); + if (ret < 0 || (size_t)ret != sizeof(cmd->req)) + goto on_error; + + if (cmd->req.datalen <= 0) + return client_fd; + + errno = EMSGSIZE; + ret = lxc_send_nointr(client_fd, (void *)cmd->req.data, + cmd->req.datalen, MSG_NOSIGNAL); + if (ret < 0 || ret != (ssize_t)cmd->req.datalen) + goto on_error; + + return client_fd; + +on_error: + saved_errno = errno; + close(client_fd); + errno = saved_errno; + + return -1; +} + +static int lxc_exec_cmd(const char *name, struct lxc_exec_cmd_rr *cmd, const char *lxcpath, const char *hashed_sock_name, const char *suffix) +{ + int client_fd = -1; + int saved_errno; + int ret = -1; + + client_fd = lxc_exec_cmd_send(name, cmd, lxcpath, hashed_sock_name, suffix); + if (client_fd < 0) { + SYSTRACE("Command \"%s\" failed to connect command socket", + lxc_exec_cmd_str(cmd->req.cmd)); + return -1; + } + + ret = lxc_exec_cmd_rsp_recv(client_fd, cmd); + + saved_errno = errno; + close(client_fd); + errno = saved_errno; + return ret; +} + +int lxc_exec_cmd_set_terminal_winch(const char *name, const char *lxcpath, const char *suffix, unsigned int height, unsigned int width) +{ + int ret = 0; + struct lxc_exec_cmd_set_terminal_winch_request data = { 0 }; + + data.height = height; + data.width = width; + + struct lxc_exec_cmd_rr cmd = { + .req = { + .cmd = LXC_EXEC_CMD_SET_TERMINAL_WINCH, + .datalen = sizeof(struct lxc_exec_cmd_set_terminal_winch_request), + .data = &data, + }, + }; + + ret = lxc_exec_cmd(name, &cmd, lxcpath, NULL, suffix); + if (ret < 0) { + ERROR("Failed to send command to container"); + return -1; + } + + if (cmd.rsp.ret != 0) { + ERROR("Command response error:%d", cmd.rsp.ret); + return -1; + } + return 0; +} + +static int lxc_exec_cmd_set_terminal_winch_callback(int fd, struct lxc_exec_cmd_req *req, + struct lxc_exec_command_handler *handler) +{ + struct lxc_exec_cmd_rsp rsp; + struct lxc_exec_cmd_set_terminal_winch_request *data = (struct lxc_exec_cmd_set_terminal_winch_request *)(req->data); + memset(&rsp, 0, sizeof(rsp)); + + rsp.ret = lxc_set_terminal_winsz(handler->terminal, data->height, data->width);; + + return lxc_exec_cmd_rsp_send(fd, &rsp); + +} + +static int lxc_exec_cmd_process(int fd, struct lxc_exec_cmd_req *req, + struct lxc_exec_command_handler *handler) +{ + typedef int (*callback)(int, struct lxc_exec_cmd_req *, struct lxc_exec_command_handler *); + + callback cb[LXC_EXEC_CMD_MAX] = { + [LXC_EXEC_CMD_SET_TERMINAL_WINCH] = lxc_exec_cmd_set_terminal_winch_callback, + }; + + if (req->cmd >= LXC_EXEC_CMD_MAX) { + ERROR("Undefined command id %d", req->cmd); + return -1; + } + return cb[req->cmd](fd, req, handler); +} + +static void lxc_exec_cmd_fd_cleanup(int fd, struct lxc_epoll_descr *descr) +{ + lxc_mainloop_del_handler(descr, fd); + close(fd); + return; +} + +static int lxc_exec_cmd_handler(int fd, uint32_t events, void *data, + struct lxc_epoll_descr *descr) +{ + int ret; + struct lxc_exec_cmd_req req; + void *reqdata = NULL; + struct lxc_exec_command_handler *handler = data; + + ret = lxc_abstract_unix_rcv_credential(fd, &req, sizeof(req)); + if (ret < 0) { + SYSERROR("Failed to receive data on command socket for command " + "\"%s\"", lxc_exec_cmd_str(req.cmd)); + + if (errno == EACCES) { + /* We don't care for the peer, just send and close. */ + struct lxc_exec_cmd_rsp rsp = {.ret = ret}; + + lxc_exec_cmd_rsp_send(fd, &rsp); + } + + goto out_close; + } + + if (ret == 0) + goto out_close; + + if (ret != sizeof(req)) { + WARN("Failed to receive full command request. Ignoring request " + "for \"%s\"", lxc_exec_cmd_str(req.cmd)); + ret = -1; + goto out_close; + } + + if (req.datalen > LXC_CMD_DATA_MAX) { + ERROR("Received command data length %d is too large for " + "command \"%s\"", req.datalen, lxc_exec_cmd_str(req.cmd)); + errno = EFBIG; + ret = -EFBIG; + goto out_close; + } + + if (req.datalen > 0) { + reqdata = alloca(req.datalen); + if (!reqdata) { + ERROR("Failed to allocate memory for \"%s\" command", + lxc_exec_cmd_str(req.cmd)); + errno = ENOMEM; + ret = -ENOMEM; + goto out_close; + } + + ret = lxc_recv_nointr(fd, reqdata, req.datalen, 0); + if (ret != req.datalen) { + WARN("Failed to receive full command request. Ignoring " + "request for \"%s\"", lxc_exec_cmd_str(req.cmd)); + ret = LXC_MAINLOOP_ERROR; + goto out_close; + } + + req.data = reqdata; + } + + ret = lxc_exec_cmd_process(fd, &req, handler); + if (ret) { + /* This is not an error, but only a request to close fd. */ + ret = LXC_MAINLOOP_CONTINUE; + goto out_close; + } + +out: + return ret; + +out_close: + lxc_exec_cmd_fd_cleanup(fd, descr); + goto out; +} + +static int lxc_exec_cmd_accept(int fd, uint32_t events, void *data, + struct lxc_epoll_descr *descr) +{ + int connection = -1; + int opt = 1, ret = -1; + + connection = accept(fd, NULL, 0); + if (connection < 0) { + SYSERROR("Failed to accept connection to run command"); + return LXC_MAINLOOP_ERROR; + } + + ret = fcntl(connection, F_SETFD, FD_CLOEXEC); + if (ret < 0) { + SYSERROR("Failed to set close-on-exec on incoming command connection"); + goto out_close; + } + + ret = setsockopt(connection, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt)); + if (ret < 0) { + SYSERROR("Failed to enable necessary credentials on command socket"); + goto out_close; + } + + ret = lxc_mainloop_add_handler(descr, connection, lxc_exec_cmd_handler, data); + if (ret) { + ERROR("Failed to add command handler"); + goto out_close; + } + +out: + return ret; + +out_close: + close(connection); + goto out; +} + +int lxc_exec_cmd_init(const char *name, const char *lxcpath, const char *suffix) +{ + int fd, ret; + char path[LXC_AUDS_ADDR_LEN] = {0}; + + ret = lxc_make_abstract_socket_name(path, sizeof(path), name, lxcpath, NULL, suffix); + if (ret < 0) + return -1; + TRACE("Creating abstract unix socket \"%s\"", &path[1]); + + fd = lxc_abstract_unix_open(path, SOCK_STREAM, 0); + if (fd < 0) { + SYSERROR("Failed to create command socket %s", &path[1]); + if (errno == EADDRINUSE) + ERROR("Container \"%s\" appears to be already running", name); + + return -1; + } + + ret = fcntl(fd, F_SETFD, FD_CLOEXEC); + if (ret < 0) { + SYSERROR("Failed to set FD_CLOEXEC on command socket file descriptor"); + close(fd); + return -1; + } + + return fd; +} + +int lxc_exec_cmd_mainloop_add(struct lxc_epoll_descr *descr, struct lxc_exec_command_handler *handler) +{ + int ret; + int fd = handler->maincmd_fd; + + ret = lxc_mainloop_add_handler(descr, fd, lxc_exec_cmd_accept, handler); + if (ret < 0) { + ERROR("Failed to add handler for command socket"); + close(fd); + } + + return ret; +} diff --git a/src/lxc/exec_commands.h b/src/lxc/exec_commands.h new file mode 100644 index 0000000..2581ee9 --- /dev/null +++ b/src/lxc/exec_commands.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved. + * Author: lifeng + * Create: 2019-12-08 + * Description: provide container definition + * lxc: linux Container library + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + ******************************************************************************/ + +#ifndef __LXC_EXEC_COMMANDS_H +#define __LXC_EXEC_COMMANDS_H + +#include +#include +#include + +#include "lxccontainer.h" +#include "macro.h" +#include "state.h" +#include "terminal.h" + +struct lxc_exec_command_handler { + int maincmd_fd; + struct lxc_terminal *terminal; +}; + +typedef enum { + LXC_EXEC_CMD_SET_TERMINAL_WINCH, + LXC_EXEC_CMD_MAX, +} lxc_exec_cmd_t; + +struct lxc_exec_cmd_req { + lxc_exec_cmd_t cmd; + int datalen; + const void *data; +}; + +struct lxc_exec_cmd_rsp { + int ret; /* 0 on success, -errno on failure */ + int datalen; + void *data; +}; + +struct lxc_exec_cmd_rr { + struct lxc_exec_cmd_req req; + struct lxc_exec_cmd_rsp rsp; +}; + +struct lxc_exec_cmd_set_terminal_winch_request { + unsigned int height; + unsigned int width; +}; + +struct lxc_epoll_descr; +struct lxc_handler; + +extern int lxc_exec_cmd_init(const char *name, const char *lxcpath, const char *suffix); +extern int lxc_exec_cmd_mainloop_add(struct lxc_epoll_descr *descr, struct lxc_exec_command_handler *handler); +extern int lxc_exec_cmd_set_terminal_winch(const char *name, const char *lxcpath, const char *suffix, unsigned int height, unsigned int width); + +#endif /* __exec_commands_h */ diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 9f9cbfc..7ef57f0 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -47,6 +47,7 @@ #include "cgroup.h" #include "commands.h" #include "commands_utils.h" +#include "exec_commands.h" #include "conf.h" #include "config.h" #include "confile.h" @@ -4214,7 +4215,7 @@ static bool do_lxcapi_rename(struct lxc_container *c, const char *newname) WRAP_API_1(bool, lxcapi_rename, const char *) -static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process) +static int lxcapi_attach(struct lxc_container *c, const char *suffix, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process) { int ret; @@ -4223,12 +4224,12 @@ static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_functio current_config = c->lxc_conf; - ret = lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process, &c->lxc_conf->errmsg); + ret = lxc_attach(c->name, c->config_path, suffix, exec_function, exec_payload, options, attached_process, &c->lxc_conf->errmsg); current_config = NULL; return ret; } -static int do_lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[]) +static int do_lxcapi_attach_run_wait(struct lxc_container *c, const char *suffix, lxc_attach_options_t *options, const char *program, const char * const argv[]) { lxc_attach_command_t command; pid_t pid; @@ -4240,7 +4241,7 @@ static int do_lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options command.program = (char*)program; command.argv = (char**)argv; - r = lxc_attach(c->name, c->config_path, lxc_attach_run_command, &command, options, &pid, NULL); + r = lxc_attach(c->name, c->config_path, suffix, lxc_attach_run_command, &command, options, &pid, NULL); if (r < 0) { ERROR("ups"); return r; @@ -4249,12 +4250,12 @@ static int do_lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options return lxc_wait_for_pid_status(pid); } -static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[]) +static int lxcapi_attach_run_wait(struct lxc_container *c, const char *suffix, lxc_attach_options_t *options, const char *program, const char * const argv[]) { int ret; current_config = c ? c->lxc_conf : NULL; - ret = do_lxcapi_attach_run_wait(c, options, program, argv); + ret = do_lxcapi_attach_run_wait(c, suffix, options, program, argv); current_config = NULL; return ret; @@ -5109,7 +5110,7 @@ static bool do_lxcapi_restore(struct lxc_container *c, char *directory, bool ver WRAP_API_2(bool, lxcapi_restore, char *, bool) -static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char *arg, ...) +static int lxcapi_attach_run_waitl(struct lxc_container *c, const char *suffix, lxc_attach_options_t *options, const char *program, const char *arg, ...) { va_list ap; const char **argv; @@ -5131,7 +5132,7 @@ static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t } argv[0] = arg; - ret = do_lxcapi_attach_run_wait(c, options, program, (const char * const *)argv); + ret = do_lxcapi_attach_run_wait(c, suffix, options, program, (const char * const *)argv); free((void*)argv); out: @@ -5230,6 +5231,51 @@ static bool do_lxcapi_clean_container_resource(struct lxc_container *c, pid_t pi WRAP_API_1(bool, lxcapi_clean_container_resource, pid_t) +static bool do_lxcapi_set_terminal_winch(struct lxc_container *c, unsigned int height, unsigned int width) +{ + bool ret = true; + + if (!c || !c->lxc_conf) + return false; + if (container_mem_lock(c)) { + ERROR("Error getting mem lock"); + return false; + } + + if (lxc_cmd_set_terminal_winch(c->name, c->config_path, height, width)) { + ERROR("Error set terminal winch"); + ret = false; + } + + container_mem_unlock(c); + return ret; +} + +WRAP_API_2(bool, lxcapi_set_terminal_winch, unsigned int, unsigned int) + +static bool do_lxcapi_set_exec_terminal_winch(struct lxc_container *c, const char *suffix, unsigned int height, unsigned int width) +{ + bool ret = true; + + if (!c || !c->lxc_conf) + return false; + if (container_mem_lock(c)) { + ERROR("Error getting mem lock"); + return false; + } + + if (lxc_exec_cmd_set_terminal_winch(c->name, c->config_path, suffix, height, width)) { + ERROR("Error set terminal winch"); + ret = false; + } + + container_mem_unlock(c); + return ret; +} + +WRAP_API_3(bool, lxcapi_set_exec_terminal_winch, const char *, unsigned int, unsigned int) + + /* isulad get coantainer pids */ static bool do_lxcapi_get_container_pids(struct lxc_container *c, pid_t **pids,size_t *pids_len) { @@ -5484,6 +5530,8 @@ static struct lxc_container *do_lxc_container_new(const char *name, const char * c->clean_container_resource = lxcapi_clean_container_resource; c->add_terminal_fifos = lxcapi_add_terminal_fifo; c->get_container_pids = lxcapi_get_container_pids; + c->set_terminal_winch = lxcapi_set_terminal_winch; + c->set_exec_terminal_winch = lxcapi_set_exec_terminal_winch; /* isulad add end */ return c; diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h index 608f815..976acf4 100644 --- a/src/lxc/lxccontainer.h +++ b/src/lxc/lxccontainer.h @@ -674,7 +674,7 @@ struct lxc_container { * * \return \c 0 on success, \c -1 on error. */ - int (*attach)(struct lxc_container *c, lxc_attach_exec_t exec_function, + int (*attach)(struct lxc_container *c, const char *suffix, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process); /*! @@ -688,7 +688,7 @@ struct lxc_container { * \return \c waitpid(2) status of exited process that ran \p * program, or \c -1 on error. */ - int (*attach_run_wait)(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[]); + int (*attach_run_wait)(struct lxc_container *c, const char *suffix, lxc_attach_options_t *options, const char *program, const char * const argv[]); /*! * \brief Run a program inside a container and wait for it to exit (list variant). @@ -701,7 +701,7 @@ struct lxc_container { * \return \c waitpid(2) status of exited process that ran \p * program, or \c -1 on error. */ - int (*attach_run_waitl)(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char *arg, ...); + int (*attach_run_waitl)(struct lxc_container *c, const char *suffix, lxc_attach_options_t *options, const char *program, const char *arg, ...); /*! * \brief Create a container snapshot. @@ -958,6 +958,15 @@ struct lxc_container { * \return \c true on success, else \c false. */ bool (*get_container_pids)(struct lxc_container *c,pid_t **pids,size_t *pids_len); + /*! isulad add + * \brief An API call to set terminal winch + * + * \param c Container. + * \return \c true on success, else \c false. + */ + bool (*set_terminal_winch)(struct lxc_container *c, unsigned int height, unsigned int width); + + bool (*set_exec_terminal_winch)(struct lxc_container *c, const char *suffix, unsigned int height, unsigned int width); }; /*! diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c index bccc23d..535f374 100644 --- a/src/lxc/terminal.c +++ b/src/lxc/terminal.c @@ -69,6 +69,32 @@ __attribute__((constructor)) void lxc_terminal_init_global(void) lxc_list_init(&lxc_ttys); } +int lxc_set_terminal_winsz(struct lxc_terminal *terminal, unsigned int height, unsigned int width) +{ + int ret = 0; + struct winsize wsz; + + if (terminal->master < 0) { + return 0; + } + + ret = ioctl(terminal->master, TIOCGWINSZ, &wsz); + if (ret < 0) { + WARN("Failed to get window size"); + return -1; + } + wsz.ws_col = width; + wsz.ws_row = height; + + ret = ioctl(terminal->master, TIOCSWINSZ, &wsz); + if (ret < 0) + WARN("Failed to set window size"); + else + DEBUG("Set window size to %d columns and %d rows", wsz.ws_col, + wsz.ws_row); + return ret; +} + void lxc_terminal_winsz(int srcfd, int dstfd) { int ret; diff --git a/src/lxc/terminal.h b/src/lxc/terminal.h index 9bb341f..4b5c70e 100644 --- a/src/lxc/terminal.h +++ b/src/lxc/terminal.h @@ -313,5 +313,6 @@ extern int lxc_terminal_map_ids(struct lxc_conf *c, /* isulad: if fd == -1, means delete all the fifos*/ int lxc_terminal_delete_fifo(int fd, struct lxc_list *list); int lxc_terminal_add_fifos(struct lxc_conf *conf, const char *fifonames); +int lxc_set_terminal_winsz(struct lxc_terminal *terminal, unsigned int height, unsigned int width); #endif /* __LXC_TERMINAL_H */ diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h index de02aeb..cb7f776 100644 --- a/src/lxc/tools/arguments.h +++ b/src/lxc/tools/arguments.h @@ -71,6 +71,7 @@ struct lxc_arguments { /* for lxc-attach */ int64_t attach_timeout; + const char *suffix; /* isulad add, suffix used for connect with parent of execed process*/ /* for lxc-console */ unsigned int ttynum; @@ -191,7 +192,7 @@ struct lxc_arguments { #define OPT_DISABLE_PTY OPT_USAGE - 13 #define OPT_OPEN_STDIN OPT_USAGE - 14 #define OPT_ATTACH_TIMEOUT OPT_USAGE - 15 - +#define OPT_ATTACH_SUFFIX OPT_USAGE - 16 /* isulad add end*/ extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c index 0d40155..56684e7 100644 --- a/src/lxc/tools/lxc_attach.c +++ b/src/lxc/tools/lxc_attach.c @@ -82,6 +82,7 @@ static const struct option my_longopts[] = { {"out-fifo", required_argument, 0, OPT_OUTPUT_FIFO}, {"err-fifo", required_argument, 0, OPT_STDERR_FIFO}, {"timeout", required_argument, 0, OPT_ATTACH_TIMEOUT}, + {"suffix", required_argument, 0, OPT_ATTACH_SUFFIX}, LXC_COMMON_OPTIONS }; @@ -287,6 +288,9 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) } args->attach_timeout = (unsigned int)atoll(arg); break; + case OPT_ATTACH_SUFFIX: + args->suffix = arg; + break; } return 0; @@ -351,7 +355,7 @@ static int lxc_attach_create_log_file(const char *log_file) } /*isulad: attach with terminal*/ -static int do_attach_foreground(struct lxc_container *c, lxc_attach_command_t *command, +static int do_attach_foreground(struct lxc_container *c, const char *suffix, lxc_attach_command_t *command, lxc_attach_options_t *attach_options, char **errmsg) { @@ -361,9 +365,9 @@ static int do_attach_foreground(struct lxc_container *c, lxc_attach_command_t *c int signal; if (command->program) - ret = c->attach(c, lxc_attach_run_command, command, attach_options, &pid); + ret = c->attach(c, suffix, lxc_attach_run_command, command, attach_options, &pid); else - ret = c->attach(c, lxc_attach_run_shell, NULL, attach_options, &pid); + ret = c->attach(c, suffix, lxc_attach_run_shell, NULL, attach_options, &pid); if (ret < 0) goto out; @@ -399,7 +403,7 @@ static void close_msg_pipe(int *errpipe) } /*isulad: attach without terminal in background */ -static int do_attach_background(struct lxc_container *c, lxc_attach_command_t *command, +static int do_attach_background(struct lxc_container *c, const char *suffix, lxc_attach_command_t *command, lxc_attach_options_t *attach_options, char **errmsg) { @@ -458,9 +462,9 @@ static int do_attach_background(struct lxc_container *c, lxc_attach_command_t *c setsid(); if (command->program) - ret = c->attach(c, lxc_attach_run_command, command, attach_options, &pid); + ret = c->attach(c, suffix, lxc_attach_run_command, command, attach_options, &pid); else - ret = c->attach(c, lxc_attach_run_shell, NULL, attach_options, &pid); + ret = c->attach(c, suffix, lxc_attach_run_shell, NULL, attach_options, &pid); if (ret < 0) { if (c->lxc_conf->errmsg) lxc_write_error_message(msgpipe[1], "%s", c->lxc_conf->errmsg); @@ -580,9 +584,9 @@ int main(int argc, char *argv[]) /* isulad: add do attach background */ if (attach_options.attach_flags & LXC_ATTACH_TERMINAL) - wexit = do_attach_foreground(c, &command, &attach_options, &errmsg); + wexit = do_attach_foreground(c, my_args.suffix, &command, &attach_options, &errmsg); else - wexit = do_attach_background(c, &command, &attach_options, &errmsg); + wexit = do_attach_background(c, my_args.suffix, &command, &attach_options, &errmsg); if (errmsg) { fprintf(stderr, "%s:%s:%s:%d starting container process caused \"%s\"", c->name, diff --git a/src/lxc/tools/lxc_copy.c b/src/lxc/tools/lxc_copy.c index 954f1dd..b4e2b8f 100644 --- a/src/lxc/tools/lxc_copy.c +++ b/src/lxc/tools/lxc_copy.c @@ -467,7 +467,7 @@ static int do_clone_ephemeral(struct lxc_container *c, goto destroy_and_put; if (arg->daemonize && arg->argc) { - ret = clone->attach_run_wait(clone, &attach_options, arg->argv[0], (const char *const *)arg->argv); + ret = clone->attach_run_wait(clone, NULL, &attach_options, arg->argv[0], (const char *const *)arg->argv); if (ret < 0) goto destroy_and_put; clone->shutdown(clone, -1); diff --git a/src/lxc/tools/lxc_ls.c b/src/lxc/tools/lxc_ls.c index e261c7b..9fd1bf3 100644 --- a/src/lxc/tools/lxc_ls.c +++ b/src/lxc/tools/lxc_ls.c @@ -544,7 +544,7 @@ static int ls_get(struct ls **m, size_t *size, const struct lxc_arguments *args, /* fork(): Attach to the namespace of the container and * run ls_get() in it which is called in ls_get_wrapper(). */ - check = c->attach(c, ls_get_wrapper, &wargs, &aopt, &out); + check = c->attach(c, NULL, ls_get_wrapper, &wargs, &aopt, &out); /* close the socket */ close(wargs.pipefd[1]); -- 1.8.3.1