]> git.ozlabs.org Git - petitboot/blob - lib/process/process.c
lib/process: Add option to pipe to process stdin
[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         int                     stdin_pipe[2];
54         void                    *orig_ctx;
55 };
56
57 static struct procset *procset;
58
59 static struct process_info *get_info(struct process *process)
60 {
61         return container_of(process, struct process_info, process);
62 }
63
64 struct process *procinfo_get_process(struct process_info *procinfo)
65 {
66         return &procinfo->process;
67 }
68
69 /* Read as much as possible into the currently-allocated stdout buffer, and
70  * possibly realloc it for the next read
71  * If the line pointer is not NULL, it is set to the start of the latest
72  * output.
73  *
74  * Returns:
75  *  > 0 on success (even though no bytes may have been read)
76  *    0 on EOF (no error, but no more reads can be performed)
77  *  < 0 on error
78  **/
79 static int process_read_stdout_once(struct process_info *procinfo, char **line)
80 {
81         struct process *process = &procinfo->process;
82         int rc, fd, max_len;
83
84         assert(process->keep_stdout);
85
86         fd = procinfo->stdout_pipe[0];
87
88         max_len =  procinfo->stdout_buf_len - process->stdout_len - 1;
89
90         rc = read(fd, process->stdout_buf + process->stdout_len, max_len);
91         if (rc == 0)
92                 return 0;
93         if (rc < 0) {
94                 if (errno == EINTR)
95                         return 1;
96                 pb_log_fn("read failed: %s\n", strerror(errno));
97                 return rc;
98         }
99
100         if (line)
101                 *line = process->stdout_buf + process->stdout_len;
102
103         process->stdout_len += rc;
104         if (process->stdout_len == procinfo->stdout_buf_len - 1) {
105                 procinfo->stdout_buf_len *= 2;
106                 process->stdout_buf = talloc_realloc(procinfo,
107                                 process->stdout_buf, char,
108                                 procinfo->stdout_buf_len);
109         }
110
111         return 1;
112 }
113
114 static int process_setup_stdout_pipe(struct process_info *procinfo)
115 {
116         int rc;
117
118         if (!procinfo->process.keep_stdout || procinfo->process.raw_stdout)
119                 return 0;
120
121         procinfo->stdout_buf_len = 4096;
122         procinfo->process.stdout_len = 0;
123         procinfo->process.stdout_buf = talloc_array(procinfo, char,
124                         procinfo->stdout_buf_len);
125
126         rc = pipe(procinfo->stdout_pipe);
127         if (rc) {
128                 pb_log("pipe failed");
129                 return rc;
130         }
131         return 0;
132 }
133
134 static void process_setup_stdin_parent(struct process_info *procinfo)
135 {
136         FILE *in;
137
138         if (!procinfo->process.pipe_stdin)
139                 return;
140
141         close(procinfo->stdin_pipe[0]);
142         in = fdopen(procinfo->stdin_pipe[1], "w");
143         if (!in) {
144                 pb_log_fn("Failed to open stdin\n");
145                 return;
146         }
147         fputs(procinfo->process.pipe_stdin, in);
148         fflush(in);
149 }
150
151 static void process_setup_stdin_child(struct process_info *procinfo)
152 {
153         if (procinfo->process.pipe_stdin) {
154                 close(procinfo->stdin_pipe[1]);
155                 dup2(procinfo->stdin_pipe[0], STDIN_FILENO);
156         }
157 }
158 static void process_setup_stdout_parent(struct process_info *procinfo)
159 {
160         if (!procinfo->process.keep_stdout || procinfo->process.raw_stdout)
161                 return;
162
163         close(procinfo->stdout_pipe[1]);
164
165 }
166
167 static void process_setup_stdout_child(struct process_info *procinfo)
168 {
169         int log = fileno(pb_log_get_stream());
170
171         if (procinfo->process.raw_stdout)
172                 return;
173
174         if (procinfo->process.keep_stdout)
175                 dup2(procinfo->stdout_pipe[1], STDOUT_FILENO);
176         else
177                 dup2(log, STDOUT_FILENO);
178
179         if (procinfo->process.keep_stdout && procinfo->process.add_stderr)
180                 dup2(procinfo->stdout_pipe[1], STDERR_FILENO);
181         else
182                 dup2(log, STDERR_FILENO);
183 }
184
185 static void process_finish_stdout(struct process_info *procinfo)
186 {
187         close(procinfo->stdout_pipe[0]);
188         procinfo->process.stdout_buf[procinfo->process.stdout_len] = '\0';
189 }
190
191 static int process_read_stdout(struct process_info *procinfo)
192 {
193         int rc;
194
195         if (!procinfo->process.keep_stdout)
196                 return 0;
197
198         do {
199                 rc = process_read_stdout_once(procinfo, NULL);
200         } while (rc > 0);
201
202         process_finish_stdout(procinfo);
203
204         return rc < 0 ? rc : 0;
205 }
206
207 int process_process_stdout(struct process_info *procinfo, char **line)
208 {
209         int rc;
210
211         rc = process_read_stdout_once(procinfo, line);
212
213         /* if we're going to signal to the waitset that we're done (ie, non-zero
214          * return value), then the waiters will remove us, so we drop the
215          * reference */
216         if (rc < 0) {
217                 talloc_unlink(procset, procinfo);
218                 procinfo->stdout_waiter = NULL;
219                 rc = -1;
220         } else {
221                 rc = 0;
222         }
223
224         return rc;
225 }
226
227 static void sigchld_sigaction(int signo, siginfo_t *info,
228                 void *arg __attribute__((unused)))
229 {
230         pid_t pid;
231         int rc;
232
233         if (signo != SIGCHLD)
234                 return;
235
236         pid = info->si_pid;
237
238         rc = write(procset->sigchld_pipe[1], &pid, sizeof(pid));
239         if (rc != sizeof(pid))
240                 pb_log_fn("write failed: %s\n", strerror(errno));
241 }
242
243 static int sigchld_pipe_event(void *arg)
244 {
245         struct process_info *procinfo;
246         struct procset *procset = arg;
247         struct process *process;
248         int pid, rc;
249
250         rc = read(procset->sigchld_pipe[0], &pid, sizeof(pid));
251         if (rc != sizeof(pid))
252                 return 0;
253
254         process = NULL;
255         list_for_each_entry(&procset->async_list, procinfo, async_list) {
256                 if (procinfo->process.pid == pid) {
257                         process = &procinfo->process;
258                         break;
259                 }
260         }
261
262         /* We'll receive SIGCHLD for synchronous processes too; just ignore */
263         if (!process)
264                 return 0;
265
266         rc = waitpid(process->pid, &process->exit_status, WNOHANG);
267
268         /* if the process is still running, ignore the event. We leave
269          * the process in async_list so we can manage the final signal */
270         if (rc == 0)
271                 return 0;
272
273         /* ensure we have all of the child's stdout */
274         process_read_stdout(procinfo);
275
276         if (process->exit_cb)
277                 process->exit_cb(process);
278
279         list_remove(&procinfo->async_list);
280         talloc_unlink(procset, procinfo);
281
282         return 0;
283 }
284
285 static int process_fini(void *p)
286 {
287         struct procset *procset = p;
288         struct sigaction sa;
289
290         memset(&sa, 0, sizeof(sa));
291         sa.sa_handler = SIG_DFL;
292
293         sigaction(SIGCHLD, &sa, NULL);
294
295         waiter_remove(procset->sigchld_waiter);
296
297         close(procset->sigchld_pipe[0]);
298         close(procset->sigchld_pipe[1]);
299         return 0;
300 }
301
302 struct procset *process_init(void *ctx, struct waitset *set, bool dry_run)
303 {
304         struct sigaction sa;
305         int rc;
306
307         procset = talloc(ctx, struct procset);
308         procset->waitset = set;
309         procset->dry_run = dry_run;
310         list_init(&procset->async_list);
311
312         rc = pipe(procset->sigchld_pipe);
313         if (rc) {
314                 pb_log_fn("pipe() failed: %s\n", strerror(errno));
315                 goto err_free;
316         }
317
318         procset->sigchld_waiter = waiter_register_io(set,
319                                         procset->sigchld_pipe[0], WAIT_IN,
320                                         sigchld_pipe_event, procset);
321         if (!procset->sigchld_waiter)
322                 goto err_close;
323
324         memset(&sa, 0, sizeof(sa));
325         sa.sa_sigaction = sigchld_sigaction;
326         sa.sa_flags = SA_SIGINFO | SA_NOCLDSTOP;
327
328         rc = sigaction(SIGCHLD, &sa, NULL);
329         if (rc) {
330                 pb_log_fn("sigaction() failed: %s\n",
331                                 strerror(errno));
332                 goto err_remove;
333         }
334
335         talloc_set_destructor(procset, process_fini);
336
337         return procset;
338
339 err_remove:
340         waiter_remove(procset->sigchld_waiter);
341 err_close:
342         close(procset->sigchld_pipe[0]);
343         close(procset->sigchld_pipe[1]);
344 err_free:
345         talloc_free(procset);
346         return NULL;
347 }
348
349 struct process *process_create(void *ctx)
350 {
351         struct process_info *info = talloc_zero(ctx, struct process_info);
352         info->orig_ctx = ctx;
353         return &info->process;
354 }
355
356 void process_release(struct process *process)
357 {
358         struct process_info *info = get_info(process);
359         talloc_unlink(info->orig_ctx, info);
360 }
361
362 static int process_run_common(struct process_info *procinfo)
363 {
364         struct process *process = &procinfo->process;
365         const char *arg;
366         char *logmsg;
367         pid_t pid;
368         int rc, i;
369
370         logmsg = talloc_asprintf(procinfo, " exe:  %s\n argv:", process->path);
371         for (i = 0, arg = process->argv[i]; arg; i++, arg = process->argv[i])
372                 logmsg = talloc_asprintf_append(logmsg, " '%s'", arg);
373
374         pb_log("Running command:\n%s\n", logmsg);
375
376         rc = process_setup_stdout_pipe(procinfo);
377         if (rc)
378                 return rc;
379         if (procinfo->process.pipe_stdin) {
380                 rc = pipe(procinfo->stdin_pipe);
381                 if (rc)
382                         return rc;
383         }
384
385         pid = fork();
386         if (pid < 0) {
387                 pb_log_fn("fork failed: %s\n", strerror(errno));
388                 return pid;
389         }
390
391         if (pid == 0) {
392                 process_setup_stdout_child(procinfo);
393                 process_setup_stdin_child(procinfo);
394                 if (procset->dry_run)
395                         exit(EXIT_SUCCESS);
396                 execvp(process->path, (char * const *)process->argv);
397                 exit(EXIT_FAILURE);
398         }
399
400         process_setup_stdout_parent(procinfo);
401         process_setup_stdin_parent(procinfo);
402         process->pid = pid;
403
404         return 0;
405 }
406
407 int process_run_sync(struct process *process)
408 {
409         struct process_info *procinfo = get_info(process);
410         int rc;
411
412         rc = process_run_common(procinfo);
413         if (rc)
414                 return rc;
415
416         process_read_stdout(procinfo);
417
418         for (;;) {
419                 rc = waitpid(process->pid, &process->exit_status, 0);
420                 if (rc >= 0)
421                         break;
422                 if (errno == EINTR)
423                         continue;
424
425                 pb_log_fn("waitpid failed: %s\n", strerror(errno));
426                 return rc;
427         }
428
429         return 0;
430 }
431
432 static int process_stdout_cb(struct process_info *procinfo)
433 {
434         return process_process_stdout(procinfo, NULL);
435 }
436
437 int process_run_async(struct process *process)
438 {
439         struct process_info *procinfo = get_info(process);
440         int rc;
441
442         rc = process_run_common(procinfo);
443         if (rc)
444                 return rc;
445
446         if (process->keep_stdout) {
447                 waiter_cb stdout_cb = process->stdout_cb ?:
448                         (waiter_cb)process_stdout_cb;
449                 procinfo->stdout_waiter = waiter_register_io(procset->waitset,
450                                                 procinfo->stdout_pipe[0],
451                                                 WAIT_IN, stdout_cb, procinfo);
452                 talloc_reference(procset, procinfo);
453         }
454
455         list_add(&procset->async_list, &procinfo->async_list);
456         talloc_reference(procset, procinfo);
457
458         return 0;
459 }
460
461 void process_stop_async(struct process *process)
462 {
463         /* Avoid signalling an old pid */
464         if (process->cancelled)
465                 return;
466
467         pb_debug("process: sending SIGTERM to pid %d\n", process->pid);
468         kill(process->pid, SIGTERM);
469         process->cancelled = true;
470 }
471
472 void process_stop_async_all(void)
473 {
474         struct process_info *procinfo;
475         struct process *process = NULL;
476
477         pb_debug("process: cancelling all async jobs\n");
478
479         list_for_each_entry(&procset->async_list, procinfo, async_list) {
480                 process = &procinfo->process;
481                 /* Ignore the process completion - callbacks may use stale data */
482                 process->exit_cb = NULL;
483                 process->stdout_cb = NULL;
484                 process_stop_async(process);
485         }
486 }
487
488 int process_get_stdout_argv(void *ctx, struct process_stdout **stdout,
489         const char *argv[])
490 {
491         struct process *p;
492         int rc;
493
494         p = process_create(NULL);
495         p->path = argv[0];
496         p->argv = argv;
497
498         if (stdout) {
499                 p->keep_stdout = true;
500                 *stdout = NULL;
501         }
502
503         rc = process_run_sync(p);
504
505         if (!rc)
506                 rc = p->exit_status;
507         else {
508                 pb_debug("%s: process_run_sync failed: %s.\n", __func__,
509                         p->path);
510                 if (stdout)
511                         pb_debug("%s: stdout: %s\n\n", __func__, p->stdout_buf);
512                 goto exit;
513         }
514
515         if (!stdout)
516                 goto exit;
517
518         *stdout = talloc(ctx, struct process_stdout);
519
520         if (!*stdout) {
521                 rc = -1;
522                 goto exit;
523         }
524
525         (*stdout)->len = p->stdout_len;
526         (*stdout)->buf = talloc_memdup(*stdout, p->stdout_buf,
527                 p->stdout_len + 1);
528         (*stdout)->buf[p->stdout_len] = 0;
529
530 exit:
531         process_release(p);
532         return rc;
533 }
534
535 int process_get_stdout(void *ctx, struct process_stdout **stdout,
536         const char *path, ...)
537 {
538         int rc, i, n_argv = 1;
539         const char **argv;
540         va_list ap;
541
542         va_start(ap, path);
543         while (va_arg(ap, char *))
544                 n_argv++;
545         va_end(ap);
546
547         argv = talloc_array(ctx, const char *, n_argv + 1);
548         argv[0] = path;
549
550         va_start(ap, path);
551         for (i = 1; i < n_argv; i++)
552                 argv[i] = va_arg(ap, const char *);
553         va_end(ap);
554
555         argv[i] = NULL;
556
557         rc = process_get_stdout_argv(ctx, stdout, argv);
558
559         talloc_free(argv);
560
561         return rc;
562 }
563
564 bool process_exit_ok(struct process *process)
565 {
566         return WIFEXITED(process->exit_status) &&
567                 WEXITSTATUS(process->exit_status) == 0;
568 }