2 * Copyright (C) 2012-2013 ProFUSION embedded systems
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
30 #include <sys/epoll.h>
31 #include <sys/prctl.h>
35 #include <shared/util.h>
37 #include "testsuite.h"
39 static const char *ANSI_HIGHLIGHT_GREEN_ON
= "\x1B[1;32m";
40 static const char *ANSI_HIGHLIGHT_RED_ON
= "\x1B[1;31m";
41 static const char *ANSI_HIGHLIGHT_OFF
= "\x1B[0m";
43 static const char *progname
;
44 static int oneshot
= 0;
45 static const char options_short
[] = "lhn";
46 static const struct option options
[] = {
47 { "list", no_argument
, 0, 'l' },
48 { "help", no_argument
, 0, 'h' },
52 #define OVERRIDE_LIBDIR ABS_TOP_BUILDDIR "/testsuite/.libs/"
56 const char *ldpreload
;
57 } env_config
[_TC_LAST
] = {
58 [TC_UNAME_R
] = { S_TC_UNAME_R
, OVERRIDE_LIBDIR
"uname.so" },
59 [TC_ROOTFS
] = { S_TC_ROOTFS
, OVERRIDE_LIBDIR
"path.so" },
60 [TC_INIT_MODULE_RETCODES
] = { S_TC_INIT_MODULE_RETCODES
, OVERRIDE_LIBDIR
"init_module.so" },
61 [TC_DELETE_MODULE_RETCODES
] = { S_TC_DELETE_MODULE_RETCODES
, OVERRIDE_LIBDIR
"delete_module.so" },
64 #define USEC_PER_SEC 1000000ULL
65 #define USEC_PER_MSEC 1000ULL
66 #define TEST_TIMEOUT_USEC 2 * USEC_PER_SEC
67 static unsigned long long now_usec(void)
71 if (clock_gettime(CLOCK_MONOTONIC
, &ts
) != 0)
77 static void help(void)
79 const struct option
*itr
;
80 const char *itr_short
;
83 "\t%s [options] <test>\n"
84 "Options:\n", basename(progname
));
86 for (itr
= options
, itr_short
= options_short
;
87 itr
->name
!= NULL
; itr
++, itr_short
++)
88 printf("\t-%c, --%s\n", *itr_short
, itr
->name
);
91 static void test_list(const struct test
*start
, const struct test
*stop
)
95 printf("Available tests:\n");
96 for (t
= start
; t
< stop
; t
++)
97 printf("\t%s, %s\n", t
->name
, t
->description
);
100 int test_init(const struct test
*start
, const struct test
*stop
,
101 int argc
, char *const argv
[])
107 c
= getopt_long(argc
, argv
, options_short
, options
, &idx
);
112 test_list(start
, stop
);
123 ERR("unexpected getopt_long() value %c\n", c
);
128 if (isatty(STDOUT_FILENO
) == 0) {
129 ANSI_HIGHLIGHT_OFF
= "";
130 ANSI_HIGHLIGHT_RED_ON
= "";
131 ANSI_HIGHLIGHT_GREEN_ON
= "";
137 const struct test
*test_find(const struct test
*start
,
138 const struct test
*stop
, const char *name
)
140 const struct test
*t
;
142 for (t
= start
; t
< stop
; t
++) {
143 if (streq(t
->name
, name
))
150 static int test_spawn_test(const struct test
*t
)
152 const char *const args
[] = { progname
, "-n", t
->name
, NULL
};
154 execv(progname
, (char *const *) args
);
156 ERR("failed to spawn %s for %s: %m\n", progname
, t
->name
);
160 static int test_run_spawned(const struct test
*t
)
162 int err
= t
->func(t
);
168 int test_spawn_prog(const char *prog
, const char *const args
[])
170 execv(prog
, (char *const *) args
);
172 ERR("failed to spawn %s\n", prog
);
173 ERR("did you forget to build tools?\n");
177 static void test_export_environ(const struct test
*t
)
179 char *preload
= NULL
;
180 size_t preloadlen
= 0;
182 const struct keyval
*env
;
184 unsetenv("LD_PRELOAD");
186 for (i
= 0; i
< _TC_LAST
; i
++) {
187 const char *ldpreload
;
191 if (t
->config
[i
] == NULL
)
194 setenv(env_config
[i
].key
, t
->config
[i
], 1);
196 ldpreload
= env_config
[i
].ldpreload
;
197 ldpreloadlen
= strlen(ldpreload
);
198 tmp
= realloc(preload
, preloadlen
+ 2 + ldpreloadlen
);
200 ERR("oom: test_export_environ()\n");
206 preload
[preloadlen
++] = ' ';
207 memcpy(preload
+ preloadlen
, ldpreload
, ldpreloadlen
);
208 preloadlen
+= ldpreloadlen
;
209 preload
[preloadlen
] = '\0';
213 setenv("LD_PRELOAD", preload
, 1);
217 for (env
= t
->env_vars
; env
&& env
->key
; env
++)
218 setenv(env
->key
, env
->val
, 1);
221 static inline int test_run_child(const struct test
*t
, int fdout
[2],
222 int fderr
[2], int fdmonitor
[2])
224 /* kill child if parent dies */
225 prctl(PR_SET_PDEATHSIG
, SIGTERM
);
227 test_export_environ(t
);
229 /* Close read-fds and redirect std{out,err} to the write-fds */
230 if (t
->output
.out
!= NULL
) {
232 if (dup2(fdout
[1], STDOUT_FILENO
) < 0) {
233 ERR("could not redirect stdout to pipe: %m\n");
238 if (t
->output
.err
!= NULL
) {
240 if (dup2(fderr
[1], STDERR_FILENO
) < 0) {
241 ERR("could not redirect stderr to pipe: %m\n");
248 if (t
->config
[TC_ROOTFS
] != NULL
) {
249 const char *stamp
= TESTSUITE_ROOTFS
"../stamp-rootfs";
250 const char *rootfs
= t
->config
[TC_ROOTFS
];
251 struct stat rootfsst
, stampst
;
253 if (stat(stamp
, &stampst
) != 0) {
254 ERR("could not stat %s\n - %m", stamp
);
258 if (stat(rootfs
, &rootfsst
) != 0) {
259 ERR("could not stat %s\n - %m", rootfs
);
263 if (stat_mstamp(&rootfsst
) > stat_mstamp(&stampst
)) {
264 ERR("rootfs %s is dirty, please run 'make rootfs' before runnning this test\n",
271 return test_spawn_test(t
);
273 return test_run_spawned(t
);
282 FD_CMP_MAX
= FD_CMP_ERR
,
286 enum fd_cmp_type type
;
293 char buf_match
[BUFSZ
];
295 unsigned int head_match
;
298 static int fd_cmp_check_activity(struct fd_cmp
*fd_cmp
)
302 /* not monitoring or monitoring and it has activity */
303 if (fd_cmp
== NULL
|| fd_cmp
->fd
< 0 || fd_cmp
->activity
)
306 /* monitoring, there was no activity and size matches */
307 if (stat(fd_cmp
->path
, &st
) == 0 && st
.st_size
== 0)
310 ERR("Expecting output on %s, but test didn't produce any\n",
316 static bool fd_cmp_is_active(struct fd_cmp
*fd_cmp
)
318 return fd_cmp
->fd
!= -1;
321 static int fd_cmp_open_monitor(struct fd_cmp
*fd_cmp
, int fd
, int fd_ep
)
323 struct epoll_event ep
= {};
325 ep
.events
= EPOLLHUP
;
326 ep
.data
.ptr
= fd_cmp
;
327 if (epoll_ctl(fd_ep
, EPOLL_CTL_ADD
, fd
, &ep
) < 0) {
328 ERR("could not add monitor fd to epoll: %m\n");
335 static int fd_cmp_open_std(struct fd_cmp
*fd_cmp
,
336 const char *fn
, int fd
, int fd_ep
)
338 struct epoll_event ep
= {};
341 fd_match
= open(fn
, O_RDONLY
);
343 ERR("could not open %s for read: %m\n", fn
);
347 ep
.data
.ptr
= fd_cmp
;
348 if (epoll_ctl(fd_ep
, EPOLL_CTL_ADD
, fd
, &ep
) < 0) {
349 ERR("could not add fd to epoll: %m\n");
357 /* opens output file AND adds descriptor to epoll */
358 static int fd_cmp_open(struct fd_cmp
**fd_cmp_out
,
359 enum fd_cmp_type type
, const char *fn
, int fd
,
363 struct fd_cmp
*fd_cmp
;
365 fd_cmp
= calloc(1, sizeof(*fd_cmp
));
366 if (fd_cmp
== NULL
) {
367 ERR("could not allocate fd_cmp\n");
373 err
= fd_cmp_open_monitor(fd_cmp
, fd
, fd_ep
);
376 fd_cmp
->name
= "STDOUT";
377 err
= fd_cmp_open_std(fd_cmp
, fn
, fd
, fd_ep
);
380 fd_cmp
->name
= "STDERR";
381 err
= fd_cmp_open_std(fd_cmp
, fn
, fd
, fd_ep
);
384 ERR("unknown fd type %d\n", type
);
393 fd_cmp
->fd_match
= err
;
398 *fd_cmp_out
= fd_cmp
;
402 static int fd_cmp_check_ev_in(struct fd_cmp
*fd_cmp
)
404 if (fd_cmp
->type
== FD_CMP_MONITOR
) {
405 ERR("Unexpected activity on monitor pipe\n");
408 fd_cmp
->activity
= true;
413 static void fd_cmp_delete_ep(struct fd_cmp
*fd_cmp
, int fd_ep
)
415 if (epoll_ctl(fd_ep
, EPOLL_CTL_DEL
, fd_cmp
->fd
, NULL
) < 0) {
416 ERR("could not remove fd %d from epoll: %m\n", fd_cmp
->fd
);
421 static void fd_cmp_close(struct fd_cmp
*fd_cmp
)
431 static bool fd_cmp_regex_one(const char *pattern
, const char *s
)
433 _cleanup_(regfree
) regex_t re
= { };
435 return !regcomp(&re
, pattern
, REG_EXTENDED
|REG_NOSUB
) &&
436 !regexec(&re
, s
, 0, NULL
, 0);
440 * read fd and fd_match, checking the first matches the regex of the second,
443 static bool fd_cmp_regex(struct fd_cmp
*fd_cmp
, const struct test
*t
)
446 int done
= 0, done_match
= 0, r
;
448 if (fd_cmp
->head
>= sizeof(fd_cmp
->buf
)) {
449 ERR("Read %zu bytes without a newline\n", sizeof(fd_cmp
->buf
));
450 ERR("output: %.*s", (int)sizeof(fd_cmp
->buf
), fd_cmp
->buf
);
454 r
= read(fd_cmp
->fd
, fd_cmp
->buf
+ fd_cmp
->head
,
455 sizeof(fd_cmp
->buf
) - fd_cmp
->head
);
462 * Process as many lines as read from fd and that fits in the buffer -
463 * it's assumed that if we get N lines from fd, we should be able to
464 * get the same amount from fd_match
467 p
= memchr(fd_cmp
->buf
+ done
, '\n', fd_cmp
->head
- done
);
472 p_match
= memchr(fd_cmp
->buf_match
+ done_match
, '\n',
473 fd_cmp
->head_match
- done_match
);
475 if (fd_cmp
->head_match
>= sizeof(fd_cmp
->buf_match
)) {
476 ERR("Read %zu bytes without a match\n", sizeof(fd_cmp
->buf_match
));
477 ERR("output: %.*s", (int)sizeof(fd_cmp
->buf_match
), fd_cmp
->buf_match
);
481 /* pump more data from file */
482 r
= read(fd_cmp
->fd_match
, fd_cmp
->buf_match
+ fd_cmp
->head_match
,
483 sizeof(fd_cmp
->buf_match
) - fd_cmp
->head_match
);
485 ERR("could not read match fd %d\n", fd_cmp
->fd_match
);
488 fd_cmp
->head_match
+= r
;
489 p_match
= memchr(fd_cmp
->buf_match
+ done_match
, '\n',
490 fd_cmp
->head_match
- done_match
);
492 ERR("could not find match line from fd %d\n", fd_cmp
->fd_match
);
498 if (!fd_cmp_regex_one(fd_cmp
->buf_match
+ done_match
, fd_cmp
->buf
+ done
)) {
499 ERR("Output does not match pattern on %s:\n", fd_cmp
->name
);
500 ERR("pattern: %s\n", fd_cmp
->buf_match
+ done_match
);
501 ERR("output : %s\n", fd_cmp
->buf
+ done
);
505 done
= p
- fd_cmp
->buf
+ 1;
506 done_match
= p_match
- fd_cmp
->buf_match
+ 1;
510 * Prepare for the next call: anything we processed we remove from the
511 * buffer by memmoving the remaining bytes up to the beginning
514 if (fd_cmp
->head
- done
)
515 memmove(fd_cmp
->buf
, fd_cmp
->buf
+ done
, fd_cmp
->head
- done
);
516 fd_cmp
->head
-= done
;
520 if (fd_cmp
->head_match
- done_match
)
521 memmove(fd_cmp
->buf_match
, fd_cmp
->buf_match
+ done_match
,
522 fd_cmp
->head_match
- done_match
);
523 fd_cmp
->head_match
-= done_match
;
529 /* read fd and fd_match, checking they match exactly */
530 static bool fd_cmp_exact(struct fd_cmp
*fd_cmp
, const struct test
*t
)
532 int r
, rmatch
, done
= 0;
534 r
= read(fd_cmp
->fd
, fd_cmp
->buf
, sizeof(fd_cmp
->buf
) - 1);
536 /* try again later */
539 /* read as much data from fd_match as we read from fd */
541 rmatch
= read(fd_cmp
->fd_match
, fd_cmp
->buf_match
+ done
, r
- done
);
548 ERR("could not read match fd %d\n", fd_cmp
->fd_match
);
555 fd_cmp
->buf
[r
] = '\0';
556 fd_cmp
->buf_match
[r
] = '\0';
558 if (t
->print_outputs
)
559 printf("%s: %s\n", fd_cmp
->name
, fd_cmp
->buf
);
561 if (!streq(fd_cmp
->buf
, fd_cmp
->buf_match
)) {
562 ERR("Outputs do not match on %s:\n", fd_cmp
->name
);
563 ERR("correct:\n%s\n", fd_cmp
->buf_match
);
564 ERR("wrong:\n%s\n", fd_cmp
->buf
);
571 static bool test_run_parent_check_outputs(const struct test
*t
,
572 int fdout
, int fderr
, int fdmonitor
,
576 unsigned long long end_usec
, start_usec
;
577 struct fd_cmp
*fd_cmp_out
= NULL
;
578 struct fd_cmp
*fd_cmp_err
= NULL
;
579 struct fd_cmp
*fd_cmp_monitor
= NULL
;
582 fd_ep
= epoll_create1(EPOLL_CLOEXEC
);
584 ERR("could not create epoll fd: %m\n");
588 if (t
->output
.out
!= NULL
) {
589 err
= fd_cmp_open(&fd_cmp_out
,
590 FD_CMP_OUT
, t
->output
.out
, fdout
, fd_ep
);
596 if (t
->output
.err
!= NULL
) {
597 err
= fd_cmp_open(&fd_cmp_err
,
598 FD_CMP_ERR
, t
->output
.err
, fderr
, fd_ep
);
604 err
= fd_cmp_open(&fd_cmp_monitor
, FD_CMP_MONITOR
, NULL
, fdmonitor
, fd_ep
);
609 start_usec
= now_usec();
610 end_usec
= start_usec
+ TEST_TIMEOUT_USEC
;
612 for (err
= 0; n_fd
> 0;) {
613 int fdcount
, i
, timeout
;
614 struct epoll_event ev
[4];
615 unsigned long long curr_usec
= now_usec();
617 if (curr_usec
> end_usec
)
620 timeout
= (end_usec
- curr_usec
) / USEC_PER_MSEC
;
621 fdcount
= epoll_wait(fd_ep
, ev
, 4, timeout
);
626 ERR("could not poll: %m\n");
630 for (i
= 0; i
< fdcount
; i
++) {
631 struct fd_cmp
*fd_cmp
= ev
[i
].data
.ptr
;
634 if (ev
[i
].events
& EPOLLIN
) {
635 err
= fd_cmp_check_ev_in(fd_cmp
);
640 ret
= fd_cmp_regex(fd_cmp
, t
);
642 ret
= fd_cmp_exact(fd_cmp
, t
);
648 } else if (ev
[i
].events
& EPOLLHUP
) {
649 fd_cmp_delete_ep(fd_cmp
, fd_ep
);
655 err
= fd_cmp_check_activity(fd_cmp_out
);
656 err
|= fd_cmp_check_activity(fd_cmp_err
);
658 if (err
== 0 && fd_cmp_is_active(fd_cmp_monitor
)) {
660 ERR("Test '%s' timed out, killing %d\n", t
->name
, child
);
661 kill(child
, SIGKILL
);
665 fd_cmp_close(fd_cmp_out
);
666 fd_cmp_close(fd_cmp_err
);
667 fd_cmp_close(fd_cmp_monitor
);
673 static inline int safe_read(int fd
, void *buf
, size_t count
)
678 r
= read(fd
, buf
, count
);
679 if (r
== -1 && errno
== EINTR
)
687 static bool check_generated_files(const struct test
*t
)
689 const struct keyval
*k
;
691 /* This is not meant to be a diff replacement, just stupidly check if
692 * the files match. Bear in mind they can be binary files */
693 for (k
= t
->output
.files
; k
&& k
->key
; k
++) {
694 struct stat sta
, stb
;
695 int fda
= -1, fdb
= -1;
699 fda
= open(k
->key
, O_RDONLY
);
701 ERR("could not open %s\n - %m\n", k
->key
);
705 fdb
= open(k
->val
, O_RDONLY
);
707 ERR("could not open %s\n - %m\n", k
->val
);
711 if (fstat(fda
, &sta
) != 0) {
712 ERR("could not fstat %d %s\n - %m\n", fda
, k
->key
);
716 if (fstat(fdb
, &stb
) != 0) {
717 ERR("could not fstat %d %s\n - %m\n", fdb
, k
->key
);
721 if (sta
.st_size
!= stb
.st_size
) {
722 ERR("sizes do not match %s %s\n", k
->key
, k
->val
);
729 r
= safe_read(fda
, bufa
, sizeof(bufa
));
734 /* size is already checked, go to next file */
737 for (done
= 0; done
< r
;) {
738 int r2
= safe_read(fdb
, bufb
+ done
, r
- done
);
746 if (memcmp(bufa
, bufb
, r
) != 0)
767 static int cmp_modnames(const void *m1
, const void *m2
)
769 const char *s1
= *(char *const *)m1
;
770 const char *s2
= *(char *const *)m2
;
773 for (i
= 0; s1
[i
] || s2
[i
]; i
++) {
774 char c1
= s1
[i
], c2
= s2
[i
];
786 * Store the expected module names in buf and return a list of pointers to
789 static const char **read_expected_modules(const struct test
*t
,
790 char **buf
, int *count
)
797 if (t
->modules_loaded
[0] == '\0') {
802 *buf
= strdup(t
->modules_loaded
);
808 for (p
= *buf
; *p
; p
++)
811 res
= malloc(sizeof(char *) * len
);
821 for (p
= *buf
; i
< len
; p
++)
830 static char **read_loaded_modules(const struct test
*t
, char **buf
, int *count
)
832 char dirname
[PATH_MAX
];
834 struct dirent
*dirent
;
839 const char *rootfs
= t
->config
[TC_ROOTFS
] ? t
->config
[TC_ROOTFS
] : "";
841 /* Store the entries in /sys/module to res */
842 if (snprintf(dirname
, sizeof(dirname
), "%s/sys/module", rootfs
)
843 >= (int)sizeof(dirname
)) {
844 ERR("rootfs path too long: %s\n", rootfs
);
849 dir
= opendir(dirname
);
850 /* not an error, simply return empty list */
856 while ((dirent
= readdir(dir
))) {
857 if (dirent
->d_name
[0] == '.')
860 bufsz
+= strlen(dirent
->d_name
) + 1;
862 res
= malloc(sizeof(char *) * len
);
868 *buf
= malloc(bufsz
);
879 while ((dirent
= readdir(dir
))) {
882 if (dirent
->d_name
[0] == '.')
884 size
= strlen(dirent
->d_name
) + 1;
885 memcpy(p
, dirent
->d_name
, size
);
896 static int check_loaded_modules(const struct test
*t
)
904 a1
= read_expected_modules(t
, &buf1
, &l1
);
907 a2
= read_loaded_modules(t
, &buf2
, &l2
);
910 qsort(a1
, l1
, sizeof(char *), cmp_modnames
);
911 qsort(a2
, l2
, sizeof(char *), cmp_modnames
);
914 while (i1
< l1
|| i2
< l2
) {
922 cmp
= cmp_modnames(&a1
[i1
], &a2
[i2
]);
926 } else if (cmp
< 0) {
928 ERR("module %s not loaded\n", a1
[i1
]);
932 ERR("module %s is loaded but should not be \n", a2
[i2
]);
944 static inline int test_run_parent(const struct test
*t
, int fdout
[2],
945 int fderr
[2], int fdmonitor
[2], pid_t child
)
949 bool matchout
, match_modules
;
951 /* Close write-fds */
952 if (t
->output
.out
!= NULL
)
954 if (t
->output
.err
!= NULL
)
958 matchout
= test_run_parent_check_outputs(t
, fdout
[0], fderr
[0],
959 fdmonitor
[0], child
);
962 * break pipe on the other end: either child already closed or we want
965 if (t
->output
.out
!= NULL
)
967 if (t
->output
.err
!= NULL
)
974 ERR("error waitpid(): %m\n");
978 } while (!WIFEXITED(err
) && !WIFSIGNALED(err
));
980 if (WIFEXITED(err
)) {
981 if (WEXITSTATUS(err
) != 0)
982 ERR("'%s' [%u] exited with return code %d\n",
983 t
->name
, pid
, WEXITSTATUS(err
));
985 LOG("'%s' [%u] exited with return code %d\n",
986 t
->name
, pid
, WEXITSTATUS(err
));
987 } else if (WIFSIGNALED(err
)) {
988 ERR("'%s' [%u] terminated by signal %d (%s)\n", t
->name
, pid
,
989 WTERMSIG(err
), strsignal(WTERMSIG(err
)));
990 err
= t
->expected_fail
? EXIT_SUCCESS
: EXIT_FAILURE
;
995 matchout
= check_generated_files(t
);
996 if (t
->modules_loaded
)
997 match_modules
= check_loaded_modules(t
);
999 match_modules
= true;
1001 if (t
->expected_fail
== false) {
1003 if (matchout
&& match_modules
)
1004 LOG("%sPASSED%s: %s\n",
1005 ANSI_HIGHLIGHT_GREEN_ON
, ANSI_HIGHLIGHT_OFF
,
1008 ERR("%sFAILED%s: exit ok but %s do not match: %s\n",
1009 ANSI_HIGHLIGHT_RED_ON
, ANSI_HIGHLIGHT_OFF
,
1010 matchout
? "loaded modules" : "outputs",
1015 ERR("%sFAILED%s: %s\n",
1016 ANSI_HIGHLIGHT_RED_ON
, ANSI_HIGHLIGHT_OFF
,
1022 ERR("%sUNEXPECTED PASS%s: exit with 0: %s\n",
1023 ANSI_HIGHLIGHT_RED_ON
, ANSI_HIGHLIGHT_OFF
,
1027 ERR("%sUNEXPECTED PASS%s: exit with 0 and outputs do not match: %s\n",
1028 ANSI_HIGHLIGHT_RED_ON
, ANSI_HIGHLIGHT_OFF
,
1034 LOG("%sEXPECTED FAIL%s: %s\n",
1035 ANSI_HIGHLIGHT_GREEN_ON
, ANSI_HIGHLIGHT_OFF
,
1039 LOG("%sEXPECTED FAIL%s: exit with %d but outputs do not match: %s\n",
1040 ANSI_HIGHLIGHT_GREEN_ON
, ANSI_HIGHLIGHT_OFF
,
1041 WEXITSTATUS(err
), t
->name
);
1052 static int prepend_path(const char *extra
)
1054 char *oldpath
, *newpath
;
1060 oldpath
= getenv("PATH");
1061 if (oldpath
== NULL
)
1062 return setenv("PATH", extra
, 1);
1064 if (asprintf(&newpath
, "%s:%s", extra
, oldpath
) < 0) {
1065 ERR("failed to allocate memory to new PATH\n");
1069 r
= setenv("PATH", newpath
, 1);
1075 int test_run(const struct test
*t
)
1082 if (t
->need_spawn
&& oneshot
)
1083 test_run_spawned(t
);
1085 if (t
->output
.out
!= NULL
) {
1086 if (pipe(fdout
) != 0) {
1087 ERR("could not create out pipe for %s\n", t
->name
);
1088 return EXIT_FAILURE
;
1092 if (t
->output
.err
!= NULL
) {
1093 if (pipe(fderr
) != 0) {
1094 ERR("could not create err pipe for %s\n", t
->name
);
1095 return EXIT_FAILURE
;
1099 if (pipe(fdmonitor
) != 0) {
1100 ERR("could not create monitor pipe for %s\n", t
->name
);
1101 return EXIT_FAILURE
;
1104 if (prepend_path(t
->path
) < 0) {
1105 ERR("failed to prepend '%s' to PATH\n", t
->path
);
1106 return EXIT_FAILURE
;
1109 LOG("running %s, in forked context\n", t
->name
);
1113 ERR("could not fork(): %m\n");
1114 LOG("FAILED: %s\n", t
->name
);
1115 return EXIT_FAILURE
;
1119 return test_run_parent(t
, fdout
, fderr
, fdmonitor
, pid
);
1121 return test_run_child(t
, fdout
, fderr
, fdmonitor
);