From f690df5983011dd3b61f0e139c3e939f3fecf37a Mon Sep 17 00:00:00 2001
From: LiFeng <lifeng68@huawei.com>
Date: Tue, 14 Apr 2020 16:04:15 +0800
Subject: [PATCH 19/49] resize: implement resize function in exec/start

Signed-off-by: LiFeng <lifeng68@huawei.com>
---
 src/lxc/Makefile.am     |  10 +-
 src/lxc/af_unix.c       |  33 +++-
 src/lxc/af_unix.h       |   5 +-
 src/lxc/attach.c        |  51 +++++-
 src/lxc/commands.c      |  50 ++++++
 src/lxc/commands.h      |   2 +
 src/lxc/exec_commands.c | 416 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/exec_commands.h |  73 +++++++++
 src/lxc/lxccontainer.c  |  50 ++++++
 src/lxc/terminal.c      |  27 ++++
 src/lxc/terminal.h      |   1 +
 11 files changed, 710 insertions(+), 8 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 23935e5..c288c51 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -52,14 +52,15 @@ noinst_HEADERS = api_extensions.h \
 		 utils.h \
 		 uuid.h
 
-#if HAVE_ISULAD
+if HAVE_ISULAD
 noinst_HEADERS += isulad_utils.h path.h \
 				  json/json_common.h json/defs.h \
 				  json/oci_runtime_hooks.h \
 				  json/logger_json_file.h \
 				  json/oci_runtime_spec.h \
-				  json/read-file.h
-#endif
+				  json/read-file.h \
+				  exec_commands.h
+endif
 
 if IS_BIONIC
 noinst_HEADERS += ../include/fexecve.h \
@@ -172,7 +173,8 @@ liblxc_la_SOURCES += isulad_utils.c isulad_utils.h \
 			json/oci_runtime_hooks.c json/oci_runtime_hooks.h \
 			json/logger_json_file.c json/logger_json_file.h \
 			json/oci_runtime_spec.c json/oci_runtime_spec.h \
-			json/read-file.c json/read-file.h
+			json/read-file.c json/read-file.h \
+			exec_commands.c exec_commands.h
 endif
 
 if IS_BIONIC
diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c
index e172088..9f268be 100644
--- a/src/lxc/af_unix.c
+++ b/src/lxc/af_unix.c
@@ -168,7 +168,7 @@ int lxc_unix_send_fds(int fd, int *sendfds, int num_sendfds, void *data,
 }
 
 static int lxc_abstract_unix_recv_fds_iov(int fd, int *recvfds, int num_recvfds,
-					  struct iovec *iov, size_t iovlen)
+					  struct iovec *iov, size_t iovlen, unsigned int timeout)
 {
 	__do_free char *cmsgbuf = NULL;
 	int ret;
@@ -188,6 +188,22 @@ static int lxc_abstract_unix_recv_fds_iov(int fd, int *recvfds, int num_recvfds,
 	msg.msg_iov = iov;
 	msg.msg_iovlen = iovlen;
 
+#ifdef HAVE_ISULAD
+	struct timeval out;
+	if (timeout > 0) {
+		memset(&out, 0, sizeof(out));
+		out.tv_sec = timeout / 1000000;
+		out.tv_usec = timeout % 1000000;
+		ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
+		                 (const void *)&out, sizeof(out));
+		if (ret < 0) {
+			ERROR("Failed to set %u timeout on containter "
+			      "state socket", timeout);
+			return ret;
+		}
+	}
+#endif
+
 	do {
 		ret = recvmsg(fd, &msg, 0);
 	} while (ret < 0 && errno == EINTR);
@@ -220,8 +236,21 @@ int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
 		.iov_base = data ? data : buf,
 		.iov_len = data ? size : sizeof(buf),
 	};
-	return lxc_abstract_unix_recv_fds_iov(fd, recvfds, num_recvfds, &iov, 1);
+	return lxc_abstract_unix_recv_fds_iov(fd, recvfds, num_recvfds, &iov, 1, 0);
+}
+
+#ifdef HAVE_ISULAD
+int lxc_abstract_unix_recv_fds_timeout(int fd, int *recvfds, int num_recvfds,
+                                       void *data, size_t size, unsigned int timeout)
+{
+	char buf[1] = {0};
+	struct iovec iov = {
+		.iov_base = data ? data : buf,
+		.iov_len = data ? size : sizeof(buf),
+	};
+	return lxc_abstract_unix_recv_fds_iov(fd, recvfds, num_recvfds, &iov, 1, timeout);
 }
+#endif
 
 int lxc_abstract_unix_send_credential(int fd, void *data, size_t size)
 {
diff --git a/src/lxc/af_unix.h b/src/lxc/af_unix.h
index 2531b0b..6943a61 100644
--- a/src/lxc/af_unix.h
+++ b/src/lxc/af_unix.h
@@ -27,5 +27,8 @@ extern int lxc_unix_sockaddr(struct sockaddr_un *ret, const char *path);
 extern int lxc_unix_connect(struct sockaddr_un *addr);
 extern int lxc_unix_connect_type(struct sockaddr_un *addr, int type);
 extern int lxc_socket_set_timeout(int fd, int rcv_timeout, int snd_timeout);
-
+#ifdef HAVE_ISULAD
+int lxc_abstract_unix_recv_fds_timeout(int fd, int *recvfds, int num_recvfds,
+                                       void *data, size_t size, unsigned int timeout);
+#endif
 #endif /* __LXC_AF_UNIX_H */
diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index e66ca1c..33946bb 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -45,6 +45,10 @@
 #include "terminal.h"
 #include "utils.h"
 
+#ifdef HAVE_ISULAD
+#include "exec_commands.h"
+#endif
+
 #if HAVE_SYS_PERSONALITY_H
 #include <sys/personality.h>
 #endif
@@ -998,6 +1002,13 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
 	struct lxc_conf *conf;
 	char *name, *lxcpath;
 	struct attach_clone_payload payload = {0};
+#ifdef HAVE_ISULAD
+	struct lxc_exec_command_handler exec_command;
+	const char *suffix = options->suffix;
+
+	exec_command.maincmd_fd = -1;
+	exec_command.terminal = &terminal;
+#endif
 
 	ret = access("/proc/self/ns", X_OK);
 	if (ret)
@@ -1129,6 +1140,12 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
 		}
 
 		terminal.log_fd = options->log_fd;
+#ifdef HAVE_ISULAD
+		if (suffix != NULL) {
+			exec_command.maincmd_fd = lxc_exec_cmd_init(name, lxcpath, suffix);
+			exec_command.terminal = &terminal;
+		}
+#endif
 	} else {
 		lxc_terminal_init(&terminal);
 	}
@@ -1169,6 +1186,15 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
 	ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
 	if (ret < 0) {
 		SYSERROR("Could not set up required IPC mechanism for attaching");
+#ifdef HAVE_ISULAD
+		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);
+			}
+		}
+#endif
 		free(cwd);
 		lxc_proc_put_context_info(init_ctx);
 		return -1;
@@ -1184,6 +1210,17 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
 	pid = fork();
 	if (pid < 0) {
 		SYSERROR("Failed to create first subprocess");
+#ifdef HAVE_ISULAD
+		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]);
+#endif
 		free(cwd);
 		lxc_proc_put_context_info(init_ctx);
 		return -1;
@@ -1239,7 +1276,9 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
 			ret = lxc_attach_terminal_mainloop_init(&terminal, &descr);
 			if (ret < 0)
 				goto on_error;
-
+#ifdef HAVE_ISULAD
+			(void)lxc_exec_cmd_mainloop_add(&descr, &exec_command);
+#endif
 			TRACE("Initialized terminal mainloop");
 		}
 
@@ -1352,6 +1391,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
 		if (options->attach_flags & LXC_ATTACH_TERMINAL) {
 			lxc_terminal_delete(&terminal);
 			lxc_terminal_conf_free(&terminal);
+#ifdef HAVE_ISULAD
+			if (exec_command.maincmd_fd != -1) {
+				close(exec_command.maincmd_fd);
+			}
+#endif
 		}
 
 		lxc_proc_put_context_info(init_ctx);
@@ -1365,6 +1409,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
 		lxc_attach_terminal_close_master(&terminal);
 		lxc_attach_terminal_close_peer(&terminal);
 		lxc_attach_terminal_close_log(&terminal);
+#ifdef HAVE_ISULAD
+		if (exec_command.maincmd_fd != -1) {
+			close(exec_command.maincmd_fd);
+		}
+#endif
 	}
 
 	/* Wait for the parent to have setup cgroups. */
diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index 0ffc5c7..184a219 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -86,6 +86,7 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd)
 		[LXC_CMD_GET_INIT_PIDFD]        	= "get_init_pidfd",
 #ifdef HAVE_ISULAD
 		[LXC_CMD_SET_TERMINAL_FIFOS]  		= "set_terminal_fifos",
+		[LXC_CMD_SET_TERMINAL_WINCH]  		= "set_terminal_winch",
 #endif
 	};
 
@@ -1459,6 +1460,54 @@ static int lxc_cmd_set_terminal_fifos_callback(int fd, struct lxc_cmd_req *req,
 
 	return lxc_cmd_rsp_send(fd, &rsp);
 }
+
+struct lxc_cmd_set_terminal_winch_request {
+	unsigned int height;
+	unsigned int width;
+};
+
+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_epoll_descr *descr)
+{
+	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);
+
+}
+
 #endif
 
 static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
@@ -1490,6 +1539,7 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
 		[LXC_CMD_GET_INIT_PIDFD]                = lxc_cmd_get_init_pidfd_callback,
 #ifdef HAVE_ISULAD
 		[LXC_CMD_SET_TERMINAL_FIFOS]  			= lxc_cmd_set_terminal_fifos_callback,
+		[LXC_CMD_SET_TERMINAL_WINCH]  			= lxc_cmd_set_terminal_winch_callback,
 #endif
 	};
 
diff --git a/src/lxc/commands.h b/src/lxc/commands.h
index 95815e6..aa8289d 100644
--- a/src/lxc/commands.h
+++ b/src/lxc/commands.h
@@ -40,6 +40,7 @@ typedef enum {
 	LXC_CMD_GET_INIT_PIDFD,
 #ifdef HAVE_ISULAD
 	LXC_CMD_SET_TERMINAL_FIFOS,
+	LXC_CMD_SET_TERMINAL_WINCH,
 #endif
 	LXC_CMD_MAX,
 } lxc_cmd_t;
@@ -136,6 +137,7 @@ extern int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath);
 #ifdef HAVE_ISULAD
 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
 
 #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 <caps.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#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 <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#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 d0e6e2b..75c1bbc 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -62,6 +62,10 @@
 #include "utils.h"
 #include "version.h"
 
+#ifdef HAVE_ISULAD
+#include "exec_commands.h"
+#endif
+
 #if HAVE_OPENSSL
 #include <openssl/evp.h>
 #endif
@@ -5444,6 +5448,50 @@ static bool do_lxcapi_add_terminal_fifo(struct lxc_container *c, const char *in_
 }
 
 WRAP_API_3(bool, lxcapi_add_terminal_fifo, const char *, const char *, const char *)
+
+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)
 #endif
 
 struct lxc_container *lxc_container_new(const char *name, const char *configpath)
@@ -5591,6 +5639,8 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
 	c->set_container_info_file = lxcapi_set_container_info_file;
 	c->set_terminal_init_fifos = lxcapi_set_terminal_default_fifos;
 	c->add_terminal_fifos = lxcapi_add_terminal_fifo;
+	c->set_terminal_winch = lxcapi_set_terminal_winch;
+	c->set_exec_terminal_winch = lxcapi_set_exec_terminal_winch;
 #endif
 	return c;
 
diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c
index 1f46d49..39a6718 100644
--- a/src/lxc/terminal.c
+++ b/src/lxc/terminal.c
@@ -187,6 +187,33 @@ static int lxc_terminal_truncate_log_file(struct lxc_terminal *terminal)
 }
 
 #ifdef HAVE_ISULAD
+
+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;
+}
+
 /*
  * isulad: support mult-logfiles
  * */
diff --git a/src/lxc/terminal.h b/src/lxc/terminal.h
index b4160b3..f49142d 100644
--- a/src/lxc/terminal.h
+++ b/src/lxc/terminal.h
@@ -276,6 +276,7 @@ extern int lxc_terminal_map_ids(struct lxc_conf *c,
 
 #ifdef HAVE_ISULAD
 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
 
 #endif /* __LXC_TERMINAL_H */
-- 
1.8.3.1

