1
2#include "tests.h"
3#include <mach/mach.h>
4
5extern 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 */
15int 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 */
84int 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
149failure_exit:
150	my_result = -1;
151routine_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 */
172int 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	/* vfork then execve sleep system command (which we will kill from the parent process) */
183	my_pid = vfork();
184	if (my_pid == -1) {
185		printf( "vfork failed with errno %d - %s \n", errno, strerror( errno ) );
186		goto test_failed_exit;
187	}
188	if ( my_pid == 0 ) {
189		/*
190		 * child process - use execve to start one of the customized helper
191		 * binaries, which just sleep for 120 seconds. Let our parent kill us.
192		 */
193
194		my_err = execve(path, argv, envp);
195		if ( my_err != 0 ) { /* TODO: execve() on x86_64 inca returns weird error codes, see rdar://4655612 */
196			printf( "execve call failed with return value: %d, errno: %d - \"%s\"; path: %s \n",
197				my_err, errno, strerror( errno), path );
198			fflush(stdout);
199			exit(-2);
200		}
201
202		/* should never get here */
203		printf("Execve failed and it was not caught by our test\n");
204		return(-1);
205	}
206	/*
207	 * parent process - let's kill our sleeping child
208	 */
209	sleep(killwait);
210	my_err = kill( my_pid, SIGKILL );
211	if ( my_err == -1 ) {
212		printf( "kill call failed with error %d - \"%s\" \n", errno, strerror( errno) );
213		goto test_failed_exit;
214	}
215
216	/* wait for child to exit */
217	my_wait_pid = wait4( my_pid, &my_status, 0, NULL );
218	if ( my_wait_pid == -1 ) {
219		printf( "wait4 failed with errno %d - %s \n", errno, strerror( errno ) );
220		goto test_failed_exit;
221	}
222
223	/* wait4 should return our child's pid when it exits */
224	if ( my_wait_pid != my_pid ) {
225		printf( "wait4 did not return child pid - returned %d should be %d \n", my_wait_pid, my_pid );
226		goto test_failed_exit;
227	}
228
229	if (!(WIFSIGNALED( my_status ))) {
230		printf( "child process was not signaled and should have been\n", my_status );
231		goto test_failed_exit;
232	}
233
234	if (WTERMSIG( my_status ) != SIGKILL) {
235		printf( "wait4 returned wrong signal status - 0x%02X \n", my_status );
236		goto test_failed_exit;
237	}
238
239	my_err = 0;
240	goto test_passed_exit;
241
242test_failed_exit:
243	my_err = 1;
244
245test_passed_exit:
246	return( my_err );
247} /* do_execve_test */
248
249/*
250 * Helper function for posix_spawn test
251 * 	arch: target architecture to spawn for
252 */
253int do_spawn_test(int arch, int shouldfail)
254{
255	int my_err, my_pid, my_status;
256	size_t my_size;
257	posix_spawnattr_t attr;
258
259	char * args[] = {"helpers/arch", NULL};
260
261	my_err = posix_spawnattr_init(&attr);
262	if (my_err != 0) {
263		printf("posix_spawnattr_init failed\n");
264		goto done;
265	}
266
267	/* set spawn to only succeed for arch 'arch' */
268	my_err = posix_spawnattr_setbinpref_np(&attr, 1, &arch, &my_size);
269	if (my_err != 0 || my_size != 1) {
270		printf("posix_spawnattr_setbinpref_np failed\n");
271		goto done;
272	}
273
274	/* spawn off child process */
275	my_err = posix_spawn(&my_pid, args[0], NULL, &attr, args, NULL);
276	if (shouldfail) {
277		if( my_err == 0) {
278			printf("posix_spawn should have failed on arch %d\n", arch);
279			goto done;
280		}
281		my_err = 0;
282	} else {
283		/*
284		 * child should exit with return code == arch; note that the
285		 * posix_spawn error numers are *returned*, NOT set in errno!!!
286		 */
287		if (my_err != 0) {
288			printf("posix_spawn failed with errno %d - %s\n", my_err, strerror(my_err));
289			goto done;
290		}
291
292		my_err = wait4(my_pid, &my_status, 0, NULL);
293		if (my_err == -1) {
294			printf("wait4 failed with errno %d - %s\n", errno, strerror(errno));
295			goto done;
296		}
297		my_err = 0;
298
299		if (WEXITSTATUS(my_status) != (arch & 0xff)) {
300			printf("child exited with status %d (expected %d)\n",
301					(WEXITSTATUS(my_status)),
302					(arch & 0xff));
303			my_err = -1;
304			goto done;
305		}
306	}
307
308done:
309	return my_err;
310}
311
312/*
313 * Uses sysctlbyname to determine the cpu type. Currently, XNU classifies G5 as a
314 * 32-bit CPU, so this shouldn't be used to determine whether or not a CPU
315 * is 64-bit.
316 */
317int get_architecture()
318{
319	int rval = -1;
320	size_t length = 0;
321	int my_err, buf;
322	char *errmsg = NULL;
323
324	errmsg = "sysctlbyname() failed when getting hw.cputype";
325	if ((my_err = sysctlbyname("hw.cputype", NULL, &length, NULL, 0))) goto finished;	/* get length of data */
326	if (length != sizeof(buf))					 goto finished;
327	if ((my_err = sysctlbyname("hw.cputype", &buf, &length, NULL, 0))) goto finished; /* copy data */
328	switch (buf) {
329	case CPU_TYPE_X86:
330	case CPU_TYPE_X86_64:
331		rval = INTEL;
332		break;
333	case CPU_TYPE_ARM:
334		rval = ARM;
335		break;
336	}
337
338finished:
339	if (rval == -1 && errmsg)
340		printf("%s", errmsg);
341
342	return rval;
343}
344
345
346/*
347 * Gets the bit'ed-ness of the current host. Returns either 32 or 64.
348 * This get the hardware capability, but does not tell us whether this
349 * binary is executing in 64 bit or 32 bit mode. Check sizeof long
350 * or pointer to determine that.
351 */
352int get_bits()
353{
354	int  my_err, buf;
355	size_t len = 0;
356	int rval = 32;	/*
357			 * On 32-bit systems the sysctls 64bitops and x86_64 don't
358			 * even exists, so if we don't find them then we assume
359			 * a 32-bit system.
360			 */
361
362	/* Check for PPC 64 */
363	if ((my_err = sysctlbyname("hw.optional.64bitops", NULL, &len, NULL, 0)))	goto check64bit; /* Request size */
364	if (len > sizeof(buf))								goto check64bit;
365	if ((my_err = sysctlbyname("hw.optional.64bitops", &buf, &len, NULL, 0)))	goto check64bit; /* Copy value out from kernel */
366	if (buf == 1) rval = 64;
367	goto finished;
368
369check64bit:
370#if defined(__i386__) || defined(__x86_64__)
371	/* Check for x86_64 */
372	if ((my_err = sysctlbyname("hw.optional.x86_64", NULL, &len, NULL, 0)))	goto finished; /* Request size */
373	if (len > sizeof(buf))							goto finished;
374	if ((my_err = sysctlbyname("hw.optional.x86_64", &buf, &len, NULL, 0)))	goto finished; /* Copy value out from kernel */
375	if (buf == 1) rval = 64;
376
377#else
378#error Unknown architecture.
379#endif
380
381finished:
382	return rval;
383}
384
385/*
386 * printf with a date and time stamp so that we can correlate printf's
387 * with the log files of a system in case of test failure.
388 *
389 * NB: MY_PRINTF_DATE_FMT chosen to look like syslog to aid "grep".
390 */
391#define MY_PRINTF_DATE_FMT	"%b %e %T"
392#undef printf	/* was my_printf */
393int
394my_printf(const char * __restrict fmt, ...)
395{
396	char *bufp;
397	char datebuf[256];
398	struct tm *timeptr;
399	time_t result;
400	int rv;
401	va_list ap;
402
403	/* if we are running under a TestBot, do a normal printf */
404	if (g_testbots_active) {
405		va_start(ap, fmt);
406		rv = vprintf(fmt, ap);
407		va_end(ap);
408		return rv;
409	}
410
411	/* Get the timestamp for this printf */
412	result = time(NULL);
413	timeptr = localtime(&result);
414	strftime(datebuf, sizeof(datebuf), MY_PRINTF_DATE_FMT, timeptr);
415
416	/* do the printf of the requested data to a local buffer */
417	va_start(ap, fmt);
418	rv = vasprintf(&bufp, fmt, ap);
419	va_end(ap);
420
421	/*
422	 * if we successfully got a local buffer, then we want to
423	 * print a timestamp plus what we would have printed before,
424	 * then free the allocated memory.
425	 */
426	if (rv != -1) {
427		rv = printf("%s %s", datebuf, bufp);
428		free(bufp);
429	}
430
431	return(rv);
432}
433