1 /* General tests for execpve.
2    Copyright (C) 2016-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <wait.h>
25 
26 
27 /* Nonzero if the program gets called via `exec'.  */
28 static int restart;
29 
30 
31 #define CMDLINE_OPTIONS \
32   { "restart", no_argument, &restart, 1 },
33 
34 /* Prototype for our test function.  */
35 extern void do_prepare (int argc, char *argv[]);
36 extern int do_test (int argc, char *argv[]);
37 
38 #include "../test-skeleton.c"
39 
40 #define EXECVPE_KEY    "EXECVPE_ENV"
41 #define EXECVPE_VALUE  "execvpe_test"
42 
43 
44 static int
handle_restart(void)45 handle_restart (void)
46 {
47   /* First check if only one variable is passed on execvpe.  */
48   int env_count = 0;
49   for (char **e = environ; *e != NULL; ++e)
50     if (++env_count == INT_MAX)
51       {
52 	printf ("Environment variable number overflow");
53 	exit (EXIT_FAILURE);
54       }
55   if (env_count != 1)
56     {
57       printf ("Wrong number of environment variables");
58       exit (EXIT_FAILURE);
59     }
60 
61   /* Check if the combinarion os "EXECVPE_ENV=execvpe_test"  */
62   const char *env = getenv (EXECVPE_KEY);
63   if (env == NULL)
64     {
65       printf ("Test environment variable not found");
66       exit (EXIT_FAILURE);
67     }
68 
69   if (strncmp (env, EXECVPE_VALUE, sizeof (EXECVPE_VALUE)))
70     {
71       printf ("Test environment variable with wrong value");
72       exit (EXIT_FAILURE);
73     }
74 
75   return 0;
76 }
77 
78 
79 int
do_test(int argc,char * argv[])80 do_test (int argc, char *argv[])
81 {
82   pid_t pid;
83   int status;
84 
85   /* We must have
86      - one or four parameters left if called initially
87        + path for ld.so		optional
88        + "--library-path"	optional
89        + the library path	optional
90        + the application name
91 
92     if --enable-hardcoded-path-in-tests is used, just
93       + the application name
94   */
95 
96   if (restart)
97     {
98       if (argc != 1)
99 	{
100 	  printf ("Wrong number of arguments (%d) in restart\n", argc);
101 	  exit (EXIT_FAILURE);
102 	}
103 
104       return handle_restart ();
105     }
106 
107   if (argc != 2 && argc != 5)
108     {
109       printf ("Wrong number of arguments (%d)\n", argc);
110       exit (EXIT_FAILURE);
111     }
112 
113   /* We want to test the `execvpe' function.  To do this we restart the
114      program with an additional parameter.  */
115   pid = fork ();
116   if (pid == 0)
117     {
118       /* This is the child.  Construct the command line.  */
119 
120       /* We cast here to char* because the test itself does not modify neither
121 	 the argument nor the environment list.  */
122       char *envs[] = { (char*)(EXECVPE_KEY "=" EXECVPE_VALUE), NULL };
123       if (argc == 5)
124 	{
125 	  char *args[] = { argv[1], argv[2], argv[3], argv[4],
126 			   (char *) "--direct", (char *) "--restart", NULL };
127 	  execvpe (args[0], args, envs);
128 	}
129       else
130 	{
131 	  char *args[] = { argv[0],
132 			   (char *) "--direct", (char *) "--restart", NULL };
133 	  execvpe (args[0], args, envs);
134 	}
135 
136       puts ("Cannot exec");
137       exit (EXIT_FAILURE);
138     }
139   else if (pid == (pid_t) -1)
140     {
141       puts ("Cannot fork");
142       return 1;
143     }
144 
145   /* Wait for the child.  */
146   if (waitpid (pid, &status, 0) != pid)
147     {
148       puts ("Wrong child");
149       return 1;
150     }
151 
152   if (WTERMSIG (status) != 0)
153     {
154       puts ("Child terminated incorrectly");
155       return 1;
156     }
157   status = WEXITSTATUS (status);
158 
159   return status;
160 }
161