1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
3 */
4
5 #ifndef _PROCESS_H_
6 #define _PROCESS_H_
7
8 #include <errno.h> /* errno */
9 #include <limits.h> /* PATH_MAX */
10 #ifndef RTE_EXEC_ENV_WINDOWS
11 #include <libgen.h> /* basename et al */
12 #include <sys/wait.h>
13 #endif
14 #include <stdlib.h> /* NULL */
15 #include <string.h> /* strerror */
16 #include <unistd.h> /* readlink */
17 #include <dirent.h>
18
19 #include <rte_string_fns.h> /* strlcpy */
20 #include <rte_devargs.h>
21
22 #ifdef RTE_EXEC_ENV_FREEBSD
23 #define self "curproc"
24 #define exe "file"
25 #else
26 #define self "self"
27 #define exe "exe"
28 #endif
29
30 #ifdef RTE_LIB_PDUMP
31 #ifdef RTE_NET_RING
32 #include <rte_thread.h>
33 extern uint32_t send_pkts(void *empty);
34 extern uint16_t flag_for_send_pkts;
35 #endif
36 #endif
37
38 #define PREFIX_ALLOW "--allow="
39
40 static int
add_parameter_allow(char ** argv,int max_capacity)41 add_parameter_allow(char **argv, int max_capacity)
42 {
43 struct rte_devargs *devargs;
44 int count = 0;
45
46 RTE_EAL_DEVARGS_FOREACH(NULL, devargs) {
47 if (strlen(devargs->name) == 0)
48 continue;
49
50 if (devargs->data == NULL || strlen(devargs->data) == 0) {
51 if (asprintf(&argv[count], PREFIX_ALLOW"%s", devargs->name) < 0)
52 break;
53 } else {
54 if (asprintf(&argv[count], PREFIX_ALLOW"%s,%s",
55 devargs->name, devargs->data) < 0)
56 break;
57 }
58
59 if (++count == max_capacity)
60 break;
61 }
62
63 return count;
64 }
65
66 /*
67 * launches a second copy of the test process using the given argv parameters,
68 * which should include argv[0] as the process name. To identify in the
69 * subprocess the source of the call, the env_value parameter is set in the
70 * environment as $RTE_TEST
71 */
72 static inline int
process_dup(const char * const argv[],int numargs,const char * env_value)73 process_dup(const char *const argv[], int numargs, const char *env_value)
74 {
75 int num = 0;
76 char **argv_cpy;
77 int allow_num;
78 int argv_num;
79 int i, status;
80 char path[32];
81 #ifdef RTE_LIB_PDUMP
82 #ifdef RTE_NET_RING
83 rte_thread_t thread;
84 int rc;
85 #endif
86 #endif
87
88 pid_t pid = fork();
89 if (pid < 0)
90 return -1;
91 else if (pid == 0) {
92 allow_num = rte_devargs_type_count(RTE_DEVTYPE_ALLOWED);
93 argv_num = numargs + allow_num + 1;
94 argv_cpy = calloc(argv_num, sizeof(char *));
95 if (!argv_cpy)
96 rte_panic("Memory allocation failed\n");
97
98 /* make a copy of the arguments to be passed to exec */
99 for (i = 0; i < numargs; i++) {
100 argv_cpy[i] = strdup(argv[i]);
101 if (argv_cpy[i] == NULL)
102 rte_panic("Error dup args\n");
103 }
104 if (allow_num > 0)
105 num = add_parameter_allow(&argv_cpy[i], allow_num);
106 num += numargs;
107
108 #ifdef RTE_EXEC_ENV_LINUX
109 {
110 const char *procdir = "/proc/" self "/fd/";
111 struct dirent *dirent;
112 char *endptr;
113 int fd, fdir;
114 DIR *dir;
115
116 /* close all open file descriptors, check /proc/self/fd
117 * to only call close on open fds. Exclude fds 0, 1 and
118 * 2
119 */
120 dir = opendir(procdir);
121 if (dir == NULL) {
122 rte_panic("Error opening %s: %s\n", procdir,
123 strerror(errno));
124 }
125
126 fdir = dirfd(dir);
127 if (fdir < 0) {
128 status = errno;
129 closedir(dir);
130 rte_panic("Error %d obtaining fd for dir %s: %s\n",
131 fdir, procdir,
132 strerror(status));
133 }
134
135 while ((dirent = readdir(dir)) != NULL) {
136
137 if (strcmp(dirent->d_name, ".") == 0 ||
138 strcmp(dirent->d_name, "..") == 0)
139 continue;
140
141 errno = 0;
142 fd = strtol(dirent->d_name, &endptr, 10);
143 if (errno != 0 || endptr[0] != '\0') {
144 printf("Error converting name fd %d %s:\n",
145 fd, dirent->d_name);
146 continue;
147 }
148
149 if (fd == fdir || fd <= 2)
150 continue;
151
152 close(fd);
153 }
154 closedir(dir);
155 }
156 #endif
157 printf("Running binary with argv[]:");
158 for (i = 0; i < num; i++)
159 printf("'%s' ", argv_cpy[i]);
160 printf("\n");
161 fflush(stdout);
162
163 /* set the environment variable */
164 if (setenv(RECURSIVE_ENV_VAR, env_value, 1) != 0)
165 rte_panic("Cannot export environment variable\n");
166
167 strlcpy(path, "/proc/" self "/" exe, sizeof(path));
168 if (execv(path, argv_cpy) < 0) {
169 if (errno == ENOENT) {
170 printf("Could not find '%s', is procfs mounted?\n",
171 path);
172 }
173 rte_panic("Cannot exec: %s\n", strerror(errno));
174 }
175 }
176 /* parent process does a wait */
177 #ifdef RTE_LIB_PDUMP
178 #ifdef RTE_NET_RING
179 if ((strcmp(env_value, "run_pdump_server_tests") == 0)) {
180 rc = rte_thread_create(&thread, NULL, send_pkts, NULL);
181 if (rc != 0) {
182 rte_panic("Cannot start send pkts thread: %s\n",
183 strerror(rc));
184 }
185 }
186 #endif
187 #endif
188
189 while (wait(&status) != pid)
190 ;
191 #ifdef RTE_LIB_PDUMP
192 #ifdef RTE_NET_RING
193 if ((strcmp(env_value, "run_pdump_server_tests") == 0)) {
194 flag_for_send_pkts = 0;
195 rte_thread_join(thread, NULL);
196 }
197 #endif
198 #endif
199 return status;
200 }
201
202 /* FreeBSD doesn't support file prefixes, so force compile failures for any
203 * tests attempting to use this function on FreeBSD.
204 */
205 #ifdef RTE_EXEC_ENV_LINUX
206 static char *
get_current_prefix(char * prefix,int size)207 get_current_prefix(char *prefix, int size)
208 {
209 char path[PATH_MAX] = {0};
210 char buf[PATH_MAX] = {0};
211
212 /* get file for config (fd is always 3) */
213 snprintf(path, sizeof(path), "/proc/self/fd/%d", 3);
214
215 /* return NULL on error */
216 if (readlink(path, buf, sizeof(buf)) == -1)
217 return NULL;
218
219 /* get the prefix */
220 snprintf(prefix, size, "%s", basename(dirname(buf)));
221
222 return prefix;
223 }
224 #endif
225
226 #endif /* _PROCESS_H_ */
227