[CRIU] [PATCH cr 1/2] util: add a function for executing an extrenal tools

Andrey Vagin avagin at openvz.org
Thu Sep 20 09:24:44 EDT 2012


For executing an external tools we need to block a SIGCHLD
and to juggle file descriptors.

SIGCHLD is blocked for getting an exit code.
A problem with file descriptors can be if we want to set 2 to STDIN,
1 to STDERR, 0 to STDOUT for example.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/util.h |    2 +
 util.c         |   93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+), 0 deletions(-)

diff --git a/include/util.h b/include/util.h
index 93749b3..ae74fa0 100644
--- a/include/util.h
+++ b/include/util.h
@@ -325,4 +325,6 @@ extern void *shmalloc(size_t bytes);
 extern void shfree_last(void *ptr);
 extern int run_scripts(char *action);
 
+extern int cr_system(int in, int out, int err, char *cmd, char *const argv[]);
+
 #endif /* UTIL_H_ */
diff --git a/util.c b/util.c
index e459527..1c52aae 100644
--- a/util.c
+++ b/util.c
@@ -404,3 +404,96 @@ int run_scripts(char *action)
 	unsetenv("CRTOOLS_SCRIPT_ACTION");
 	return ret;
 }
+
+#define SYSTEM_DUPFD(old, new)							\
+	do {									\
+		if ((old) == -1)						\
+			close(new);						\
+		else {								\
+			if (dup2(old, new) == -1) {				\
+				pr_perror("dup2(%d, %d) failed", old, new);	\
+				_exit(1);					\
+			}							\
+		}								\
+	} while (0)
+
+/* Duplicate a descriptor into non standard number */
+#define SYSTEM_DUPAWAY(fd)							\
+	do {								\
+		if (fd == -1)						\
+			break;						\
+		while (1) {						\
+			if (fd >= 0 && fd < 3)				\
+				fd = dup(fd);				\
+			else						\
+				break;					\
+		}							\
+		if (fd == -1) {						\
+			pr_perror("dup() failed");			\
+			_exit(1);					\
+		}							\
+	} while (0)
+
+int cr_system(int in, int out, int err, char *cmd, char *const argv[])
+{
+	sigset_t blockmask, oldmask;
+	int ret = -1, status;
+	pid_t pid;
+
+	sigemptyset(&blockmask);
+	sigaddset(&blockmask, SIGCHLD);
+	if (sigprocmask(SIG_BLOCK, &blockmask, &oldmask) == -1) {
+		pr_perror("Can not set mask of blocked signals");
+		return -1;
+	}
+
+	pid = fork();
+	if (pid == -1) {
+		pr_perror("fork() failed\n");
+		goto out;
+	} else if (pid == 0) {
+		/* to be sure that (in, out, err) are not intersected with STD* */
+		SYSTEM_DUPAWAY(in);
+		SYSTEM_DUPAWAY(out);
+		SYSTEM_DUPAWAY(err);
+
+		SYSTEM_DUPFD(in,  STDIN_FILENO);
+		SYSTEM_DUPFD(out, STDOUT_FILENO);
+		SYSTEM_DUPFD(err, STDERR_FILENO);
+
+		execvp(cmd, argv);
+
+		pr_perror("exec failed");
+		_exit(1);
+	}
+
+	while (1) {
+		ret = waitpid(pid, &status, 0);
+		if (ret == -1) {
+			pr_perror("waitpid() failed");
+			goto out;
+		}
+
+		if (WIFEXITED(status)) {
+			if (WEXITSTATUS(status))
+				pr_err("exited, status=%d\n", WEXITSTATUS(status));
+			break;
+		} else if (WIFSIGNALED(status)) {
+			pr_err("killed by signal %d\n", WTERMSIG(status));
+			break;
+		} else if (WIFSTOPPED(status)) {
+			pr_err("stopped by signal %d\n", WSTOPSIG(status));
+		} else if (WIFCONTINUED(status)) {
+			pr_err("continued\n");
+		}
+	}
+
+	ret = status ? -1 : 0;
+out:
+	if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) {
+		pr_perror("Can not set mask of blocked signals");
+		BUG();
+	}
+
+	return ret;
+}
-- 
1.7.1



More information about the CRIU mailing list