[CRIU] Re: [PATCH cr 1/2] util: add a function for executing an
extrenal tools
Pavel Emelyanov
xemul at parallels.com
Tue Sep 25 07:58:11 EDT 2012
On 09/20/2012 05:24 PM, Andrey Vagin wrote:
> 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); \
BUG -- old fd remains open.
But this doesn't matter. Can't we use our reopen_fd_as() instead?
> + 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;
> +}
More information about the CRIU
mailing list