Merge branch 'turbostat' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
[linux-2.6-block.git] / tools / lib / subcmd / run-command.c
1 #include <unistd.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <sys/wait.h>
8 #include "subcmd-util.h"
9 #include "run-command.h"
10 #include "exec-cmd.h"
11
12 #define STRERR_BUFSIZE 128
13
14 static inline void close_pair(int fd[2])
15 {
16         close(fd[0]);
17         close(fd[1]);
18 }
19
20 static inline void dup_devnull(int to)
21 {
22         int fd = open("/dev/null", O_RDWR);
23         dup2(fd, to);
24         close(fd);
25 }
26
27 int start_command(struct child_process *cmd)
28 {
29         int need_in, need_out, need_err;
30         int fdin[2], fdout[2], fderr[2];
31         char sbuf[STRERR_BUFSIZE];
32
33         /*
34          * In case of errors we must keep the promise to close FDs
35          * that have been passed in via ->in and ->out.
36          */
37
38         need_in = !cmd->no_stdin && cmd->in < 0;
39         if (need_in) {
40                 if (pipe(fdin) < 0) {
41                         if (cmd->out > 0)
42                                 close(cmd->out);
43                         return -ERR_RUN_COMMAND_PIPE;
44                 }
45                 cmd->in = fdin[1];
46         }
47
48         need_out = !cmd->no_stdout
49                 && !cmd->stdout_to_stderr
50                 && cmd->out < 0;
51         if (need_out) {
52                 if (pipe(fdout) < 0) {
53                         if (need_in)
54                                 close_pair(fdin);
55                         else if (cmd->in)
56                                 close(cmd->in);
57                         return -ERR_RUN_COMMAND_PIPE;
58                 }
59                 cmd->out = fdout[0];
60         }
61
62         need_err = !cmd->no_stderr && cmd->err < 0;
63         if (need_err) {
64                 if (pipe(fderr) < 0) {
65                         if (need_in)
66                                 close_pair(fdin);
67                         else if (cmd->in)
68                                 close(cmd->in);
69                         if (need_out)
70                                 close_pair(fdout);
71                         else if (cmd->out)
72                                 close(cmd->out);
73                         return -ERR_RUN_COMMAND_PIPE;
74                 }
75                 cmd->err = fderr[0];
76         }
77
78         fflush(NULL);
79         cmd->pid = fork();
80         if (!cmd->pid) {
81                 if (cmd->no_stdin)
82                         dup_devnull(0);
83                 else if (need_in) {
84                         dup2(fdin[0], 0);
85                         close_pair(fdin);
86                 } else if (cmd->in) {
87                         dup2(cmd->in, 0);
88                         close(cmd->in);
89                 }
90
91                 if (cmd->no_stderr)
92                         dup_devnull(2);
93                 else if (need_err) {
94                         dup2(fderr[1], 2);
95                         close_pair(fderr);
96                 }
97
98                 if (cmd->no_stdout)
99                         dup_devnull(1);
100                 else if (cmd->stdout_to_stderr)
101                         dup2(2, 1);
102                 else if (need_out) {
103                         dup2(fdout[1], 1);
104                         close_pair(fdout);
105                 } else if (cmd->out > 1) {
106                         dup2(cmd->out, 1);
107                         close(cmd->out);
108                 }
109
110                 if (cmd->dir && chdir(cmd->dir))
111                         die("exec %s: cd to %s failed (%s)", cmd->argv[0],
112                             cmd->dir, strerror_r(errno, sbuf, sizeof(sbuf)));
113                 if (cmd->env) {
114                         for (; *cmd->env; cmd->env++) {
115                                 if (strchr(*cmd->env, '='))
116                                         putenv((char*)*cmd->env);
117                                 else
118                                         unsetenv(*cmd->env);
119                         }
120                 }
121                 if (cmd->preexec_cb)
122                         cmd->preexec_cb();
123                 if (cmd->exec_cmd) {
124                         execv_cmd(cmd->argv);
125                 } else {
126                         execvp(cmd->argv[0], (char *const*) cmd->argv);
127                 }
128                 exit(127);
129         }
130
131         if (cmd->pid < 0) {
132                 int err = errno;
133                 if (need_in)
134                         close_pair(fdin);
135                 else if (cmd->in)
136                         close(cmd->in);
137                 if (need_out)
138                         close_pair(fdout);
139                 else if (cmd->out)
140                         close(cmd->out);
141                 if (need_err)
142                         close_pair(fderr);
143                 return err == ENOENT ?
144                         -ERR_RUN_COMMAND_EXEC :
145                         -ERR_RUN_COMMAND_FORK;
146         }
147
148         if (need_in)
149                 close(fdin[0]);
150         else if (cmd->in)
151                 close(cmd->in);
152
153         if (need_out)
154                 close(fdout[1]);
155         else if (cmd->out)
156                 close(cmd->out);
157
158         if (need_err)
159                 close(fderr[1]);
160
161         return 0;
162 }
163
164 static int wait_or_whine(pid_t pid)
165 {
166         char sbuf[STRERR_BUFSIZE];
167
168         for (;;) {
169                 int status, code;
170                 pid_t waiting = waitpid(pid, &status, 0);
171
172                 if (waiting < 0) {
173                         if (errno == EINTR)
174                                 continue;
175                         fprintf(stderr, " Error: waitpid failed (%s)",
176                                 strerror_r(errno, sbuf, sizeof(sbuf)));
177                         return -ERR_RUN_COMMAND_WAITPID;
178                 }
179                 if (waiting != pid)
180                         return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
181                 if (WIFSIGNALED(status))
182                         return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
183
184                 if (!WIFEXITED(status))
185                         return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
186                 code = WEXITSTATUS(status);
187                 switch (code) {
188                 case 127:
189                         return -ERR_RUN_COMMAND_EXEC;
190                 case 0:
191                         return 0;
192                 default:
193                         return -code;
194                 }
195         }
196 }
197
198 int finish_command(struct child_process *cmd)
199 {
200         return wait_or_whine(cmd->pid);
201 }
202
203 int run_command(struct child_process *cmd)
204 {
205         int code = start_command(cmd);
206         if (code)
207                 return code;
208         return finish_command(cmd);
209 }
210
211 static void prepare_run_command_v_opt(struct child_process *cmd,
212                                       const char **argv,
213                                       int opt)
214 {
215         memset(cmd, 0, sizeof(*cmd));
216         cmd->argv = argv;
217         cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
218         cmd->exec_cmd = opt & RUN_EXEC_CMD ? 1 : 0;
219         cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
220 }
221
222 int run_command_v_opt(const char **argv, int opt)
223 {
224         struct child_process cmd;
225         prepare_run_command_v_opt(&cmd, argv, opt);
226         return run_command(&cmd);
227 }