xref: /dpdk/app/test/process.h (revision b3ce7891ad386310abab56352053a46ba06ca72f)
1a9de470cSBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2a9de470cSBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
3a9de470cSBruce Richardson  */
4a9de470cSBruce Richardson 
5a9de470cSBruce Richardson #ifndef _PROCESS_H_
6a9de470cSBruce Richardson #define _PROCESS_H_
7a9de470cSBruce Richardson 
8b8d5e544SAnatoly Burakov #include <errno.h>  /* errno */
9a9de470cSBruce Richardson #include <limits.h> /* PATH_MAX */
10987d40a0SJie Zhou #ifndef RTE_EXEC_ENV_WINDOWS
11a9de470cSBruce Richardson #include <libgen.h> /* basename et al */
12987d40a0SJie Zhou #include <sys/wait.h>
13987d40a0SJie Zhou #endif
14a9de470cSBruce Richardson #include <stdlib.h> /* NULL */
15b8d5e544SAnatoly Burakov #include <string.h> /* strerror */
16a9de470cSBruce Richardson #include <unistd.h> /* readlink */
1718562261SKrzysztof Kanas #include <dirent.h>
18a9de470cSBruce Richardson 
19b8d5e544SAnatoly Burakov #include <rte_string_fns.h> /* strlcpy */
20*b3ce7891SMingjin Ye #include <rte_devargs.h>
21b8d5e544SAnatoly Burakov 
225fbc1d49SBruce Richardson #ifdef RTE_EXEC_ENV_FREEBSD
23a9de470cSBruce Richardson #define self "curproc"
24a9de470cSBruce Richardson #define exe "file"
25a9de470cSBruce Richardson #else
26a9de470cSBruce Richardson #define self "self"
27a9de470cSBruce Richardson #define exe "exe"
28a9de470cSBruce Richardson #endif
29a9de470cSBruce Richardson 
30a8d0d473SBruce Richardson #ifdef RTE_LIB_PDUMP
31a8d0d473SBruce Richardson #ifdef RTE_NET_RING
328eea1437SThomas Monjalon #include <rte_thread.h>
338eea1437SThomas Monjalon extern uint32_t send_pkts(void *empty);
34a9de470cSBruce Richardson extern uint16_t flag_for_send_pkts;
356d27d8c0SReshma Pattan #endif
36207b1c81SReshma Pattan #endif
37a9de470cSBruce Richardson 
38*b3ce7891SMingjin Ye #define PREFIX_ALLOW "--allow="
39*b3ce7891SMingjin Ye 
40*b3ce7891SMingjin Ye static int
add_parameter_allow(char ** argv,int max_capacity)41*b3ce7891SMingjin Ye add_parameter_allow(char **argv, int max_capacity)
42*b3ce7891SMingjin Ye {
43*b3ce7891SMingjin Ye 	struct rte_devargs *devargs;
44*b3ce7891SMingjin Ye 	int count = 0;
45*b3ce7891SMingjin Ye 
46*b3ce7891SMingjin Ye 	RTE_EAL_DEVARGS_FOREACH(NULL, devargs) {
47*b3ce7891SMingjin Ye 		if (strlen(devargs->name) == 0)
48*b3ce7891SMingjin Ye 			continue;
49*b3ce7891SMingjin Ye 
50*b3ce7891SMingjin Ye 		if (devargs->data == NULL || strlen(devargs->data) == 0) {
51*b3ce7891SMingjin Ye 			if (asprintf(&argv[count], PREFIX_ALLOW"%s", devargs->name) < 0)
52*b3ce7891SMingjin Ye 				break;
53*b3ce7891SMingjin Ye 		} else {
54*b3ce7891SMingjin Ye 			if (asprintf(&argv[count], PREFIX_ALLOW"%s,%s",
55*b3ce7891SMingjin Ye 					 devargs->name, devargs->data) < 0)
56*b3ce7891SMingjin Ye 				break;
57*b3ce7891SMingjin Ye 		}
58*b3ce7891SMingjin Ye 
59*b3ce7891SMingjin Ye 		if (++count == max_capacity)
60*b3ce7891SMingjin Ye 			break;
61*b3ce7891SMingjin Ye 	}
62*b3ce7891SMingjin Ye 
63*b3ce7891SMingjin Ye 	return count;
64*b3ce7891SMingjin Ye }
65*b3ce7891SMingjin Ye 
66a9de470cSBruce Richardson /*
67a9de470cSBruce Richardson  * launches a second copy of the test process using the given argv parameters,
68a9de470cSBruce Richardson  * which should include argv[0] as the process name. To identify in the
69a9de470cSBruce Richardson  * subprocess the source of the call, the env_value parameter is set in the
70a9de470cSBruce Richardson  * environment as $RTE_TEST
71a9de470cSBruce Richardson  */
72a9de470cSBruce Richardson static inline int
process_dup(const char * const argv[],int numargs,const char * env_value)73a9de470cSBruce Richardson process_dup(const char *const argv[], int numargs, const char *env_value)
74a9de470cSBruce Richardson {
75*b3ce7891SMingjin Ye 	int num = 0;
76*b3ce7891SMingjin Ye 	char **argv_cpy;
77*b3ce7891SMingjin Ye 	int allow_num;
78*b3ce7891SMingjin Ye 	int argv_num;
7918562261SKrzysztof Kanas 	int i, status;
80a9de470cSBruce Richardson 	char path[32];
81a8d0d473SBruce Richardson #ifdef RTE_LIB_PDUMP
82a8d0d473SBruce Richardson #ifdef RTE_NET_RING
838eea1437SThomas Monjalon 	rte_thread_t thread;
84a20cb9d0SChengwen Feng 	int rc;
856d27d8c0SReshma Pattan #endif
86207b1c81SReshma Pattan #endif
87a9de470cSBruce Richardson 
88a9de470cSBruce Richardson 	pid_t pid = fork();
89a9de470cSBruce Richardson 	if (pid < 0)
90a9de470cSBruce Richardson 		return -1;
91a9de470cSBruce Richardson 	else if (pid == 0) {
92*b3ce7891SMingjin Ye 		allow_num = rte_devargs_type_count(RTE_DEVTYPE_ALLOWED);
93*b3ce7891SMingjin Ye 		argv_num = numargs + allow_num + 1;
94*b3ce7891SMingjin Ye 		argv_cpy = calloc(argv_num, sizeof(char *));
95*b3ce7891SMingjin Ye 		if (!argv_cpy)
96*b3ce7891SMingjin Ye 			rte_panic("Memory allocation failed\n");
97*b3ce7891SMingjin Ye 
98a9de470cSBruce Richardson 		/* make a copy of the arguments to be passed to exec */
9968edcacfSChengwen Feng 		for (i = 0; i < numargs; i++) {
100a9de470cSBruce Richardson 			argv_cpy[i] = strdup(argv[i]);
10168edcacfSChengwen Feng 			if (argv_cpy[i] == NULL)
10268edcacfSChengwen Feng 				rte_panic("Error dup args\n");
10368edcacfSChengwen Feng 		}
104*b3ce7891SMingjin Ye 		if (allow_num > 0)
105*b3ce7891SMingjin Ye 			num = add_parameter_allow(&argv_cpy[i], allow_num);
106*b3ce7891SMingjin Ye 		num += numargs;
107a9de470cSBruce Richardson 
10818562261SKrzysztof Kanas #ifdef RTE_EXEC_ENV_LINUX
10918562261SKrzysztof Kanas 		{
11018562261SKrzysztof Kanas 			const char *procdir = "/proc/" self "/fd/";
11118562261SKrzysztof Kanas 			struct dirent *dirent;
11218562261SKrzysztof Kanas 			char *endptr;
11318562261SKrzysztof Kanas 			int fd, fdir;
11418562261SKrzysztof Kanas 			DIR *dir;
11518562261SKrzysztof Kanas 
11618562261SKrzysztof Kanas 			/* close all open file descriptors, check /proc/self/fd
11718562261SKrzysztof Kanas 			 * to only call close on open fds. Exclude fds 0, 1 and
11818562261SKrzysztof Kanas 			 * 2
11918562261SKrzysztof Kanas 			 */
12018562261SKrzysztof Kanas 			dir = opendir(procdir);
12118562261SKrzysztof Kanas 			if (dir == NULL) {
12218562261SKrzysztof Kanas 				rte_panic("Error opening %s: %s\n", procdir,
12318562261SKrzysztof Kanas 						strerror(errno));
12418562261SKrzysztof Kanas 			}
12518562261SKrzysztof Kanas 
12618562261SKrzysztof Kanas 			fdir = dirfd(dir);
12718562261SKrzysztof Kanas 			if (fdir < 0) {
12818562261SKrzysztof Kanas 				status = errno;
12918562261SKrzysztof Kanas 				closedir(dir);
13018562261SKrzysztof Kanas 				rte_panic("Error %d obtaining fd for dir %s: %s\n",
13118562261SKrzysztof Kanas 						fdir, procdir,
13218562261SKrzysztof Kanas 						strerror(status));
13318562261SKrzysztof Kanas 			}
13418562261SKrzysztof Kanas 
13518562261SKrzysztof Kanas 			while ((dirent = readdir(dir)) != NULL) {
136b13da15eSJohn Levon 
137b13da15eSJohn Levon 				if (strcmp(dirent->d_name, ".") == 0 ||
138b13da15eSJohn Levon 					strcmp(dirent->d_name, "..") == 0)
139b13da15eSJohn Levon 					continue;
140b13da15eSJohn Levon 
14118562261SKrzysztof Kanas 				errno = 0;
14218562261SKrzysztof Kanas 				fd = strtol(dirent->d_name, &endptr, 10);
14318562261SKrzysztof Kanas 				if (errno != 0 || endptr[0] != '\0') {
14418562261SKrzysztof Kanas 					printf("Error converting name fd %d %s:\n",
14518562261SKrzysztof Kanas 						fd, dirent->d_name);
14618562261SKrzysztof Kanas 					continue;
14718562261SKrzysztof Kanas 				}
14818562261SKrzysztof Kanas 
14918562261SKrzysztof Kanas 				if (fd == fdir || fd <= 2)
15018562261SKrzysztof Kanas 					continue;
15118562261SKrzysztof Kanas 
152a9de470cSBruce Richardson 				close(fd);
153a9de470cSBruce Richardson 			}
15418562261SKrzysztof Kanas 			closedir(dir);
15518562261SKrzysztof Kanas 		}
15618562261SKrzysztof Kanas #endif
157a9de470cSBruce Richardson 		printf("Running binary with argv[]:");
158a9de470cSBruce Richardson 		for (i = 0; i < num; i++)
159a9de470cSBruce Richardson 			printf("'%s' ", argv_cpy[i]);
160a9de470cSBruce Richardson 		printf("\n");
161b73c8edeSJohn Levon 		fflush(stdout);
162a9de470cSBruce Richardson 
163a9de470cSBruce Richardson 		/* set the environment variable */
164a9de470cSBruce Richardson 		if (setenv(RECURSIVE_ENV_VAR, env_value, 1) != 0)
165a9de470cSBruce Richardson 			rte_panic("Cannot export environment variable\n");
166b8d5e544SAnatoly Burakov 
167b8d5e544SAnatoly Burakov 		strlcpy(path, "/proc/" self "/" exe, sizeof(path));
168b8d5e544SAnatoly Burakov 		if (execv(path, argv_cpy) < 0) {
169b8d5e544SAnatoly Burakov 			if (errno == ENOENT) {
170b8d5e544SAnatoly Burakov 				printf("Could not find '%s', is procfs mounted?\n",
171b8d5e544SAnatoly Burakov 						path);
172b8d5e544SAnatoly Burakov 			}
173b8d5e544SAnatoly Burakov 			rte_panic("Cannot exec: %s\n", strerror(errno));
174b8d5e544SAnatoly Burakov 		}
175a9de470cSBruce Richardson 	}
176a9de470cSBruce Richardson 	/* parent process does a wait */
177a8d0d473SBruce Richardson #ifdef RTE_LIB_PDUMP
178a8d0d473SBruce Richardson #ifdef RTE_NET_RING
179a20cb9d0SChengwen Feng 	if ((strcmp(env_value, "run_pdump_server_tests") == 0)) {
1808eea1437SThomas Monjalon 		rc = rte_thread_create(&thread, NULL, send_pkts, NULL);
181a20cb9d0SChengwen Feng 		if (rc != 0) {
182a20cb9d0SChengwen Feng 			rte_panic("Cannot start send pkts thread: %s\n",
183a20cb9d0SChengwen Feng 				  strerror(rc));
184a20cb9d0SChengwen Feng 		}
185a20cb9d0SChengwen Feng 	}
1866d27d8c0SReshma Pattan #endif
187207b1c81SReshma Pattan #endif
188a9de470cSBruce Richardson 
189a9de470cSBruce Richardson 	while (wait(&status) != pid)
190a9de470cSBruce Richardson 		;
191a8d0d473SBruce Richardson #ifdef RTE_LIB_PDUMP
192a8d0d473SBruce Richardson #ifdef RTE_NET_RING
193a9de470cSBruce Richardson 	if ((strcmp(env_value, "run_pdump_server_tests") == 0)) {
194a9de470cSBruce Richardson 		flag_for_send_pkts = 0;
1958eea1437SThomas Monjalon 		rte_thread_join(thread, NULL);
196a9de470cSBruce Richardson 	}
1976d27d8c0SReshma Pattan #endif
198207b1c81SReshma Pattan #endif
199a9de470cSBruce Richardson 	return status;
200a9de470cSBruce Richardson }
201a9de470cSBruce Richardson 
202a9de470cSBruce Richardson /* FreeBSD doesn't support file prefixes, so force compile failures for any
203a9de470cSBruce Richardson  * tests attempting to use this function on FreeBSD.
204a9de470cSBruce Richardson  */
205742bde12SBruce Richardson #ifdef RTE_EXEC_ENV_LINUX
206a9de470cSBruce Richardson static char *
get_current_prefix(char * prefix,int size)207a9de470cSBruce Richardson get_current_prefix(char *prefix, int size)
208a9de470cSBruce Richardson {
209a9de470cSBruce Richardson 	char path[PATH_MAX] = {0};
210a9de470cSBruce Richardson 	char buf[PATH_MAX] = {0};
211a9de470cSBruce Richardson 
212a9de470cSBruce Richardson 	/* get file for config (fd is always 3) */
213a9de470cSBruce Richardson 	snprintf(path, sizeof(path), "/proc/self/fd/%d", 3);
214a9de470cSBruce Richardson 
215a9de470cSBruce Richardson 	/* return NULL on error */
216a9de470cSBruce Richardson 	if (readlink(path, buf, sizeof(buf)) == -1)
217a9de470cSBruce Richardson 		return NULL;
218a9de470cSBruce Richardson 
219a9de470cSBruce Richardson 	/* get the prefix */
220a9de470cSBruce Richardson 	snprintf(prefix, size, "%s", basename(dirname(buf)));
221a9de470cSBruce Richardson 
222a9de470cSBruce Richardson 	return prefix;
223a9de470cSBruce Richardson }
224a9de470cSBruce Richardson #endif
225a9de470cSBruce Richardson 
226a9de470cSBruce Richardson #endif /* _PROCESS_H_ */
227