1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
/*
* Utility routines.
*
* Licensed under GPLv2, see file COPYING in this tarball for details.
*/
#include "abrtlib.h"
/* Returns pid */
pid_t fork_execv_on_steroids(int flags,
char **argv,
int *pipefds,
char **unsetenv_vec,
const char *dir,
uid_t uid)
{
pid_t child;
/* Reminder: [0] is read end, [1] is write end */
int pipe_to_child[2];
int pipe_fm_child[2];
/* Sanitize flags */
if (!pipefds)
flags &= ~(EXECFLG_INPUT | EXECFLG_OUTPUT);
if (flags & EXECFLG_INPUT)
xpipe(pipe_to_child);
if (flags & EXECFLG_OUTPUT)
xpipe(pipe_fm_child);
child = fork();
if (child == -1) {
perror_msg_and_die("fork");
}
if (child == 0) {
/* Child */
/* Play with stdio descriptors */
if (flags & EXECFLG_INPUT) {
xmove_fd(pipe_to_child[0], STDIN_FILENO);
} else if (flags & EXECFLG_INPUT_NUL) {
xmove_fd(xopen("/dev/null", O_RDWR), STDIN_FILENO);
}
if (flags & EXECFLG_OUTPUT) {
xmove_fd(pipe_fm_child[1], STDOUT_FILENO);
} else if (flags & EXECFLG_OUTPUT_NUL) {
xmove_fd(xopen("/dev/null", O_RDWR), STDOUT_FILENO);
}
if (flags & EXECFLG_ERR2OUT) {
/* Want parent to see errors in the same stream */
xdup2(STDOUT_FILENO, STDERR_FILENO);
} else if (flags & EXECFLG_ERR_NUL) {
xmove_fd(xopen("/dev/null", O_RDWR), STDERR_FILENO);
}
if (flags & EXECFLG_SETGUID) {
struct passwd* pw = getpwuid(uid);
gid_t gid = pw ? pw->pw_gid : uid;
setgroups(1, &gid);
xsetregid(gid, gid);
xsetreuid(uid, uid);
}
if (flags & EXECFLG_SETSID)
setsid();
if (unsetenv_vec) {
while (*unsetenv_vec)
unsetenv(*unsetenv_vec++);
}
if (dir)
xchdir(dir);
execvp(argv[0], argv);
if (!(flags & EXECFLG_QUIET))
perror_msg("Can't execute '%s'", argv[0]);
exit(127); /* shell uses this exitcode in this case */
}
if (flags & EXECFLG_INPUT) {
close(pipe_to_child[0]);
pipefds[1] = pipe_to_child[1];
}
if (flags & EXECFLG_OUTPUT) {
close(pipe_fm_child[1]);
pipefds[0] = pipe_fm_child[0];
}
return child;
}
char *run_in_shell_and_save_output(int flags,
const char *cmd,
const char *dir,
size_t *size_p)
{
flags |= EXECFLG_OUTPUT;
flags &= ~EXECFLG_INPUT;
const char *argv[] = { "/bin/sh", "sh", "-c", cmd, NULL };
int pipeout[2];
pid_t child = fork_execv_on_steroids(flags, (char **)argv, pipeout,
/*unsetenv_vec:*/ NULL, dir, /*uid (unused):*/ 0);
size_t pos = 0;
char *result = NULL;
while (1) {
result = (char*) xrealloc(result, pos + 4*1024 + 1);
size_t sz = safe_read(pipeout[0], result + pos, 4*1024);
if (sz <= 0) {
break;
}
pos += sz;
}
result[pos] = '\0';
if (size_p)
*size_p = pos;
close(pipeout[0]);
waitpid(child, NULL, 0);
return result;
}
|