]>
Commit | Line | Data |
---|---|---|
a334319f | 1 | /* Copyright (C) 1991,92,1995-99,2002,2004 Free Software Foundation, Inc. |
c84142e8 | 2 | This file is part of the GNU C Library. |
28f540f4 | 3 | |
c84142e8 | 4 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
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. | |
28f540f4 | 8 | |
c84142e8 UD |
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 | |
41bdb6e2 | 12 | Lesser General Public License for more details. |
28f540f4 | 13 | |
41bdb6e2 AJ |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, write to the Free | |
16 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
17 | 02111-1307 USA. */ | |
28f540f4 | 18 | |
28f540f4 RM |
19 | #include <unistd.h> |
20 | #include <stdarg.h> | |
21 | #include <stdlib.h> | |
22 | #include <string.h> | |
60092701 | 23 | #include <errno.h> |
6a032d81 | 24 | #include <paths.h> |
28f540f4 | 25 | |
dfd2257a | 26 | |
c4563d2d UD |
27 | /* The file is accessible but it is not an executable file. Invoke |
28 | the shell to interpret it as a script. */ | |
dfd2257a UD |
29 | static void |
30 | internal_function | |
a334319f | 31 | script_execute (const char *file, char *const argv[]) |
28f540f4 | 32 | { |
a334319f UD |
33 | /* Count the arguments. */ |
34 | int argc = 0; | |
35 | while (argv[argc++]) | |
36 | ; | |
37 | ||
c4563d2d | 38 | /* Construct an argument list for the shell. */ |
a334319f UD |
39 | { |
40 | char *new_argv[argc + 1]; | |
41 | new_argv[0] = (char *) _PATH_BSHELL; | |
42 | new_argv[1] = (char *) file; | |
43 | while (argc > 1) | |
44 | { | |
45 | new_argv[argc] = argv[argc - 1]; | |
46 | --argc; | |
47 | } | |
48 | ||
49 | /* Execute the shell. */ | |
50 | __execve (new_argv[0], new_argv, __environ); | |
51 | } | |
dfd2257a UD |
52 | } |
53 | ||
54 | ||
55 | /* Execute FILE, searching in the `PATH' environment variable if it contains | |
56 | no slashes, with arguments ARGV and environment from `environ'. */ | |
57 | int | |
58 | execvp (file, argv) | |
59 | const char *file; | |
60 | char *const argv[]; | |
61 | { | |
9271a050 UD |
62 | if (*file == '\0') |
63 | { | |
64 | /* We check the simple case first. */ | |
65 | __set_errno (ENOENT); | |
66 | return -1; | |
67 | } | |
68 | ||
c4bf5a3e | 69 | if (strchr (file, '/') != NULL) |
c4563d2d UD |
70 | { |
71 | /* Don't search when it contains a slash. */ | |
d13ec59a | 72 | __execve (file, argv, __environ); |
c4563d2d UD |
73 | |
74 | if (errno == ENOEXEC) | |
a334319f | 75 | script_execute (file, argv); |
c4563d2d | 76 | } |
c4bf5a3e | 77 | else |
28f540f4 | 78 | { |
a334319f UD |
79 | int got_eacces = 0; |
80 | char *path, *p, *name; | |
81 | size_t len; | |
69c0500a | 82 | size_t pathlen; |
28f540f4 | 83 | |
a334319f | 84 | path = getenv ("PATH"); |
28f540f4 RM |
85 | if (path == NULL) |
86 | { | |
87 | /* There is no `PATH' in the environment. | |
88 | The default search path is the current directory | |
89 | followed by the path `confstr' returns for `_CS_PATH'. */ | |
a334319f UD |
90 | len = confstr (_CS_PATH, (char *) NULL, 0); |
91 | path = (char *) __alloca (1 + len); | |
28f540f4 | 92 | path[0] = ':'; |
a334319f | 93 | (void) confstr (_CS_PATH, path + 1, len); |
28f540f4 RM |
94 | } |
95 | ||
a334319f UD |
96 | len = strlen (file) + 1; |
97 | pathlen = strlen (path); | |
98 | name = __alloca (pathlen + len + 1); | |
d13ec59a | 99 | /* Copy the file name at the top. */ |
69c0500a | 100 | name = (char *) memcpy (name + pathlen + 1, file, len); |
d13ec59a UD |
101 | /* And add the slash. */ |
102 | *--name = '/'; | |
103 | ||
a334319f | 104 | p = path; |
28f540f4 RM |
105 | do |
106 | { | |
d13ec59a UD |
107 | char *startp; |
108 | ||
28f540f4 | 109 | path = p; |
c4563d2d | 110 | p = __strchrnul (path, ':'); |
28f540f4 RM |
111 | |
112 | if (p == path) | |
113 | /* Two adjacent colons, or a colon at the beginning or the end | |
114 | of `PATH' means to search the current directory. */ | |
d13ec59a | 115 | startp = name + 1; |
28f540f4 | 116 | else |
d13ec59a | 117 | startp = (char *) memcpy (name - (p - path), path, p - path); |
c4bf5a3e | 118 | |
a334319f | 119 | /* Try to execute this name. If it works, execv will not return. */ |
d13ec59a | 120 | __execve (startp, argv, __environ); |
c4563d2d UD |
121 | |
122 | if (errno == ENOEXEC) | |
a334319f | 123 | script_execute (startp, argv); |
6a032d81 RM |
124 | |
125 | switch (errno) | |
126 | { | |
6a032d81 | 127 | case EACCES: |
a1c46301 RM |
128 | /* Record the we got a `Permission denied' error. If we end |
129 | up finding no executable we can use, we want to diagnose | |
130 | that we did find one but were denied access. */ | |
a334319f | 131 | got_eacces = 1; |
a1c46301 | 132 | case ENOENT: |
2d7da676 | 133 | case ESTALE: |
c94a8080 | 134 | case ENOTDIR: |
6a032d81 RM |
135 | /* Those errors indicate the file is missing or not executable |
136 | by us, in which case we want to just try the next path | |
137 | directory. */ | |
da9f699f UD |
138 | case ENODEV: |
139 | case ETIMEDOUT: | |
140 | /* Some strange filesystems like AFS return even | |
141 | stranger error numbers. They cannot reasonably mean | |
142 | anything else so ignore those, too. */ | |
6a032d81 RM |
143 | break; |
144 | ||
145 | default: | |
146 | /* Some other error means we found an executable file, but | |
147 | something went wrong executing it; return the error to our | |
148 | caller. */ | |
149 | return -1; | |
150 | } | |
28f540f4 RM |
151 | } |
152 | while (*p++ != '\0'); | |
a1c46301 | 153 | |
c4563d2d UD |
154 | /* We tried every element and none of them worked. */ |
155 | if (got_eacces) | |
156 | /* At least one failure was due to permissions, so report that | |
a334319f | 157 | error. */ |
c4563d2d UD |
158 | __set_errno (EACCES); |
159 | } | |
a1c46301 RM |
160 | |
161 | /* Return the error from the last attempt (probably ENOENT). */ | |
c4bf5a3e | 162 | return -1; |
28f540f4 | 163 | } |
c41f555e | 164 | libc_hidden_def (execvp) |