1ddba0402SEnji Cooper /* $NetBSD: t_fileactions.c,v 1.6 2017/01/10 22:36:29 christos Exp $ */
257718be8SEnji Cooper
357718be8SEnji Cooper /*-
457718be8SEnji Cooper * Copyright (c) 2012 The NetBSD Foundation, Inc.
557718be8SEnji Cooper * All rights reserved.
657718be8SEnji Cooper *
757718be8SEnji Cooper * This code is derived from software contributed to The NetBSD Foundation
857718be8SEnji Cooper * by Charles Zhang <charles@NetBSD.org> and
957718be8SEnji Cooper * Martin Husemann <martin@NetBSD.org>.
1057718be8SEnji Cooper *
1157718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without
1257718be8SEnji Cooper * modification, are permitted provided that the following conditions
1357718be8SEnji Cooper * are met:
1457718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright
1557718be8SEnji Cooper * notice, this list of conditions and the following disclaimer.
1657718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright
1757718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the
1857718be8SEnji Cooper * documentation and/or other materials provided with the distribution.
1957718be8SEnji Cooper *
2057718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2157718be8SEnji Cooper * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2257718be8SEnji Cooper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2357718be8SEnji Cooper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2457718be8SEnji Cooper * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2557718be8SEnji Cooper * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2657718be8SEnji Cooper * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2757718be8SEnji Cooper * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2857718be8SEnji Cooper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2957718be8SEnji Cooper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3057718be8SEnji Cooper * POSSIBILITY OF SUCH DAMAGE.
3157718be8SEnji Cooper */
3257718be8SEnji Cooper
3357718be8SEnji Cooper
3457718be8SEnji Cooper #include <atf-c.h>
35ddba0402SEnji Cooper
36ddba0402SEnji Cooper #include <sys/wait.h>
37ddba0402SEnji Cooper #include <sys/stat.h>
38ddba0402SEnji Cooper
3957718be8SEnji Cooper #include <stdio.h>
4057718be8SEnji Cooper #include <stdlib.h>
4157718be8SEnji Cooper #include <string.h>
4257718be8SEnji Cooper #include <errno.h>
4357718be8SEnji Cooper #include <fcntl.h>
4457718be8SEnji Cooper #include <spawn.h>
4557718be8SEnji Cooper #include <unistd.h>
4657718be8SEnji Cooper
4757718be8SEnji Cooper
4857718be8SEnji Cooper ATF_TC(t_spawn_openmode);
4957718be8SEnji Cooper
ATF_TC_HEAD(t_spawn_openmode,tc)5057718be8SEnji Cooper ATF_TC_HEAD(t_spawn_openmode, tc)
5157718be8SEnji Cooper {
5257718be8SEnji Cooper atf_tc_set_md_var(tc, "descr",
5357718be8SEnji Cooper "Test the proper handling of 'mode' for 'open' fileactions");
5457718be8SEnji Cooper atf_tc_set_md_var(tc, "require.progs", "/bin/cat");
5557718be8SEnji Cooper }
5657718be8SEnji Cooper
5757718be8SEnji Cooper static off_t
filesize(const char * restrict fname)5857718be8SEnji Cooper filesize(const char * restrict fname)
5957718be8SEnji Cooper {
6057718be8SEnji Cooper struct stat st;
6157718be8SEnji Cooper int err;
6257718be8SEnji Cooper
6357718be8SEnji Cooper err = stat(fname, &st);
6457718be8SEnji Cooper ATF_REQUIRE(err == 0);
6557718be8SEnji Cooper return st.st_size;
6657718be8SEnji Cooper }
6757718be8SEnji Cooper
6857718be8SEnji Cooper #define TESTFILE "./the_input_data"
6957718be8SEnji Cooper #define CHECKFILE "./the_output_data"
7057718be8SEnji Cooper #define TESTCONTENT "marry has a little lamb"
7157718be8SEnji Cooper
7257718be8SEnji Cooper static void
make_testfile(const char * restrict file)7357718be8SEnji Cooper make_testfile(const char *restrict file)
7457718be8SEnji Cooper {
7557718be8SEnji Cooper FILE *f;
7657718be8SEnji Cooper size_t written;
7757718be8SEnji Cooper
7857718be8SEnji Cooper f = fopen(file, "w");
7957718be8SEnji Cooper ATF_REQUIRE(f != NULL);
8057718be8SEnji Cooper written = fwrite(TESTCONTENT, 1, strlen(TESTCONTENT), f);
8157718be8SEnji Cooper fclose(f);
8257718be8SEnji Cooper ATF_REQUIRE(written == strlen(TESTCONTENT));
8357718be8SEnji Cooper }
8457718be8SEnji Cooper
8557718be8SEnji Cooper static void
empty_outfile(const char * restrict filename)8657718be8SEnji Cooper empty_outfile(const char *restrict filename)
8757718be8SEnji Cooper {
8857718be8SEnji Cooper FILE *f;
8957718be8SEnji Cooper
9057718be8SEnji Cooper f = fopen(filename, "w");
9157718be8SEnji Cooper ATF_REQUIRE(f != NULL);
9257718be8SEnji Cooper fclose(f);
9357718be8SEnji Cooper }
9457718be8SEnji Cooper
ATF_TC_BODY(t_spawn_openmode,tc)9557718be8SEnji Cooper ATF_TC_BODY(t_spawn_openmode, tc)
9657718be8SEnji Cooper {
9757718be8SEnji Cooper int status, err;
9857718be8SEnji Cooper pid_t pid;
9957718be8SEnji Cooper size_t insize, outsize;
10057718be8SEnji Cooper char * const args[2] = { __UNCONST("cat"), NULL };
10157718be8SEnji Cooper posix_spawn_file_actions_t fa;
10257718be8SEnji Cooper
10357718be8SEnji Cooper /*
10457718be8SEnji Cooper * try a "cat < testfile > checkfile"
10557718be8SEnji Cooper */
10657718be8SEnji Cooper make_testfile(TESTFILE);
10757718be8SEnji Cooper unlink(CHECKFILE);
10857718be8SEnji Cooper
10957718be8SEnji Cooper posix_spawn_file_actions_init(&fa);
11057718be8SEnji Cooper posix_spawn_file_actions_addopen(&fa, fileno(stdin),
11157718be8SEnji Cooper TESTFILE, O_RDONLY, 0);
11257718be8SEnji Cooper posix_spawn_file_actions_addopen(&fa, fileno(stdout),
11357718be8SEnji Cooper CHECKFILE, O_WRONLY|O_CREAT, 0600);
11457718be8SEnji Cooper err = posix_spawn(&pid, "/bin/cat", &fa, NULL, args, NULL);
11557718be8SEnji Cooper posix_spawn_file_actions_destroy(&fa);
11657718be8SEnji Cooper
11757718be8SEnji Cooper ATF_REQUIRE(err == 0);
11857718be8SEnji Cooper
11957718be8SEnji Cooper /* ok, wait for the child to finish */
12057718be8SEnji Cooper waitpid(pid, &status, 0);
12157718be8SEnji Cooper ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS);
12257718be8SEnji Cooper
12357718be8SEnji Cooper /* now check that input and output have the same size */
12457718be8SEnji Cooper insize = filesize(TESTFILE);
12557718be8SEnji Cooper outsize = filesize(CHECKFILE);
12657718be8SEnji Cooper ATF_REQUIRE(insize == strlen(TESTCONTENT));
12757718be8SEnji Cooper ATF_REQUIRE(insize == outsize);
12857718be8SEnji Cooper
12957718be8SEnji Cooper /*
13057718be8SEnji Cooper * try a "cat < testfile >> checkfile"
13157718be8SEnji Cooper */
13257718be8SEnji Cooper make_testfile(TESTFILE);
13357718be8SEnji Cooper make_testfile(CHECKFILE);
13457718be8SEnji Cooper
13557718be8SEnji Cooper posix_spawn_file_actions_init(&fa);
13657718be8SEnji Cooper posix_spawn_file_actions_addopen(&fa, fileno(stdin),
13757718be8SEnji Cooper TESTFILE, O_RDONLY, 0);
13857718be8SEnji Cooper posix_spawn_file_actions_addopen(&fa, fileno(stdout),
13957718be8SEnji Cooper CHECKFILE, O_WRONLY|O_APPEND, 0);
14057718be8SEnji Cooper err = posix_spawn(&pid, "/bin/cat", &fa, NULL, args, NULL);
14157718be8SEnji Cooper posix_spawn_file_actions_destroy(&fa);
14257718be8SEnji Cooper
14357718be8SEnji Cooper ATF_REQUIRE(err == 0);
14457718be8SEnji Cooper
14557718be8SEnji Cooper /* ok, wait for the child to finish */
14657718be8SEnji Cooper waitpid(pid, &status, 0);
14757718be8SEnji Cooper ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS);
14857718be8SEnji Cooper
14957718be8SEnji Cooper /* now check that output is twice as long as input */
15057718be8SEnji Cooper insize = filesize(TESTFILE);
15157718be8SEnji Cooper outsize = filesize(CHECKFILE);
15257718be8SEnji Cooper ATF_REQUIRE(insize == strlen(TESTCONTENT));
15357718be8SEnji Cooper ATF_REQUIRE(insize*2 == outsize);
15457718be8SEnji Cooper
15557718be8SEnji Cooper /*
15657718be8SEnji Cooper * try a "cat < testfile > checkfile" with input and output swapped
15757718be8SEnji Cooper */
15857718be8SEnji Cooper make_testfile(TESTFILE);
15957718be8SEnji Cooper empty_outfile(CHECKFILE);
16057718be8SEnji Cooper
16157718be8SEnji Cooper posix_spawn_file_actions_init(&fa);
16257718be8SEnji Cooper posix_spawn_file_actions_addopen(&fa, fileno(stdout),
16357718be8SEnji Cooper TESTFILE, O_RDONLY, 0);
16457718be8SEnji Cooper posix_spawn_file_actions_addopen(&fa, fileno(stdin),
16557718be8SEnji Cooper CHECKFILE, O_WRONLY, 0);
16657718be8SEnji Cooper err = posix_spawn(&pid, "/bin/cat", &fa, NULL, args, NULL);
16757718be8SEnji Cooper posix_spawn_file_actions_destroy(&fa);
16857718be8SEnji Cooper
16957718be8SEnji Cooper ATF_REQUIRE(err == 0);
17057718be8SEnji Cooper
17157718be8SEnji Cooper /* ok, wait for the child to finish */
17257718be8SEnji Cooper waitpid(pid, &status, 0);
17357718be8SEnji Cooper ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_FAILURE);
17457718be8SEnji Cooper
17557718be8SEnji Cooper /* now check that input and output are still the same size */
17657718be8SEnji Cooper insize = filesize(TESTFILE);
17757718be8SEnji Cooper outsize = filesize(CHECKFILE);
17857718be8SEnji Cooper ATF_REQUIRE(insize == strlen(TESTCONTENT));
17957718be8SEnji Cooper ATF_REQUIRE(outsize == 0);
18057718be8SEnji Cooper }
18157718be8SEnji Cooper
18257718be8SEnji Cooper ATF_TC(t_spawn_reopen);
18357718be8SEnji Cooper
ATF_TC_HEAD(t_spawn_reopen,tc)18457718be8SEnji Cooper ATF_TC_HEAD(t_spawn_reopen, tc)
18557718be8SEnji Cooper {
18657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr",
18757718be8SEnji Cooper "an open filehandle can be replaced by a 'open' fileaction");
18857718be8SEnji Cooper atf_tc_set_md_var(tc, "require.progs", "/bin/cat");
18957718be8SEnji Cooper }
19057718be8SEnji Cooper
ATF_TC_BODY(t_spawn_reopen,tc)19157718be8SEnji Cooper ATF_TC_BODY(t_spawn_reopen, tc)
19257718be8SEnji Cooper {
19357718be8SEnji Cooper int status, err;
19457718be8SEnji Cooper pid_t pid;
19557718be8SEnji Cooper char * const args[2] = { __UNCONST("cat"), NULL };
19657718be8SEnji Cooper posix_spawn_file_actions_t fa;
19757718be8SEnji Cooper
19857718be8SEnji Cooper /*
19957718be8SEnji Cooper * make sure stdin is open in the parent
20057718be8SEnji Cooper */
20157718be8SEnji Cooper freopen("/dev/zero", "r", stdin);
20257718be8SEnji Cooper /*
20357718be8SEnji Cooper * now request an open for this fd again in the child
20457718be8SEnji Cooper */
20557718be8SEnji Cooper posix_spawn_file_actions_init(&fa);
20657718be8SEnji Cooper posix_spawn_file_actions_addopen(&fa, fileno(stdin),
20757718be8SEnji Cooper "/dev/null", O_RDONLY, 0);
20857718be8SEnji Cooper err = posix_spawn(&pid, "/bin/cat", &fa, NULL, args, NULL);
20957718be8SEnji Cooper posix_spawn_file_actions_destroy(&fa);
21057718be8SEnji Cooper
21157718be8SEnji Cooper ATF_REQUIRE(err == 0);
21257718be8SEnji Cooper
21357718be8SEnji Cooper waitpid(pid, &status, 0);
21457718be8SEnji Cooper ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS);
21557718be8SEnji Cooper }
21657718be8SEnji Cooper
21757718be8SEnji Cooper ATF_TC(t_spawn_open_nonexistent);
21857718be8SEnji Cooper
ATF_TC_HEAD(t_spawn_open_nonexistent,tc)21957718be8SEnji Cooper ATF_TC_HEAD(t_spawn_open_nonexistent, tc)
22057718be8SEnji Cooper {
22157718be8SEnji Cooper atf_tc_set_md_var(tc, "descr",
22257718be8SEnji Cooper "posix_spawn fails when a file to open does not exist");
22357718be8SEnji Cooper atf_tc_set_md_var(tc, "require.progs", "/bin/cat");
22457718be8SEnji Cooper }
22557718be8SEnji Cooper
ATF_TC_BODY(t_spawn_open_nonexistent,tc)22657718be8SEnji Cooper ATF_TC_BODY(t_spawn_open_nonexistent, tc)
22757718be8SEnji Cooper {
22857718be8SEnji Cooper int err, status;
22957718be8SEnji Cooper pid_t pid;
23057718be8SEnji Cooper char * const args[2] = { __UNCONST("cat"), NULL };
23157718be8SEnji Cooper posix_spawn_file_actions_t fa;
23257718be8SEnji Cooper
23357718be8SEnji Cooper posix_spawn_file_actions_init(&fa);
23457718be8SEnji Cooper posix_spawn_file_actions_addopen(&fa, STDIN_FILENO,
23557718be8SEnji Cooper "./non/ex/ist/ent", O_RDONLY, 0);
23657718be8SEnji Cooper err = posix_spawn(&pid, "/bin/cat", &fa, NULL, args, NULL);
23757718be8SEnji Cooper if (err == 0) {
23857718be8SEnji Cooper /*
23957718be8SEnji Cooper * The child has been created - it should fail and
24057718be8SEnji Cooper * return exit code 127
24157718be8SEnji Cooper */
24257718be8SEnji Cooper waitpid(pid, &status, 0);
24357718be8SEnji Cooper ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 127);
24457718be8SEnji Cooper } else {
24557718be8SEnji Cooper /*
24657718be8SEnji Cooper * The error has been noticed early enough, no child has
24757718be8SEnji Cooper * been run
24857718be8SEnji Cooper */
24957718be8SEnji Cooper ATF_REQUIRE(err == ENOENT);
25057718be8SEnji Cooper }
25157718be8SEnji Cooper posix_spawn_file_actions_destroy(&fa);
25257718be8SEnji Cooper }
25357718be8SEnji Cooper
254ff0ba872SEnji Cooper #ifdef __NetBSD__
25557718be8SEnji Cooper ATF_TC(t_spawn_open_nonexistent_diag);
25657718be8SEnji Cooper
ATF_TC_HEAD(t_spawn_open_nonexistent_diag,tc)25757718be8SEnji Cooper ATF_TC_HEAD(t_spawn_open_nonexistent_diag, tc)
25857718be8SEnji Cooper {
25957718be8SEnji Cooper atf_tc_set_md_var(tc, "descr",
26057718be8SEnji Cooper "posix_spawn fails when a file to open does not exist "
26157718be8SEnji Cooper "and delivers proper diagnostic");
26257718be8SEnji Cooper atf_tc_set_md_var(tc, "require.progs", "/bin/cat");
26357718be8SEnji Cooper }
26457718be8SEnji Cooper
ATF_TC_BODY(t_spawn_open_nonexistent_diag,tc)26557718be8SEnji Cooper ATF_TC_BODY(t_spawn_open_nonexistent_diag, tc)
26657718be8SEnji Cooper {
26757718be8SEnji Cooper int err;
26857718be8SEnji Cooper pid_t pid;
26957718be8SEnji Cooper char * const args[2] = { __UNCONST("cat"), NULL };
27057718be8SEnji Cooper posix_spawnattr_t attr;
27157718be8SEnji Cooper posix_spawn_file_actions_t fa;
27257718be8SEnji Cooper
27357718be8SEnji Cooper posix_spawnattr_init(&attr);
27457718be8SEnji Cooper /*
27557718be8SEnji Cooper * POSIX_SPAWN_RETURNERROR is a NetBSD specific flag that
27657718be8SEnji Cooper * will cause a "proper" return value from posix_spawn(2)
27757718be8SEnji Cooper * instead of a (potential) success there and a 127 exit
27857718be8SEnji Cooper * status from the child process (c.f. the non-diag variant
27957718be8SEnji Cooper * of this test).
28057718be8SEnji Cooper */
28157718be8SEnji Cooper posix_spawnattr_setflags(&attr, POSIX_SPAWN_RETURNERROR);
28257718be8SEnji Cooper posix_spawn_file_actions_init(&fa);
28357718be8SEnji Cooper posix_spawn_file_actions_addopen(&fa, STDIN_FILENO,
28457718be8SEnji Cooper "./non/ex/ist/ent", O_RDONLY, 0);
28557718be8SEnji Cooper err = posix_spawn(&pid, "/bin/cat", &fa, &attr, args, NULL);
28657718be8SEnji Cooper ATF_REQUIRE(err == ENOENT);
28757718be8SEnji Cooper posix_spawn_file_actions_destroy(&fa);
28857718be8SEnji Cooper posix_spawnattr_destroy(&attr);
28957718be8SEnji Cooper }
2901068aa42SEnji Cooper #endif
29157718be8SEnji Cooper
29257718be8SEnji Cooper ATF_TC(t_spawn_fileactions);
29357718be8SEnji Cooper
ATF_TC_HEAD(t_spawn_fileactions,tc)29457718be8SEnji Cooper ATF_TC_HEAD(t_spawn_fileactions, tc)
29557718be8SEnji Cooper {
29657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr",
29757718be8SEnji Cooper "Tests various complex fileactions");
29857718be8SEnji Cooper }
29957718be8SEnji Cooper
ATF_TC_BODY(t_spawn_fileactions,tc)30057718be8SEnji Cooper ATF_TC_BODY(t_spawn_fileactions, tc)
30157718be8SEnji Cooper {
30257718be8SEnji Cooper int fd1, fd2, fd3, status, err;
30357718be8SEnji Cooper pid_t pid;
3042aa3ef28SAlex Richardson char *args[3] = { __UNCONST("h_fileactions"), NULL, NULL };
3052aa3ef28SAlex Richardson int lowfd;
3062aa3ef28SAlex Richardson char lowfdstr[32];
30757718be8SEnji Cooper char helper[FILENAME_MAX];
30857718be8SEnji Cooper posix_spawn_file_actions_t fa;
30957718be8SEnji Cooper
31057718be8SEnji Cooper posix_spawn_file_actions_init(&fa);
31157718be8SEnji Cooper
3122aa3ef28SAlex Richardson /* Note: this assumes no gaps in the fd table */
3132aa3ef28SAlex Richardson lowfd = open("/", O_RDONLY);
3142aa3ef28SAlex Richardson ATF_REQUIRE(lowfd > 0);
3152aa3ef28SAlex Richardson ATF_REQUIRE_EQ(0, close(lowfd));
3162aa3ef28SAlex Richardson snprintf(lowfdstr, sizeof(lowfdstr), "%d", lowfd);
3172aa3ef28SAlex Richardson args[1] = lowfdstr;
31857718be8SEnji Cooper
31957718be8SEnji Cooper fd1 = open("/dev/null", O_RDONLY);
3202aa3ef28SAlex Richardson ATF_REQUIRE_EQ(fd1, lowfd);
32157718be8SEnji Cooper
32257718be8SEnji Cooper fd2 = open("/dev/null", O_WRONLY, O_CLOEXEC);
3232aa3ef28SAlex Richardson ATF_REQUIRE_EQ(fd2, lowfd + 1);
32457718be8SEnji Cooper
32557718be8SEnji Cooper fd3 = open("/dev/null", O_WRONLY);
3262aa3ef28SAlex Richardson ATF_REQUIRE_EQ(fd3, lowfd + 2);
32757718be8SEnji Cooper
32857718be8SEnji Cooper posix_spawn_file_actions_addclose(&fa, fd1);
3292aa3ef28SAlex Richardson posix_spawn_file_actions_addopen(&fa, lowfd + 3, "/dev/null", O_RDWR,
3302aa3ef28SAlex Richardson 0);
3312aa3ef28SAlex Richardson posix_spawn_file_actions_adddup2(&fa, 1, lowfd + 4);
33257718be8SEnji Cooper
33357718be8SEnji Cooper snprintf(helper, sizeof helper, "%s/h_fileactions",
33457718be8SEnji Cooper atf_tc_get_config_var(tc, "srcdir"));
33557718be8SEnji Cooper err = posix_spawn(&pid, helper, &fa, NULL, args, NULL);
33657718be8SEnji Cooper posix_spawn_file_actions_destroy(&fa);
33757718be8SEnji Cooper
33857718be8SEnji Cooper ATF_REQUIRE(err == 0);
33957718be8SEnji Cooper
34057718be8SEnji Cooper waitpid(pid, &status, 0);
34157718be8SEnji Cooper ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS);
34257718be8SEnji Cooper }
34357718be8SEnji Cooper
34457718be8SEnji Cooper ATF_TC(t_spawn_empty_fileactions);
34557718be8SEnji Cooper
ATF_TC_HEAD(t_spawn_empty_fileactions,tc)34657718be8SEnji Cooper ATF_TC_HEAD(t_spawn_empty_fileactions, tc)
34757718be8SEnji Cooper {
34857718be8SEnji Cooper atf_tc_set_md_var(tc, "descr",
34957718be8SEnji Cooper "posix_spawn with empty fileactions (PR kern/46038)");
35057718be8SEnji Cooper atf_tc_set_md_var(tc, "require.progs", "/bin/cat");
35157718be8SEnji Cooper }
35257718be8SEnji Cooper
ATF_TC_BODY(t_spawn_empty_fileactions,tc)35357718be8SEnji Cooper ATF_TC_BODY(t_spawn_empty_fileactions, tc)
35457718be8SEnji Cooper {
35557718be8SEnji Cooper int status, err;
35657718be8SEnji Cooper pid_t pid;
35757718be8SEnji Cooper char * const args[2] = { __UNCONST("cat"), NULL };
35857718be8SEnji Cooper posix_spawn_file_actions_t fa;
35957718be8SEnji Cooper size_t insize, outsize;
36057718be8SEnji Cooper
36157718be8SEnji Cooper /*
36257718be8SEnji Cooper * try a "cat < testfile > checkfile", but set up stdin/stdout
36357718be8SEnji Cooper * already in the parent and pass empty file actions to the child.
36457718be8SEnji Cooper */
36557718be8SEnji Cooper make_testfile(TESTFILE);
36657718be8SEnji Cooper unlink(CHECKFILE);
36757718be8SEnji Cooper
36857718be8SEnji Cooper freopen(TESTFILE, "r", stdin);
36957718be8SEnji Cooper freopen(CHECKFILE, "w", stdout);
37057718be8SEnji Cooper
37157718be8SEnji Cooper posix_spawn_file_actions_init(&fa);
37257718be8SEnji Cooper err = posix_spawn(&pid, "/bin/cat", &fa, NULL, args, NULL);
37357718be8SEnji Cooper posix_spawn_file_actions_destroy(&fa);
37457718be8SEnji Cooper
37557718be8SEnji Cooper ATF_REQUIRE(err == 0);
37657718be8SEnji Cooper
37757718be8SEnji Cooper /* ok, wait for the child to finish */
37857718be8SEnji Cooper waitpid(pid, &status, 0);
37957718be8SEnji Cooper ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS);
38057718be8SEnji Cooper
38157718be8SEnji Cooper /* now check that input and output have the same size */
38257718be8SEnji Cooper insize = filesize(TESTFILE);
38357718be8SEnji Cooper outsize = filesize(CHECKFILE);
38457718be8SEnji Cooper ATF_REQUIRE(insize == strlen(TESTCONTENT));
38557718be8SEnji Cooper ATF_REQUIRE(insize == outsize);
38657718be8SEnji Cooper }
38757718be8SEnji Cooper
388*f16ec9c6SKonstantin Belousov static const char bin_pwd[] = "/bin/pwd";
389*f16ec9c6SKonstantin Belousov
390*f16ec9c6SKonstantin Belousov static void
t_spawn_chdir_impl(bool chdir)391*f16ec9c6SKonstantin Belousov t_spawn_chdir_impl(bool chdir)
392*f16ec9c6SKonstantin Belousov {
393*f16ec9c6SKonstantin Belousov int status, err, tmpdir_fd;
394*f16ec9c6SKonstantin Belousov pid_t pid;
395*f16ec9c6SKonstantin Belousov char * const args[2] = { __UNCONST("pwd"), NULL };
396*f16ec9c6SKonstantin Belousov posix_spawn_file_actions_t fa;
397*f16ec9c6SKonstantin Belousov FILE *f;
398*f16ec9c6SKonstantin Belousov char read_pwd[128];
399*f16ec9c6SKonstantin Belousov size_t ss;
400*f16ec9c6SKonstantin Belousov static const char tmp_path[] = "/tmp";
401*f16ec9c6SKonstantin Belousov
402*f16ec9c6SKonstantin Belousov unlink(TESTFILE);
403*f16ec9c6SKonstantin Belousov
404*f16ec9c6SKonstantin Belousov posix_spawn_file_actions_init(&fa);
405*f16ec9c6SKonstantin Belousov posix_spawn_file_actions_addopen(&fa, fileno(stdout),
406*f16ec9c6SKonstantin Belousov TESTFILE, O_WRONLY | O_CREAT, 0600);
407*f16ec9c6SKonstantin Belousov if (chdir) {
408*f16ec9c6SKonstantin Belousov ATF_REQUIRE(posix_spawn_file_actions_addchdir_np(&fa,
409*f16ec9c6SKonstantin Belousov tmp_path) == 0);
410*f16ec9c6SKonstantin Belousov } else {
411*f16ec9c6SKonstantin Belousov tmpdir_fd = open(tmp_path, O_DIRECTORY | O_RDONLY);
412*f16ec9c6SKonstantin Belousov ATF_REQUIRE(tmpdir_fd > 0);
413*f16ec9c6SKonstantin Belousov ATF_REQUIRE(posix_spawn_file_actions_addfchdir_np(&fa,
414*f16ec9c6SKonstantin Belousov tmpdir_fd) == 0);
415*f16ec9c6SKonstantin Belousov }
416*f16ec9c6SKonstantin Belousov err = posix_spawn(&pid, bin_pwd, &fa, NULL, args, NULL);
417*f16ec9c6SKonstantin Belousov posix_spawn_file_actions_destroy(&fa);
418*f16ec9c6SKonstantin Belousov if (!chdir)
419*f16ec9c6SKonstantin Belousov close(tmpdir_fd);
420*f16ec9c6SKonstantin Belousov
421*f16ec9c6SKonstantin Belousov ATF_REQUIRE(err == 0);
422*f16ec9c6SKonstantin Belousov waitpid(pid, &status, 0);
423*f16ec9c6SKonstantin Belousov ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS);
424*f16ec9c6SKonstantin Belousov
425*f16ec9c6SKonstantin Belousov f = fopen(TESTFILE, "r");
426*f16ec9c6SKonstantin Belousov ATF_REQUIRE(f != NULL);
427*f16ec9c6SKonstantin Belousov ss = fread(read_pwd, 1, sizeof(read_pwd), f);
428*f16ec9c6SKonstantin Belousov fclose(f);
429*f16ec9c6SKonstantin Belousov ATF_REQUIRE(ss == strlen(tmp_path) + 1);
430*f16ec9c6SKonstantin Belousov ATF_REQUIRE(strncmp(read_pwd, tmp_path, strlen(tmp_path)) == 0);
431*f16ec9c6SKonstantin Belousov }
432*f16ec9c6SKonstantin Belousov
433*f16ec9c6SKonstantin Belousov ATF_TC(t_spawn_chdir);
434*f16ec9c6SKonstantin Belousov
ATF_TC_HEAD(t_spawn_chdir,tc)435*f16ec9c6SKonstantin Belousov ATF_TC_HEAD(t_spawn_chdir, tc)
436*f16ec9c6SKonstantin Belousov {
437*f16ec9c6SKonstantin Belousov atf_tc_set_md_var(tc, "descr",
438*f16ec9c6SKonstantin Belousov "posix_spawn changes directory for the spawned program");
439*f16ec9c6SKonstantin Belousov atf_tc_set_md_var(tc, "require.progs", bin_pwd);
440*f16ec9c6SKonstantin Belousov }
441*f16ec9c6SKonstantin Belousov
ATF_TC_BODY(t_spawn_chdir,tc)442*f16ec9c6SKonstantin Belousov ATF_TC_BODY(t_spawn_chdir, tc)
443*f16ec9c6SKonstantin Belousov {
444*f16ec9c6SKonstantin Belousov t_spawn_chdir_impl(true);
445*f16ec9c6SKonstantin Belousov }
446*f16ec9c6SKonstantin Belousov
447*f16ec9c6SKonstantin Belousov ATF_TC(t_spawn_fchdir);
448*f16ec9c6SKonstantin Belousov
ATF_TC_HEAD(t_spawn_fchdir,tc)449*f16ec9c6SKonstantin Belousov ATF_TC_HEAD(t_spawn_fchdir, tc)
450*f16ec9c6SKonstantin Belousov {
451*f16ec9c6SKonstantin Belousov atf_tc_set_md_var(tc, "descr",
452*f16ec9c6SKonstantin Belousov "posix_spawn changes directory for the spawned program");
453*f16ec9c6SKonstantin Belousov atf_tc_set_md_var(tc, "require.progs", bin_pwd);
454*f16ec9c6SKonstantin Belousov }
455*f16ec9c6SKonstantin Belousov
ATF_TC_BODY(t_spawn_fchdir,tc)456*f16ec9c6SKonstantin Belousov ATF_TC_BODY(t_spawn_fchdir, tc)
457*f16ec9c6SKonstantin Belousov {
458*f16ec9c6SKonstantin Belousov t_spawn_chdir_impl(false);
459*f16ec9c6SKonstantin Belousov }
460*f16ec9c6SKonstantin Belousov
ATF_TP_ADD_TCS(tp)46157718be8SEnji Cooper ATF_TP_ADD_TCS(tp)
46257718be8SEnji Cooper {
46357718be8SEnji Cooper ATF_TP_ADD_TC(tp, t_spawn_fileactions);
46457718be8SEnji Cooper ATF_TP_ADD_TC(tp, t_spawn_open_nonexistent);
465ff0ba872SEnji Cooper #ifdef __NetBSD__
46657718be8SEnji Cooper ATF_TP_ADD_TC(tp, t_spawn_open_nonexistent_diag);
4671068aa42SEnji Cooper #endif
46857718be8SEnji Cooper ATF_TP_ADD_TC(tp, t_spawn_reopen);
46957718be8SEnji Cooper ATF_TP_ADD_TC(tp, t_spawn_openmode);
47057718be8SEnji Cooper ATF_TP_ADD_TC(tp, t_spawn_empty_fileactions);
471*f16ec9c6SKonstantin Belousov ATF_TP_ADD_TC(tp, t_spawn_chdir);
472*f16ec9c6SKonstantin Belousov ATF_TP_ADD_TC(tp, t_spawn_fchdir);
47357718be8SEnji Cooper
47457718be8SEnji Cooper return atf_no_error();
47557718be8SEnji Cooper }
476