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