1 /* $NetBSD: process.c,v 1.3 2014/12/10 04:38:03 christos Exp $ */
2
3 /*
4 * Automated Testing Framework (atf)
5 *
6 * Copyright (c) 2007 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
19 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
29 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/types.h>
33 #include <sys/wait.h>
34
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 #include "atf-c/defs.h"
43 #include "atf-c/error.h"
44
45 #include "process.h"
46 #include "sanity.h"
47
48 /* This prototype is not in the header file because this is a private
49 * function; however, we need to access it during testing. */
50 atf_error_t atf_process_status_init(atf_process_status_t *, int);
51
52 /* ---------------------------------------------------------------------
53 * The "stream_prepare" auxiliary type.
54 * --------------------------------------------------------------------- */
55
56 struct stream_prepare {
57 const atf_process_stream_t *m_sb;
58
59 bool m_pipefds_ok;
60 int m_pipefds[2];
61 };
62 typedef struct stream_prepare stream_prepare_t;
63
64 static
65 atf_error_t
stream_prepare_init(stream_prepare_t * sp,const atf_process_stream_t * sb)66 stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb)
67 {
68 atf_error_t err;
69
70 const int type = atf_process_stream_type(sb);
71
72 sp->m_sb = sb;
73 sp->m_pipefds_ok = false;
74
75 if (type == atf_process_stream_type_capture) {
76 if (pipe(sp->m_pipefds) == -1)
77 err = atf_libc_error(errno, "Failed to create pipe");
78 else {
79 err = atf_no_error();
80 sp->m_pipefds_ok = true;
81 }
82 } else
83 err = atf_no_error();
84
85 return err;
86 }
87
88 static
89 void
stream_prepare_fini(stream_prepare_t * sp)90 stream_prepare_fini(stream_prepare_t *sp)
91 {
92 if (sp->m_pipefds_ok) {
93 close(sp->m_pipefds[0]);
94 close(sp->m_pipefds[1]);
95 }
96 }
97
98 /* ---------------------------------------------------------------------
99 * The "atf_process_stream" type.
100 * --------------------------------------------------------------------- */
101
102 const int atf_process_stream_type_capture = 1;
103 const int atf_process_stream_type_connect = 2;
104 const int atf_process_stream_type_inherit = 3;
105 const int atf_process_stream_type_redirect_fd = 4;
106 const int atf_process_stream_type_redirect_path = 5;
107
108 static
109 bool
stream_is_valid(const atf_process_stream_t * sb)110 stream_is_valid(const atf_process_stream_t *sb)
111 {
112 return (sb->m_type == atf_process_stream_type_capture) ||
113 (sb->m_type == atf_process_stream_type_connect) ||
114 (sb->m_type == atf_process_stream_type_inherit) ||
115 (sb->m_type == atf_process_stream_type_redirect_fd) ||
116 (sb->m_type == atf_process_stream_type_redirect_path);
117 }
118
119 atf_error_t
atf_process_stream_init_capture(atf_process_stream_t * sb)120 atf_process_stream_init_capture(atf_process_stream_t *sb)
121 {
122 sb->m_type = atf_process_stream_type_capture;
123
124 POST(stream_is_valid(sb));
125 return atf_no_error();
126 }
127
128 atf_error_t
atf_process_stream_init_connect(atf_process_stream_t * sb,const int src_fd,const int tgt_fd)129 atf_process_stream_init_connect(atf_process_stream_t *sb,
130 const int src_fd, const int tgt_fd)
131 {
132 PRE(src_fd >= 0);
133 PRE(tgt_fd >= 0);
134 PRE(src_fd != tgt_fd);
135
136 sb->m_type = atf_process_stream_type_connect;
137 sb->m_src_fd = src_fd;
138 sb->m_tgt_fd = tgt_fd;
139
140 POST(stream_is_valid(sb));
141 return atf_no_error();
142 }
143
144 atf_error_t
atf_process_stream_init_inherit(atf_process_stream_t * sb)145 atf_process_stream_init_inherit(atf_process_stream_t *sb)
146 {
147 sb->m_type = atf_process_stream_type_inherit;
148
149 POST(stream_is_valid(sb));
150 return atf_no_error();
151 }
152
153 atf_error_t
atf_process_stream_init_redirect_fd(atf_process_stream_t * sb,const int fd)154 atf_process_stream_init_redirect_fd(atf_process_stream_t *sb,
155 const int fd)
156 {
157 sb->m_type = atf_process_stream_type_redirect_fd;
158 sb->m_fd = fd;
159
160 POST(stream_is_valid(sb));
161 return atf_no_error();
162 }
163
164 atf_error_t
atf_process_stream_init_redirect_path(atf_process_stream_t * sb,const atf_fs_path_t * path)165 atf_process_stream_init_redirect_path(atf_process_stream_t *sb,
166 const atf_fs_path_t *path)
167 {
168 sb->m_type = atf_process_stream_type_redirect_path;
169 sb->m_path = path;
170
171 POST(stream_is_valid(sb));
172 return atf_no_error();
173 }
174
175 void
atf_process_stream_fini(atf_process_stream_t * sb)176 atf_process_stream_fini(atf_process_stream_t *sb)
177 {
178 PRE(stream_is_valid(sb));
179 }
180
181 int
atf_process_stream_type(const atf_process_stream_t * sb)182 atf_process_stream_type(const atf_process_stream_t *sb)
183 {
184 PRE(stream_is_valid(sb));
185
186 return sb->m_type;
187 }
188
189 /* ---------------------------------------------------------------------
190 * The "atf_process_status" type.
191 * --------------------------------------------------------------------- */
192
193 atf_error_t
atf_process_status_init(atf_process_status_t * s,int status)194 atf_process_status_init(atf_process_status_t *s, int status)
195 {
196 s->m_status = status;
197
198 return atf_no_error();
199 }
200
201 void
atf_process_status_fini(atf_process_status_t * s ATF_DEFS_ATTRIBUTE_UNUSED)202 atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)
203 {
204 }
205
206 bool
atf_process_status_exited(const atf_process_status_t * s)207 atf_process_status_exited(const atf_process_status_t *s)
208 {
209 int mutable_status = s->m_status;
210 return WIFEXITED(mutable_status);
211 }
212
213 int
atf_process_status_exitstatus(const atf_process_status_t * s)214 atf_process_status_exitstatus(const atf_process_status_t *s)
215 {
216 PRE(atf_process_status_exited(s));
217 int mutable_status = s->m_status;
218 return WEXITSTATUS(mutable_status);
219 }
220
221 bool
atf_process_status_signaled(const atf_process_status_t * s)222 atf_process_status_signaled(const atf_process_status_t *s)
223 {
224 int mutable_status = s->m_status;
225 return WIFSIGNALED(mutable_status);
226 }
227
228 int
atf_process_status_termsig(const atf_process_status_t * s)229 atf_process_status_termsig(const atf_process_status_t *s)
230 {
231 PRE(atf_process_status_signaled(s));
232 int mutable_status = s->m_status;
233 return WTERMSIG(mutable_status);
234 }
235
236 bool
atf_process_status_coredump(const atf_process_status_t * s)237 atf_process_status_coredump(const atf_process_status_t *s)
238 {
239 PRE(atf_process_status_signaled(s));
240 #if defined(WCOREDUMP)
241 int mutable_status = s->m_status;
242 return WCOREDUMP(mutable_status);
243 #else
244 return false;
245 #endif
246 }
247
248 /* ---------------------------------------------------------------------
249 * The "atf_process_child" type.
250 * --------------------------------------------------------------------- */
251
252 static
253 atf_error_t
atf_process_child_init(atf_process_child_t * c)254 atf_process_child_init(atf_process_child_t *c)
255 {
256 c->m_pid = 0;
257 c->m_stdout = -1;
258 c->m_stderr = -1;
259
260 return atf_no_error();
261 }
262
263 static
264 void
atf_process_child_fini(atf_process_child_t * c)265 atf_process_child_fini(atf_process_child_t *c)
266 {
267 if (c->m_stdout != -1)
268 close(c->m_stdout);
269 if (c->m_stderr != -1)
270 close(c->m_stderr);
271 }
272
273 atf_error_t
atf_process_child_wait(atf_process_child_t * c,atf_process_status_t * s)274 atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s)
275 {
276 atf_error_t err;
277 int status;
278
279 if (waitpid(c->m_pid, &status, 0) == -1)
280 err = atf_libc_error(errno, "Failed waiting for process %d",
281 c->m_pid);
282 else {
283 atf_process_child_fini(c);
284 err = atf_process_status_init(s, status);
285 }
286
287 return err;
288 }
289
290 pid_t
atf_process_child_pid(const atf_process_child_t * c)291 atf_process_child_pid(const atf_process_child_t *c)
292 {
293 return c->m_pid;
294 }
295
296 int
atf_process_child_stdout(atf_process_child_t * c)297 atf_process_child_stdout(atf_process_child_t *c)
298 {
299 PRE(c->m_stdout != -1);
300 return c->m_stdout;
301 }
302
303 int
atf_process_child_stderr(atf_process_child_t * c)304 atf_process_child_stderr(atf_process_child_t *c)
305 {
306 PRE(c->m_stderr != -1);
307 return c->m_stderr;
308 }
309
310 /* ---------------------------------------------------------------------
311 * Free functions.
312 * --------------------------------------------------------------------- */
313
314 static
315 atf_error_t
safe_dup(const int oldfd,const int newfd)316 safe_dup(const int oldfd, const int newfd)
317 {
318 atf_error_t err;
319
320 if (oldfd != newfd) {
321 if (dup2(oldfd, newfd) == -1) {
322 err = atf_libc_error(errno, "Could not allocate file descriptor");
323 } else {
324 close(oldfd);
325 err = atf_no_error();
326 }
327 } else
328 err = atf_no_error();
329
330 return err;
331 }
332
333 static
334 atf_error_t
child_connect(const stream_prepare_t * sp,int procfd)335 child_connect(const stream_prepare_t *sp, int procfd)
336 {
337 atf_error_t err;
338 const int type = atf_process_stream_type(sp->m_sb);
339
340 if (type == atf_process_stream_type_capture) {
341 close(sp->m_pipefds[0]);
342 err = safe_dup(sp->m_pipefds[1], procfd);
343 } else if (type == atf_process_stream_type_connect) {
344 if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1)
345 err = atf_libc_error(errno, "Cannot connect descriptor %d to %d",
346 sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd);
347 else
348 err = atf_no_error();
349 } else if (type == atf_process_stream_type_inherit) {
350 err = atf_no_error();
351 } else if (type == atf_process_stream_type_redirect_fd) {
352 err = safe_dup(sp->m_sb->m_fd, procfd);
353 } else if (type == atf_process_stream_type_redirect_path) {
354 int aux = open(atf_fs_path_cstring(sp->m_sb->m_path),
355 O_WRONLY | O_CREAT | O_TRUNC, 0644);
356 if (aux == -1)
357 err = atf_libc_error(errno, "Could not create %s",
358 atf_fs_path_cstring(sp->m_sb->m_path));
359 else {
360 err = safe_dup(aux, procfd);
361 if (atf_is_error(err))
362 close(aux);
363 }
364 } else {
365 UNREACHABLE;
366 err = atf_no_error();
367 }
368
369 return err;
370 }
371
372 static
373 void
parent_connect(const stream_prepare_t * sp,int * fd)374 parent_connect(const stream_prepare_t *sp, int *fd)
375 {
376 const int type = atf_process_stream_type(sp->m_sb);
377
378 if (type == atf_process_stream_type_capture) {
379 close(sp->m_pipefds[1]);
380 *fd = sp->m_pipefds[0];
381 } else if (type == atf_process_stream_type_connect) {
382 /* Do nothing. */
383 } else if (type == atf_process_stream_type_inherit) {
384 /* Do nothing. */
385 } else if (type == atf_process_stream_type_redirect_fd) {
386 /* Do nothing. */
387 } else if (type == atf_process_stream_type_redirect_path) {
388 /* Do nothing. */
389 } else {
390 UNREACHABLE;
391 }
392 }
393
394 static
395 atf_error_t
do_parent(atf_process_child_t * c,const pid_t pid,const stream_prepare_t * outsp,const stream_prepare_t * errsp)396 do_parent(atf_process_child_t *c,
397 const pid_t pid,
398 const stream_prepare_t *outsp,
399 const stream_prepare_t *errsp)
400 {
401 atf_error_t err;
402
403 err = atf_process_child_init(c);
404 if (atf_is_error(err))
405 goto out;
406
407 c->m_pid = pid;
408
409 parent_connect(outsp, &c->m_stdout);
410 parent_connect(errsp, &c->m_stderr);
411
412 out:
413 return err;
414 }
415
416 static
417 void
418 do_child(void (*)(void *),
419 void *,
420 const stream_prepare_t *,
421 const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
422
423 static
424 void
do_child(void (* start)(void *),void * v,const stream_prepare_t * outsp,const stream_prepare_t * errsp)425 do_child(void (*start)(void *),
426 void *v,
427 const stream_prepare_t *outsp,
428 const stream_prepare_t *errsp)
429 {
430 atf_error_t err;
431
432 err = child_connect(outsp, STDOUT_FILENO);
433 if (atf_is_error(err))
434 goto out;
435
436 err = child_connect(errsp, STDERR_FILENO);
437 if (atf_is_error(err))
438 goto out;
439
440 start(v);
441 UNREACHABLE;
442
443 out:
444 if (atf_is_error(err)) {
445 char buf[1024];
446
447 atf_error_format(err, buf, sizeof(buf));
448 fprintf(stderr, "Unhandled error: %s\n", buf);
449 atf_error_free(err);
450
451 exit(EXIT_FAILURE);
452 } else
453 exit(EXIT_SUCCESS);
454 }
455
456 static
457 atf_error_t
fork_with_streams(atf_process_child_t * c,void (* start)(void *),const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void * v)458 fork_with_streams(atf_process_child_t *c,
459 void (*start)(void *),
460 const atf_process_stream_t *outsb,
461 const atf_process_stream_t *errsb,
462 void *v)
463 {
464 atf_error_t err;
465 stream_prepare_t outsp;
466 stream_prepare_t errsp;
467 pid_t pid;
468
469 err = stream_prepare_init(&outsp, outsb);
470 if (atf_is_error(err))
471 goto out;
472
473 err = stream_prepare_init(&errsp, errsb);
474 if (atf_is_error(err))
475 goto err_outpipe;
476
477 pid = fork();
478 if (pid == -1) {
479 err = atf_libc_error(errno, "Failed to fork");
480 goto err_errpipe;
481 }
482
483 if (pid == 0) {
484 do_child(start, v, &outsp, &errsp);
485 UNREACHABLE;
486 abort();
487 err = atf_no_error();
488 } else {
489 err = do_parent(c, pid, &outsp, &errsp);
490 if (atf_is_error(err))
491 goto err_errpipe;
492 }
493
494 goto out;
495
496 err_errpipe:
497 stream_prepare_fini(&errsp);
498 err_outpipe:
499 stream_prepare_fini(&outsp);
500
501 out:
502 return err;
503 }
504
505 static
506 atf_error_t
init_stream_w_default(const atf_process_stream_t * usersb,atf_process_stream_t * inheritsb,const atf_process_stream_t ** realsb)507 init_stream_w_default(const atf_process_stream_t *usersb,
508 atf_process_stream_t *inheritsb,
509 const atf_process_stream_t **realsb)
510 {
511 atf_error_t err;
512
513 if (usersb == NULL) {
514 err = atf_process_stream_init_inherit(inheritsb);
515 if (!atf_is_error(err))
516 *realsb = inheritsb;
517 } else {
518 err = atf_no_error();
519 *realsb = usersb;
520 }
521
522 return err;
523 }
524
525 atf_error_t
atf_process_fork(atf_process_child_t * c,void (* start)(void *),const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void * v)526 atf_process_fork(atf_process_child_t *c,
527 void (*start)(void *),
528 const atf_process_stream_t *outsb,
529 const atf_process_stream_t *errsb,
530 void *v)
531 {
532 atf_error_t err;
533 atf_process_stream_t inherit_outsb, inherit_errsb;
534 const atf_process_stream_t *real_outsb, *real_errsb;
535
536 real_outsb = NULL; /* Shut up GCC warning. */
537 err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb);
538 if (atf_is_error(err))
539 goto out;
540
541 real_errsb = NULL; /* Shut up GCC warning. */
542 err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb);
543 if (atf_is_error(err))
544 goto out_out;
545
546 err = fork_with_streams(c, start, real_outsb, real_errsb, v);
547
548 if (errsb == NULL)
549 atf_process_stream_fini(&inherit_errsb);
550 out_out:
551 if (outsb == NULL)
552 atf_process_stream_fini(&inherit_outsb);
553 out:
554 return err;
555 }
556
557 static
558 int
const_execvp(const char * file,const char * const * argv)559 const_execvp(const char *file, const char *const *argv)
560 {
561 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
562 return execvp(file, UNCONST(argv));
563 #undef UNCONST
564 }
565
566 static
567 atf_error_t
list_to_array(const atf_list_t * l,const char *** ap)568 list_to_array(const atf_list_t *l, const char ***ap)
569 {
570 atf_error_t err;
571 const char **a;
572
573 a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *));
574 if (a == NULL)
575 err = atf_no_memory_error();
576 else {
577 const char **aiter;
578 atf_list_citer_t liter;
579
580 aiter = a;
581 atf_list_for_each_c(liter, l) {
582 *aiter = (const char *)atf_list_citer_data(liter);
583 aiter++;
584 }
585 *aiter = NULL;
586
587 err = atf_no_error();
588 *ap = a;
589 }
590
591 return err;
592 }
593
594 struct exec_args {
595 const atf_fs_path_t *m_prog;
596 const char *const *m_argv;
597 void (*m_prehook)(void);
598 };
599
600 static
601 void
do_exec(void * v)602 do_exec(void *v)
603 {
604 struct exec_args *ea = v;
605
606 if (ea->m_prehook != NULL)
607 ea->m_prehook();
608
609 const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv);
610 const int errnocopy = errno;
611 INV(ret == -1);
612 fprintf(stderr, "exec(%s) failed: %s\n",
613 atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));
614 exit(EXIT_FAILURE);
615 }
616
617 atf_error_t
atf_process_exec_array(atf_process_status_t * s,const atf_fs_path_t * prog,const char * const * argv,const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void (* prehook)(void))618 atf_process_exec_array(atf_process_status_t *s,
619 const atf_fs_path_t *prog,
620 const char *const *argv,
621 const atf_process_stream_t *outsb,
622 const atf_process_stream_t *errsb,
623 void (*prehook)(void))
624 {
625 atf_error_t err;
626 atf_process_child_t c;
627 struct exec_args ea = { prog, argv, prehook };
628
629 PRE(outsb == NULL ||
630 atf_process_stream_type(outsb) != atf_process_stream_type_capture);
631 PRE(errsb == NULL ||
632 atf_process_stream_type(errsb) != atf_process_stream_type_capture);
633
634 err = atf_process_fork(&c, do_exec, outsb, errsb, &ea);
635 if (atf_is_error(err))
636 goto out;
637
638 again:
639 err = atf_process_child_wait(&c, s);
640 if (atf_is_error(err)) {
641 INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR);
642 atf_error_free(err);
643 goto again;
644 }
645
646 out:
647 return err;
648 }
649
650 atf_error_t
atf_process_exec_list(atf_process_status_t * s,const atf_fs_path_t * prog,const atf_list_t * argv,const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void (* prehook)(void))651 atf_process_exec_list(atf_process_status_t *s,
652 const atf_fs_path_t *prog,
653 const atf_list_t *argv,
654 const atf_process_stream_t *outsb,
655 const atf_process_stream_t *errsb,
656 void (*prehook)(void))
657 {
658 atf_error_t err;
659 const char **argv2;
660
661 PRE(outsb == NULL ||
662 atf_process_stream_type(outsb) != atf_process_stream_type_capture);
663 PRE(errsb == NULL ||
664 atf_process_stream_type(errsb) != atf_process_stream_type_capture);
665
666 argv2 = NULL; /* Silence GCC warning. */
667 err = list_to_array(argv, &argv2);
668 if (atf_is_error(err))
669 goto out;
670
671 err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook);
672
673 free(argv2);
674 out:
675 return err;
676 }
677