Root/tools/perf/util/run-command.c

1#include "cache.h"
2#include "run-command.h"
3#include "exec_cmd.h"
4
5static inline void close_pair(int fd[2])
6{
7    close(fd[0]);
8    close(fd[1]);
9}
10
11static inline void dup_devnull(int to)
12{
13    int fd = open("/dev/null", O_RDWR);
14    dup2(fd, to);
15    close(fd);
16}
17
18int start_command(struct child_process *cmd)
19{
20    int need_in, need_out, need_err;
21    int fdin[2], fdout[2], fderr[2];
22
23    /*
24     * In case of errors we must keep the promise to close FDs
25     * that have been passed in via ->in and ->out.
26     */
27
28    need_in = !cmd->no_stdin && cmd->in < 0;
29    if (need_in) {
30        if (pipe(fdin) < 0) {
31            if (cmd->out > 0)
32                close(cmd->out);
33            return -ERR_RUN_COMMAND_PIPE;
34        }
35        cmd->in = fdin[1];
36    }
37
38    need_out = !cmd->no_stdout
39        && !cmd->stdout_to_stderr
40        && cmd->out < 0;
41    if (need_out) {
42        if (pipe(fdout) < 0) {
43            if (need_in)
44                close_pair(fdin);
45            else if (cmd->in)
46                close(cmd->in);
47            return -ERR_RUN_COMMAND_PIPE;
48        }
49        cmd->out = fdout[0];
50    }
51
52    need_err = !cmd->no_stderr && cmd->err < 0;
53    if (need_err) {
54        if (pipe(fderr) < 0) {
55            if (need_in)
56                close_pair(fdin);
57            else if (cmd->in)
58                close(cmd->in);
59            if (need_out)
60                close_pair(fdout);
61            else if (cmd->out)
62                close(cmd->out);
63            return -ERR_RUN_COMMAND_PIPE;
64        }
65        cmd->err = fderr[0];
66    }
67
68    fflush(NULL);
69    cmd->pid = fork();
70    if (!cmd->pid) {
71        if (cmd->no_stdin)
72            dup_devnull(0);
73        else if (need_in) {
74            dup2(fdin[0], 0);
75            close_pair(fdin);
76        } else if (cmd->in) {
77            dup2(cmd->in, 0);
78            close(cmd->in);
79        }
80
81        if (cmd->no_stderr)
82            dup_devnull(2);
83        else if (need_err) {
84            dup2(fderr[1], 2);
85            close_pair(fderr);
86        }
87
88        if (cmd->no_stdout)
89            dup_devnull(1);
90        else if (cmd->stdout_to_stderr)
91            dup2(2, 1);
92        else if (need_out) {
93            dup2(fdout[1], 1);
94            close_pair(fdout);
95        } else if (cmd->out > 1) {
96            dup2(cmd->out, 1);
97            close(cmd->out);
98        }
99
100        if (cmd->dir && chdir(cmd->dir))
101            die("exec %s: cd to %s failed (%s)", cmd->argv[0],
102                cmd->dir, strerror(errno));
103        if (cmd->env) {
104            for (; *cmd->env; cmd->env++) {
105                if (strchr(*cmd->env, '='))
106                    putenv((char*)*cmd->env);
107                else
108                    unsetenv(*cmd->env);
109            }
110        }
111        if (cmd->preexec_cb)
112            cmd->preexec_cb();
113        if (cmd->perf_cmd) {
114            execv_perf_cmd(cmd->argv);
115        } else {
116            execvp(cmd->argv[0], (char *const*) cmd->argv);
117        }
118        exit(127);
119    }
120
121    if (cmd->pid < 0) {
122        int err = errno;
123        if (need_in)
124            close_pair(fdin);
125        else if (cmd->in)
126            close(cmd->in);
127        if (need_out)
128            close_pair(fdout);
129        else if (cmd->out)
130            close(cmd->out);
131        if (need_err)
132            close_pair(fderr);
133        return err == ENOENT ?
134            -ERR_RUN_COMMAND_EXEC :
135            -ERR_RUN_COMMAND_FORK;
136    }
137
138    if (need_in)
139        close(fdin[0]);
140    else if (cmd->in)
141        close(cmd->in);
142
143    if (need_out)
144        close(fdout[1]);
145    else if (cmd->out)
146        close(cmd->out);
147
148    if (need_err)
149        close(fderr[1]);
150
151    return 0;
152}
153
154static int wait_or_whine(pid_t pid)
155{
156    for (;;) {
157        int status, code;
158        pid_t waiting = waitpid(pid, &status, 0);
159
160        if (waiting < 0) {
161            if (errno == EINTR)
162                continue;
163            error("waitpid failed (%s)", strerror(errno));
164            return -ERR_RUN_COMMAND_WAITPID;
165        }
166        if (waiting != pid)
167            return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
168        if (WIFSIGNALED(status))
169            return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
170
171        if (!WIFEXITED(status))
172            return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
173        code = WEXITSTATUS(status);
174        switch (code) {
175        case 127:
176            return -ERR_RUN_COMMAND_EXEC;
177        case 0:
178            return 0;
179        default:
180            return -code;
181        }
182    }
183}
184
185int finish_command(struct child_process *cmd)
186{
187    return wait_or_whine(cmd->pid);
188}
189
190int run_command(struct child_process *cmd)
191{
192    int code = start_command(cmd);
193    if (code)
194        return code;
195    return finish_command(cmd);
196}
197
198static void prepare_run_command_v_opt(struct child_process *cmd,
199                      const char **argv,
200                      int opt)
201{
202    memset(cmd, 0, sizeof(*cmd));
203    cmd->argv = argv;
204    cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
205    cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0;
206    cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
207}
208
209int run_command_v_opt(const char **argv, int opt)
210{
211    struct child_process cmd;
212    prepare_run_command_v_opt(&cmd, argv, opt);
213    return run_command(&cmd);
214}
215
216int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
217{
218    struct child_process cmd;
219    prepare_run_command_v_opt(&cmd, argv, opt);
220    cmd.dir = dir;
221    cmd.env = env;
222    return run_command(&cmd);
223}
224
225int start_async(struct async *async)
226{
227    int pipe_out[2];
228
229    if (pipe(pipe_out) < 0)
230        return error("cannot create pipe: %s", strerror(errno));
231    async->out = pipe_out[0];
232
233    /* Flush stdio before fork() to avoid cloning buffers */
234    fflush(NULL);
235
236    async->pid = fork();
237    if (async->pid < 0) {
238        error("fork (async) failed: %s", strerror(errno));
239        close_pair(pipe_out);
240        return -1;
241    }
242    if (!async->pid) {
243        close(pipe_out[0]);
244        exit(!!async->proc(pipe_out[1], async->data));
245    }
246    close(pipe_out[1]);
247
248    return 0;
249}
250
251int finish_async(struct async *async)
252{
253    int ret = 0;
254
255    if (wait_or_whine(async->pid))
256        ret = error("waitpid (async) failed");
257
258    return ret;
259}
260
261int run_hook(const char *index_file, const char *name, ...)
262{
263    struct child_process hook;
264    const char **argv = NULL, *env[2];
265    char idx[PATH_MAX];
266    va_list args;
267    int ret;
268    size_t i = 0, alloc = 0;
269
270    if (access(perf_path("hooks/%s", name), X_OK) < 0)
271        return 0;
272
273    va_start(args, name);
274    ALLOC_GROW(argv, i + 1, alloc);
275    argv[i++] = perf_path("hooks/%s", name);
276    while (argv[i-1]) {
277        ALLOC_GROW(argv, i + 1, alloc);
278        argv[i++] = va_arg(args, const char *);
279    }
280    va_end(args);
281
282    memset(&hook, 0, sizeof(hook));
283    hook.argv = argv;
284    hook.no_stdin = 1;
285    hook.stdout_to_stderr = 1;
286    if (index_file) {
287        snprintf(idx, sizeof(idx), "PERF_INDEX_FILE=%s", index_file);
288        env[0] = idx;
289        env[1] = NULL;
290        hook.env = env;
291    }
292
293    ret = start_command(&hook);
294    free(argv);
295    if (ret) {
296        warning("Could not spawn %s", argv[0]);
297        return ret;
298    }
299    ret = finish_command(&hook);
300    if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
301        warning("%s exited due to uncaught signal", argv[0]);
302
303    return ret;
304}
305

Archive Download this file



interactive