1*bc2346d6Sandvar /* $NetBSD: t_spawn.c,v 1.8 2022/05/31 11:22:34 andvar Exp $ */
20ce98f42Smartin
30ce98f42Smartin /*-
488c7966bSchristos * Copyright (c) 2012, 2021 The NetBSD Foundation, Inc.
50ce98f42Smartin * All rights reserved.
60ce98f42Smartin *
70ce98f42Smartin * This code is derived from software contributed to The NetBSD Foundation
80ce98f42Smartin * by Charles Zhang <charles@NetBSD.org> and
90ce98f42Smartin * Martin Husemann <martin@NetBSD.org>.
100ce98f42Smartin *
110ce98f42Smartin * Redistribution and use in source and binary forms, with or without
120ce98f42Smartin * modification, are permitted provided that the following conditions
130ce98f42Smartin * are met:
140ce98f42Smartin * 1. Redistributions of source code must retain the above copyright
150ce98f42Smartin * notice, this list of conditions and the following disclaimer.
160ce98f42Smartin * 2. Redistributions in binary form must reproduce the above copyright
170ce98f42Smartin * notice, this list of conditions and the following disclaimer in the
180ce98f42Smartin * documentation and/or other materials provided with the distribution.
190ce98f42Smartin *
200ce98f42Smartin * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
210ce98f42Smartin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
220ce98f42Smartin * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
230ce98f42Smartin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
240ce98f42Smartin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
250ce98f42Smartin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
260ce98f42Smartin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
270ce98f42Smartin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
280ce98f42Smartin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
290ce98f42Smartin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
300ce98f42Smartin * POSSIBILITY OF SUCH DAMAGE.
310ce98f42Smartin */
32c0746c1eSchristos #include <sys/cdefs.h>
33*bc2346d6Sandvar __RCSID("$NetBSD: t_spawn.c,v 1.8 2022/05/31 11:22:34 andvar Exp $");
340ce98f42Smartin
350ce98f42Smartin #include <atf-c.h>
36c0746c1eSchristos
37c0746c1eSchristos #include <sys/fcntl.h>
38c0746c1eSchristos #include <sys/types.h>
39c0746c1eSchristos #include <sys/wait.h>
40c0746c1eSchristos #include <sys/stat.h>
41c0746c1eSchristos
420ce98f42Smartin #include <spawn.h>
430ce98f42Smartin #include <string.h>
440ce98f42Smartin #include <stdio.h>
450ce98f42Smartin #include <stdlib.h>
460ce98f42Smartin #include <errno.h>
47c0746c1eSchristos #include <stdarg.h>
48c0746c1eSchristos #include <fcntl.h>
49c0746c1eSchristos #include <unistd.h>
50c0746c1eSchristos
51c0746c1eSchristos #include "fa_spawn_utils.h"
52c0746c1eSchristos
53c0746c1eSchristos
54c0746c1eSchristos static void check_success(const char *, int, ...);
550ce98f42Smartin
560ce98f42Smartin ATF_TC(t_spawn_ls);
570ce98f42Smartin
ATF_TC_HEAD(t_spawn_ls,tc)580ce98f42Smartin ATF_TC_HEAD(t_spawn_ls, tc)
590ce98f42Smartin {
600ce98f42Smartin atf_tc_set_md_var(tc, "descr",
610ce98f42Smartin "Tests a simple posix_spawn executing /bin/ls");
620ce98f42Smartin }
630ce98f42Smartin
ATF_TC_BODY(t_spawn_ls,tc)640ce98f42Smartin ATF_TC_BODY(t_spawn_ls, tc)
650ce98f42Smartin {
660ce98f42Smartin char * const args[] = { __UNCONST("ls"), __UNCONST("-la"), NULL };
670ce98f42Smartin int err;
680ce98f42Smartin
690ce98f42Smartin err = posix_spawn(NULL, "/bin/ls", NULL, NULL, args, NULL);
700ce98f42Smartin ATF_REQUIRE(err == 0);
710ce98f42Smartin }
720ce98f42Smartin
730ce98f42Smartin ATF_TC(t_spawnp_ls);
740ce98f42Smartin
ATF_TC_HEAD(t_spawnp_ls,tc)750ce98f42Smartin ATF_TC_HEAD(t_spawnp_ls, tc)
760ce98f42Smartin {
770ce98f42Smartin atf_tc_set_md_var(tc, "descr",
780ce98f42Smartin "Tests a simple posix_spawnp executing ls via $PATH");
790ce98f42Smartin }
800ce98f42Smartin
ATF_TC_BODY(t_spawnp_ls,tc)810ce98f42Smartin ATF_TC_BODY(t_spawnp_ls, tc)
820ce98f42Smartin {
830ce98f42Smartin char * const args[] = { __UNCONST("ls"), __UNCONST("-la"), NULL };
840ce98f42Smartin int err;
850ce98f42Smartin
860ce98f42Smartin err = posix_spawnp(NULL, "ls", NULL, NULL, args, NULL);
870ce98f42Smartin ATF_REQUIRE(err == 0);
880ce98f42Smartin }
890ce98f42Smartin
9088c7966bSchristos static void
spawn_error(const atf_tc_t * tc,const char * name,int error)9188c7966bSchristos spawn_error(const atf_tc_t *tc, const char *name, int error)
9288c7966bSchristos {
9388c7966bSchristos char buf[FILENAME_MAX];
9488c7966bSchristos char * const args[] = { __UNCONST(name), NULL };
9588c7966bSchristos int err;
9688c7966bSchristos
9788c7966bSchristos snprintf(buf, sizeof buf, "%s/%s",
9888c7966bSchristos atf_tc_get_config_var(tc, "srcdir"), name);
9988c7966bSchristos err = posix_spawn(NULL, buf, NULL, NULL, args, NULL);
10088c7966bSchristos ATF_REQUIRE_MSG(err == error, "expected error %d, "
10188c7966bSchristos "got %d when spawning %s", error, err, buf);
10288c7966bSchristos }
10388c7966bSchristos
1040ce98f42Smartin ATF_TC(t_spawn_zero);
1050ce98f42Smartin
ATF_TC_HEAD(t_spawn_zero,tc)1060ce98f42Smartin ATF_TC_HEAD(t_spawn_zero, tc)
1070ce98f42Smartin {
1080ce98f42Smartin atf_tc_set_md_var(tc, "descr",
1090ce98f42Smartin "posix_spawn an invalid binary");
1100ce98f42Smartin }
1110ce98f42Smartin
ATF_TC_BODY(t_spawn_zero,tc)1120ce98f42Smartin ATF_TC_BODY(t_spawn_zero, tc)
1130ce98f42Smartin {
11488c7966bSchristos spawn_error(tc, "h_zero", ENOEXEC);
1150ce98f42Smartin }
1160ce98f42Smartin
1170ce98f42Smartin ATF_TC(t_spawn_missing);
1180ce98f42Smartin
ATF_TC_HEAD(t_spawn_missing,tc)1190ce98f42Smartin ATF_TC_HEAD(t_spawn_missing, tc)
1200ce98f42Smartin {
1210ce98f42Smartin atf_tc_set_md_var(tc, "descr",
122c0746c1eSchristos "posix_spawn a non existant binary");
1230ce98f42Smartin }
1240ce98f42Smartin
ATF_TC_BODY(t_spawn_missing,tc)1250ce98f42Smartin ATF_TC_BODY(t_spawn_missing, tc)
1260ce98f42Smartin {
12788c7966bSchristos spawn_error(tc, "h_nonexist", ENOENT);
1280ce98f42Smartin }
1290ce98f42Smartin
1300ce98f42Smartin ATF_TC(t_spawn_nonexec);
1310ce98f42Smartin
ATF_TC_HEAD(t_spawn_nonexec,tc)1320ce98f42Smartin ATF_TC_HEAD(t_spawn_nonexec, tc)
1330ce98f42Smartin {
1340ce98f42Smartin atf_tc_set_md_var(tc, "descr",
135c0746c1eSchristos "posix_spawn a script with non existing interpreter");
1360ce98f42Smartin }
1370ce98f42Smartin
ATF_TC_BODY(t_spawn_nonexec,tc)1380ce98f42Smartin ATF_TC_BODY(t_spawn_nonexec, tc)
1390ce98f42Smartin {
14088c7966bSchristos spawn_error(tc, "h_nonexec", ENOENT);
1410ce98f42Smartin }
1420ce98f42Smartin
1430ce98f42Smartin ATF_TC(t_spawn_child);
1440ce98f42Smartin
ATF_TC_HEAD(t_spawn_child,tc)1450ce98f42Smartin ATF_TC_HEAD(t_spawn_child, tc)
1460ce98f42Smartin {
1470ce98f42Smartin atf_tc_set_md_var(tc, "descr",
148f0a7346dSsnj "posix_spawn a child and get its return code");
1490ce98f42Smartin }
1500ce98f42Smartin
ATF_TC_BODY(t_spawn_child,tc)1510ce98f42Smartin ATF_TC_BODY(t_spawn_child, tc)
1520ce98f42Smartin {
1530ce98f42Smartin char buf[FILENAME_MAX];
15488c7966bSchristos char rv[2] = { '0', '\0' };
15588c7966bSchristos char * const args0[] = { __UNCONST("h_spawn"), rv, NULL };
15688c7966bSchristos int rets[] = { 0, 1, 7 };
1570ce98f42Smartin int err, status;
1580ce98f42Smartin pid_t pid;
1590ce98f42Smartin
1600ce98f42Smartin snprintf(buf, sizeof buf, "%s/h_spawn",
1610ce98f42Smartin atf_tc_get_config_var(tc, "srcdir"));
1620ce98f42Smartin
16388c7966bSchristos for (size_t i = 0; i < __arraycount(rets); i++) {
16488c7966bSchristos rv[0] = rets[i] + '0';
1650ce98f42Smartin err = posix_spawn(&pid, buf, NULL, NULL, args0, NULL);
1660ce98f42Smartin ATF_REQUIRE(err == 0);
1670ce98f42Smartin ATF_REQUIRE(pid > 0);
1680ce98f42Smartin waitpid(pid, &status, 0);
16988c7966bSchristos ATF_REQUIRE(WIFEXITED(status) &&
17088c7966bSchristos WEXITSTATUS(status) == rets[i]);
17188c7966bSchristos }
1720ce98f42Smartin }
1730ce98f42Smartin
174c0746c1eSchristos #define CHDIRPATH "/tmp"
175c0746c1eSchristos #define FILENAME "output"
176c0746c1eSchristos #define FILEPATH "/tmp/output"
177c0746c1eSchristos
17888c7966bSchristos #define CHDIR 1
17988c7966bSchristos #define FCHDIR 2
18088c7966bSchristos
181c0746c1eSchristos static void
check_success(const char * file,int argc,...)182c0746c1eSchristos check_success(const char *file, int argc, ...)
183c0746c1eSchristos {
184c0746c1eSchristos va_list ap;
18526c0d3c6Schristos ssize_t bytesRead;
18626c0d3c6Schristos int fd;
187c0746c1eSchristos size_t sizeOfFile = (size_t)filesize(file);
188c0746c1eSchristos size_t sizeOfStr;
189c0746c1eSchristos char *contents;
190c0746c1eSchristos const char *dir;
191c0746c1eSchristos
192c0746c1eSchristos contents = malloc(sizeOfFile);
193c0746c1eSchristos ATF_REQUIRE(contents != NULL);
194c0746c1eSchristos
195c0746c1eSchristos /*
196c0746c1eSchristos * for now only 1 variadic argument expected
19726c0d3c6Schristos * only from t_spawn_[f]chdir_rel
198c0746c1eSchristos */
199c0746c1eSchristos if (argc != 0) {
200c0746c1eSchristos va_start(ap, argc);
201c0746c1eSchristos dir = va_arg(ap, char *);
202c0746c1eSchristos ATF_REQUIRE(dir != NULL);
203c0746c1eSchristos va_end(ap);
204c0746c1eSchristos } else
205c0746c1eSchristos dir = CHDIRPATH;
206c0746c1eSchristos
207c0746c1eSchristos fd = open(file, O_RDONLY);
20888c7966bSchristos ATF_REQUIRE_MSG(fd != -1, "Can't open `%s' (%s)", file,
20988c7966bSchristos strerror(errno));
210c0746c1eSchristos
211c0746c1eSchristos /*
212c0746c1eSchristos * file contains form feed i.e ASCII - 10 at the end.
213c0746c1eSchristos * Therefore sizeOfFile - 1
214c0746c1eSchristos */
215c0746c1eSchristos sizeOfStr = strlen(dir);
216c0746c1eSchristos ATF_CHECK_MSG(sizeOfStr == sizeOfFile - 1, "%zu (%s) != %zu (%s)",
217c0746c1eSchristos sizeOfStr, dir, sizeOfFile - 1, file);
218c0746c1eSchristos
219c0746c1eSchristos bytesRead = read(fd, contents, sizeOfFile - 1);
220c0746c1eSchristos contents[sizeOfFile - 1] = '\0';
221c0746c1eSchristos ATF_REQUIRE_MSG(strcmp(dir, contents) == 0,
222c0746c1eSchristos "[%s] != [%s] Directories dont match", dir, contents);
223c0746c1eSchristos
224c0746c1eSchristos fd = close(fd);
225c0746c1eSchristos ATF_REQUIRE(fd == 0);
226c0746c1eSchristos
227c0746c1eSchristos unlink(file);
228c0746c1eSchristos free(contents);
229c0746c1eSchristos
230c0746c1eSchristos /* XXX not really required */
23126c0d3c6Schristos ATF_REQUIRE((size_t)bytesRead == sizeOfStr);
232c0746c1eSchristos }
233c0746c1eSchristos
23488c7966bSchristos static void
spawn_chdir(const char * dirpath,const char * filepath,int operation,int expected_error)23588c7966bSchristos spawn_chdir(const char *dirpath, const char *filepath, int operation,
23688c7966bSchristos int expected_error)
23788c7966bSchristos {
23888c7966bSchristos int error, fd=-1, status;
23988c7966bSchristos char * const args[2] = { __UNCONST("pwd"), NULL };
24088c7966bSchristos pid_t pid;
24188c7966bSchristos posix_spawnattr_t attr, *attr_p;
24288c7966bSchristos posix_spawn_file_actions_t fa;
24388c7966bSchristos
24488c7966bSchristos if (filepath)
24588c7966bSchristos empty_outfile(filepath);
24688c7966bSchristos
24788c7966bSchristos error = posix_spawn_file_actions_init(&fa);
24888c7966bSchristos ATF_REQUIRE(error == 0);
24988c7966bSchristos
25088c7966bSchristos switch(operation) {
25188c7966bSchristos case CHDIR:
25288c7966bSchristos error = posix_spawn_file_actions_addchdir(&fa, dirpath);
25388c7966bSchristos break;
25488c7966bSchristos
25588c7966bSchristos case FCHDIR:
25688c7966bSchristos fd = open(dirpath, O_RDONLY);
25788c7966bSchristos ATF_REQUIRE(fd != -1);
25888c7966bSchristos
25988c7966bSchristos error = posix_spawn_file_actions_addfchdir(&fa, fd);
26088c7966bSchristos break;
26188c7966bSchristos }
26288c7966bSchristos ATF_REQUIRE(error == 0);
26388c7966bSchristos
26488c7966bSchristos /*
26588c7966bSchristos * if POSIX_SPAWN_RETURNERROR is expected, then no need to open the
26688c7966bSchristos * file
26788c7966bSchristos */
26888c7966bSchristos if (expected_error == 0) {
26988c7966bSchristos error = posix_spawn_file_actions_addopen(&fa, STDOUT_FILENO,
27088c7966bSchristos FILENAME, O_WRONLY, 0);
27188c7966bSchristos ATF_REQUIRE(error == 0);
27288c7966bSchristos attr_p = NULL;
27388c7966bSchristos } else {
27488c7966bSchristos error = posix_spawnattr_init(&attr);
27588c7966bSchristos ATF_REQUIRE(error == 0);
27688c7966bSchristos
27788c7966bSchristos /*
27888c7966bSchristos * POSIX_SPAWN_RETURNERROR is a NetBSD specific flag that
27988c7966bSchristos * will cause a "proper" return value from posix_spawn(2)
28088c7966bSchristos * instead of a (potential) success there and a 127 exit
28188c7966bSchristos * status from the child process (c.f. the non-diag variant
28288c7966bSchristos * of this test).
28388c7966bSchristos */
28488c7966bSchristos error = posix_spawnattr_setflags(&attr,
28588c7966bSchristos POSIX_SPAWN_RETURNERROR);
28688c7966bSchristos ATF_REQUIRE(error == 0);
28788c7966bSchristos attr_p = &attr;
28888c7966bSchristos }
28988c7966bSchristos
29088c7966bSchristos error = posix_spawn(&pid, "/bin/pwd", &fa, attr_p, args, NULL);
29188c7966bSchristos ATF_REQUIRE(error == expected_error);
29288c7966bSchristos
29388c7966bSchristos /* wait for the child to finish only when no spawnattr */
29488c7966bSchristos if (attr_p) {
29588c7966bSchristos posix_spawnattr_destroy(&attr);
29688c7966bSchristos } else {
29788c7966bSchristos waitpid(pid, &status, 0);
29888c7966bSchristos ATF_REQUIRE_MSG(WIFEXITED(status) &&
29988c7966bSchristos WEXITSTATUS(status) == EXIT_SUCCESS,
30088c7966bSchristos "%s", "[f]chdir failed");
30188c7966bSchristos }
30288c7966bSchristos
30388c7966bSchristos posix_spawn_file_actions_destroy(&fa);
30488c7966bSchristos
30588c7966bSchristos /*
30688c7966bSchristos * The file incase of fchdir(),
30788c7966bSchristos * should be closed before reopening in 'check_success'
30888c7966bSchristos */
30988c7966bSchristos if (fd != -1) {
31088c7966bSchristos error = close(fd);
31188c7966bSchristos ATF_REQUIRE(error == 0);
31288c7966bSchristos }
31388c7966bSchristos }
31488c7966bSchristos
315c0746c1eSchristos ATF_TC(t_spawn_chdir_abs);
316c0746c1eSchristos
ATF_TC_HEAD(t_spawn_chdir_abs,tc)317c0746c1eSchristos ATF_TC_HEAD(t_spawn_chdir_abs, tc)
318c0746c1eSchristos {
319c0746c1eSchristos atf_tc_set_md_var(tc, "descr",
320c0746c1eSchristos "Test posix_spawn_fa_addchdir for absolute path");
321c0746c1eSchristos atf_tc_set_md_var(tc, "require.progs", "/bin/pwd");
322c0746c1eSchristos }
323c0746c1eSchristos
ATF_TC_BODY(t_spawn_chdir_abs,tc)324c0746c1eSchristos ATF_TC_BODY(t_spawn_chdir_abs, tc)
325c0746c1eSchristos {
32688c7966bSchristos spawn_chdir(CHDIRPATH, FILEPATH, 1, 0);
327c0746c1eSchristos
328c0746c1eSchristos /* finally cross check the output of "pwd" directory */
329c0746c1eSchristos check_success(FILEPATH, 0);
330c0746c1eSchristos }
331c0746c1eSchristos
332c0746c1eSchristos ATF_TC(t_spawn_chdir_rel);
333c0746c1eSchristos
ATF_TC_HEAD(t_spawn_chdir_rel,tc)334c0746c1eSchristos ATF_TC_HEAD(t_spawn_chdir_rel, tc)
335c0746c1eSchristos {
336c0746c1eSchristos atf_tc_set_md_var(tc, "descr",
337c0746c1eSchristos "Test posix_spawn_fa_addchdir for relative path");
338c0746c1eSchristos atf_tc_set_md_var(tc, "require.progs", "/bin/pwd");
339c0746c1eSchristos }
340c0746c1eSchristos
341c0746c1eSchristos
ATF_TC_BODY(t_spawn_chdir_rel,tc)342c0746c1eSchristos ATF_TC_BODY(t_spawn_chdir_rel, tc)
343c0746c1eSchristos {
34488c7966bSchristos int error;
345c0746c1eSchristos const char *relative_dir = "ch-dir";
346c0746c1eSchristos const char *testdir = getcwd(NULL, 0);
347c0746c1eSchristos char *chdirwd, *filepath;
348c0746c1eSchristos
349c0746c1eSchristos /* cleanup previous */
350c0746c1eSchristos error = asprintf(&filepath, "%s/%s", relative_dir, FILENAME);
351c0746c1eSchristos ATF_CHECK(error != -1);
352c0746c1eSchristos unlink(filepath);
353c0746c1eSchristos free(filepath);
354c0746c1eSchristos
35588c7966bSchristos rmdir(relative_dir);
356c0746c1eSchristos error = mkdir(relative_dir, 0777);
357c0746c1eSchristos ATF_REQUIRE_MSG(error == 0, "mkdir `%s' (%s)", relative_dir,
358c0746c1eSchristos strerror(errno));
359c0746c1eSchristos
360c0746c1eSchristos error = asprintf(&chdirwd, "%s/%s", testdir, relative_dir);
361c0746c1eSchristos ATF_CHECK(error != -1);
362c0746c1eSchristos
363c0746c1eSchristos error = asprintf(&filepath, "%s/%s", chdirwd, FILENAME);
364c0746c1eSchristos ATF_CHECK(error != -1);
365c0746c1eSchristos
366c0746c1eSchristos #ifdef DEBUG
367c0746c1eSchristos printf("cwd: %s\n", testdir);
368c0746c1eSchristos printf("chdirwd: %s\n", chdirwd);
369c0746c1eSchristos printf("filepath: %s\n", filepath);
370c0746c1eSchristos #endif
371c0746c1eSchristos
37288c7966bSchristos spawn_chdir(relative_dir, filepath, 1, 0);
373c0746c1eSchristos
374c0746c1eSchristos /* finally cross check the directory */
375c0746c1eSchristos check_success(filepath, 1, chdirwd);
376c0746c1eSchristos free(chdirwd);
377c0746c1eSchristos free(filepath);
378c0746c1eSchristos }
379c0746c1eSchristos
380c0746c1eSchristos ATF_TC(t_spawn_chdir_file);
381c0746c1eSchristos
ATF_TC_HEAD(t_spawn_chdir_file,tc)382c0746c1eSchristos ATF_TC_HEAD(t_spawn_chdir_file, tc)
383c0746c1eSchristos {
384c0746c1eSchristos atf_tc_set_md_var(tc, "descr",
385c0746c1eSchristos "Test posix_spawn_fa_addchdir on plain file (not a directory)");
386c0746c1eSchristos atf_tc_set_md_var(tc, "require.progs", "/bin/pwd");
387c0746c1eSchristos }
388c0746c1eSchristos
ATF_TC_BODY(t_spawn_chdir_file,tc)389c0746c1eSchristos ATF_TC_BODY(t_spawn_chdir_file, tc)
390c0746c1eSchristos {
39188c7966bSchristos spawn_chdir(FILEPATH, FILEPATH, 1, ENOTDIR);
392c0746c1eSchristos
393c0746c1eSchristos unlink(FILEPATH);
394c0746c1eSchristos }
395c0746c1eSchristos
396c0746c1eSchristos ATF_TC(t_spawn_chdir_invalid);
397c0746c1eSchristos
ATF_TC_HEAD(t_spawn_chdir_invalid,tc)398c0746c1eSchristos ATF_TC_HEAD(t_spawn_chdir_invalid, tc)
399c0746c1eSchristos {
400c0746c1eSchristos atf_tc_set_md_var(tc, "descr",
401c0746c1eSchristos "Test posix_spawn_fa_addchdir for an invalid dir");
402c0746c1eSchristos atf_tc_set_md_var(tc, "require.progs", "/bin/pwd");
403c0746c1eSchristos }
404c0746c1eSchristos
ATF_TC_BODY(t_spawn_chdir_invalid,tc)405c0746c1eSchristos ATF_TC_BODY(t_spawn_chdir_invalid, tc)
406c0746c1eSchristos {
40788c7966bSchristos spawn_chdir("/not/a/valid/dir", NULL, 1, ENOENT);
408c0746c1eSchristos
409c0746c1eSchristos }
410c0746c1eSchristos
411c0746c1eSchristos ATF_TC(t_spawn_chdir_permissions);
412c0746c1eSchristos
ATF_TC_HEAD(t_spawn_chdir_permissions,tc)413c0746c1eSchristos ATF_TC_HEAD(t_spawn_chdir_permissions, tc)
414c0746c1eSchristos {
415c0746c1eSchristos atf_tc_set_md_var(tc, "descr",
416c0746c1eSchristos "Test posix_spawn_file_actions_addchdir for prohibited directory");
417c0746c1eSchristos atf_tc_set_md_var(tc, "require.progs", "/bin/pwd");
418c0746c1eSchristos atf_tc_set_md_var(tc, "require.user", "unprivileged");
419c0746c1eSchristos }
420c0746c1eSchristos
ATF_TC_BODY(t_spawn_chdir_permissions,tc)421c0746c1eSchristos ATF_TC_BODY(t_spawn_chdir_permissions, tc)
422c0746c1eSchristos {
423c0746c1eSchristos int error;
424c0746c1eSchristos const char *restrRelDir = "prohibited";
425c0746c1eSchristos
42688c7966bSchristos rmdir(restrRelDir);
427c0746c1eSchristos error = mkdir(restrRelDir, 0055);
428c0746c1eSchristos ATF_REQUIRE(error == 0);
429c0746c1eSchristos
43088c7966bSchristos spawn_chdir(restrRelDir, NULL, 1, EACCES);
431c0746c1eSchristos }
432c0746c1eSchristos
433c0746c1eSchristos
43426c0d3c6Schristos ATF_TC(t_spawn_fchdir_abs);
435c0746c1eSchristos
ATF_TC_HEAD(t_spawn_fchdir_abs,tc)43626c0d3c6Schristos ATF_TC_HEAD(t_spawn_fchdir_abs, tc)
437c0746c1eSchristos {
438c0746c1eSchristos atf_tc_set_md_var(tc, "descr", "Test posix_spawn_fa_fchdir");
439c0746c1eSchristos atf_tc_set_md_var(tc, "require.progs", "/bin/pwd");
440c0746c1eSchristos }
441c0746c1eSchristos
ATF_TC_BODY(t_spawn_fchdir_abs,tc)44226c0d3c6Schristos ATF_TC_BODY(t_spawn_fchdir_abs, tc)
443c0746c1eSchristos {
44488c7966bSchristos spawn_chdir(CHDIRPATH, FILEPATH, 2, 0);
445c0746c1eSchristos
446c0746c1eSchristos /* finally cross check the directory */
447c0746c1eSchristos check_success(FILEPATH, 0);
448c0746c1eSchristos }
449c0746c1eSchristos
45026c0d3c6Schristos ATF_TC(t_spawn_fchdir_rel);
451c0746c1eSchristos
ATF_TC_HEAD(t_spawn_fchdir_rel,tc)45226c0d3c6Schristos ATF_TC_HEAD(t_spawn_fchdir_rel, tc)
453c0746c1eSchristos {
454c0746c1eSchristos atf_tc_set_md_var(tc, "descr",
45526c0d3c6Schristos "Testing posix_spawn_file_actions_addfchdir on a relative "
45626c0d3c6Schristos "directory");
457c0746c1eSchristos atf_tc_set_md_var(tc, "require.progs", "/bin/pwd");
458c0746c1eSchristos }
459c0746c1eSchristos
ATF_TC_BODY(t_spawn_fchdir_rel,tc)46026c0d3c6Schristos ATF_TC_BODY(t_spawn_fchdir_rel, tc)
461c0746c1eSchristos {
46288c7966bSchristos int error;
46326c0d3c6Schristos const char *relative_dir = "ch-dir";
46426c0d3c6Schristos const char *testdir = getcwd(NULL, 0);
46526c0d3c6Schristos char *chdirwd, *filepath;
466c0746c1eSchristos
46788c7966bSchristos rmdir(relative_dir);
46826c0d3c6Schristos error = mkdir(relative_dir, 0755);
469c0746c1eSchristos ATF_REQUIRE(error == 0);
470c0746c1eSchristos
47126c0d3c6Schristos /*
47226c0d3c6Schristos * This is done in parts purposely.
473*bc2346d6Sandvar * It enables the abs path of the relative dir
47426c0d3c6Schristos * to be passed to 'check_success()' for comparing
47526c0d3c6Schristos */
47626c0d3c6Schristos error = asprintf(&chdirwd, "%s/%s", testdir, relative_dir);
47726c0d3c6Schristos ATF_CHECK(error != -1);
47826c0d3c6Schristos
47926c0d3c6Schristos error = asprintf(&filepath, "%s/%s", chdirwd, FILENAME);
48026c0d3c6Schristos ATF_CHECK(error != -1);
48126c0d3c6Schristos
48288c7966bSchristos spawn_chdir(relative_dir, filepath, 2, 0);
48326c0d3c6Schristos
48426c0d3c6Schristos /* finally cross check the directory */
48526c0d3c6Schristos check_success(filepath, 1, chdirwd);
48626c0d3c6Schristos free(chdirwd);
48726c0d3c6Schristos free(filepath);
488c0746c1eSchristos }
489c0746c1eSchristos
490c0746c1eSchristos ATF_TC(t_spawn_fchdir_file);
491c0746c1eSchristos
ATF_TC_HEAD(t_spawn_fchdir_file,tc)492c0746c1eSchristos ATF_TC_HEAD(t_spawn_fchdir_file, tc)
493c0746c1eSchristos {
494c0746c1eSchristos atf_tc_set_md_var(tc, "descr",
495c0746c1eSchristos "Testing posix_spawn_file_actions_addfchdir on a "
496c0746c1eSchristos "regular file (not a directory)");
497c0746c1eSchristos atf_tc_set_md_var(tc, "require.progs", "/bin/pwd");
498c0746c1eSchristos }
499c0746c1eSchristos
ATF_TC_BODY(t_spawn_fchdir_file,tc)500c0746c1eSchristos ATF_TC_BODY(t_spawn_fchdir_file, tc)
501c0746c1eSchristos {
502c0746c1eSchristos int error, fd;
503c0746c1eSchristos
504c0746c1eSchristos fd = open(FILEPATH, O_WRONLY | O_CREAT | O_TRUNC, 0644);
505c0746c1eSchristos ATF_REQUIRE_MSG(fd != -1, "Can't open `%s' (%s)", FILEPATH,
506c0746c1eSchristos strerror(errno));
507c0746c1eSchristos
508c0746c1eSchristos error = close(fd);
509c0746c1eSchristos ATF_REQUIRE(error == 0);
510c0746c1eSchristos
51188c7966bSchristos spawn_chdir(FILEPATH, NULL, 2, ENOTDIR);
51288c7966bSchristos
513c0746c1eSchristos unlink(FILEPATH);
514c0746c1eSchristos
515c0746c1eSchristos }
516c0746c1eSchristos
51726c0d3c6Schristos ATF_TC(t_spawn_fchdir_neg_fd);
51826c0d3c6Schristos
ATF_TC_HEAD(t_spawn_fchdir_neg_fd,tc)51926c0d3c6Schristos ATF_TC_HEAD(t_spawn_fchdir_neg_fd, tc)
52026c0d3c6Schristos {
52126c0d3c6Schristos atf_tc_set_md_var(tc, "descr",
52226c0d3c6Schristos "Testing posix_spawn_file_actions_addfchdir on a negative file "
52326c0d3c6Schristos "descriptor");
52426c0d3c6Schristos atf_tc_set_md_var(tc, "require.progs", "/bin/pwd");
52526c0d3c6Schristos }
52626c0d3c6Schristos
ATF_TC_BODY(t_spawn_fchdir_neg_fd,tc)52726c0d3c6Schristos ATF_TC_BODY(t_spawn_fchdir_neg_fd, tc)
52826c0d3c6Schristos {
52926c0d3c6Schristos int error, fd;
53026c0d3c6Schristos posix_spawn_file_actions_t fa;
53126c0d3c6Schristos
53226c0d3c6Schristos fd = -1;
53326c0d3c6Schristos
53426c0d3c6Schristos error = posix_spawn_file_actions_init(&fa);
53526c0d3c6Schristos ATF_REQUIRE(error == 0);
53626c0d3c6Schristos
53726c0d3c6Schristos error = posix_spawn_file_actions_addfchdir(&fa, fd);
53826c0d3c6Schristos ATF_REQUIRE(error == EBADF);
53926c0d3c6Schristos
54026c0d3c6Schristos posix_spawn_file_actions_destroy(&fa);
54126c0d3c6Schristos }
54226c0d3c6Schristos
54326c0d3c6Schristos ATF_TC(t_spawn_fchdir_closed);
54426c0d3c6Schristos
ATF_TC_HEAD(t_spawn_fchdir_closed,tc)54526c0d3c6Schristos ATF_TC_HEAD(t_spawn_fchdir_closed, tc)
54626c0d3c6Schristos {
54726c0d3c6Schristos atf_tc_set_md_var(tc, "descr",
54826c0d3c6Schristos "Testing posix_spawn_file_actions_addfchdir for a closed fd");
54926c0d3c6Schristos atf_tc_set_md_var(tc, "require.progs", "/bin/pwd");
55026c0d3c6Schristos }
55126c0d3c6Schristos
ATF_TC_BODY(t_spawn_fchdir_closed,tc)55226c0d3c6Schristos ATF_TC_BODY(t_spawn_fchdir_closed, tc)
55326c0d3c6Schristos {
55426c0d3c6Schristos int error, fd;
55526c0d3c6Schristos pid_t pid;
55626c0d3c6Schristos char * const args[2] = { __UNCONST("pwd"), NULL };
55726c0d3c6Schristos posix_spawnattr_t attr;
55826c0d3c6Schristos posix_spawn_file_actions_t fa;
55926c0d3c6Schristos
56026c0d3c6Schristos fd = 3;
56126c0d3c6Schristos error = posix_spawnattr_init(&attr);
56226c0d3c6Schristos ATF_CHECK(error == 0);
56326c0d3c6Schristos /*
56426c0d3c6Schristos * POSIX_SPAWN_RETURNERROR is a NetBSD specific flag that
56526c0d3c6Schristos * will cause a "proper" return value from posix_spawn(2)
56626c0d3c6Schristos * instead of a (potential) success there and a 127 exit
56726c0d3c6Schristos * status from the child process (c.f. the non-diag variant
56826c0d3c6Schristos * of this test).
56926c0d3c6Schristos */
57026c0d3c6Schristos error = posix_spawnattr_setflags(&attr, POSIX_SPAWN_RETURNERROR);
57126c0d3c6Schristos ATF_REQUIRE(error == 0);
57226c0d3c6Schristos
57326c0d3c6Schristos error = posix_spawn_file_actions_init(&fa);
57426c0d3c6Schristos ATF_REQUIRE(error == 0);
57526c0d3c6Schristos
57626c0d3c6Schristos error = posix_spawn_file_actions_addfchdir(&fa, fd);
57726c0d3c6Schristos ATF_REQUIRE(error == 0);
57826c0d3c6Schristos
57926c0d3c6Schristos error = posix_spawn(&pid, "/bin/pwd", &fa, &attr, args, NULL);
58026c0d3c6Schristos ATF_REQUIRE(error == EBADF);
58126c0d3c6Schristos
58226c0d3c6Schristos posix_spawn_file_actions_destroy(&fa);
58326c0d3c6Schristos posix_spawnattr_destroy(&attr);
58426c0d3c6Schristos }
58526c0d3c6Schristos
5861aef28daSchristos #undef CHDIR
5871aef28daSchristos #undef FCHDIR
588c0746c1eSchristos #undef CHDIRPATH
589c0746c1eSchristos #undef FILENAME
590c0746c1eSchristos #undef FILEPATH
591c0746c1eSchristos
ATF_TP_ADD_TCS(tp)5920ce98f42Smartin ATF_TP_ADD_TCS(tp)
5930ce98f42Smartin {
5940ce98f42Smartin ATF_TP_ADD_TC(tp, t_spawn_ls);
5950ce98f42Smartin ATF_TP_ADD_TC(tp, t_spawnp_ls);
5960ce98f42Smartin ATF_TP_ADD_TC(tp, t_spawn_zero);
5970ce98f42Smartin ATF_TP_ADD_TC(tp, t_spawn_missing);
5980ce98f42Smartin ATF_TP_ADD_TC(tp, t_spawn_nonexec);
5990ce98f42Smartin ATF_TP_ADD_TC(tp, t_spawn_child);
600c0746c1eSchristos ATF_TP_ADD_TC(tp, t_spawn_chdir_abs);
601c0746c1eSchristos ATF_TP_ADD_TC(tp, t_spawn_chdir_rel);
602c0746c1eSchristos ATF_TP_ADD_TC(tp, t_spawn_chdir_file);
603c0746c1eSchristos ATF_TP_ADD_TC(tp, t_spawn_chdir_invalid);
604c0746c1eSchristos ATF_TP_ADD_TC(tp, t_spawn_chdir_permissions);
60526c0d3c6Schristos ATF_TP_ADD_TC(tp, t_spawn_fchdir_abs);
60626c0d3c6Schristos ATF_TP_ADD_TC(tp, t_spawn_fchdir_rel);
60726c0d3c6Schristos ATF_TP_ADD_TC(tp, t_spawn_fchdir_file);
608c0746c1eSchristos ATF_TP_ADD_TC(tp, t_spawn_fchdir_neg_fd);
609c0746c1eSchristos ATF_TP_ADD_TC(tp, t_spawn_fchdir_closed);
6100ce98f42Smartin
6110ce98f42Smartin return atf_no_error();
6120ce98f42Smartin }
613