[lxc-devel] [lxc/master] RFC: API: add console ringbuffer extension

brauner on Github lxc-bot at linuxcontainers.org
Sun Oct 22 07:59:43 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 381 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20171022/565d8fdc/attachment.bin>
-------------- next part --------------
From d88f9a21938e4ae4b7fffbbf23e5516b0a7c92b6 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 22 Oct 2017 00:46:39 +0200
Subject: [PATCH 1/4] commands: add LXC_CMD_GET_CONSOLE_LOG

Add infrastructure to query console ringbuffer.

Closes #1870.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/commands.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/lxc/commands.h |  3 +++
 2 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index 4d440ba78..75345869b 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -91,6 +91,7 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd)
 		[LXC_CMD_GET_LXCPATH]      = "get_lxcpath",
 		[LXC_CMD_ADD_STATE_CLIENT] = "add_state_client",
 		[LXC_CMD_SET_CONFIG_ITEM]  = "set_config_item",
+		[LXC_CMD_GET_CONSOLE_LOG]  = "get_console_log",
 	};
 
 	if (cmd >= LXC_CMD_MAX)
@@ -153,14 +154,19 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
 		      lxc_cmd_str(cmd->req.cmd));
 		return ret;
 	}
-	if (rsp->datalen > LXC_CMD_DATA_MAX) {
+	if (rsp->datalen > LXC_CMD_DATA_MAX && cmd->req.cmd != LXC_CMD_GET_CONSOLE_LOG) {
 		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 (cmd->req.cmd == LXC_CMD_GET_CONSOLE_LOG) {
+		rsp->data = malloc(rsp->datalen + 1);
+		((char *)rsp->data)[rsp->datalen] = '\0';
+	} else {
+		rsp->data = malloc(rsp->datalen);
+	}
 	if (!rsp->data) {
 		ERROR("Command %s was unable to allocate response buffer.",
 		      lxc_cmd_str(cmd->req.cmd));
@@ -986,6 +992,52 @@ static int lxc_cmd_add_state_client_callback(int fd, struct lxc_cmd_req *req,
 	return lxc_cmd_rsp_send(fd, &rsp);
 }
 
+char *lxc_cmd_get_console_log(const char *name, const char *lxcpath, size_t *len)
+{
+	int ret, stopped;
+	struct lxc_cmd_rr cmd = {
+		.req = { .cmd = LXC_CMD_GET_CONSOLE_LOG,
+			 .data = &len,
+			 .datalen = 0,
+		       },
+	};
+
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
+	if (ret < 0)
+		return NULL;
+
+	if (cmd.rsp.ret < 0)
+		return NULL;
+
+	*len = cmd.rsp.datalen;
+
+	return cmd.rsp.data;
+}
+
+static int lxc_cmd_get_console_log_callback(int fd, struct lxc_cmd_req *req,
+					    struct lxc_handler *handler)
+{
+	struct lxc_cmd_rsp rsp;
+	size_t len = *(size_t *)req->data;
+	struct lxc_ringbuf *buf = &handler->conf->console.ringbuf;
+
+	rsp.ret = -ENODATA;
+	rsp.data = NULL;
+	rsp.datalen = 0;
+
+	/* there's nothing to read */
+	if (buf->r_off == buf->w_off)
+		return lxc_cmd_rsp_send(fd, &rsp);
+
+	rsp.ret = 0;
+	rsp.data = lxc_ringbuf_get_read_addr(buf);
+	rsp.datalen = lxc_ringbuf_used(buf);
+	if (len > 0 && len <= rsp.datalen)
+		rsp.datalen = len;
+	lxc_ringbuf_move_read_addr(buf, rsp.datalen);
+	return lxc_cmd_rsp_send(fd, &rsp);
+}
+
 static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
 			   struct lxc_handler *handler)
 {
@@ -1004,6 +1056,7 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
 		[LXC_CMD_GET_LXCPATH]      = lxc_cmd_get_lxcpath_callback,
 		[LXC_CMD_ADD_STATE_CLIENT] = lxc_cmd_add_state_client_callback,
 		[LXC_CMD_SET_CONFIG_ITEM]  = lxc_cmd_set_config_item_callback,
+		[LXC_CMD_GET_CONSOLE_LOG]  = lxc_cmd_get_console_log_callback,
 	};
 
 	if (req->cmd >= LXC_CMD_MAX) {
@@ -1026,6 +1079,7 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
 {
 	int ret;
 	struct lxc_cmd_req req;
+	void *reqdata = NULL;
 	struct lxc_handler *handler = data;
 
 	ret = lxc_abstract_unix_rcv_credential(fd, &req, sizeof(req));
@@ -1066,9 +1120,19 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
 	}
 
 	if (req.datalen > 0) {
-		void *reqdata;
+		/* LXC_CMD_GET_CONSOLE_LOG needs to be able to allocate data
+		 * that exceeds LXC_CMD_DATA_MAX: use malloc() for that.
+		 */
+		if (req.cmd == LXC_CMD_GET_CONSOLE_LOG)
+			reqdata = alloca(req.datalen);
+		else
+			reqdata = malloc(req.datalen);
+		if (!reqdata) {
+			ERROR("Failed to allocate memory for \"%s\" command",
+			      lxc_cmd_str(req.cmd));
+			goto out_close;
+		}
 
-		reqdata = alloca(req.datalen);
 		ret = recv(fd, reqdata, req.datalen, 0);
 		if (ret != req.datalen) {
 			WARN("Failed to receive full command request. Ignoring "
@@ -1088,6 +1152,9 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
 	}
 
 out:
+	if (req.cmd == LXC_CMD_GET_CONSOLE_LOG && reqdata)
+		free(reqdata);
+
 	return ret;
 out_close:
 	lxc_cmd_fd_cleanup(fd, handler, descr);
diff --git a/src/lxc/commands.h b/src/lxc/commands.h
index cc5eec3c5..a8176b3e3 100644
--- a/src/lxc/commands.h
+++ b/src/lxc/commands.h
@@ -49,6 +49,7 @@ typedef enum {
 	LXC_CMD_GET_LXCPATH,
 	LXC_CMD_ADD_STATE_CLIENT,
 	LXC_CMD_SET_CONFIG_ITEM,
+	LXC_CMD_GET_CONSOLE_LOG,
 	LXC_CMD_MAX,
 } lxc_cmd_t;
 
@@ -124,5 +125,7 @@ extern int lxc_try_cmd(const char *name, const char *lxcpath);
 
 extern int lxc_cmd_set_config_item(const char *name, const char *item,
 				   const char *value, const char *lxcpath);
+extern char *lxc_cmd_get_console_log(const char *name, const char *lxcpath,
+				     size_t *len);
 
 #endif /* __commands_h */

From d614c2e63980905a614546e780908c455c9642be Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 22 Oct 2017 00:47:28 +0200
Subject: [PATCH 2/4] commands: non-functional changes

Closes #1870.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/commands.c | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index 75345869b..8be1b8c84 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -997,8 +997,8 @@ char *lxc_cmd_get_console_log(const char *name, const char *lxcpath, size_t *len
 	int ret, stopped;
 	struct lxc_cmd_rr cmd = {
 		.req = { .cmd = LXC_CMD_GET_CONSOLE_LOG,
-			 .data = &len,
-			 .datalen = 0,
+			 .data = len,
+			 .datalen = sizeof(size_t),
 		       },
 	};
 
@@ -1084,8 +1084,8 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
 
 	ret = lxc_abstract_unix_rcv_credential(fd, &req, sizeof(req));
 	if (ret == -EACCES) {
-		/* we don't care for the peer, just send and close */
-		struct lxc_cmd_rsp rsp = { .ret = ret };
+		/* We don't care for the peer, just send and close. */
+		struct lxc_cmd_rsp rsp = {.ret = ret};
 
 		lxc_cmd_rsp_send(fd, &rsp);
 		goto out_close;
@@ -1098,23 +1098,21 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
 		goto out_close;
 	}
 
-	if (!ret) {
+	if (ret == 0) {
 		DEBUG("Peer has disconnected for \"%s\"", lxc_cmd_str(req.cmd));
 		goto out_close;
 	}
 
 	if (ret != sizeof(req)) {
 		WARN("Failed to receive full command request. Ignoring request "
-		     "for \"%s\"",
-		     lxc_cmd_str(req.cmd));
+		     "for \"%s\"", lxc_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_cmd_str(req.cmd));
+		      "command \"%s\"", req.datalen, lxc_cmd_str(req.cmd));
 		ret = -1;
 		goto out_close;
 	}
@@ -1124,9 +1122,9 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
 		 * that exceeds LXC_CMD_DATA_MAX: use malloc() for that.
 		 */
 		if (req.cmd == LXC_CMD_GET_CONSOLE_LOG)
-			reqdata = alloca(req.datalen);
-		else
 			reqdata = malloc(req.datalen);
+		else
+			reqdata = alloca(req.datalen);
 		if (!reqdata) {
 			ERROR("Failed to allocate memory for \"%s\" command",
 			      lxc_cmd_str(req.cmd));
@@ -1136,17 +1134,17 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
 		ret = recv(fd, reqdata, req.datalen, 0);
 		if (ret != req.datalen) {
 			WARN("Failed to receive full command request. Ignoring "
-			     "request for \"%s\"",
-			     lxc_cmd_str(req.cmd));
+			     "request for \"%s\"", lxc_cmd_str(req.cmd));
 			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 */
+		/* This is not an error, but only a request to close fd. */
 		ret = 0;
 		goto out_close;
 	}
@@ -1156,6 +1154,7 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
 		free(reqdata);
 
 	return ret;
+
 out_close:
 	lxc_cmd_fd_cleanup(fd, handler, descr);
 	goto out;

From 2f70fee4622f4c78c9e5fe14087cbe36d7b8183f Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 22 Oct 2017 00:48:02 +0200
Subject: [PATCH 3/4] lxccontainer: add console_get_log()

Closes #1870.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/lxccontainer.c | 8 ++++++++
 src/lxc/lxccontainer.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index efb1bf7ae..e56e0b421 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -516,6 +516,13 @@ static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd,
 	return ret;
 }
 
+static char *do_lxcapi_console_get_log(struct lxc_container *c, size_t *len)
+{
+	return lxc_cmd_get_console_log(c->name, do_lxcapi_get_config_path(c), len);
+}
+
+WRAP_API_1(char *, lxcapi_console_get_log, size_t *)
+
 static pid_t do_lxcapi_init_pid(struct lxc_container *c)
 {
 	if (!c)
@@ -4607,6 +4614,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
 	c->checkpoint = lxcapi_checkpoint;
 	c->restore = lxcapi_restore;
 	c->migrate = lxcapi_migrate;
+	c->console_get_log = lxcapi_console_get_log;
 
 	return c;
 
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index 84bdab81c..89a69088d 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -834,6 +834,8 @@ struct lxc_container {
 	 * \return \c true on success, else \c false.
 	 */
 	bool (*set_running_config_item)(struct lxc_container *c, const char *key, const char *value);
+
+	char *(*console_get_log)(struct lxc_container *c, size_t *len);
 };
 
 /*!

From b282c8d9c0066f6f57bd2456838fb2247c23bce2 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 22 Oct 2017 00:48:28 +0200
Subject: [PATCH 4/4] [DO NOT MERGE - TESTING ONLY] tools: retrieve console log

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/arguments.h         |  1 +
 src/lxc/tools/lxc_console.c | 21 ++++++++++++++++++---
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h
index b07caf42b..adc1cafbd 100644
--- a/src/lxc/arguments.h
+++ b/src/lxc/arguments.h
@@ -63,6 +63,7 @@ struct lxc_arguments {
 	/* for lxc-console */
 	unsigned int ttynum;
 	char escape;
+	bool show_log;
 
 	/* for lxc-wait */
 	char *states;
diff --git a/src/lxc/tools/lxc_console.c b/src/lxc/tools/lxc_console.c
index 66b909162..e2fa9b8ed 100644
--- a/src/lxc/tools/lxc_console.c
+++ b/src/lxc/tools/lxc_console.c
@@ -65,11 +65,15 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
 	case 'e':
 		args->escape = etoc(arg);
 		break;
+	case 's':
+		args->show_log = true;
+		break;
 	}
 	return 0;
 }
 
 static const struct option my_longopts[] = {
+	{"show-log", no_argument, 0, 's'},
 	{"tty", required_argument, 0, 't'},
 	{"escape", required_argument, 0, 'e'},
 	LXC_COMMON_OPTIONS
@@ -86,17 +90,20 @@ Options :\n\
   -n, --name=NAME      NAME of the container\n\
   -t, --tty=NUMBER     console tty number\n\
   -e, --escape=PREFIX  prefix for escape command\n\
+  -s, --show-log       show console log\n\
   --rcfile=FILE        Load configuration file FILE\n",
 	.options  = my_longopts,
 	.parser   = my_parser,
 	.checker  = NULL,
 	.ttynum = -1,
 	.escape = 1,
+	.show_log = false,
 };
 
 int main(int argc, char *argv[])
 {
 	int ret;
+	char *ringbuf;
 	struct lxc_container *c;
 	struct lxc_log log;
 
@@ -155,11 +162,19 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	ret = c->console(c, my_args.ttynum, 0, 1, 2, my_args.escape);
-	if (ret < 0) {
+	if (my_args.show_log) {
+		ringbuf = c->console_get_log(c, &(size_t){0});
 		lxc_container_put(c);
-		exit(EXIT_FAILURE);
+		if (!ringbuf)
+			exit(EXIT_FAILURE);
+
+		printf("%s\n", ringbuf);
+		exit(EXIT_SUCCESS);
 	}
+	ret = c->console(c, my_args.ttynum, 0, 1, 2, my_args.escape);
 	lxc_container_put(c);
+	if (ret < 0)
+		exit(EXIT_FAILURE);
+
 	exit(EXIT_SUCCESS);
 }


More information about the lxc-devel mailing list