]> git.ozlabs.org Git - petitboot/blob - lib/process/process.c
6e143e0e4784e086b9f171bdb61d670e31efe523
[petitboot] / lib / process / process.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; version 2 of the License.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program; if not, write to the Free Software
13  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14  */
15
16 #include <assert.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/wait.h>
21
22 #include <process/process.h>
23 #include <talloc/talloc.h>
24 #include <waiter/waiter.h>
25 #include <log/log.h>
26
27 struct procset {
28         struct waitset          *waitset;
29         struct list             async_list;
30         int                     sigchld_pipe[2];
31         struct waiter           *sigchld_waiter;
32         bool                    dry_run;
33 };
34
35 /* Internal data type for process handling
36  *
37  * Allocation: these structures may have multiple references:
38  *  - from the original ctx pointer
39  *  - due to inclusion in async_list
40  *  - due to a currently-registered waiter
41  *
42  */
43 struct process_info {
44 #ifdef DEBUG
45         /* prevent talloc_free(process) from working */
46         int                     __pad;
47 #endif
48         struct process          process;
49         struct list_item        async_list;
50         int                     stdout_buf_len;
51         struct waiter           *stdout_waiter;
52         int                     stdout_pipe[2];
53         void                    *orig_ctx;
54 };
55
56 static struct procset *procset;
57
58 static struct process_info *get_info(struct process *process)
59 {
60         return container_of(process, struct process_info, process);
61 }
62
63 /* Read as much as possible into the currently-allocated stdout buffer, and
64  * possibly realloc it for the next read
65  *
66  * Returns:
67  *  > 0 on success (even though no bytes may have been read)
68  *    0 on EOF (no error, but no more reads can be performed)
69  *  < 0 on error
70  **/
71 static int process_read_stdout_once(struct process_info *procinfo)
72 {
73         struct process *process = &procinfo->process;
74         int rc, fd, max_len;
75
76         assert(process->keep_stdout);
77
78         fd = procinfo->stdout_pipe[0];
79
80         max_len =  procinfo->stdout_buf_len - process->stdout_len - 1;
81
82         rc = read(fd, process->stdout_buf + process->stdout_len, max_len);
83         if (rc == 0)
84                 return 0;
85         if (rc < 0) {
86                 if (errno == EINTR)
87                         return 1;
88                 pb_log("%s: read failed: %s\n", __func__, strerror(errno));
89                 return rc;
90         }
91
92         process->stdout_len += rc;
93         if (process->stdout_len == procinfo->stdout_buf_len - 1) {
94                 procinfo->stdout_buf_len *= 2;
95                 process->stdout_buf = talloc_realloc(procinfo,
96                                 process->stdout_buf, char,
97                                 procinfo->stdout_buf_len);
98         }
99
100         return 1;
101 }
102
103 static int process_setup_stdout_pipe(struct process_info *procinfo)
104 {
105         int rc;
106
107         if (!procinfo->process.keep_stdout)
108                 return 0;
109
110         procinfo->stdout_buf_len = 4096;
111         procinfo->process.stdout_len = 0;
112         procinfo->process.stdout_buf = talloc_array(procinfo, char,
113                         procinfo->stdout_buf_len);
114
115         rc = pipe(procinfo->stdout_pipe);
116         if (rc) {
117                 pb_log("pipe failed");
118                 return rc;
119         }
120         return 0;
121 }
122
123 static void process_setup_stdout_parent(struct process_info *procinfo)
124 {
125         if (!procinfo->process.keep_stdout)
126                 return;
127
128         close(procinfo->stdout_pipe[1]);
129 }
130
131 static void process_setup_stdout_child(struct process_info *procinfo)
132 {
133         int log = fileno(pb_log_get_stream());
134
135         if (procinfo->process.keep_stdout)
136                 dup2(procinfo->stdout_pipe[1], STDOUT_FILENO);
137         else
138                 dup2(log, STDOUT_FILENO);
139
140         if (procinfo->process.keep_stdout && procinfo->process.add_stderr)
141                 dup2(procinfo->stdout_pipe[1], STDERR_FILENO);
142         else
143                 dup2(log, STDERR_FILENO);
144 }
145
146 static void process_finish_stdout(struct process_info *procinfo)
147 {
148         close(procinfo->stdout_pipe[0]);
149         procinfo->process.stdout_buf[procinfo->process.stdout_len] = '\0';
150 }
151
152 static int process_read_stdout(struct process_info *procinfo)
153 {
154         int rc;
155
156         if (!procinfo->process.keep_stdout)
157                 return 0;
158
159         do {
160                 rc = process_read_stdout_once(procinfo);
161         } while (rc > 0);
162
163         process_finish_stdout(procinfo);
164
165         return rc < 0 ? rc : 0;
166 }
167
168 static int process_stdout_cb(void *arg)
169 {
170         struct process_info *procinfo = arg;
171         int rc;
172
173         rc = process_read_stdout_once(procinfo);
174
175         /* if we're going to signal to the waitset that we're done (ie, non-zero
176          * return value), then the waiters will remove us, so we drop the
177          * reference */
178         if (rc < 0) {
179                 talloc_unlink(procset, procinfo);
180                 procinfo->stdout_waiter = NULL;
181                 rc = -1;
182         } else {
183                 rc = 0;
184         }
185
186         return rc;
187 }
188
189 static void sigchld_sigaction(int signo, siginfo_t *info,
190                 void *arg __attribute__((unused)))
191 {
192         pid_t pid;
193         int rc;
194
195         if (signo != SIGCHLD)
196                 return;
197
198         pid = info->si_pid;
199
200         rc = write(procset->sigchld_pipe[1], &pid, sizeof(pid));
201         if (rc != sizeof(pid))
202                 pb_log("%s: write failed: %s\n", __func__, strerror(errno));
203 }
204
205 static int sigchld_pipe_event(void *arg)
206 {
207         struct process_info *procinfo;
208         struct procset *procset = arg;
209         struct process *process;
210         int pid, rc;
211
212         rc = read(procset->sigchld_pipe[0], &pid, sizeof(pid));
213         if (rc != sizeof(pid))
214                 return 0;
215
216         process = NULL;
217         list_for_each_entry(&procset->async_list, procinfo, async_list) {
218                 if (procinfo->process.pid == pid) {
219                         process = &procinfo->process;
220                         break;
221                 }
222         }
223
224         /* We'll receive SIGCHLD for synchronous processes too; just ignore */
225         if (!process)
226                 return 0;
227
228         rc = waitpid(process->pid, &process->exit_status, WNOHANG);
229
230         /* if the process is still running, ignore the event. We leave
231          * the process in async_list so we can manage the final signal */
232         if (rc == 0)
233                 return 0;
234
235         /* ensure we have all of the child's stdout */
236         process_read_stdout(procinfo);
237
238         if (process->exit_cb)
239                 process->exit_cb(process);
240
241         list_remove(&procinfo->async_list);
242         talloc_unlink(procset, procinfo);
243
244         return 0;
245 }
246
247 static int process_fini(void *p)
248 {
249         struct procset *procset = p;
250         struct sigaction sa;
251
252         memset(&sa, 0, sizeof(sa));
253         sa.sa_handler = SIG_DFL;
254
255         sigaction(SIGCHLD, &sa, NULL);
256
257         waiter_remove(procset->sigchld_waiter);
258
259         close(procset->sigchld_pipe[0]);
260         close(procset->sigchld_pipe[1]);
261         return 0;
262 }
263
264 struct procset *process_init(void *ctx, struct waitset *set, bool dry_run)
265 {
266         struct sigaction sa;
267         int rc;
268
269         procset = talloc(ctx, struct procset);
270         procset->waitset = set;
271         procset->dry_run = dry_run;
272         list_init(&procset->async_list);
273
274         rc = pipe(procset->sigchld_pipe);
275         if (rc) {
276                 pb_log("%s: pipe() failed: %s\n", __func__, strerror(errno));
277                 goto err_free;
278         }
279
280         procset->sigchld_waiter = waiter_register_io(set,
281                                         procset->sigchld_pipe[0], WAIT_IN,
282                                         sigchld_pipe_event, procset);
283         if (!procset->sigchld_waiter)
284                 goto err_close;
285
286         memset(&sa, 0, sizeof(sa));
287         sa.sa_sigaction = sigchld_sigaction;
288         sa.sa_flags = SA_SIGINFO | SA_NOCLDSTOP;
289
290         rc = sigaction(SIGCHLD, &sa, NULL);
291         if (rc) {
292                 pb_log("%s: sigaction() failed: %s\n", __func__,
293                                 strerror(errno));
294                 goto err_remove;
295         }
296
297         talloc_set_destructor(procset, process_fini);
298
299         return procset;
300
301 err_remove:
302         waiter_remove(procset->sigchld_waiter);
303 err_close:
304         close(procset->sigchld_pipe[0]);
305         close(procset->sigchld_pipe[1]);
306 err_free:
307         talloc_free(procset);
308         return NULL;
309 }
310
311 struct process *process_create(void *ctx)
312 {
313         struct process_info *info = talloc_zero(ctx, struct process_info);
314         info->orig_ctx = ctx;
315         return &info->process;
316 }
317
318 void process_release(struct process *process)
319 {
320         struct process_info *info = get_info(process);
321         talloc_unlink(info->orig_ctx, info);
322 }
323
324 static int process_run_common(struct process_info *procinfo)
325 {
326         struct process *process = &procinfo->process;
327         const char *arg;
328         char *logmsg;
329         pid_t pid;
330         int rc, i;
331
332         logmsg = talloc_asprintf(procinfo, " exe:  %s\n argv:", process->path);
333         for (i = 0, arg = process->argv[i]; arg; i++, arg = process->argv[i])
334                 logmsg = talloc_asprintf_append(logmsg, " '%s'", arg);
335
336         pb_log("Running command:\n%s\n", logmsg);
337
338         rc = process_setup_stdout_pipe(procinfo);
339         if (rc)
340                 return rc;
341
342         pid = fork();
343         if (pid < 0) {
344                 pb_log("%s: fork failed: %s\n", __func__, strerror(errno));
345                 return pid;
346         }
347
348         if (pid == 0) {
349                 process_setup_stdout_child(procinfo);
350                 if (procset->dry_run)
351                         exit(EXIT_SUCCESS);
352                 execvp(process->path, (char * const *)process->argv);
353                 exit(EXIT_FAILURE);
354         }
355
356         process_setup_stdout_parent(procinfo);
357         process->pid = pid;
358
359         return 0;
360 }
361
362 int process_run_sync(struct process *process)
363 {
364         struct process_info *procinfo = get_info(process);
365         int rc;
366
367         rc = process_run_common(procinfo);
368         if (rc)
369                 return rc;
370
371         process_read_stdout(procinfo);
372
373         for (;;) {
374                 rc = waitpid(process->pid, &process->exit_status, 0);
375                 if (rc >= 0)
376                         break;
377                 if (errno == EINTR)
378                         continue;
379
380                 pb_log("%s: waitpid failed: %s\n", __func__, strerror(errno));
381                 return rc;
382         }
383
384         return 0;
385 }
386
387 int process_run_async(struct process *process)
388 {
389         struct process_info *procinfo = get_info(process);
390         int rc;
391
392         rc = process_run_common(procinfo);
393         if (rc)
394                 return rc;
395
396         if (process->keep_stdout) {
397                 procinfo->stdout_waiter = waiter_register_io(procset->waitset,
398                                                 procinfo->stdout_pipe[0],
399                                                 WAIT_IN, process_stdout_cb,
400                                                 procinfo);
401                 talloc_reference(procset, procinfo);
402         }
403
404         list_add(&procset->async_list, &procinfo->async_list);
405         talloc_reference(procset, procinfo);
406
407         return 0;
408 }
409
410 void process_stop_async(struct process *process)
411 {
412         pb_debug("process: sending SIGTERM to pid %d\n", process->pid);
413         kill(process->pid, SIGTERM);
414 }
415
416 int process_run_simple_argv(void *ctx, const char *argv[])
417 {
418         struct process *process;
419         int rc;
420
421         process = process_create(ctx);
422
423         process->path = argv[0];
424         process->argv = argv;
425
426         rc = process_run_sync(process);
427
428         if (!rc)
429                 rc = process->exit_status;
430
431         process_release(process);
432
433         return rc;
434 }
435
436 int process_run_simple(void *ctx, const char *name, ...)
437 {
438         int rc, i, n_argv = 1;
439         const char **argv;
440         va_list ap;
441
442         va_start(ap, name);
443         while (va_arg(ap, char *))
444                 n_argv++;
445         va_end(ap);
446
447         argv = talloc_array(ctx, const char *, n_argv + 1);
448         argv[0] = name;
449
450         va_start(ap, name);
451         for (i = 1; i < n_argv; i++)
452                 argv[i] = va_arg(ap, const char *);
453         va_end(ap);
454
455         argv[i] = NULL;
456
457         rc = process_run_simple_argv(ctx, argv);
458
459         talloc_free(argv);
460
461         return rc;
462 }
463
464 bool process_exit_ok(struct process *process)
465 {
466         return WIFEXITED(process->exit_status) &&
467                 WEXITSTATUS(process->exit_status) == 0;
468 }