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