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