[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