1// SPDX-License-Identifier: GPL-2.0-only
2/* Test that empty argvs are swapped out for a single empty string. */
3#include <stdio.h>
4#include <unistd.h>
5#include <sys/types.h>
6#include <sys/wait.h>
7
8#include "../kselftest.h"
9
10#define FORK(exec)				\
11do {						\
12	pid = fork();				\
13	if (pid == 0) {				\
14		/* Child */			\
15		exec; /* Some kind of exec */	\
16		perror("# " #exec);		\
17		return 1;			\
18	}					\
19	check_result(pid, #exec);		\
20} while (0)
21
22void check_result(pid_t pid, const char *msg)
23{
24	int wstatus;
25
26	if (pid == (pid_t)-1) {
27		perror("# fork");
28		ksft_test_result_fail("fork failed: %s\n", msg);
29		return;
30	}
31	if (waitpid(pid, &wstatus, 0) < 0) {
32		perror("# waitpid");
33		ksft_test_result_fail("waitpid failed: %s\n", msg);
34		return;
35	}
36	if (!WIFEXITED(wstatus)) {
37		ksft_test_result_fail("child did not exit: %s\n", msg);
38		return;
39	}
40	if (WEXITSTATUS(wstatus) != 0) {
41		ksft_test_result_fail("non-zero exit: %s\n", msg);
42		return;
43	}
44	ksft_test_result_pass("%s\n", msg);
45}
46
47int main(int argc, char *argv[], char *envp[])
48{
49	pid_t pid;
50	static char * const args[] = { NULL };
51	static char * const str[] = { "", NULL };
52
53	/* argc counting checks */
54	if (argc < 1) {
55		fprintf(stderr, "# FAIL: saw argc == 0 (old kernel?)\n");
56		return 1;
57	}
58	if (argc != 1) {
59		fprintf(stderr, "# FAIL: unknown argc (%d)\n", argc);
60		return 1;
61	}
62	if (argv[0][0] == '\0') {
63		/* Good, we found a NULL terminated string at argv[0]! */
64		return 0;
65	}
66
67	/* Test runner. */
68	ksft_print_header();
69	ksft_set_plan(5);
70
71	FORK(execve(argv[0], str, NULL));
72	FORK(execve(argv[0], NULL, NULL));
73	FORK(execve(argv[0], NULL, envp));
74	FORK(execve(argv[0], args, NULL));
75	FORK(execve(argv[0], args, envp));
76
77	ksft_exit(ksft_cnt.ksft_pass == ksft_plan);
78}
79