]>
Commit | Line | Data |
---|---|---|
08c7f6b0 | 1 | /* Tests for spawn. |
04277e02 | 2 | Copyright (C) 2000-2019 Free Software Foundation, Inc. |
41bdb6e2 | 3 | This file is part of the GNU C Library. |
08c7f6b0 UD |
4 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000. |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
08c7f6b0 UD |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
08c7f6b0 | 15 | |
41bdb6e2 | 16 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
17 | License along with the GNU C Library; if not, see |
18 | <http://www.gnu.org/licenses/>. */ | |
08c7f6b0 | 19 | |
c7027166 AZ |
20 | #include <stdio.h> |
21 | #include <getopt.h> | |
08c7f6b0 UD |
22 | #include <errno.h> |
23 | #include <error.h> | |
24 | #include <fcntl.h> | |
25 | #include <spawn.h> | |
26 | #include <stdlib.h> | |
27 | #include <string.h> | |
08c7f6b0 | 28 | #include <sys/param.h> |
c7027166 | 29 | |
5ba41de9 SN |
30 | #include <support/check.h> |
31 | #include <support/xunistd.h> | |
c7027166 AZ |
32 | #include <support/temp_file.h> |
33 | #include <support/support.h> | |
08c7f6b0 UD |
34 | |
35 | ||
36 | /* Nonzero if the program gets called via `exec'. */ | |
37 | static int restart; | |
38 | ||
39 | ||
40 | #define CMDLINE_OPTIONS \ | |
41 | { "restart", no_argument, &restart, 1 }, | |
42 | ||
08c7f6b0 UD |
43 | /* Name of the temporary files. */ |
44 | static char *name1; | |
45 | static char *name2; | |
46 | static char *name3; | |
805334b2 | 47 | static char *name5; |
08c7f6b0 | 48 | |
c22553ef FW |
49 | /* Descriptors for the temporary files. */ |
50 | static int temp_fd1 = -1; | |
51 | static int temp_fd2 = -1; | |
52 | static int temp_fd3 = -1; | |
805334b2 | 53 | static int temp_fd5 = -1; |
c22553ef | 54 | |
08c7f6b0 UD |
55 | /* The contents of our files. */ |
56 | static const char fd1string[] = "This file should get closed"; | |
57 | static const char fd2string[] = "This file should stay opened"; | |
58 | static const char fd3string[] = "This file will be opened"; | |
805334b2 | 59 | static const char fd5string[] = "This file should stay opened (O_CLOEXEC)"; |
08c7f6b0 UD |
60 | |
61 | ||
62 | /* We have a preparation function. */ | |
c7027166 | 63 | static void |
08c7f6b0 UD |
64 | do_prepare (int argc, char *argv[]) |
65 | { | |
c22553ef FW |
66 | /* We must not open any files in the restart case. */ |
67 | if (restart) | |
68 | return; | |
69 | ||
c7027166 AZ |
70 | TEST_VERIFY_EXIT ((temp_fd1 = create_temp_file ("spawn", &name1)) != -1); |
71 | TEST_VERIFY_EXIT ((temp_fd2 = create_temp_file ("spawn", &name2)) != -1); | |
72 | TEST_VERIFY_EXIT ((temp_fd3 = create_temp_file ("spawn", &name3)) != -1); | |
805334b2 AZ |
73 | TEST_VERIFY_EXIT ((temp_fd5 = create_temp_file ("spawn", &name5)) != -1); |
74 | ||
75 | int flags; | |
76 | TEST_VERIFY_EXIT ((flags = fcntl (temp_fd5, F_GETFD, &flags)) != -1); | |
77 | TEST_COMPARE (fcntl (temp_fd5, F_SETFD, flags | FD_CLOEXEC), 0); | |
08c7f6b0 | 78 | } |
c7027166 | 79 | #define PREPARE do_prepare |
08c7f6b0 UD |
80 | |
81 | ||
82 | static int | |
83 | handle_restart (const char *fd1s, const char *fd2s, const char *fd3s, | |
805334b2 | 84 | const char *fd4s, const char *name, const char *fd5s) |
08c7f6b0 UD |
85 | { |
86 | char buf[100]; | |
87 | int fd1; | |
88 | int fd2; | |
89 | int fd3; | |
90 | int fd4; | |
805334b2 | 91 | int fd5; |
08c7f6b0 UD |
92 | |
93 | /* First get the descriptors. */ | |
94 | fd1 = atol (fd1s); | |
95 | fd2 = atol (fd2s); | |
96 | fd3 = atol (fd3s); | |
97 | fd4 = atol (fd4s); | |
805334b2 | 98 | fd5 = atol (fd5s); |
08c7f6b0 UD |
99 | |
100 | /* Sanity check. */ | |
c7027166 AZ |
101 | TEST_VERIFY_EXIT (fd1 != fd2); |
102 | TEST_VERIFY_EXIT (fd1 != fd3); | |
103 | TEST_VERIFY_EXIT (fd1 != fd4); | |
104 | TEST_VERIFY_EXIT (fd2 != fd3); | |
105 | TEST_VERIFY_EXIT (fd2 != fd4); | |
106 | TEST_VERIFY_EXIT (fd3 != fd4); | |
805334b2 | 107 | TEST_VERIFY_EXIT (fd4 != fd5); |
08c7f6b0 UD |
108 | |
109 | /* First the easy part: read from the file descriptor which is | |
110 | supposed to be open. */ | |
c7027166 | 111 | TEST_COMPARE (xlseek (fd2, 0, SEEK_CUR), strlen (fd2string)); |
08c7f6b0 | 112 | /* The duped descriptor must have the same position. */ |
c7027166 AZ |
113 | TEST_COMPARE (xlseek (fd4, 0, SEEK_CUR), strlen (fd2string)); |
114 | TEST_COMPARE (xlseek (fd2, 0, SEEK_SET), 0); | |
115 | TEST_COMPARE (xlseek (fd4, 0, SEEK_CUR), 0); | |
116 | TEST_COMPARE (read (fd2, buf, sizeof buf), strlen (fd2string)); | |
117 | TEST_COMPARE_BLOB (fd2string, strlen (fd2string), buf, strlen (fd2string)); | |
08c7f6b0 UD |
118 | |
119 | /* Now read from the third file. */ | |
c7027166 AZ |
120 | TEST_COMPARE (read (fd3, buf, sizeof buf), strlen (fd3string)); |
121 | TEST_COMPARE_BLOB (fd3string, strlen (fd3string), buf, strlen (fd3string)); | |
08c7f6b0 | 122 | /* Try to write to the file. This should not be allowed. */ |
c7027166 AZ |
123 | TEST_COMPARE (write (fd3, "boo!", 4), -1); |
124 | TEST_COMPARE (errno, EBADF); | |
08c7f6b0 UD |
125 | |
126 | /* Now try to read the first file. First make sure it is not opened. */ | |
c7027166 AZ |
127 | TEST_COMPARE (lseek (fd1, 0, SEEK_CUR), (off_t) -1); |
128 | TEST_COMPARE (errno, EBADF); | |
08c7f6b0 UD |
129 | |
130 | /* Now open the file and read it. */ | |
c7027166 | 131 | fd1 = xopen (name, O_RDONLY, 0600); |
08c7f6b0 | 132 | |
c7027166 AZ |
133 | TEST_COMPARE (read (fd1, buf, sizeof buf), strlen (fd1string)); |
134 | TEST_COMPARE_BLOB (fd1string, strlen (fd1string), buf, strlen (fd1string)); | |
08c7f6b0 | 135 | |
805334b2 AZ |
136 | TEST_COMPARE (xlseek (fd5, 0, SEEK_SET), 0); |
137 | TEST_COMPARE (read (fd5, buf, sizeof buf), strlen (fd5string)); | |
138 | TEST_COMPARE_BLOB (fd5string, strlen (fd5string), buf, strlen (fd5string)); | |
139 | ||
08c7f6b0 UD |
140 | return 0; |
141 | } | |
142 | ||
143 | ||
c7027166 | 144 | static int |
08c7f6b0 UD |
145 | do_test (int argc, char *argv[]) |
146 | { | |
147 | pid_t pid; | |
08c7f6b0 UD |
148 | int fd4; |
149 | int status; | |
150 | posix_spawn_file_actions_t actions; | |
151 | char fd1name[18]; | |
152 | char fd2name[18]; | |
153 | char fd3name[18]; | |
154 | char fd4name[18]; | |
805334b2 | 155 | char fd5name[18]; |
89e435f3 | 156 | char *name3_copy; |
b79dc8d0 | 157 | char *spargv[13]; |
4cf8f209 | 158 | int i; |
08c7f6b0 UD |
159 | |
160 | /* We must have | |
4cf8f209 L |
161 | - one or four parameters left if called initially |
162 | + path for ld.so optional | |
163 | + "--library-path" optional | |
164 | + the library path optional | |
08c7f6b0 | 165 | + the application name |
805334b2 | 166 | - six parameters left if called through re-execution |
08c7f6b0 UD |
167 | + file descriptor number which is supposed to be closed |
168 | + the open file descriptor | |
169 | + the newly opened file descriptor | |
805334b2 | 170 | + the duped second descriptor |
08c7f6b0 | 171 | + the name of the closed descriptor |
b79dc8d0 | 172 | + the duped fourth file descriptor which O_CLOEXEC should be |
805334b2 | 173 | remove by adddup2. |
08c7f6b0 | 174 | */ |
805334b2 | 175 | if (argc != (restart ? 7 : 2) && argc != (restart ? 7 : 5)) |
c7027166 | 176 | FAIL_EXIT1 ("wrong number of arguments (%d)", argc); |
08c7f6b0 UD |
177 | |
178 | if (restart) | |
805334b2 AZ |
179 | return handle_restart (argv[1], argv[2], argv[3], argv[4], argv[5], |
180 | argv[6]); | |
08c7f6b0 | 181 | |
805334b2 | 182 | /* Prepare the test. We are creating four files: two which file descriptor |
08c7f6b0 UD |
183 | will be marked with FD_CLOEXEC, another which is not. */ |
184 | ||
c7027166 AZ |
185 | /* Write something in the files. */ |
186 | xwrite (temp_fd1, fd1string, strlen (fd1string)); | |
187 | xwrite (temp_fd2, fd2string, strlen (fd2string)); | |
188 | xwrite (temp_fd3, fd3string, strlen (fd3string)); | |
805334b2 | 189 | xwrite (temp_fd5, fd5string, strlen (fd5string)); |
c7027166 AZ |
190 | |
191 | /* Close the third file. It'll be opened by `spawn'. */ | |
192 | xclose (temp_fd3); | |
193 | ||
194 | /* Tell `spawn' what to do. */ | |
195 | TEST_COMPARE (posix_spawn_file_actions_init (&actions), 0); | |
196 | /* Close `temp_fd1'. */ | |
197 | TEST_COMPARE (posix_spawn_file_actions_addclose (&actions, temp_fd1), 0); | |
198 | /* We want to open the third file. */ | |
199 | name3_copy = xstrdup (name3); | |
200 | TEST_COMPARE (posix_spawn_file_actions_addopen (&actions, temp_fd3, | |
201 | name3_copy, | |
202 | O_RDONLY, 0666), | |
203 | 0); | |
204 | /* Overwrite the name to check that a copy has been made. */ | |
205 | memset (name3_copy, 'X', strlen (name3_copy)); | |
206 | ||
207 | /* We dup the second descriptor. */ | |
805334b2 | 208 | fd4 = MAX (2, MAX (temp_fd1, MAX (temp_fd2, MAX (temp_fd3, temp_fd5)))) + 1; |
c7027166 AZ |
209 | TEST_COMPARE (posix_spawn_file_actions_adddup2 (&actions, temp_fd2, fd4), |
210 | 0); | |
211 | ||
805334b2 AZ |
212 | /* We clear the O_CLOEXEC on fourth descriptor, so it should be |
213 | stay open on child. */ | |
214 | TEST_COMPARE (posix_spawn_file_actions_adddup2 (&actions, temp_fd5, | |
215 | temp_fd5), | |
216 | 0); | |
217 | ||
c7027166 AZ |
218 | /* Now spawn the process. */ |
219 | snprintf (fd1name, sizeof fd1name, "%d", temp_fd1); | |
220 | snprintf (fd2name, sizeof fd2name, "%d", temp_fd2); | |
221 | snprintf (fd3name, sizeof fd3name, "%d", temp_fd3); | |
222 | snprintf (fd4name, sizeof fd4name, "%d", fd4); | |
805334b2 | 223 | snprintf (fd5name, sizeof fd5name, "%d", temp_fd5); |
c7027166 | 224 | |
805334b2 | 225 | for (i = 0; i < (argc == (restart ? 7 : 5) ? 4 : 1); i++) |
c7027166 AZ |
226 | spargv[i] = argv[i + 1]; |
227 | spargv[i++] = (char *) "--direct"; | |
228 | spargv[i++] = (char *) "--restart"; | |
229 | spargv[i++] = fd1name; | |
230 | spargv[i++] = fd2name; | |
231 | spargv[i++] = fd3name; | |
232 | spargv[i++] = fd4name; | |
233 | spargv[i++] = name1; | |
805334b2 | 234 | spargv[i++] = fd5name; |
c7027166 AZ |
235 | spargv[i] = NULL; |
236 | ||
237 | TEST_COMPARE (posix_spawn (&pid, argv[1], &actions, NULL, spargv, environ), | |
238 | 0); | |
239 | ||
240 | /* Same test but with a NULL pid argument. */ | |
241 | TEST_COMPARE (posix_spawn (NULL, argv[1], &actions, NULL, spargv, environ), | |
242 | 0); | |
243 | ||
244 | /* Cleanup. */ | |
245 | TEST_COMPARE (posix_spawn_file_actions_destroy (&actions), 0); | |
246 | free (name3_copy); | |
08c7f6b0 | 247 | |
5ba41de9 | 248 | /* Wait for the children. */ |
c7027166 | 249 | TEST_COMPARE (xwaitpid (pid, &status, 0), pid); |
5ba41de9 SN |
250 | TEST_VERIFY (WIFEXITED (status)); |
251 | TEST_VERIFY (!WIFSIGNALED (status)); | |
c7027166 | 252 | TEST_COMPARE (WEXITSTATUS (status), 0); |
08c7f6b0 | 253 | |
5ba41de9 SN |
254 | xwaitpid (-1, &status, 0); |
255 | TEST_VERIFY (WIFEXITED (status)); | |
256 | TEST_VERIFY (!WIFSIGNALED (status)); | |
c7027166 | 257 | TEST_COMPARE (WEXITSTATUS (status), 0); |
08c7f6b0 | 258 | |
5ba41de9 | 259 | return 0; |
08c7f6b0 | 260 | } |
c7027166 AZ |
261 | |
262 | #define TEST_FUNCTION_ARGV do_test | |
263 | #include <support/test-driver.c> |