]>
Commit | Line | Data |
---|---|---|
08c7f6b0 | 1 | /* Tests for spawn. |
d4697bc9 | 2 | Copyright (C) 2000-2014 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 UD |
19 | |
20 | #include <errno.h> | |
21 | #include <error.h> | |
22 | #include <fcntl.h> | |
23 | #include <spawn.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <unistd.h> | |
27 | #include <wait.h> | |
28 | #include <sys/param.h> | |
29 | ||
30 | ||
31 | /* Nonzero if the program gets called via `exec'. */ | |
32 | static int restart; | |
33 | ||
34 | ||
35 | #define CMDLINE_OPTIONS \ | |
36 | { "restart", no_argument, &restart, 1 }, | |
37 | ||
38 | /* Prototype for our test function. */ | |
39 | extern void do_prepare (int argc, char *argv[]); | |
40 | extern int do_test (int argc, char *argv[]); | |
41 | ||
42 | /* We have a preparation function. */ | |
43 | #define PREPARE do_prepare | |
44 | ||
45 | #include "../test-skeleton.c" | |
46 | ||
47 | ||
48 | /* Name of the temporary files. */ | |
49 | static char *name1; | |
50 | static char *name2; | |
51 | static char *name3; | |
52 | ||
53 | /* The contents of our files. */ | |
54 | static const char fd1string[] = "This file should get closed"; | |
55 | static const char fd2string[] = "This file should stay opened"; | |
56 | static const char fd3string[] = "This file will be opened"; | |
57 | ||
58 | ||
59 | /* We have a preparation function. */ | |
60 | void | |
61 | do_prepare (int argc, char *argv[]) | |
62 | { | |
30aa5785 | 63 | size_t name_len; |
08c7f6b0 UD |
64 | |
65 | name_len = strlen (test_dir); | |
66 | name1 = (char *) malloc (name_len + sizeof ("/spawnXXXXXX")); | |
67 | mempcpy (mempcpy (name1, test_dir, name_len), | |
68 | "/spawnXXXXXX", sizeof ("/spawnXXXXXX")); | |
69 | add_temp_file (name1); | |
70 | ||
71 | name2 = (char *) malloc (name_len + sizeof ("/spawnXXXXXX")); | |
72 | mempcpy (mempcpy (name2, test_dir, name_len), | |
73 | "/spawnXXXXXX", sizeof ("/spawnXXXXXX")); | |
74 | add_temp_file (name2); | |
75 | ||
76 | name3 = (char *) malloc (name_len + sizeof ("/spawnXXXXXX")); | |
77 | mempcpy (mempcpy (name3, test_dir, name_len), | |
78 | "/spawnXXXXXX", sizeof ("/spawnXXXXXX")); | |
79 | add_temp_file (name3); | |
80 | } | |
81 | ||
82 | ||
83 | static int | |
84 | handle_restart (const char *fd1s, const char *fd2s, const char *fd3s, | |
85 | const char *fd4s, const char *name) | |
86 | { | |
87 | char buf[100]; | |
88 | int fd1; | |
89 | int fd2; | |
90 | int fd3; | |
91 | int fd4; | |
92 | ||
93 | /* First get the descriptors. */ | |
94 | fd1 = atol (fd1s); | |
95 | fd2 = atol (fd2s); | |
96 | fd3 = atol (fd3s); | |
97 | fd4 = atol (fd4s); | |
98 | ||
99 | /* Sanity check. */ | |
100 | if (fd1 == fd2) | |
101 | error (EXIT_FAILURE, 0, "value of fd1 and fd2 is the same"); | |
102 | if (fd1 == fd3) | |
103 | error (EXIT_FAILURE, 0, "value of fd1 and fd3 is the same"); | |
104 | if (fd1 == fd4) | |
105 | error (EXIT_FAILURE, 0, "value of fd1 and fd4 is the same"); | |
106 | if (fd2 == fd3) | |
107 | error (EXIT_FAILURE, 0, "value of fd2 and fd3 is the same"); | |
108 | if (fd2 == fd4) | |
109 | error (EXIT_FAILURE, 0, "value of fd2 and fd4 is the same"); | |
110 | if (fd3 == fd4) | |
111 | error (EXIT_FAILURE, 0, "value of fd3 and fd4 is the same"); | |
112 | ||
113 | /* First the easy part: read from the file descriptor which is | |
114 | supposed to be open. */ | |
115 | if (lseek (fd2, 0, SEEK_CUR) != strlen (fd2string)) | |
116 | error (EXIT_FAILURE, errno, "file 2 not in right position"); | |
117 | /* The duped descriptor must have the same position. */ | |
118 | if (lseek (fd4, 0, SEEK_CUR) != strlen (fd2string)) | |
119 | error (EXIT_FAILURE, errno, "file 4 not in right position"); | |
120 | if (lseek (fd2, 0, SEEK_SET) != 0) | |
121 | error (EXIT_FAILURE, 0, "cannot reset position in file 2"); | |
122 | if (lseek (fd4, 0, SEEK_CUR) != 0) | |
123 | error (EXIT_FAILURE, errno, "file 4 not set back, too"); | |
124 | if (read (fd2, buf, sizeof buf) != strlen (fd2string)) | |
125 | error (EXIT_FAILURE, 0, "cannot read file 2"); | |
126 | if (memcmp (fd2string, buf, strlen (fd2string)) != 0) | |
127 | error (EXIT_FAILURE, 0, "file 2 does not match"); | |
128 | ||
129 | /* Now read from the third file. */ | |
130 | if (read (fd3, buf, sizeof buf) != strlen (fd3string)) | |
131 | error (EXIT_FAILURE, 0, "cannot read file 3"); | |
132 | if (memcmp (fd3string, buf, strlen (fd3string)) != 0) | |
133 | error (EXIT_FAILURE, 0, "file 3 does not match"); | |
134 | /* Try to write to the file. This should not be allowed. */ | |
135 | if (write (fd3, "boo!", 4) != -1 || errno != EBADF) | |
136 | error (EXIT_FAILURE, 0, "file 3 is writable"); | |
137 | ||
138 | /* Now try to read the first file. First make sure it is not opened. */ | |
139 | if (lseek (fd1, 0, SEEK_CUR) != (off_t) -1 || errno != EBADF) | |
140 | error (EXIT_FAILURE, 0, "file 1 (%d) is not closed", fd1); | |
141 | ||
142 | /* Now open the file and read it. */ | |
143 | fd1 = open (name, O_RDONLY); | |
144 | if (fd1 == -1) | |
145 | error (EXIT_FAILURE, errno, | |
146 | "cannot open first file \"%s\" for verification", name); | |
147 | ||
148 | if (read (fd1, buf, sizeof buf) != strlen (fd1string)) | |
149 | error (EXIT_FAILURE, errno, "cannot read file 1"); | |
150 | if (memcmp (fd1string, buf, strlen (fd1string)) != 0) | |
151 | error (EXIT_FAILURE, 0, "file 1 does not match"); | |
152 | ||
153 | return 0; | |
154 | } | |
155 | ||
156 | ||
157 | int | |
158 | do_test (int argc, char *argv[]) | |
159 | { | |
160 | pid_t pid; | |
161 | int fd1; | |
162 | int fd2; | |
163 | int fd3; | |
164 | int fd4; | |
165 | int status; | |
166 | posix_spawn_file_actions_t actions; | |
167 | char fd1name[18]; | |
168 | char fd2name[18]; | |
169 | char fd3name[18]; | |
170 | char fd4name[18]; | |
171 | char *spargv[12]; | |
4cf8f209 | 172 | int i; |
08c7f6b0 UD |
173 | |
174 | /* We must have | |
4cf8f209 L |
175 | - one or four parameters left if called initially |
176 | + path for ld.so optional | |
177 | + "--library-path" optional | |
178 | + the library path optional | |
08c7f6b0 | 179 | + the application name |
726b7b0f | 180 | - five parameters left if called through re-execution |
08c7f6b0 UD |
181 | + file descriptor number which is supposed to be closed |
182 | + the open file descriptor | |
183 | + the newly opened file descriptor | |
184 | + thhe duped second descriptor | |
185 | + the name of the closed descriptor | |
186 | */ | |
4cf8f209 | 187 | if (argc != (restart ? 6 : 2) && argc != (restart ? 6 : 5)) |
08c7f6b0 UD |
188 | error (EXIT_FAILURE, 0, "wrong number of arguments (%d)", argc); |
189 | ||
190 | if (restart) | |
726b7b0f | 191 | return handle_restart (argv[1], argv[2], argv[3], argv[4], argv[5]); |
08c7f6b0 UD |
192 | |
193 | /* Prepare the test. We are creating two files: one which file descriptor | |
194 | will be marked with FD_CLOEXEC, another which is not. */ | |
195 | ||
196 | /* Open our test files. */ | |
197 | fd1 = mkstemp (name1); | |
198 | if (fd1 == -1) | |
199 | error (EXIT_FAILURE, errno, "cannot open test file `%s'", name1); | |
200 | fd2 = mkstemp (name2); | |
201 | if (fd2 == -1) | |
202 | error (EXIT_FAILURE, errno, "cannot open test file `%s'", name2); | |
203 | fd3 = mkstemp (name3); | |
204 | if (fd3 == -1) | |
205 | error (EXIT_FAILURE, errno, "cannot open test file `%s'", name3); | |
206 | ||
207 | /* Write something in the files. */ | |
208 | if (write (fd1, fd1string, strlen (fd1string)) != strlen (fd1string)) | |
209 | error (EXIT_FAILURE, errno, "cannot write to first file"); | |
210 | if (write (fd2, fd2string, strlen (fd2string)) != strlen (fd2string)) | |
211 | error (EXIT_FAILURE, errno, "cannot write to second file"); | |
212 | if (write (fd3, fd3string, strlen (fd3string)) != strlen (fd3string)) | |
213 | error (EXIT_FAILURE, errno, "cannot write to third file"); | |
214 | ||
215 | /* Close the third file. It'll be opened by `spawn'. */ | |
216 | close (fd3); | |
217 | ||
218 | /* Tell `spawn' what to do. */ | |
219 | if (posix_spawn_file_actions_init (&actions) != 0) | |
220 | error (EXIT_FAILURE, errno, "posix_spawn_file_actions_init"); | |
221 | /* Close `fd1'. */ | |
222 | if (posix_spawn_file_actions_addclose (&actions, fd1) != 0) | |
223 | error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addclose"); | |
224 | /* We want to open the third file. */ | |
225 | if (posix_spawn_file_actions_addopen (&actions, fd3, name3, | |
226 | O_RDONLY, 0666) != 0) | |
227 | error (EXIT_FAILURE, errno, "posix_spawn_file_actions_addopen"); | |
228 | /* We dup the second descriptor. */ | |
229 | fd4 = MAX (2, MAX (fd1, MAX (fd2, fd3))) + 1; | |
230 | if (posix_spawn_file_actions_adddup2 (&actions, fd2, fd4) != 0) | |
231 | error (EXIT_FAILURE, errno, "posix_spawn_file_actions_adddup2"); | |
232 | ||
233 | /* Now spawn the process. */ | |
234 | snprintf (fd1name, sizeof fd1name, "%d", fd1); | |
235 | snprintf (fd2name, sizeof fd2name, "%d", fd2); | |
236 | snprintf (fd3name, sizeof fd3name, "%d", fd3); | |
237 | snprintf (fd4name, sizeof fd4name, "%d", fd4); | |
238 | ||
4cf8f209 L |
239 | for (i = 0; i < (argc == (restart ? 6 : 5) ? 4 : 1); i++) |
240 | spargv[i] = argv[i + 1]; | |
241 | spargv[i++] = (char *) "--direct"; | |
242 | spargv[i++] = (char *) "--restart"; | |
243 | spargv[i++] = fd1name; | |
244 | spargv[i++] = fd2name; | |
245 | spargv[i++] = fd3name; | |
246 | spargv[i++] = fd4name; | |
247 | spargv[i++] = name1; | |
248 | spargv[i] = NULL; | |
08c7f6b0 | 249 | |
726b7b0f | 250 | if (posix_spawn (&pid, argv[1], &actions, NULL, spargv, environ) != 0) |
08c7f6b0 UD |
251 | error (EXIT_FAILURE, errno, "posix_spawn"); |
252 | ||
253 | /* Cleanup. */ | |
254 | if (posix_spawn_file_actions_destroy (&actions) != 0) | |
255 | error (EXIT_FAILURE, errno, "posix_spawn_file_actions_destroy"); | |
256 | ||
257 | /* Wait for the child. */ | |
258 | if (waitpid (pid, &status, 0) != pid) | |
259 | error (EXIT_FAILURE, errno, "wrong child"); | |
260 | ||
261 | if (WTERMSIG (status) != 0) | |
262 | error (EXIT_FAILURE, 0, "Child terminated incorrectly"); | |
263 | status = WEXITSTATUS (status); | |
264 | ||
265 | /* Remove the test files. */ | |
266 | unlink (name1); | |
267 | unlink (name2); | |
268 | unlink (name3); | |
269 | ||
270 | return status; | |
271 | } |