]>
Commit | Line | Data |
---|---|---|
2d21ac55 A |
1 | |
2 | #include "tests.h" | |
3 | ||
4 | /* | |
5 | * create_random_name - creates a file with a random / unique name in the given directory. | |
6 | * when do_open is true we create a file else we generaate a name that does not exist in the | |
7 | * given directory (we do not create anything when do_open is 0). | |
8 | * WARNING - caller provides enough space in path buffer for longest possible name. | |
9 | * WARNING - assumes caller has appended a trailing '/' on the path passed to us. | |
10 | * RAND_MAX is currently 2147483647 (ten characters plus one for a slash) | |
11 | */ | |
12 | int create_random_name( char *the_pathp, int do_open ) { | |
13 | int i, my_err; | |
14 | int my_fd = -1; | |
15 | ||
16 | for ( i = 0; i < 1; i++ ) { | |
17 | int my_rand; | |
18 | char *myp; | |
19 | char my_name[32]; | |
20 | ||
21 | my_rand = rand( ); | |
22 | sprintf( &my_name[0], "%d", my_rand ); | |
23 | if ( (strlen( &my_name[0] ) + strlen( the_pathp ) + 2) > PATH_MAX ) { | |
24 | printf( "%s - path to test file greater than PATH_MAX \n", __FUNCTION__ ); | |
25 | return( -1 ); | |
26 | } | |
27 | ||
28 | // append generated file name onto our path | |
29 | myp = strrchr( the_pathp, '/' ); | |
30 | *(myp + 1) = 0x00; | |
31 | strcat( the_pathp, &my_name[0] ); | |
32 | if ( do_open ) { | |
33 | /* create a file with this name */ | |
34 | my_fd = open( the_pathp, (O_RDWR | O_CREAT | O_EXCL), | |
35 | (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) ); | |
36 | if ( my_fd == -1 ) { | |
37 | if ( errno != EEXIST ) { | |
38 | printf( "%s - open failed with errno %d - %s \n", | |
39 | __FUNCTION__, errno, strerror( errno ) ); | |
40 | return( -1 ); | |
41 | } | |
42 | // name already exists, try another | |
43 | i--; | |
44 | continue; | |
45 | } | |
46 | } | |
47 | else { | |
48 | /* make sure the name is unique */ | |
49 | struct stat my_sb; | |
50 | my_err = stat( the_pathp, &my_sb ); | |
51 | if ( my_err != 0 ) { | |
52 | if ( errno == ENOENT ) { | |
53 | break; | |
54 | } | |
55 | else { | |
56 | printf( "%s - open failed with errno %d - %s \n", | |
57 | __FUNCTION__, errno, strerror( errno ) ); | |
58 | return( -1 ); | |
59 | } | |
60 | } | |
61 | /* name already exists, try another */ | |
62 | i--; | |
63 | continue; | |
64 | } | |
65 | } | |
66 | ||
67 | if ( my_fd != -1 ) | |
68 | close( my_fd ); | |
69 | ||
70 | return( 0 ); | |
71 | ||
72 | } /* create_random_name */ | |
73 | ||
74 | /* | |
75 | * create_file_with_name - create a file in the given target directory using the given name. | |
76 | * If an existing file or directory is present use the value of remove_existing to determine if the | |
77 | * object is to be deleted. | |
78 | * returns 0 if file could be created, 1 if file exists, 2 if directory exists, else -1 | |
79 | * NOTE - will fail if a directory is present with the given name and it is not empty. | |
80 | */ | |
81 | int create_file_with_name( char *the_target_dirp, char *the_namep, int remove_existing ) { | |
82 | int create_test_file, my_err, my_result; | |
83 | int my_fd = -1; | |
84 | char * my_pathp = NULL; | |
85 | struct stat my_sb; | |
86 | ||
87 | create_test_file = 0; | |
88 | my_pathp = (char *) malloc( PATH_MAX ); | |
89 | if ( my_pathp == NULL ) { | |
90 | printf( "malloc failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
91 | goto failure_exit; | |
92 | } | |
93 | strcpy( my_pathp, the_target_dirp ); | |
94 | strcat( my_pathp, the_namep ); | |
95 | ||
96 | /* make sure the name is unique */ | |
97 | my_result = 0; | |
98 | my_err = stat( my_pathp, &my_sb ); | |
99 | if ( my_err != 0 ) { | |
100 | create_test_file = 1; | |
101 | if ( errno != ENOENT ) { | |
102 | goto failure_exit; | |
103 | } | |
104 | } | |
105 | else { | |
106 | /* name already exists */ | |
107 | if ( S_ISDIR( my_sb.st_mode ) ) { | |
108 | my_result = 2; /* tell caller directory exists with target name */ | |
109 | if ( remove_existing ) { | |
110 | my_err = rmdir( my_pathp ); | |
111 | if ( my_err == -1 ) { | |
112 | printf( "rmdir failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
113 | goto failure_exit; | |
114 | } | |
115 | create_test_file = 1; | |
116 | } | |
117 | } | |
118 | else { | |
119 | my_result = 1; /* tell caller file exists with target name */ | |
120 | if ( remove_existing ) { | |
121 | my_err = unlink( my_pathp ); | |
122 | if ( my_err == -1 ) { | |
123 | printf( "unlink failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
124 | goto failure_exit; | |
125 | } | |
126 | create_test_file = 1; | |
127 | } | |
128 | } | |
129 | } | |
130 | ||
131 | if ( create_test_file ) { | |
132 | /* create a file with this name */ | |
133 | my_fd = open( my_pathp, (O_RDWR | O_CREAT | O_EXCL), | |
134 | (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) ); | |
135 | if ( my_fd == -1 ) { | |
136 | printf( "open failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
137 | goto failure_exit; | |
138 | } | |
139 | close( my_fd ); | |
140 | } | |
141 | goto routine_exit; | |
142 | ||
143 | failure_exit: | |
144 | my_result = -1; | |
145 | routine_exit: | |
146 | if ( my_pathp != NULL ) { | |
147 | if ( my_result == -1 && create_test_file ) { | |
148 | remove( my_pathp ); | |
149 | } | |
150 | free( my_pathp ); | |
151 | } | |
152 | ||
153 | return( my_result ); | |
154 | ||
155 | } /* create_file_with_name */ | |
156 | ||
157 | ||
158 | ||
159 | ||
160 | /* | |
161 | * This function is needed by both xnu_quick_test proper and the execve() helper | |
162 | * program. It forks a child process and then exec()s an image on that child. | |
163 | * Path, argv, and envp are fed directly to the execve() call. | |
164 | * Parameter killwait decides how long to wait before killing the child. | |
165 | */ | |
166 | int do_execve_test(char * path, char * argv[], void * envp, int killwait) | |
167 | { | |
168 | int my_err = 0, my_status; | |
169 | pid_t my_pid, my_wait_pid; | |
170 | ||
171 | #if DEBUG | |
172 | printf("do_execve_test(path = %s)\n", path); | |
173 | printf("CWD= %s\n", getwd(NULL)); | |
174 | fflush(stdout); | |
175 | #endif | |
176 | /* vfork then execve sleep system command (which we will kill from the parent process) */ | |
177 | my_pid = vfork(); | |
178 | if (my_pid == -1) { | |
179 | printf( "vfork failed with errno %d - %s \n", errno, strerror( errno ) ); | |
180 | goto test_failed_exit; | |
181 | } | |
182 | if ( my_pid == 0 ) { | |
183 | /* | |
184 | * child process - use execve to start one of the customized helper | |
185 | * binaries, which just sleep for 120 seconds. Let our parent kill us. | |
186 | */ | |
187 | ||
188 | my_err = execve(path, argv, envp); | |
189 | if ( my_err != 0 ) { /* TODO: execve() on x86_64 inca returns weird error codes, see rdar://4655612 */ | |
190 | printf( "execve call failed with return value: %d, errno: %d - \"%s\"; path: %s \n", | |
191 | my_err, errno, strerror( errno), path ); | |
192 | fflush(stdout); | |
193 | exit(-2); | |
194 | } | |
195 | ||
196 | /* should never get here */ | |
197 | printf("Execve failed and it was not caught by our test\n"); | |
198 | return(-1); | |
199 | } | |
200 | /* | |
201 | * parent process - let's kill our sleeping child | |
202 | */ | |
203 | sleep(killwait); | |
204 | my_err = kill( my_pid, SIGKILL ); | |
205 | if ( my_err == -1 ) { | |
206 | printf( "kill call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
207 | goto test_failed_exit; | |
208 | } | |
209 | ||
210 | /* wait for child to exit */ | |
211 | my_wait_pid = wait4( my_pid, &my_status, 0, NULL ); | |
212 | if ( my_wait_pid == -1 ) { | |
213 | printf( "wait4 failed with errno %d - %s \n", errno, strerror( errno ) ); | |
214 | goto test_failed_exit; | |
215 | } | |
216 | ||
217 | /* wait4 should return our child's pid when it exits */ | |
218 | if ( my_wait_pid != my_pid ) { | |
219 | printf( "wait4 did not return child pid - returned %d should be %d \n", my_wait_pid, my_pid ); | |
220 | goto test_failed_exit; | |
221 | } | |
222 | ||
223 | if ( WIFSIGNALED( my_status ) && WTERMSIG( my_status ) != SIGKILL ) { | |
224 | printf( "wait4 returned wrong signal status - 0x%02X \n", my_status ); | |
225 | goto test_failed_exit; | |
226 | } | |
227 | ||
228 | my_err = 0; | |
229 | goto test_passed_exit; | |
230 | ||
231 | test_failed_exit: | |
232 | my_err = 1; | |
233 | ||
234 | test_passed_exit: | |
235 | return( my_err ); | |
236 | } /* do_execve_test */ | |
237 | ||
238 | /* | |
239 | * Helper function for posix_spawn test | |
240 | * arch: target architecture to spawn for | |
241 | */ | |
242 | int do_spawn_test(int arch, int shouldfail) | |
243 | { | |
244 | int my_err, my_pid, my_status; | |
245 | size_t my_size; | |
246 | posix_spawnattr_t attr; | |
247 | ||
248 | char * args[] = {"helpers/arch", NULL}; | |
cf7d32b8 | 249 | |
2d21ac55 A |
250 | my_err = posix_spawnattr_init(&attr); |
251 | if (my_err != 0) { | |
252 | printf("posix_spawnattr_init failed\n"); | |
253 | goto done; | |
254 | } | |
255 | ||
256 | /* set spawn to only succeed for arch 'arch' */ | |
257 | my_err = posix_spawnattr_setbinpref_np(&attr, 1, &arch, &my_size); | |
258 | if (my_err != 0 || my_size != 1) { | |
259 | printf("posix_spawnattr_setbinpref_np failed\n"); | |
260 | goto done; | |
261 | } | |
262 | ||
263 | /* spawn off child process */ | |
264 | my_err = posix_spawn(&my_pid, args[0], NULL, &attr, args, NULL); | |
265 | if (shouldfail) { | |
266 | if( my_err == 0) { | |
267 | printf("posix_spawn should have failed on arch %d\n", arch); | |
268 | goto done; | |
269 | } | |
270 | my_err = 0; | |
271 | } else { | |
272 | /* child should exit with return code == arch */ | |
273 | if (my_err != 0) { | |
274 | printf("posix_spawn failed with errno %d - %s\n", errno, strerror(errno)); | |
275 | goto done; | |
276 | } | |
277 | ||
278 | my_err = wait4(my_pid, &my_status, 0, NULL); | |
279 | if (my_err == -1) { | |
280 | printf("wait4 failed with errno %d - %s\n", errno, strerror(errno)); | |
281 | goto done; | |
282 | } | |
283 | my_err = 0; | |
284 | ||
285 | if (WEXITSTATUS(my_status) != (arch & 0xff)) { | |
286 | printf("child exited with status %d (expected %d)\n", | |
287 | (WEXITSTATUS(my_status)), | |
288 | (arch & 0xff)); | |
289 | my_err = -1; | |
290 | goto done; | |
291 | } | |
292 | } | |
293 | ||
294 | done: | |
295 | return my_err; | |
296 | } | |
297 | ||
298 | /* | |
299 | * Uses sysctlbyname to determine the cpu type. Currently, XNU classifies G5 as a | |
300 | * 32-bit CPU, so this shouldn't be used to determine whether or not a CPU | |
301 | * is 64-bit. | |
302 | */ | |
303 | int get_architecture() | |
304 | { | |
305 | int rval = -1; | |
306 | size_t length = 0; | |
307 | int my_err, buf; | |
308 | char *errmsg = NULL; | |
309 | ||
310 | errmsg = "sysctlbyname() failed when getting hw.cputype"; | |
311 | if (my_err = sysctlbyname("hw.cputype", NULL, &length, NULL, 0)) goto finished; /* get length of data */ | |
312 | if (length != sizeof(buf)) goto finished; | |
313 | if (my_err = sysctlbyname("hw.cputype", &buf, &length, NULL, 0)) goto finished; /* copy data */ | |
314 | switch (buf) { | |
315 | case CPU_TYPE_X86: | |
316 | case CPU_TYPE_X86_64: | |
317 | rval = INTEL; | |
318 | break; | |
319 | case CPU_TYPE_POWERPC: | |
320 | case CPU_TYPE_POWERPC64: | |
321 | rval = POWERPC; | |
322 | break; | |
cf7d32b8 A |
323 | case CPU_TYPE_ARM: |
324 | rval = ARM; | |
325 | break; | |
2d21ac55 A |
326 | } |
327 | ||
328 | finished: | |
329 | if (rval == -1 && errmsg) | |
330 | printf("%s", errmsg); | |
331 | ||
332 | return rval; | |
333 | } | |
334 | ||
335 | ||
336 | /* | |
337 | * Gets the bit'ed-ness of the current host. Returns either 32 or 64. | |
338 | * This get the hardware capability, but does not tell us whether this | |
339 | * binary is executing in 64 bit or 32 bit mode. Check sizeof long | |
340 | * or pointer to determine that. | |
341 | */ | |
342 | int get_bits() | |
343 | { | |
344 | int my_err, buf; | |
345 | size_t len = 0; | |
346 | int rval = 32; /* | |
347 | * On 32-bit systems the sysctls 64bitops and x86_64 don't | |
348 | * even exists, so if we don't find them then we assume | |
349 | * a 32-bit system. | |
350 | */ | |
351 | ||
352 | /* Check for PPC 64 */ | |
353 | if ((my_err = sysctlbyname("hw.optional.64bitops", NULL, &len, NULL, 0))) goto x86_64check; /* Request size */ | |
354 | if (len > sizeof(buf)) goto x86_64check; | |
355 | if ((my_err = sysctlbyname("hw.optional.64bitops", &buf, &len, NULL, 0))) goto x86_64check; /* Copy value out from kernel */ | |
356 | if (buf == 1) rval = 64; | |
357 | goto finished; | |
358 | ||
359 | x86_64check: | |
360 | /* Check for x86_64 */ | |
361 | if ((my_err = sysctlbyname("hw.optional.x86_64", NULL, &len, NULL, 0))) goto finished; /* Request size */ | |
362 | if (len > sizeof(buf)) goto finished; | |
363 | if ((my_err = sysctlbyname("hw.optional.x86_64", &buf, &len, NULL, 0))) goto finished; /* Copy value out from kernel */ | |
364 | if (buf == 1) rval = 64; | |
365 | ||
366 | finished: | |
367 | return rval; | |
368 | } | |
369 |