1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-02-18 21:58:06 +03:00

exec: pipe open

Function replaces popen() system and avoids shell execution
and argument parsing (no surprices).
This commit is contained in:
Zdenek Kabelac 2013-08-06 14:27:37 +02:00
parent b6437a6180
commit f6dd5a294b
3 changed files with 130 additions and 0 deletions

@ -1,5 +1,6 @@
Version 2.02.100 -
================================
Add pipe_open/close() to replace less secure popen() glibc call.
Fix metadata area offset/size overflow if it's >= 4g and while using lvmetad.
Inherit and apply any profile attached to a VG if creating new thin pool.
Add initial support thin pool lvconvert --repair.

@ -107,3 +107,102 @@ int exec_cmd(struct cmd_context *cmd, const char *const argv[],
return 1;
}
static int _reopen_fd_to_null(int fd)
{
int null_fd;
if ((null_fd = open("/dev/null", O_RDWR)) == -1) {
log_sys_error("open", "/dev/null");
return 0;
}
if (close(fd)) {
log_sys_error("close", "");
return 0;
}
if (dup2(null_fd, fd) == -1) {
log_sys_error("dup2", "");
return 0;
}
if (close(null_fd)) {
log_sys_error("dup2", "");
return 0;
}
return 1;
}
FILE *pipe_open(struct cmd_context *cmd, const char *const argv[],
int sync_needed, struct pipe_data *pdata)
{
int pipefd[2];
char buf[PATH_MAX * 2];
if (sync_needed)
if (!sync_local_dev_names(cmd)) /* Flush ops and reset dm cookie */
return_0;
if (pipe(pipefd)) {
log_sys_error("pipe", "");
return 0;
}
log_verbose("Piping:%s", _verbose_args(argv, buf, sizeof(buf)));
if ((pdata->pid = fork()) == -1) {
log_sys_error("pipe", "");
return 0;
}
if (pdata->pid == 0) {
/* Child -> writer, convert pipe[0] to STDOUT */
if (!_reopen_fd_to_null(STDIN_FILENO))
stack;
else if (close(pipefd[0 /*read*/]))
log_sys_error("close", "pipe[0]");
else if (close(STDOUT_FILENO))
log_sys_error("close", "STDOUT");
else if (dup2(pipefd[1 /*write*/], STDOUT_FILENO) == -1)
log_sys_error("dup2", "STDOUT");
else if (close(pipefd[1]))
log_sys_error("close", "pipe[1]");
else if (argv[0]) {
execvp(argv[0], (char **) argv);
log_sys_error("execvp", argv[0]);
}
_exit(errno);
}
/* Parent -> reader */
if (close(pipefd[1 /*write*/])) {
log_sys_error("close", "STDOUT");
return NULL;
}
if (!(pdata->fp = fdopen(pipefd[0 /*read*/], "r"))) {
log_sys_error("fdopen", "STDIN");
if (close(pipefd[0]))
log_sys_error("close", "STDIN");
return NULL; /* FIXME: kill */
}
return pdata->fp;
}
int pipe_close(struct pipe_data *pdata)
{
int status;
if (fclose(pdata->fp))
log_sys_error("fclose", "STDIN");
if (waitpid(pdata->pid, &status, 0) != pdata->pid) {
log_sys_error("waitpid", "");
return 0;
}
return (status == 0) ? 1 : 0;
}

@ -37,4 +37,34 @@ struct cmd_context;
int exec_cmd(struct cmd_context *cmd, const char *const argv[],
int *rstatus, int sync_needed);
struct FILE;
struct pipe_data {
FILE *fp;
pid_t pid;
};
/**
* popen() like function to read-only output from executed command
* without running shell.
*
* \param argv
* Arguments for execvp.
*
* \param sync_needed
* Bool specifying whether local devices needs to be synchronized
* before executing command.
* Note: You cannot synchronize devices within activation context.
*
* \param pdata
* Arguments to store data needed for pclose_exec().
*
* \return
* 1 (success) or 0 (failure).
*/
FILE *pipe_open(struct cmd_context *cmd, const char *const argv[],
int sync_needed, struct pipe_data *pdata);
int pipe_close(struct pipe_data *pdata);
#endif