Fix build errors with -DNDEBUG.
[glibc.git] / posix / execvpe.c
blob61697a74f038e3960ab3f4568988349178ad69c0
1 /* Copyright (C) 1991-2016 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
18 #include <alloca.h>
19 #include <unistd.h>
20 #include <stdarg.h>
21 #include <stdbool.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <paths.h>
28 /* The file is accessible but it is not an executable file. Invoke
29 the shell to interpret it as a script. */
30 static void
31 internal_function
32 scripts_argv (const char *file, char *const argv[], int argc, char **new_argv)
34 /* Construct an argument list for the shell. */
35 new_argv[0] = (char *) _PATH_BSHELL;
36 new_argv[1] = (char *) file;
37 while (argc > 1)
39 new_argv[argc] = argv[argc - 1];
40 --argc;
45 /* Execute FILE, searching in the `PATH' environment variable if it contains
46 no slashes, with arguments ARGV and environment from ENVP. */
47 int
48 __execvpe (const char *file, char *const argv[], char *const envp[])
50 if (*file == '\0')
52 /* We check the simple case first. */
53 __set_errno (ENOENT);
54 return -1;
57 if (strchr (file, '/') != NULL)
59 /* Don't search when it contains a slash. */
60 __execve (file, argv, envp);
62 if (errno == ENOEXEC)
64 /* Count the arguments. */
65 int argc = 0;
66 while (argv[argc++])
68 size_t len = (argc + 1) * sizeof (char *);
69 char **script_argv;
70 void *ptr = NULL;
71 if (__libc_use_alloca (len))
72 script_argv = alloca (len);
73 else
74 script_argv = ptr = malloc (len);
76 if (script_argv != NULL)
78 scripts_argv (file, argv, argc, script_argv);
79 __execve (script_argv[0], script_argv, envp);
81 free (ptr);
85 else
87 size_t pathlen;
88 size_t alloclen = 0;
89 char *path = getenv ("PATH");
90 if (path == NULL)
92 pathlen = confstr (_CS_PATH, (char *) NULL, 0);
93 alloclen = pathlen + 1;
95 else
96 pathlen = strlen (path);
98 size_t len = strlen (file) + 1;
99 alloclen += pathlen + len + 1;
101 char *name;
102 char *path_malloc = NULL;
103 if (__libc_use_alloca (alloclen))
104 name = alloca (alloclen);
105 else
107 path_malloc = name = malloc (alloclen);
108 if (name == NULL)
109 return -1;
112 if (path == NULL)
114 /* There is no `PATH' in the environment.
115 The default search path is the current directory
116 followed by the path `confstr' returns for `_CS_PATH'. */
117 path = name + pathlen + len + 1;
118 path[0] = ':';
119 (void) confstr (_CS_PATH, path + 1, pathlen);
122 /* Copy the file name at the top. */
123 name = (char *) memcpy (name + pathlen + 1, file, len);
124 /* And add the slash. */
125 *--name = '/';
127 char **script_argv = NULL;
128 void *script_argv_malloc = NULL;
129 bool got_eacces = false;
130 char *p = path;
133 char *startp;
135 path = p;
136 p = __strchrnul (path, ':');
138 if (p == path)
139 /* Two adjacent colons, or a colon at the beginning or the end
140 of `PATH' means to search the current directory. */
141 startp = name + 1;
142 else
143 startp = (char *) memcpy (name - (p - path), path, p - path);
145 /* Try to execute this name. If it works, execve will not return. */
146 __execve (startp, argv, envp);
148 if (errno == ENOEXEC)
150 if (script_argv == NULL)
152 /* Count the arguments. */
153 int argc = 0;
154 while (argv[argc++])
156 size_t arglen = (argc + 1) * sizeof (char *);
157 if (__libc_use_alloca (alloclen + arglen))
158 script_argv = alloca (arglen);
159 else
160 script_argv = script_argv_malloc = malloc (arglen);
161 if (script_argv == NULL)
163 /* A possible EACCES error is not as important as
164 the ENOMEM. */
165 got_eacces = false;
166 break;
168 scripts_argv (startp, argv, argc, script_argv);
171 __execve (script_argv[0], script_argv, envp);
174 switch (errno)
176 case EACCES:
177 /* Record the we got a `Permission denied' error. If we end
178 up finding no executable we can use, we want to diagnose
179 that we did find one but were denied access. */
180 got_eacces = true;
181 case ENOENT:
182 case ESTALE:
183 case ENOTDIR:
184 /* Those errors indicate the file is missing or not executable
185 by us, in which case we want to just try the next path
186 directory. */
187 case ENODEV:
188 case ETIMEDOUT:
189 /* Some strange filesystems like AFS return even
190 stranger error numbers. They cannot reasonably mean
191 anything else so ignore those, too. */
192 break;
194 default:
195 /* Some other error means we found an executable file, but
196 something went wrong executing it; return the error to our
197 caller. */
198 return -1;
201 while (*p++ != '\0');
203 /* We tried every element and none of them worked. */
204 if (got_eacces)
205 /* At least one failure was due to permissions, so report that
206 error. */
207 __set_errno (EACCES);
209 free (script_argv_malloc);
210 free (path_malloc);
213 /* Return the error from the last attempt (probably ENOENT). */
214 return -1;
216 weak_alias (__execvpe, execvpe)