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