[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