Home | History | Annotate | Line # | Download | only in dist
      1  1.1  jmmv // Copyright 2012 Google Inc.
      2  1.1  jmmv // All rights reserved.
      3  1.1  jmmv //
      4  1.1  jmmv // Redistribution and use in source and binary forms, with or without
      5  1.1  jmmv // modification, are permitted provided that the following conditions are
      6  1.1  jmmv // met:
      7  1.1  jmmv //
      8  1.1  jmmv // * Redistributions of source code must retain the above copyright
      9  1.1  jmmv //   notice, this list of conditions and the following disclaimer.
     10  1.1  jmmv // * Redistributions in binary form must reproduce the above copyright
     11  1.1  jmmv //   notice, this list of conditions and the following disclaimer in the
     12  1.1  jmmv //   documentation and/or other materials provided with the distribution.
     13  1.1  jmmv // * Neither the name of Google Inc. nor the names of its contributors
     14  1.1  jmmv //   may be used to endorse or promote products derived from this software
     15  1.1  jmmv //   without specific prior written permission.
     16  1.1  jmmv //
     17  1.1  jmmv // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18  1.1  jmmv // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19  1.1  jmmv // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20  1.1  jmmv // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21  1.1  jmmv // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22  1.1  jmmv // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23  1.1  jmmv // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  1.1  jmmv // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  1.1  jmmv // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  1.1  jmmv // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27  1.1  jmmv // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  1.1  jmmv 
     29  1.1  jmmv #if defined(HAVE_CONFIG_H)
     30  1.1  jmmv #   include "config.h"
     31  1.1  jmmv #endif
     32  1.1  jmmv 
     33  1.1  jmmv #include "run.h"
     34  1.1  jmmv 
     35  1.1  jmmv #include <sys/resource.h>
     36  1.1  jmmv #include <sys/stat.h>
     37  1.1  jmmv #include <sys/wait.h>
     38  1.1  jmmv 
     39  1.1  jmmv #include <err.h>
     40  1.1  jmmv #include <errno.h>
     41  1.1  jmmv #include <pwd.h>
     42  1.1  jmmv #include <signal.h>
     43  1.1  jmmv #include <stdbool.h>
     44  1.1  jmmv #include <stdio.h>
     45  1.1  jmmv #include <stdlib.h>
     46  1.1  jmmv #include <unistd.h>
     47  1.1  jmmv 
     48  1.1  jmmv #include <atf-c.h>
     49  1.1  jmmv 
     50  1.1  jmmv #include "defs.h"
     51  1.1  jmmv #include "env.h"
     52  1.1  jmmv #include "error.h"
     53  1.1  jmmv #include "fs.h"
     54  1.1  jmmv 
     55  1.1  jmmv 
     56  1.1  jmmv /// Evalutes an expression and ensures it does not return an error.
     57  1.1  jmmv ///
     58  1.1  jmmv /// \param expr A expression that must evaluate to kyua_error_t.
     59  1.1  jmmv #define RE(expr) ATF_REQUIRE(!kyua_error_is_set(expr))
     60  1.1  jmmv 
     61  1.1  jmmv 
     62  1.1  jmmv static void check_env(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
     63  1.1  jmmv     KYUA_DEFS_NORETURN;
     64  1.1  jmmv 
     65  1.1  jmmv 
     66  1.1  jmmv /// Subprocess that validates the cleanliness of the environment.
     67  1.1  jmmv ///
     68  1.1  jmmv /// \param unused_cookie NULL.
     69  1.1  jmmv ///
     70  1.1  jmmv /// \post Exits with success if the environment is clean; failure otherwise.
     71  1.1  jmmv static void
     72  1.1  jmmv check_env(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
     73  1.1  jmmv {
     74  1.1  jmmv     bool failed = false;
     75  1.1  jmmv 
     76  1.1  jmmv     const char* empty[] = { "LANG", "LC_ALL", "LC_COLLATE", "LC_CTYPE",
     77  1.1  jmmv                             "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC",
     78  1.1  jmmv                             "LC_TIME", NULL };
     79  1.1  jmmv     const char** iter;
     80  1.1  jmmv     for (iter = empty; *iter != NULL; ++iter) {
     81  1.1  jmmv         if (getenv(*iter) != NULL) {
     82  1.1  jmmv             failed = true;
     83  1.1  jmmv             printf("%s was not unset\n", *iter);
     84  1.1  jmmv         }
     85  1.1  jmmv     }
     86  1.1  jmmv 
     87  1.1  jmmv     if (strcmp(getenv("HOME"), ".") != 0) {
     88  1.1  jmmv         failed = true;
     89  1.1  jmmv         printf("HOME was not set to .\n");
     90  1.1  jmmv     }
     91  1.1  jmmv     if (strcmp(getenv("TZ"), "UTC") != 0) {
     92  1.1  jmmv         failed = true;
     93  1.1  jmmv         printf("TZ was not set to UTC\n");
     94  1.1  jmmv     }
     95  1.1  jmmv     if (strcmp(getenv("LEAVE_ME_ALONE"), "kill-some-day") != 0) {
     96  1.1  jmmv         failed = true;
     97  1.1  jmmv         printf("LEAVE_ME_ALONE was modified while it should not have been\n");
     98  1.1  jmmv     }
     99  1.1  jmmv 
    100  1.1  jmmv     exit(failed ? EXIT_FAILURE : EXIT_SUCCESS);
    101  1.1  jmmv }
    102  1.1  jmmv 
    103  1.1  jmmv 
    104  1.1  jmmv static void check_process_group(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    105  1.1  jmmv     KYUA_DEFS_NORETURN;
    106  1.1  jmmv 
    107  1.1  jmmv 
    108  1.1  jmmv /// Subprocess that validates that it has become the leader of a process group.
    109  1.1  jmmv ///
    110  1.1  jmmv /// \param unused_cookie NULL.
    111  1.1  jmmv ///
    112  1.1  jmmv /// \post Exits with success if the process lives in its own process group;
    113  1.1  jmmv /// failure otherwise.
    114  1.1  jmmv static void
    115  1.1  jmmv check_process_group(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    116  1.1  jmmv {
    117  1.1  jmmv     exit(getpgid(getpid()) == getpid() ? EXIT_SUCCESS : EXIT_FAILURE);
    118  1.1  jmmv }
    119  1.1  jmmv 
    120  1.1  jmmv 
    121  1.1  jmmv static void check_signals(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    122  1.1  jmmv     KYUA_DEFS_NORETURN;
    123  1.1  jmmv 
    124  1.1  jmmv 
    125  1.1  jmmv /// Subprocess that validates that signals have been reset to their defaults.
    126  1.1  jmmv ///
    127  1.1  jmmv /// \param unused_cookie NULL.
    128  1.1  jmmv ///
    129  1.1  jmmv /// \post Exits with success if the process has its signals reset to their
    130  1.1  jmmv /// default values; failure otherwise.
    131  1.1  jmmv static void
    132  1.1  jmmv check_signals(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    133  1.1  jmmv {
    134  1.1  jmmv     int signo;
    135  1.1  jmmv     for (signo = 1; signo <= LAST_SIGNO; signo++) {
    136  1.1  jmmv         if (signo == SIGKILL || signo == SIGSTOP) {
    137  1.1  jmmv             // Don't attempt to check immutable signals, as this results in
    138  1.1  jmmv             // an unconditional error in some systems.  E.g. Mac OS X 10.8
    139  1.1  jmmv             // reports 'Invalid argument' when querying SIGKILL.
    140  1.1  jmmv             continue;
    141  1.1  jmmv         }
    142  1.1  jmmv 
    143  1.1  jmmv         struct sigaction old_sa;
    144  1.1  jmmv         if (sigaction(signo, NULL, &old_sa) == -1) {
    145  1.1  jmmv             err(EXIT_FAILURE, "Failed to query signal information for %d",
    146  1.1  jmmv                 signo);
    147  1.1  jmmv         }
    148  1.1  jmmv         if (old_sa.sa_handler != SIG_DFL) {
    149  1.1  jmmv             errx(EXIT_FAILURE, "Signal %d not reset to its default handler",
    150  1.1  jmmv                  signo);
    151  1.1  jmmv         }
    152  1.1  jmmv         printf("Signal %d has its default handler set\n", signo);
    153  1.1  jmmv     }
    154  1.1  jmmv 
    155  1.1  jmmv     exit(EXIT_SUCCESS);
    156  1.1  jmmv }
    157  1.1  jmmv 
    158  1.1  jmmv 
    159  1.1  jmmv static void check_umask(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    160  1.1  jmmv     KYUA_DEFS_NORETURN;
    161  1.1  jmmv 
    162  1.1  jmmv 
    163  1.1  jmmv /// Subprocess that validates that the umask has been reset.
    164  1.1  jmmv ///
    165  1.1  jmmv /// \param unused_cookie NULL.
    166  1.1  jmmv ///
    167  1.1  jmmv /// \post Exits with success if the umask matches the expected value; failure
    168  1.1  jmmv /// otherwise.
    169  1.1  jmmv static void
    170  1.1  jmmv check_umask(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    171  1.1  jmmv {
    172  1.1  jmmv     exit(umask(0) == 0022 ? EXIT_SUCCESS : EXIT_FAILURE);
    173  1.1  jmmv }
    174  1.1  jmmv 
    175  1.1  jmmv 
    176  1.1  jmmv static void check_work_directory(const void* cookie) KYUA_DEFS_NORETURN;
    177  1.1  jmmv 
    178  1.1  jmmv 
    179  1.1  jmmv /// Subprocess that validates that the umask has been reset.
    180  1.1  jmmv ///
    181  1.1  jmmv /// \param cookie The name of a file to expect in the current directory.
    182  1.1  jmmv ///
    183  1.1  jmmv /// \post Exits with success if the umask matches the expected value; failure
    184  1.1  jmmv /// otherwise.
    185  1.1  jmmv static void
    186  1.1  jmmv check_work_directory(const void* cookie)
    187  1.1  jmmv {
    188  1.1  jmmv     const char* exp_file = (const char*)cookie;
    189  1.1  jmmv     exit(atf_utils_file_exists(exp_file) ? EXIT_SUCCESS : EXIT_FAILURE);
    190  1.1  jmmv }
    191  1.1  jmmv 
    192  1.1  jmmv 
    193  1.1  jmmv static void check_uid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    194  1.1  jmmv     KYUA_DEFS_NORETURN;
    195  1.1  jmmv 
    196  1.1  jmmv 
    197  1.1  jmmv /// Subprocess that validates that the UID is not root.
    198  1.1  jmmv ///
    199  1.1  jmmv /// \param unused_cookie NULL.
    200  1.1  jmmv ///
    201  1.1  jmmv /// \post Exits with success if the UID is not root; failure otherwise.
    202  1.1  jmmv static void
    203  1.1  jmmv check_uid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    204  1.1  jmmv {
    205  1.1  jmmv     exit(getuid() != 0 ? EXIT_SUCCESS : EXIT_FAILURE);
    206  1.1  jmmv }
    207  1.1  jmmv 
    208  1.1  jmmv 
    209  1.1  jmmv static void check_gid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    210  1.1  jmmv     KYUA_DEFS_NORETURN;
    211  1.1  jmmv 
    212  1.1  jmmv 
    213  1.1  jmmv /// Subprocess that validates that the GID is not root.
    214  1.1  jmmv ///
    215  1.1  jmmv /// \param unused_cookie NULL.
    216  1.1  jmmv ///
    217  1.1  jmmv /// \post Exits with success if the GID is not root; failure otherwise.
    218  1.1  jmmv static void
    219  1.1  jmmv check_gid_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    220  1.1  jmmv {
    221  1.1  jmmv     exit(getgid() != 0 ? EXIT_SUCCESS : EXIT_FAILURE);
    222  1.1  jmmv }
    223  1.1  jmmv 
    224  1.1  jmmv 
    225  1.1  jmmv static void check_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    226  1.1  jmmv     KYUA_DEFS_NORETURN;
    227  1.1  jmmv 
    228  1.1  jmmv 
    229  1.1  jmmv /// Subprocess that validates that the UID and GID are not root.
    230  1.1  jmmv ///
    231  1.1  jmmv /// \param unused_cookie NULL.
    232  1.1  jmmv ///
    233  1.1  jmmv /// \post Exits with success if the UID and GID are not root; failure otherwise.
    234  1.1  jmmv static void
    235  1.1  jmmv check_not_root(const void* KYUA_DEFS_UNUSED_PARAM(cookie))
    236  1.1  jmmv {
    237  1.1  jmmv     exit(getuid() != 0 && getgid() != 0 ? EXIT_SUCCESS : EXIT_FAILURE);
    238  1.1  jmmv }
    239  1.1  jmmv 
    240  1.1  jmmv 
    241  1.1  jmmv /// Uses kyua_fork, kyua_exec and kyua_wait to execute a subprocess.
    242  1.1  jmmv ///
    243  1.1  jmmv /// \param program Path to the program to run.
    244  1.1  jmmv /// \param args Arguments to the program.
    245  1.1  jmmv /// \param [out] exitstatus The exit status of the subprocess, if it exits
    246  1.1  jmmv ///     successfully without timing out nor receiving a signal.
    247  1.1  jmmv ///
    248  1.1  jmmv /// \return Returns the error code of kyua_run_wait (which should have the
    249  1.1  jmmv ///     error representation of the exec call in the subprocess).
    250  1.1  jmmv static kyua_error_t
    251  1.1  jmmv exec_check(const char* program, const char* const* args, int* exitstatus)
    252  1.1  jmmv {
    253  1.1  jmmv     kyua_run_params_t run_params;
    254  1.1  jmmv     kyua_run_params_init(&run_params);
    255  1.1  jmmv 
    256  1.1  jmmv     pid_t pid;
    257  1.1  jmmv     kyua_error_t error = kyua_run_fork(&run_params, &pid);
    258  1.1  jmmv     if (!kyua_error_is_set(error) && pid == 0)
    259  1.1  jmmv         kyua_run_exec(program, args);
    260  1.1  jmmv     ATF_REQUIRE(!kyua_error_is_set(error));
    261  1.1  jmmv     int status; bool timed_out;
    262  1.1  jmmv     error = kyua_run_wait(pid, &status, &timed_out);
    263  1.1  jmmv     if (!kyua_error_is_set(error)) {
    264  1.1  jmmv         ATF_REQUIRE(!timed_out);
    265  1.1  jmmv         ATF_REQUIRE_MSG(WIFEXITED(status),
    266  1.1  jmmv                         "Subprocess expected to exit successfully");
    267  1.1  jmmv         *exitstatus = WEXITSTATUS(status);
    268  1.1  jmmv     }
    269  1.1  jmmv     return error;
    270  1.1  jmmv }
    271  1.1  jmmv 
    272  1.1  jmmv 
    273  1.1  jmmv /// Uses kyua_fork and kyua_wait to spawn a subprocess.
    274  1.1  jmmv ///
    275  1.1  jmmv /// \param run_params The parameters to configure the subprocess.  Can be NULL
    276  1.1  jmmv ///     to indicate to use the default set of parameters.
    277  1.1  jmmv /// \param hook Any of the check_* functions provided in this module.
    278  1.1  jmmv /// \param cookie The data to pass to the hook.
    279  1.1  jmmv ///
    280  1.1  jmmv /// \return True if the subprocess exits successfully; false otherwise.
    281  1.1  jmmv static bool
    282  1.1  jmmv fork_check(const kyua_run_params_t* run_params,
    283  1.1  jmmv            void (*hook)(const void*), const void* cookie)
    284  1.1  jmmv {
    285  1.1  jmmv     kyua_run_params_t default_run_params;
    286  1.1  jmmv     if (run_params == NULL) {
    287  1.1  jmmv         kyua_run_params_init(&default_run_params);
    288  1.1  jmmv         run_params = &default_run_params;
    289  1.1  jmmv     }
    290  1.1  jmmv 
    291  1.1  jmmv     pid_t pid;
    292  1.1  jmmv     kyua_error_t error = kyua_run_fork(run_params, &pid);
    293  1.1  jmmv     if (!kyua_error_is_set(error) && pid == 0)
    294  1.1  jmmv         hook(cookie);
    295  1.1  jmmv     ATF_REQUIRE(!kyua_error_is_set(error));
    296  1.1  jmmv     int status; bool timed_out;
    297  1.1  jmmv     error = kyua_run_wait(pid, &status, &timed_out);
    298  1.1  jmmv     if (kyua_error_is_set(error))
    299  1.1  jmmv         atf_tc_fail("wait failed; unexpected problem during exec?");
    300  1.1  jmmv     ATF_REQUIRE(!timed_out);
    301  1.1  jmmv     return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS;
    302  1.1  jmmv }
    303  1.1  jmmv 
    304  1.1  jmmv 
    305  1.1  jmmv ATF_TC_WITHOUT_HEAD(run_params_init__defaults);
    306  1.1  jmmv ATF_TC_BODY(run_params_init__defaults, tc)
    307  1.1  jmmv {
    308  1.1  jmmv     kyua_run_params_t run_params;
    309  1.1  jmmv     kyua_run_params_init(&run_params);
    310  1.1  jmmv 
    311  1.1  jmmv     ATF_REQUIRE_EQ(60, run_params.timeout_seconds);
    312  1.1  jmmv     ATF_REQUIRE_EQ(getuid(), run_params.unprivileged_user);
    313  1.1  jmmv     ATF_REQUIRE_EQ(getgid(), run_params.unprivileged_group);
    314  1.1  jmmv     ATF_REQUIRE_STREQ(".", run_params.work_directory);
    315  1.1  jmmv }
    316  1.1  jmmv 
    317  1.1  jmmv 
    318  1.1  jmmv ATF_TC_WITHOUT_HEAD(fork_exec_wait__ok);
    319  1.1  jmmv ATF_TC_BODY(fork_exec_wait__ok, tc)
    320  1.1  jmmv {
    321  1.1  jmmv     const char* const args[] = {"sh", "-c", "exit 42", NULL};
    322  1.1  jmmv     int exitstatus = -1;  // Shut up GCC warning.
    323  1.1  jmmv     const kyua_error_t error = exec_check("/bin/sh", args, &exitstatus);
    324  1.1  jmmv     ATF_REQUIRE(!kyua_error_is_set(error));
    325  1.1  jmmv     ATF_REQUIRE_EQ(42, exitstatus);
    326  1.1  jmmv }
    327  1.1  jmmv 
    328  1.1  jmmv 
    329  1.1  jmmv ATF_TC(fork_exec_wait__eacces);
    330  1.1  jmmv ATF_TC_HEAD(fork_exec_wait__eacces, tc)
    331  1.1  jmmv {
    332  1.1  jmmv     atf_tc_set_md_var(tc, "require.user", "unprivileged");
    333  1.1  jmmv }
    334  1.1  jmmv ATF_TC_BODY(fork_exec_wait__eacces, tc)
    335  1.1  jmmv {
    336  1.1  jmmv     ATF_REQUIRE(mkdir("dir", 0000) != -1);
    337  1.1  jmmv 
    338  1.1  jmmv     const char* const args[] = {"foo", NULL};
    339  1.1  jmmv     int unused_exitstatus;
    340  1.1  jmmv     const kyua_error_t error = exec_check("./dir/foo", args,
    341  1.1  jmmv                                           &unused_exitstatus);
    342  1.1  jmmv     ATF_REQUIRE(kyua_error_is_set(error));
    343  1.1  jmmv     ATF_REQUIRE(kyua_error_is_type(error, "libc"));
    344  1.1  jmmv     ATF_REQUIRE_EQ(EACCES, kyua_libc_error_errno(error));
    345  1.1  jmmv }
    346  1.1  jmmv 
    347  1.1  jmmv 
    348  1.1  jmmv ATF_TC_WITHOUT_HEAD(fork_exec_wait__enoent);
    349  1.1  jmmv ATF_TC_BODY(fork_exec_wait__enoent, tc)
    350  1.1  jmmv {
    351  1.1  jmmv     const char* const args[] = {"foo", NULL};
    352  1.1  jmmv     int unused_exitstatus;
    353  1.1  jmmv     const kyua_error_t error = exec_check("./foo", args, &unused_exitstatus);
    354  1.1  jmmv     ATF_REQUIRE(kyua_error_is_set(error));
    355  1.1  jmmv     ATF_REQUIRE(kyua_error_is_type(error, "libc"));
    356  1.1  jmmv     ATF_REQUIRE_EQ(ENOENT, kyua_libc_error_errno(error));
    357  1.1  jmmv }
    358  1.1  jmmv 
    359  1.1  jmmv 
    360  1.1  jmmv ATF_TC_WITHOUT_HEAD(fork_wait__core_size);
    361  1.1  jmmv ATF_TC_BODY(fork_wait__core_size, tc)
    362  1.1  jmmv {
    363  1.1  jmmv     struct rlimit rl;
    364  1.1  jmmv     rl.rlim_cur = 0;
    365  1.1  jmmv     rl.rlim_max = RLIM_INFINITY;
    366  1.1  jmmv     if (setrlimit(RLIMIT_CORE, &rl) == -1)
    367  1.1  jmmv         atf_tc_skip("Failed to lower the core size limit");
    368  1.1  jmmv 
    369  1.1  jmmv     kyua_run_params_t run_params;
    370  1.1  jmmv     kyua_run_params_init(&run_params);
    371  1.1  jmmv 
    372  1.1  jmmv     pid_t pid;
    373  1.1  jmmv     kyua_error_t error = kyua_run_fork(&run_params, &pid);
    374  1.1  jmmv     if (!kyua_error_is_set(error) && pid == 0)
    375  1.1  jmmv         abort();
    376  1.1  jmmv 
    377  1.1  jmmv     ATF_REQUIRE(!kyua_error_is_set(error));
    378  1.1  jmmv     int status; bool timed_out;
    379  1.1  jmmv     error = kyua_run_wait(pid, &status, &timed_out);
    380  1.1  jmmv     if (kyua_error_is_set(error))
    381  1.1  jmmv         atf_tc_fail("wait failed; unexpected problem during exec?");
    382  1.1  jmmv 
    383  1.1  jmmv     ATF_REQUIRE(!timed_out);
    384  1.1  jmmv     ATF_REQUIRE(WIFSIGNALED(status));
    385  1.1  jmmv     ATF_REQUIRE_MSG(WCOREDUMP(status), "Core not dumped as expected");
    386  1.1  jmmv }
    387  1.1  jmmv 
    388  1.1  jmmv 
    389  1.1  jmmv ATF_TC_WITHOUT_HEAD(fork_wait__env);
    390  1.1  jmmv ATF_TC_BODY(fork_wait__env, tc)
    391  1.1  jmmv {
    392  1.1  jmmv     kyua_env_set("HOME", "/non-existent/directory");
    393  1.1  jmmv     kyua_env_set("LANG", "C");
    394  1.1  jmmv     kyua_env_set("LC_ALL", "C");
    395  1.1  jmmv     kyua_env_set("LC_COLLATE", "C");
    396  1.1  jmmv     kyua_env_set("LC_CTYPE", "C");
    397  1.1  jmmv     kyua_env_set("LC_MESSAGES", "C");
    398  1.1  jmmv     kyua_env_set("LC_MONETARY", "C");
    399  1.1  jmmv     kyua_env_set("LC_NUMERIC", "C");
    400  1.1  jmmv     kyua_env_set("LC_TIME", "C");
    401  1.1  jmmv     kyua_env_set("LEAVE_ME_ALONE", "kill-some-day");
    402  1.1  jmmv     kyua_env_set("TZ", "EST+5");
    403  1.1  jmmv 
    404  1.1  jmmv     ATF_REQUIRE_MSG(fork_check(NULL, check_env, NULL),
    405  1.1  jmmv                     "Unclean environment in subprocess");
    406  1.1  jmmv }
    407  1.1  jmmv 
    408  1.1  jmmv 
    409  1.1  jmmv ATF_TC_WITHOUT_HEAD(fork_wait__process_group);
    410  1.1  jmmv ATF_TC_BODY(fork_wait__process_group, tc)
    411  1.1  jmmv {
    412  1.1  jmmv     ATF_REQUIRE_MSG(fork_check(NULL, check_process_group, NULL),
    413  1.1  jmmv                     "Subprocess not in its own process group");
    414  1.1  jmmv }
    415  1.1  jmmv 
    416  1.1  jmmv 
    417  1.1  jmmv ATF_TC_WITHOUT_HEAD(fork_wait__signals);
    418  1.1  jmmv ATF_TC_BODY(fork_wait__signals, tc)
    419  1.1  jmmv {
    420  1.1  jmmv     ATF_REQUIRE_MSG(LAST_SIGNO > 10, "LAST_SIGNO as detected by configure is "
    421  1.1  jmmv                     "suspiciously low");
    422  1.1  jmmv 
    423  1.1  jmmv     int signo;
    424  1.1  jmmv     for (signo = 1; signo <= LAST_SIGNO; signo++) {
    425  1.1  jmmv         if (signo == SIGKILL || signo == SIGSTOP) {
    426  1.1  jmmv             // Ignore immutable signals.
    427  1.1  jmmv             continue;
    428  1.1  jmmv         }
    429  1.1  jmmv         if (signo == SIGCHLD) {
    430  1.1  jmmv             // If we were to reset SIGCHLD to SIG_IGN (which is different than
    431  1.1  jmmv             // not touching the signal at all, leaving it at its default value),
    432  1.1  jmmv             // our child process will not become a zombie and the call to
    433  1.1  jmmv             // kyua_run_wait will fail.  Avoid this.
    434  1.1  jmmv             continue;
    435  1.1  jmmv         }
    436  1.1  jmmv 
    437  1.1  jmmv         struct sigaction sa;
    438  1.1  jmmv         sa.sa_handler = SIG_IGN;
    439  1.1  jmmv         sigemptyset(&sa.sa_mask);
    440  1.1  jmmv         sa.sa_flags = 0;
    441  1.1  jmmv         printf("Ignoring signal %d\n", signo);
    442  1.1  jmmv         ATF_REQUIRE(sigaction(signo, &sa, NULL) != -1);
    443  1.1  jmmv     }
    444  1.1  jmmv 
    445  1.1  jmmv     ATF_REQUIRE_MSG(fork_check(NULL, check_signals, NULL),
    446  1.1  jmmv                     "Signals not reset to their default state");
    447  1.1  jmmv }
    448  1.1  jmmv 
    449  1.1  jmmv 
    450  1.1  jmmv ATF_TC_WITHOUT_HEAD(fork_wait__timeout);
    451  1.1  jmmv ATF_TC_BODY(fork_wait__timeout, tc)
    452  1.1  jmmv {
    453  1.1  jmmv     kyua_run_params_t run_params;
    454  1.1  jmmv     kyua_run_params_init(&run_params);
    455  1.1  jmmv     run_params.timeout_seconds = 1;
    456  1.1  jmmv 
    457  1.1  jmmv     pid_t pid;
    458  1.1  jmmv     kyua_error_t error = kyua_run_fork(&run_params, &pid);
    459  1.1  jmmv     if (!kyua_error_is_set(error) && pid == 0) {
    460  1.1  jmmv         sigset_t mask;
    461  1.1  jmmv         sigemptyset(&mask);
    462  1.1  jmmv         for (;;)
    463  1.1  jmmv             sigsuspend(&mask);
    464  1.1  jmmv     }
    465  1.1  jmmv     ATF_REQUIRE(!kyua_error_is_set(error));
    466  1.1  jmmv     int status; bool timed_out;
    467  1.1  jmmv     kyua_run_wait(pid, &status, &timed_out);
    468  1.1  jmmv     ATF_REQUIRE(timed_out);
    469  1.1  jmmv     ATF_REQUIRE(WIFSIGNALED(status));
    470  1.1  jmmv     ATF_REQUIRE_EQ(SIGKILL, WTERMSIG(status));
    471  1.1  jmmv }
    472  1.1  jmmv 
    473  1.1  jmmv 
    474  1.1  jmmv ATF_TC_WITHOUT_HEAD(fork_wait__umask);
    475  1.1  jmmv ATF_TC_BODY(fork_wait__umask, tc)
    476  1.1  jmmv {
    477  1.1  jmmv     (void)umask(0222);
    478  1.1  jmmv     ATF_REQUIRE_MSG(fork_check(NULL, check_umask, NULL),
    479  1.1  jmmv                     "Subprocess does not have the predetermined 0022 umask");
    480  1.1  jmmv }
    481  1.1  jmmv 
    482  1.1  jmmv 
    483  1.1  jmmv ATF_TC(fork_wait__unprivileged_user);
    484  1.1  jmmv ATF_TC_HEAD(fork_wait__unprivileged_user, tc)
    485  1.1  jmmv {
    486  1.1  jmmv     atf_tc_set_md_var(tc, "require.config", "unprivileged-user");
    487  1.1  jmmv     atf_tc_set_md_var(tc, "require.user", "root");
    488  1.1  jmmv }
    489  1.1  jmmv ATF_TC_BODY(fork_wait__unprivileged_user, tc)
    490  1.1  jmmv {
    491  1.1  jmmv     const struct passwd* pw = getpwnam(atf_tc_get_config_var(
    492  1.1  jmmv         tc, "unprivileged-user"));
    493  1.1  jmmv     ATF_REQUIRE_MSG(pw != NULL, "Cannot find unprivileged user");
    494  1.1  jmmv 
    495  1.1  jmmv     kyua_run_params_t run_params;
    496  1.1  jmmv     kyua_run_params_init(&run_params);
    497  1.1  jmmv     run_params.unprivileged_user = pw->pw_uid;
    498  1.1  jmmv 
    499  1.1  jmmv     ATF_REQUIRE_MSG(fork_check(&run_params, check_uid_not_root, NULL),
    500  1.1  jmmv                     "Subprocess is still running with UID set to root");
    501  1.1  jmmv }
    502  1.1  jmmv 
    503  1.1  jmmv 
    504  1.1  jmmv ATF_TC(fork_wait__unprivileged_group);
    505  1.1  jmmv ATF_TC_HEAD(fork_wait__unprivileged_group, tc)
    506  1.1  jmmv {
    507  1.1  jmmv     atf_tc_set_md_var(tc, "require.config", "unprivileged-user");
    508  1.1  jmmv     atf_tc_set_md_var(tc, "require.user", "root");
    509  1.1  jmmv }
    510  1.1  jmmv ATF_TC_BODY(fork_wait__unprivileged_group, tc)
    511  1.1  jmmv {
    512  1.1  jmmv     const struct passwd* pw = getpwnam(atf_tc_get_config_var(
    513  1.1  jmmv         tc, "unprivileged-user"));
    514  1.1  jmmv     ATF_REQUIRE_MSG(pw != NULL, "Cannot find unprivileged user");
    515  1.1  jmmv 
    516  1.1  jmmv     kyua_run_params_t run_params;
    517  1.1  jmmv     kyua_run_params_init(&run_params);
    518  1.1  jmmv     run_params.unprivileged_group = pw->pw_gid;
    519  1.1  jmmv 
    520  1.1  jmmv     ATF_REQUIRE_MSG(fork_check(&run_params, check_gid_not_root, NULL),
    521  1.1  jmmv                     "Subprocess is still running with GID set to root");
    522  1.1  jmmv }
    523  1.1  jmmv 
    524  1.1  jmmv 
    525  1.1  jmmv ATF_TC(fork_wait__unprivileged_both);
    526  1.1  jmmv ATF_TC_HEAD(fork_wait__unprivileged_both, tc)
    527  1.1  jmmv {
    528  1.1  jmmv     atf_tc_set_md_var(tc, "require.config", "unprivileged-user");
    529  1.1  jmmv     atf_tc_set_md_var(tc, "require.user", "root");
    530  1.1  jmmv }
    531  1.1  jmmv ATF_TC_BODY(fork_wait__unprivileged_both, tc)
    532  1.1  jmmv {
    533  1.1  jmmv     const struct passwd* pw = getpwnam(atf_tc_get_config_var(
    534  1.1  jmmv         tc, "unprivileged-user"));
    535  1.1  jmmv     ATF_REQUIRE_MSG(pw != NULL, "Cannot find unprivileged user");
    536  1.1  jmmv 
    537  1.1  jmmv     kyua_run_params_t run_params;
    538  1.1  jmmv     kyua_run_params_init(&run_params);
    539  1.1  jmmv     run_params.unprivileged_user = pw->pw_uid;
    540  1.1  jmmv     run_params.unprivileged_group = pw->pw_gid;
    541  1.1  jmmv 
    542  1.1  jmmv     ATF_REQUIRE_MSG(fork_check(&run_params, check_not_root, NULL),
    543  1.1  jmmv                     "Subprocess is still running with root privileges");
    544  1.1  jmmv }
    545  1.1  jmmv 
    546  1.1  jmmv 
    547  1.1  jmmv ATF_TC_WITHOUT_HEAD(fork_wait__work_directory);
    548  1.1  jmmv ATF_TC_BODY(fork_wait__work_directory, tc)
    549  1.1  jmmv {
    550  1.1  jmmv     ATF_REQUIRE(mkdir("the-work-directory", 0755) != -1);
    551  1.1  jmmv     atf_utils_create_file("the-work-directory/data-file", "%s", "");
    552  1.1  jmmv 
    553  1.1  jmmv     kyua_run_params_t run_params;
    554  1.1  jmmv     kyua_run_params_init(&run_params);
    555  1.1  jmmv     run_params.work_directory = "./the-work-directory";
    556  1.1  jmmv     ATF_REQUIRE_MSG(fork_check(&run_params, check_work_directory, "data-file"),
    557  1.1  jmmv                     "Subprocess not in its own process group");
    558  1.1  jmmv }
    559  1.1  jmmv 
    560  1.1  jmmv 
    561  1.1  jmmv ATF_TC_WITHOUT_HEAD(work_directory__builtin_tmpdir);
    562  1.1  jmmv ATF_TC_BODY(work_directory__builtin_tmpdir, tc)
    563  1.1  jmmv {
    564  1.1  jmmv     char* tmpdir;
    565  1.1  jmmv     RE(kyua_fs_make_absolute("worktest", &tmpdir));
    566  1.1  jmmv     ATF_REQUIRE(mkdir(tmpdir, 0755) != -1);
    567  1.1  jmmv     RE(kyua_env_unset("TMPDIR"));
    568  1.1  jmmv     kyua_run_tmpdir = tmpdir;
    569  1.1  jmmv 
    570  1.1  jmmv     char* work_directory;
    571  1.1  jmmv     RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(),
    572  1.1  jmmv                                      &work_directory));
    573  1.1  jmmv 
    574  1.1  jmmv     {
    575  1.1  jmmv         char* template_test;
    576  1.1  jmmv         RE(kyua_fs_concat(&template_test, atf_tc_get_config_var(tc, "srcdir"),
    577  1.1  jmmv                           "worktest", "template.XXXXXX", NULL));
    578  1.1  jmmv         ATF_REQUIRE(access(template_test, X_OK) == -1);
    579  1.1  jmmv         free(template_test);
    580  1.1  jmmv     }
    581  1.1  jmmv 
    582  1.1  jmmv     ATF_REQUIRE(access(work_directory, X_OK) != -1);
    583  1.1  jmmv 
    584  1.1  jmmv     ATF_REQUIRE(rmdir(tmpdir) == -1);  // Not yet empty.
    585  1.1  jmmv     RE(kyua_run_work_directory_leave(&work_directory));
    586  1.1  jmmv     ATF_REQUIRE(rmdir(tmpdir) != -1);
    587  1.1  jmmv     free(tmpdir);
    588  1.1  jmmv }
    589  1.1  jmmv 
    590  1.1  jmmv 
    591  1.1  jmmv ATF_TC_WITHOUT_HEAD(work_directory__env_tmpdir);
    592  1.1  jmmv ATF_TC_BODY(work_directory__env_tmpdir, tc)
    593  1.1  jmmv {
    594  1.1  jmmv     char* tmpdir;
    595  1.1  jmmv     RE(kyua_fs_make_absolute("worktest", &tmpdir));
    596  1.1  jmmv     ATF_REQUIRE(mkdir(tmpdir, 0755) != -1);
    597  1.1  jmmv     RE(kyua_env_set("TMPDIR", tmpdir));
    598  1.1  jmmv 
    599  1.1  jmmv     char* work_directory;
    600  1.1  jmmv     RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(),
    601  1.1  jmmv                                      &work_directory));
    602  1.1  jmmv 
    603  1.1  jmmv     {
    604  1.1  jmmv         char* template_test;
    605  1.1  jmmv         RE(kyua_fs_concat(&template_test, atf_tc_get_config_var(tc, "srcdir"),
    606  1.1  jmmv                           "worktest", "template.XXXXXX", NULL));
    607  1.1  jmmv         ATF_REQUIRE(access(template_test, X_OK) == -1);
    608  1.1  jmmv         free(template_test);
    609  1.1  jmmv     }
    610  1.1  jmmv 
    611  1.1  jmmv     ATF_REQUIRE(access(work_directory, X_OK) != -1);
    612  1.1  jmmv 
    613  1.1  jmmv     ATF_REQUIRE(rmdir(tmpdir) == -1);  // Not yet empty.
    614  1.1  jmmv     RE(kyua_run_work_directory_leave(&work_directory));
    615  1.1  jmmv     ATF_REQUIRE(rmdir(tmpdir) != -1);
    616  1.1  jmmv     free(tmpdir);
    617  1.1  jmmv }
    618  1.1  jmmv 
    619  1.1  jmmv 
    620  1.1  jmmv ATF_TC(work_directory__permissions);
    621  1.1  jmmv ATF_TC_HEAD(work_directory__permissions, tc)
    622  1.1  jmmv {
    623  1.1  jmmv     atf_tc_set_md_var(tc, "require.config", "unprivileged-user");
    624  1.1  jmmv     atf_tc_set_md_var(tc, "require.user", "root");
    625  1.1  jmmv }
    626  1.1  jmmv ATF_TC_BODY(work_directory__permissions, tc)
    627  1.1  jmmv {
    628  1.1  jmmv     const struct passwd* pw = getpwnam(atf_tc_get_config_var(
    629  1.1  jmmv         tc, "unprivileged-user"));
    630  1.1  jmmv 
    631  1.1  jmmv     printf("%d %d %d %d\n", getuid(), getgid(), pw->pw_uid, pw->pw_gid);
    632  1.1  jmmv 
    633  1.1  jmmv     char* work_directory;
    634  1.1  jmmv     RE(kyua_run_work_directory_enter("template.XXXXXX", pw->pw_uid, pw->pw_gid,
    635  1.1  jmmv                                      &work_directory));
    636  1.1  jmmv 
    637  1.1  jmmv     struct stat sb;
    638  1.1  jmmv     ATF_REQUIRE(stat(work_directory, &sb) != -1);
    639  1.1  jmmv     ATF_REQUIRE_EQ(pw->pw_uid, sb.st_uid);
    640  1.1  jmmv     ATF_REQUIRE_EQ(pw->pw_gid, sb.st_gid);
    641  1.1  jmmv 
    642  1.1  jmmv     RE(kyua_run_work_directory_leave(&work_directory));
    643  1.1  jmmv }
    644  1.1  jmmv 
    645  1.1  jmmv 
    646  1.1  jmmv ATF_TC(work_directory__mkdtemp_error);
    647  1.1  jmmv ATF_TC_HEAD(work_directory__mkdtemp_error, tc)
    648  1.1  jmmv {
    649  1.1  jmmv     atf_tc_set_md_var(tc, "require.user", "unprivileged");
    650  1.1  jmmv }
    651  1.1  jmmv ATF_TC_BODY(work_directory__mkdtemp_error, tc)
    652  1.1  jmmv {
    653  1.1  jmmv     char* tmpdir;
    654  1.1  jmmv     RE(kyua_fs_make_absolute("worktest", &tmpdir));
    655  1.1  jmmv     ATF_REQUIRE(mkdir(tmpdir, 0555) != -1);
    656  1.1  jmmv     RE(kyua_env_set("TMPDIR", tmpdir));
    657  1.1  jmmv 
    658  1.1  jmmv     char* work_directory;
    659  1.1  jmmv     const kyua_error_t error = kyua_run_work_directory_enter(
    660  1.1  jmmv         "template.XXXXXX", getuid(), getgid(), &work_directory);
    661  1.1  jmmv     ATF_REQUIRE(kyua_error_is_set(error));
    662  1.1  jmmv     ATF_REQUIRE(kyua_error_is_type(error, "libc"));
    663  1.1  jmmv     ATF_REQUIRE_EQ(EACCES, kyua_libc_error_errno(error));
    664  1.1  jmmv     kyua_error_free(error);
    665  1.1  jmmv 
    666  1.1  jmmv     ATF_REQUIRE(rmdir(tmpdir) != -1);  // Empty; subdirectory not created.
    667  1.1  jmmv     free(tmpdir);
    668  1.1  jmmv }
    669  1.1  jmmv 
    670  1.1  jmmv 
    671  1.1  jmmv ATF_TC(work_directory__permissions_error);
    672  1.1  jmmv ATF_TC_HEAD(work_directory__permissions_error, tc)
    673  1.1  jmmv {
    674  1.1  jmmv     atf_tc_set_md_var(tc, "require.user", "unprivileged");
    675  1.1  jmmv }
    676  1.1  jmmv ATF_TC_BODY(work_directory__permissions_error, tc)
    677  1.1  jmmv {
    678  1.1  jmmv     char* tmpdir;
    679  1.1  jmmv     RE(kyua_fs_make_absolute("worktest", &tmpdir));
    680  1.1  jmmv     ATF_REQUIRE(mkdir(tmpdir, 0755) != -1);
    681  1.1  jmmv     RE(kyua_env_set("TMPDIR", tmpdir));
    682  1.1  jmmv 
    683  1.1  jmmv     char* work_directory;
    684  1.1  jmmv     const kyua_error_t error = kyua_run_work_directory_enter(
    685  1.1  jmmv         "template.XXXXXX", getuid() + 1, getgid(), &work_directory);
    686  1.1  jmmv     ATF_REQUIRE(kyua_error_is_set(error));
    687  1.1  jmmv     ATF_REQUIRE(kyua_error_is_type(error, "libc"));
    688  1.1  jmmv     ATF_REQUIRE_EQ(EPERM, kyua_libc_error_errno(error));
    689  1.1  jmmv     kyua_error_free(error);
    690  1.1  jmmv 
    691  1.1  jmmv     ATF_REQUIRE(rmdir(tmpdir) != -1);  // Empty; subdirectory not created.
    692  1.1  jmmv     free(tmpdir);
    693  1.1  jmmv }
    694  1.1  jmmv 
    695  1.1  jmmv 
    696  1.1  jmmv /// Performs a signal delivery test to the work directory handling code.
    697  1.1  jmmv ///
    698  1.1  jmmv /// \param signo The signal to deliver.
    699  1.1  jmmv static void
    700  1.1  jmmv work_directory_signal_check(const int signo)
    701  1.1  jmmv {
    702  1.1  jmmv     char* tmpdir;
    703  1.1  jmmv     RE(kyua_fs_make_absolute("worktest", &tmpdir));
    704  1.1  jmmv     ATF_REQUIRE(mkdir(tmpdir, 0755) != -1);
    705  1.1  jmmv     RE(kyua_env_set("TMPDIR", tmpdir));
    706  1.1  jmmv 
    707  1.1  jmmv     char* work_directory;
    708  1.1  jmmv     RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(),
    709  1.1  jmmv                                      &work_directory));
    710  1.1  jmmv 
    711  1.1  jmmv     kyua_run_params_t run_params;
    712  1.1  jmmv     kyua_run_params_init(&run_params);
    713  1.1  jmmv     run_params.work_directory = work_directory;
    714  1.1  jmmv 
    715  1.1  jmmv     pid_t pid;
    716  1.1  jmmv     RE(kyua_run_fork(&run_params, &pid));
    717  1.1  jmmv     if (pid == 0) {
    718  1.1  jmmv         sleep(run_params.timeout_seconds * 2);
    719  1.1  jmmv         abort();
    720  1.1  jmmv     }
    721  1.1  jmmv 
    722  1.1  jmmv     // This should cause the handled installed by the work_directory management
    723  1.1  jmmv     // code to terminate the subprocess so that we get a chance to run the
    724  1.1  jmmv     // cleanup code ourselves.
    725  1.1  jmmv     kill(getpid(), signo);
    726  1.1  jmmv 
    727  1.1  jmmv     int status; bool timed_out;
    728  1.1  jmmv     RE(kyua_run_wait(pid, &status, &timed_out));
    729  1.1  jmmv     ATF_REQUIRE(!timed_out);
    730  1.1  jmmv     ATF_REQUIRE(WIFSIGNALED(status));
    731  1.1  jmmv     ATF_REQUIRE_EQ(SIGKILL, WTERMSIG(status));
    732  1.1  jmmv 
    733  1.1  jmmv     ATF_REQUIRE(rmdir(tmpdir) == -1);  // Not yet empty.
    734  1.1  jmmv     RE(kyua_run_work_directory_leave(&work_directory));
    735  1.1  jmmv     ATF_REQUIRE(rmdir(tmpdir) != -1);
    736  1.1  jmmv     free(tmpdir);
    737  1.1  jmmv }
    738  1.1  jmmv 
    739  1.1  jmmv 
    740  1.1  jmmv ATF_TC_WITHOUT_HEAD(work_directory__sighup);
    741  1.1  jmmv ATF_TC_BODY(work_directory__sighup, tc)
    742  1.1  jmmv {
    743  1.1  jmmv     work_directory_signal_check(SIGHUP);
    744  1.1  jmmv }
    745  1.1  jmmv 
    746  1.1  jmmv 
    747  1.1  jmmv ATF_TC_WITHOUT_HEAD(work_directory__sigint);
    748  1.1  jmmv ATF_TC_BODY(work_directory__sigint, tc)
    749  1.1  jmmv {
    750  1.1  jmmv     work_directory_signal_check(SIGINT);
    751  1.1  jmmv }
    752  1.1  jmmv 
    753  1.1  jmmv 
    754  1.1  jmmv ATF_TC_WITHOUT_HEAD(work_directory__sigterm);
    755  1.1  jmmv ATF_TC_BODY(work_directory__sigterm, tc)
    756  1.1  jmmv {
    757  1.1  jmmv     work_directory_signal_check(SIGTERM);
    758  1.1  jmmv }
    759  1.1  jmmv 
    760  1.1  jmmv 
    761  1.1  jmmv ATF_TP_ADD_TCS(tp)
    762  1.1  jmmv {
    763  1.1  jmmv     ATF_TP_ADD_TC(tp, run_params_init__defaults);
    764  1.1  jmmv 
    765  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_exec_wait__ok);
    766  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_exec_wait__eacces);
    767  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_exec_wait__enoent);
    768  1.1  jmmv 
    769  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_wait__core_size);
    770  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_wait__env);
    771  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_wait__process_group);
    772  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_wait__signals);
    773  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_wait__timeout);
    774  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_wait__umask);
    775  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_wait__unprivileged_user);
    776  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_wait__unprivileged_group);
    777  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_wait__unprivileged_both);
    778  1.1  jmmv     ATF_TP_ADD_TC(tp, fork_wait__work_directory);
    779  1.1  jmmv 
    780  1.1  jmmv     ATF_TP_ADD_TC(tp, work_directory__builtin_tmpdir);
    781  1.1  jmmv     ATF_TP_ADD_TC(tp, work_directory__env_tmpdir);
    782  1.1  jmmv     ATF_TP_ADD_TC(tp, work_directory__permissions);
    783  1.1  jmmv     ATF_TP_ADD_TC(tp, work_directory__permissions_error);
    784  1.1  jmmv     ATF_TP_ADD_TC(tp, work_directory__mkdtemp_error);
    785  1.1  jmmv     ATF_TP_ADD_TC(tp, work_directory__sighup);
    786  1.1  jmmv     ATF_TP_ADD_TC(tp, work_directory__sigint);
    787  1.1  jmmv     ATF_TP_ADD_TC(tp, work_directory__sigterm);
    788  1.1  jmmv 
    789  1.1  jmmv     return atf_no_error();
    790  1.1  jmmv }
    791