]>
Commit | Line | Data |
---|---|---|
4a938cb2 | 1 | /* Test the posix_spawn_file_actions_addchdir_np function. |
04277e02 | 2 | Copyright (C) 2018-2019 Free Software Foundation, Inc. |
4a938cb2 FW |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
17 | <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | #include <array_length.h> | |
20 | #include <errno.h> | |
21 | #include <fcntl.h> | |
22 | #include <spawn.h> | |
3a3fb755 | 23 | #include <stdbool.h> |
4a938cb2 FW |
24 | #include <stdlib.h> |
25 | #include <string.h> | |
26 | #include <support/check.h> | |
27 | #include <support/support.h> | |
28 | #include <support/temp_file.h> | |
3a3fb755 | 29 | #include <support/test-driver.h> |
4a938cb2 FW |
30 | #include <support/xstdio.h> |
31 | #include <support/xunistd.h> | |
32 | #include <unistd.h> | |
33 | ||
34 | /* Reads the file at PATH, which must consist of exactly one line. | |
35 | Removes the line terminator at the end of the file. */ | |
36 | static char * | |
37 | read_one_line (const char *path) | |
38 | { | |
39 | FILE *fp = xfopen (path, "r"); | |
40 | char *buffer = NULL; | |
41 | size_t length = 0; | |
42 | ssize_t ret = getline (&buffer, &length, fp); | |
43 | if (ferror (fp)) | |
44 | FAIL_EXIT1 ("getline: %m"); | |
45 | if (ret < 1) | |
46 | FAIL_EXIT1 ("getline returned %zd", ret); | |
47 | if (fgetc (fp) != EOF) | |
48 | FAIL_EXIT1 ("trailing bytes in %s", path); | |
49 | if (ferror (fp)) | |
50 | FAIL_EXIT1 ("fgetc: %m"); | |
51 | xfclose (fp); | |
52 | if (buffer[ret - 1] != '\n') | |
53 | FAIL_EXIT1 ("missing line terminator in %s", path); | |
54 | buffer[ret - 1] = 0; | |
55 | return buffer; | |
56 | } | |
57 | ||
58 | /* Return the path to the "pwd" program. */ | |
59 | const char * | |
60 | get_pwd_program (void) | |
61 | { | |
62 | const char *const paths[] = { "/bin/pwd", "/usr/bin/pwd" }; | |
63 | for (size_t i = 0; i < array_length (paths); ++i) | |
64 | if (access (paths[i], X_OK) == 0) | |
65 | return paths[i]; | |
66 | FAIL_EXIT1 ("cannot find pwd program"); | |
67 | } | |
68 | ||
3a3fb755 FW |
69 | /* Adds chdir operations to ACTIONS, using PATH. If DO_FCHDIR, use |
70 | the open function and TMPFD to emulate chdir using fchdir. */ | |
71 | static void | |
72 | add_chdir (posix_spawn_file_actions_t *actions, const char *path, | |
73 | bool do_fchdir, int tmpfd) | |
74 | { | |
75 | if (do_fchdir) | |
76 | { | |
77 | TEST_COMPARE (posix_spawn_file_actions_addopen | |
78 | (actions, tmpfd, path, O_DIRECTORY | O_RDONLY, 0), 0); | |
79 | TEST_COMPARE (posix_spawn_file_actions_addfchdir_np | |
80 | (actions, tmpfd), 0); | |
81 | TEST_COMPARE (posix_spawn_file_actions_addclose (actions, tmpfd), 0); | |
82 | } | |
83 | else | |
84 | TEST_COMPARE (posix_spawn_file_actions_addchdir_np (actions, path), 0); | |
85 | } | |
86 | ||
4a938cb2 FW |
87 | static int |
88 | do_test (void) | |
89 | { | |
90 | /* Directory for temporary file data. Each subtest uses a numeric | |
91 | subdirectory. */ | |
92 | char *directory = support_create_temp_directory ("tst-spawn-chdir-"); | |
93 | { | |
94 | /* Avoid symbolic links, to get more consistent behavior from the | |
95 | pwd command. */ | |
96 | char *tmp = realpath (directory, NULL); | |
97 | if (tmp == NULL) | |
98 | FAIL_EXIT1 ("realpath: %m"); | |
99 | free (directory); | |
100 | directory = tmp; | |
101 | } | |
102 | ||
103 | char *original_cwd = get_current_dir_name (); | |
104 | if (original_cwd == NULL) | |
105 | FAIL_EXIT1 ("get_current_dir_name: %m"); | |
106 | ||
107 | int iteration = 0; | |
108 | for (int do_spawnp = 0; do_spawnp < 2; ++do_spawnp) | |
109 | for (int do_overwrite = 0; do_overwrite < 2; ++do_overwrite) | |
3a3fb755 | 110 | for (int do_fchdir = 0; do_fchdir < 2; ++do_fchdir) |
4a938cb2 | 111 | { |
3a3fb755 FW |
112 | /* This subtest does not make sense for fchdir. */ |
113 | if (do_overwrite && do_fchdir) | |
114 | continue; | |
115 | ||
116 | ++iteration; | |
117 | if (test_verbose > 0) | |
118 | printf ("info: iteration=%d do_spawnp=%d do_overwrite=%d" | |
119 | " do_fchdir=%d\n", | |
120 | iteration, do_spawnp, do_overwrite, do_fchdir); | |
121 | ||
122 | /* The "pwd" program runs in this directory. */ | |
123 | char *iteration_directory = xasprintf ("%s/%d", directory, iteration); | |
124 | add_temp_file (iteration_directory); | |
125 | xmkdir (iteration_directory, 0777); | |
126 | ||
127 | /* This file receives output from "pwd". */ | |
128 | char *output_file_path | |
129 | = xasprintf ("%s/output-file", iteration_directory); | |
130 | add_temp_file (output_file_path); | |
131 | ||
132 | /* This subdirectory is used for chdir ordering checks. */ | |
133 | char *subdir_path = xasprintf ("%s/subdir", iteration_directory); | |
134 | add_temp_file (subdir_path); | |
135 | xmkdir (subdir_path, 0777); | |
136 | ||
137 | /* Also used for checking the order of actions. */ | |
138 | char *probe_file_path | |
139 | = xasprintf ("%s/subdir/probe-file", iteration_directory); | |
140 | add_temp_file (probe_file_path); | |
141 | TEST_COMPARE (access (probe_file_path, F_OK), -1); | |
142 | TEST_COMPARE (errno, ENOENT); | |
143 | ||
144 | /* This symbolic link is used in a relative path with | |
145 | posix_spawn. */ | |
146 | char *pwd_symlink_path | |
147 | = xasprintf ("%s/subdir/pwd-symlink", iteration_directory); | |
148 | xsymlink (get_pwd_program (), pwd_symlink_path); | |
149 | add_temp_file (pwd_symlink_path); | |
150 | ||
151 | posix_spawn_file_actions_t actions; | |
152 | TEST_COMPARE (posix_spawn_file_actions_init (&actions), 0); | |
153 | add_chdir (&actions, subdir_path, do_fchdir, 4); | |
154 | TEST_COMPARE (posix_spawn_file_actions_addopen | |
155 | (&actions, 3, /* Arbitrary unused descriptor. */ | |
156 | "probe-file", | |
157 | O_WRONLY | O_CREAT | O_EXCL, 0777), 0); | |
158 | TEST_COMPARE (posix_spawn_file_actions_addclose (&actions, 3), 0); | |
159 | /* Run the actual in iteration_directory. */ | |
160 | add_chdir (&actions, "..", do_fchdir, 5); | |
161 | TEST_COMPARE (posix_spawn_file_actions_addopen | |
162 | (&actions, STDOUT_FILENO, "output-file", | |
163 | O_WRONLY | O_CREAT | O_EXCL, 0777), 0); | |
164 | ||
165 | /* Check that posix_spawn_file_actions_addchdir_np made a copy | |
166 | of the path. */ | |
167 | if (do_overwrite) | |
168 | subdir_path[0] = '\0'; | |
169 | ||
170 | char *const argv[] = { (char *) "pwd", NULL }; | |
171 | char *const envp[] = { NULL } ; | |
172 | pid_t pid; | |
173 | if (do_spawnp) | |
174 | TEST_COMPARE (posix_spawnp (&pid, "pwd", &actions, | |
175 | NULL, argv, envp), 0); | |
176 | else | |
177 | TEST_COMPARE (posix_spawn (&pid, "subdir/pwd-symlink", &actions, | |
178 | NULL, argv, envp), 0); | |
179 | TEST_VERIFY (pid > 0); | |
180 | int status; | |
181 | xwaitpid (pid, &status, 0); | |
182 | TEST_COMPARE (status, 0); | |
183 | ||
184 | /* Check that the current directory did not change. */ | |
185 | { | |
186 | char *cwd = get_current_dir_name (); | |
187 | if (cwd == NULL) | |
188 | FAIL_EXIT1 ("get_current_dir_name: %m"); | |
189 | TEST_COMPARE_BLOB (original_cwd, strlen (original_cwd), | |
190 | cwd, strlen (cwd)); | |
191 | free (cwd); | |
192 | } | |
193 | ||
194 | ||
195 | /* Check the output from "pwd". */ | |
196 | { | |
197 | char *pwd = read_one_line (output_file_path); | |
198 | TEST_COMPARE_BLOB (iteration_directory, strlen (iteration_directory), | |
199 | pwd, strlen (pwd)); | |
200 | free (pwd); | |
201 | } | |
202 | ||
203 | /* This file must now exist. */ | |
204 | TEST_COMPARE (access (probe_file_path, F_OK), 0); | |
205 | ||
206 | TEST_COMPARE (posix_spawn_file_actions_destroy (&actions), 0); | |
207 | free (pwd_symlink_path); | |
208 | free (probe_file_path); | |
209 | free (subdir_path); | |
210 | free (output_file_path); | |
4a938cb2 FW |
211 | } |
212 | ||
4a938cb2 FW |
213 | free (directory); |
214 | ||
215 | return 0; | |
216 | } | |
217 | ||
218 | #include <support/test-driver.c> |