xref: /dpdk/app/test/process.h (revision d38febb08d57fec29fed27a2d12a507fc6fcdfa1)
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 #include <libgen.h> /* basename et al */
11 #include <stdlib.h> /* NULL */
12 #include <string.h> /* strerror */
13 #include <unistd.h> /* readlink */
14 #include <dirent.h>
15 #include <sys/wait.h>
16 
17 #include <rte_string_fns.h> /* strlcpy */
18 
19 #ifdef RTE_EXEC_ENV_FREEBSD
20 #define self "curproc"
21 #define exe "file"
22 #else
23 #define self "self"
24 #define exe "exe"
25 #endif
26 
27 #ifdef RTE_LIB_PDUMP
28 #ifdef RTE_NET_RING
29 #include <pthread.h>
30 extern void *send_pkts(void *empty);
31 extern uint16_t flag_for_send_pkts;
32 #endif
33 #endif
34 
35 /*
36  * launches a second copy of the test process using the given argv parameters,
37  * which should include argv[0] as the process name. To identify in the
38  * subprocess the source of the call, the env_value parameter is set in the
39  * environment as $RTE_TEST
40  */
41 static inline int
42 process_dup(const char *const argv[], int numargs, const char *env_value)
43 {
44 	int num;
45 	char *argv_cpy[numargs + 1];
46 	int i, status;
47 	char path[32];
48 #ifdef RTE_LIB_PDUMP
49 #ifdef RTE_NET_RING
50 	pthread_t thread;
51 	int rc;
52 #endif
53 #endif
54 
55 	pid_t pid = fork();
56 	if (pid < 0)
57 		return -1;
58 	else if (pid == 0) {
59 		/* make a copy of the arguments to be passed to exec */
60 		for (i = 0; i < numargs; i++)
61 			argv_cpy[i] = strdup(argv[i]);
62 		argv_cpy[i] = NULL;
63 		num = numargs;
64 
65 #ifdef RTE_EXEC_ENV_LINUX
66 		{
67 			const char *procdir = "/proc/" self "/fd/";
68 			struct dirent *dirent;
69 			char *endptr;
70 			int fd, fdir;
71 			DIR *dir;
72 
73 			/* close all open file descriptors, check /proc/self/fd
74 			 * to only call close on open fds. Exclude fds 0, 1 and
75 			 * 2
76 			 */
77 			dir = opendir(procdir);
78 			if (dir == NULL) {
79 				rte_panic("Error opening %s: %s\n", procdir,
80 						strerror(errno));
81 			}
82 
83 			fdir = dirfd(dir);
84 			if (fdir < 0) {
85 				status = errno;
86 				closedir(dir);
87 				rte_panic("Error %d obtaining fd for dir %s: %s\n",
88 						fdir, procdir,
89 						strerror(status));
90 			}
91 
92 			while ((dirent = readdir(dir)) != NULL) {
93 
94 				if (strcmp(dirent->d_name, ".") == 0 ||
95 					strcmp(dirent->d_name, "..") == 0)
96 					continue;
97 
98 				errno = 0;
99 				fd = strtol(dirent->d_name, &endptr, 10);
100 				if (errno != 0 || endptr[0] != '\0') {
101 					printf("Error converting name fd %d %s:\n",
102 						fd, dirent->d_name);
103 					continue;
104 				}
105 
106 				if (fd == fdir || fd <= 2)
107 					continue;
108 
109 				close(fd);
110 			}
111 			closedir(dir);
112 		}
113 #endif
114 		printf("Running binary with argv[]:");
115 		for (i = 0; i < num; i++)
116 			printf("'%s' ", argv_cpy[i]);
117 		printf("\n");
118 		fflush(stdout);
119 
120 		/* set the environment variable */
121 		if (setenv(RECURSIVE_ENV_VAR, env_value, 1) != 0)
122 			rte_panic("Cannot export environment variable\n");
123 
124 		strlcpy(path, "/proc/" self "/" exe, sizeof(path));
125 		if (execv(path, argv_cpy) < 0) {
126 			if (errno == ENOENT) {
127 				printf("Could not find '%s', is procfs mounted?\n",
128 						path);
129 			}
130 			rte_panic("Cannot exec: %s\n", strerror(errno));
131 		}
132 	}
133 	/* parent process does a wait */
134 #ifdef RTE_LIB_PDUMP
135 #ifdef RTE_NET_RING
136 	if ((strcmp(env_value, "run_pdump_server_tests") == 0)) {
137 		rc = pthread_create(&thread, NULL, &send_pkts, NULL);
138 		if (rc != 0) {
139 			rte_panic("Cannot start send pkts thread: %s\n",
140 				  strerror(rc));
141 		}
142 	}
143 #endif
144 #endif
145 
146 	while (wait(&status) != pid)
147 		;
148 #ifdef RTE_LIB_PDUMP
149 #ifdef RTE_NET_RING
150 	if ((strcmp(env_value, "run_pdump_server_tests") == 0)) {
151 		flag_for_send_pkts = 0;
152 		pthread_join(thread, NULL);
153 	}
154 #endif
155 #endif
156 	return status;
157 }
158 
159 /* FreeBSD doesn't support file prefixes, so force compile failures for any
160  * tests attempting to use this function on FreeBSD.
161  */
162 #ifdef RTE_EXEC_ENV_LINUX
163 static char *
164 get_current_prefix(char *prefix, int size)
165 {
166 	char path[PATH_MAX] = {0};
167 	char buf[PATH_MAX] = {0};
168 
169 	/* get file for config (fd is always 3) */
170 	snprintf(path, sizeof(path), "/proc/self/fd/%d", 3);
171 
172 	/* return NULL on error */
173 	if (readlink(path, buf, sizeof(buf)) == -1)
174 		return NULL;
175 
176 	/* get the prefix */
177 	snprintf(prefix, size, "%s", basename(dirname(buf)));
178 
179 	return prefix;
180 }
181 #endif
182 
183 #endif /* _PROCESS_H_ */
184