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