[lxc-devel] [lxc/master] c/r: save dump stdout too

tych0 on Github lxc-bot at linuxcontainers.org
Wed Nov 2 15:22:26 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20161102/2addd949/attachment.bin>
-------------- next part --------------
From 5af85cb1447fec6f05513c0e34991ccd0f5a6560 Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho.andersen at canonical.com>
Date: Tue, 1 Nov 2016 17:07:26 -0600
Subject: [PATCH 1/2] c/r: save criu's stdout during dump too

This also allows us to commonize some bits of the dup2 code.

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 src/lxc/criu.c | 76 +++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 60 insertions(+), 16 deletions(-)

diff --git a/src/lxc/criu.c b/src/lxc/criu.c
index 867139b..f49968b 100644
--- a/src/lxc/criu.c
+++ b/src/lxc/criu.c
@@ -62,6 +62,9 @@
 lxc_log_define(lxc_criu, lxc);
 
 struct criu_opts {
+	/* the thing to hook to stdout and stderr for logging */
+	int pipefd;
+
 	/* The type of criu invocation, one of "dump" or "restore" */
 	char *action;
 
@@ -134,6 +137,7 @@ static void exec_criu(struct criu_opts *opts)
 
 	char buf[4096], tty_info[32];
 	size_t pos;
+
 	/* If we are currently in a cgroup /foo/bar, and the container is in a
 	 * cgroup /lxc/foo, lxcfs will give us an ENOENT if some task in the
 	 * container has an open fd that points to one of the cgroup files
@@ -541,6 +545,21 @@ static void exec_criu(struct criu_opts *opts)
 
 	INFO("execing: %s", buf);
 
+	/* before criu inits its log, it sometimes prints things to stdout/err;
+	 * let's be sure we capture that.
+	 */
+	if (dup2(opts->pipefd, STDOUT_FILENO) < 0) {
+		SYSERROR("dup2 stdout failed");
+		goto err;
+	}
+
+	if (dup2(opts->pipefd, STDERR_FILENO) < 0) {
+		SYSERROR("dup2 stderr failed");
+		goto err;
+	}
+
+	close(opts->pipefd);
+
 #undef DECLARE_ARG
 	execv(argv[0], argv);
 err:
@@ -781,15 +800,6 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
 
 		close(pipes[0]);
 		pipes[0] = -1;
-		if (dup2(pipes[1], STDERR_FILENO) < 0) {
-			SYSERROR("dup2 failed");
-			goto out_fini_handler;
-		}
-
-		if (dup2(pipes[1], STDOUT_FILENO) < 0) {
-			SYSERROR("dup2 failed");
-			goto out_fini_handler;
-		}
 
 		if (unshare(CLONE_NEWNS))
 			goto out_fini_handler;
@@ -816,6 +826,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
 			}
 		}
 
+		os.pipefd = pipes[1];
 		os.action = "restore";
 		os.user = opts;
 		os.c = c;
@@ -1013,29 +1024,38 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op
 {
 	pid_t pid;
 	char *criu_version = NULL;
+	int criuout[2];
 
 	if (!criu_ok(c, &criu_version))
 		return false;
 
-	if (mkdir_p(opts->directory, 0700) < 0)
+	if (pipe(criuout) < 0) {
+		SYSERROR("pipe() failed");
 		return false;
+	}
+
+	if (mkdir_p(opts->directory, 0700) < 0)
+		goto fail;
 
 	pid = fork();
 	if (pid < 0) {
 		SYSERROR("fork failed");
-		return false;
+		goto fail;
 	}
 
 	if (pid == 0) {
 		struct criu_opts os;
 		struct lxc_handler h;
 
+		close(criuout[0]);
+
 		h.name = c->name;
 		if (!cgroup_init(&h)) {
 			ERROR("failed to cgroup_init()");
 			exit(1);
 		}
 
+		os.pipefd = criuout[1];
 		os.action = mode;
 		os.user = opts;
 		os.c = c;
@@ -1050,27 +1070,51 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op
 		exit(1);
 	} else {
 		int status;
+		ssize_t n;
+		char buf[4096];
+		bool ret;
+
+		close(criuout[1]);
+
 		pid_t w = waitpid(pid, &status, 0);
 		if (w == -1) {
 			SYSERROR("waitpid");
+			close(criuout[0]);
 			return false;
 		}
 
+		n = read(criuout[0], buf, sizeof(buf));
+		close(criuout[0]);
+		if (n < 0) {
+			SYSERROR("read");
+			n = 0;
+		}
+		buf[n] = 0;
+
 		if (WIFEXITED(status)) {
 			if (WEXITSTATUS(status)) {
 				ERROR("dump failed with %d\n", WEXITSTATUS(status));
-				return false;
+				ret = false;
+			} else {
+				ret = true;
 			}
-
-			return true;
 		} else if (WIFSIGNALED(status)) {
 			ERROR("dump signaled with %d\n", WTERMSIG(status));
-			return false;
+			ret = false;
 		} else {
 			ERROR("unknown dump exit %d\n", status);
-			return false;
+			ret = false;
 		}
+
+		if (!ret)
+			ERROR("criu output: %s", buf);
+		return ret;
 	}
+fail:
+	close(criuout[0]);
+	close(criuout[1]);
+	rmdir(opts->directory);
+	return false;
 }
 
 bool __criu_pre_dump(struct lxc_container *c, struct migrate_opts *opts)

From 9f1f54b0c5fc600cecc43d1608271dbf9b78d20b Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho.andersen at canonical.com>
Date: Wed, 2 Nov 2016 15:10:13 +0000
Subject: [PATCH 2/2] c/r: remove extra \ns from logs

The macros put a \n in for us, so let's not put another one in.

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 src/lxc/criu.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/src/lxc/criu.c b/src/lxc/criu.c
index f49968b..3588b00 100644
--- a/src/lxc/criu.c
+++ b/src/lxc/criu.c
@@ -216,7 +216,7 @@ static void exec_criu(struct criu_opts *opts)
 
 	ret = snprintf(log, PATH_MAX, "%s/%s.log", opts->user->directory, opts->action);
 	if (ret < 0 || ret >= PATH_MAX) {
-		ERROR("logfile name too long\n");
+		ERROR("logfile name too long");
 		return;
 	}
 
@@ -239,7 +239,7 @@ static void exec_criu(struct criu_opts *opts)
 
 	argv[argc++] = on_path("criu", NULL);
 	if (!argv[argc-1]) {
-		ERROR("Couldn't find criu binary\n");
+		ERROR("Couldn't find criu binary");
 		goto err;
 	}
 
@@ -506,7 +506,7 @@ static void exec_criu(struct criu_opts *opts)
 				break;
 			case LXC_NET_MACVLAN:
 				if (!n->link) {
-					ERROR("no host interface for macvlan %s\n", n->name);
+					ERROR("no host interface for macvlan %s", n->name);
 					goto err;
 				}
 
@@ -519,7 +519,7 @@ static void exec_criu(struct criu_opts *opts)
 				break;
 			default:
 				/* we have screened for this earlier... */
-				ERROR("unexpected network type %d\n", n->type);
+				ERROR("unexpected network type %d", n->type);
 				goto err;
 			}
 
@@ -670,7 +670,7 @@ static bool criu_version_ok(char **version)
 version_error:
 		fclose(f);
 		free(tmp);
-		ERROR("must have criu " CRIU_VERSION " or greater to checkpoint/restore\n");
+		ERROR("must have criu " CRIU_VERSION " or greater to checkpoint/restore");
 		return false;
 	}
 }
@@ -685,7 +685,7 @@ static bool criu_ok(struct lxc_container *c, char **criu_version)
 		return false;
 
 	if (geteuid()) {
-		ERROR("Must be root to checkpoint\n");
+		ERROR("Must be root to checkpoint");
 		return false;
 	}
 
@@ -699,7 +699,7 @@ static bool criu_ok(struct lxc_container *c, char **criu_version)
 		case LXC_NET_MACVLAN:
 			break;
 		default:
-			ERROR("Found un-dumpable network: %s (%s)\n", lxc_net_type_to_str(n->type), n->name);
+			ERROR("Found un-dumpable network: %s (%s)", lxc_net_type_to_str(n->type), n->name);
 			return false;
 		}
 	}
@@ -885,7 +885,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
 
 				buf[n] = 0;
 
-				ERROR("criu process exited %d, output:\n%s\n", WEXITSTATUS(status), buf);
+				ERROR("criu process exited %d, output:\n%s", WEXITSTATUS(status), buf);
 				goto out_fini_handler;
 			} else {
 				ret = snprintf(buf, sizeof(buf), "/proc/self/task/%lu/children", (unsigned long)syscall(__NR_gettid));
@@ -896,7 +896,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
 
 				FILE *f = fopen(buf, "r");
 				if (!f) {
-					SYSERROR("couldn't read restore's children file %s\n", buf);
+					SYSERROR("couldn't read restore's children file %s", buf);
 					goto out_fini_handler;
 				}
 
@@ -913,7 +913,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
 				}
 			}
 		} else {
-			ERROR("CRIU was killed with signal %d\n", WTERMSIG(status));
+			ERROR("CRIU was killed with signal %d", WTERMSIG(status));
 			goto out_fini_handler;
 		}
 
@@ -1093,16 +1093,16 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op
 
 		if (WIFEXITED(status)) {
 			if (WEXITSTATUS(status)) {
-				ERROR("dump failed with %d\n", WEXITSTATUS(status));
+				ERROR("dump failed with %d", WEXITSTATUS(status));
 				ret = false;
 			} else {
 				ret = true;
 			}
 		} else if (WIFSIGNALED(status)) {
-			ERROR("dump signaled with %d\n", WTERMSIG(status));
+			ERROR("dump signaled with %d", WTERMSIG(status));
 			ret = false;
 		} else {
-			ERROR("unknown dump exit %d\n", status);
+			ERROR("unknown dump exit %d", status);
 			ret = false;
 		}
 
@@ -1132,7 +1132,7 @@ bool __criu_dump(struct lxc_container *c, struct migrate_opts *opts)
 		return false;
 
 	if (access(path, F_OK) == 0) {
-		ERROR("please use a fresh directory for the dump directory\n");
+		ERROR("please use a fresh directory for the dump directory");
 		return false;
 	}
 
@@ -1150,7 +1150,7 @@ bool __criu_restore(struct lxc_container *c, struct migrate_opts *opts)
 		return false;
 
 	if (geteuid()) {
-		ERROR("Must be root to restore\n");
+		ERROR("Must be root to restore");
 		return false;
 	}
 


More information about the lxc-devel mailing list