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