Rev 3265 | Rev 3298 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3265 | Rev 3287 | ||
---|---|---|---|
1 | /* Copyright (c) 2008, Tim Post <tinkertim@gmail.com> |
1 | /* Copyright (c) 2008, Tim Post <tinkertim@gmail.com> |
2 | * All rights reserved. |
2 | * All rights reserved. |
3 | * |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions are met: |
5 | * modification, are permitted provided that the following conditions are met: |
6 | * |
6 | * |
7 | * Redistributions of source code must retain the above copyright notice, this |
7 | * Redistributions of source code must retain the above copyright notice, this |
8 | * list of conditions and the following disclaimer. |
8 | * list of conditions and the following disclaimer. |
9 | * |
9 | * |
10 | * Redistributions in binary form must reproduce the above copyright notice, |
10 | * Redistributions in binary form must reproduce the above copyright notice, |
11 | * this list of conditions and the following disclaimer in the documentation |
11 | * this list of conditions and the following disclaimer in the documentation |
12 | * and/or other materials provided with the distribution. |
12 | * and/or other materials provided with the distribution. |
13 | * |
13 | * |
14 | * Neither the name of the original program's authors nor the names of its |
14 | * Neither the name of the original program's authors nor the names of its |
15 | * contributors may be used to endorse or promote products derived from this |
15 | * contributors may be used to endorse or promote products derived from this |
16 | * software without specific prior written permission. |
16 | * software without specific prior written permission. |
17 | * |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
28 | * POSSIBILITY OF SUCH DAMAGE. |
28 | * POSSIBILITY OF SUCH DAMAGE. |
29 | */ |
29 | */ |
30 | 30 | ||
31 | /* The VERY basics of execute in place support. These are buggy, leaky |
31 | /* The VERY basics of execute in place support. These are buggy, leaky |
32 | * and not nearly done. Only here for beta testing!! You were warned!! |
32 | * and not nearly done. Only here for beta testing!! You were warned!! |
33 | * TODO: |
33 | * TODO: |
34 | * Hash command lookups to save time |
34 | * Hash command lookups to save time |
35 | * Create a running pointer to **path and advance/rewind it as we go */ |
35 | * Create a running pointer to **path and advance/rewind it as we go */ |
36 | 36 | ||
37 | #include <stdio.h> |
37 | #include <stdio.h> |
38 | #include <stdlib.h> |
38 | #include <stdlib.h> |
39 | #include <unistd.h> |
39 | #include <unistd.h> |
40 | #include <string.h> |
40 | #include <string.h> |
41 | #include <fcntl.h> |
41 | #include <fcntl.h> |
42 | 42 | ||
43 | #ifndef HELENOS |
43 | #ifndef HELENOS |
44 | #include <linux/limits.h> |
44 | #include <linux/limits.h> |
45 | #include <sys/errno.h> |
45 | #include <sys/errno.h> |
46 | #include <sys/wait.h> |
46 | #include <sys/wait.h> |
47 | #endif |
47 | #endif |
48 | 48 | ||
49 | #include "config.h" |
49 | #include "config.h" |
50 | #include "util.h" |
50 | #include "util.h" |
51 | #include "exec.h" |
51 | #include "exec.h" |
52 | #include "errors.h" |
52 | #include "errors.h" |
53 | 53 | ||
54 | /* Easiest way to handle a shared + allocated string, a structure with |
54 | /* Easiest way to handle a shared + allocated string, a structure with |
55 | * one member is sort of silly :) */ |
55 | * one member is sort of silly :) */ |
56 | char *found; |
56 | char *found; |
57 | 57 | ||
58 | /* work-around for access() */ |
58 | /* work-around for access() */ |
59 | unsigned int try_access(const char *f) |
59 | unsigned int try_access(const char *f) |
60 | { |
60 | { |
61 | int fd; |
61 | int fd; |
62 | 62 | ||
63 | fd = open(f, O_RDONLY); |
63 | fd = open(f, O_RDONLY); |
64 | if (fd > 0) { |
64 | if (fd > -1) { |
65 | close(fd); |
65 | close(fd); |
66 | return 1; |
- | |
67 | } else |
- | |
68 | return 0; |
66 | return 0; |
- | 67 | } else |
|
- | 68 | return -1; |
|
69 | } |
69 | } |
70 | 70 | ||
71 | /* Returns the full path of "cmd" if cmd is found, else just hand back |
71 | /* Returns the full path of "cmd" if cmd is found, else just hand back |
72 | * cmd as it was presented */ |
72 | * cmd as it was presented */ |
73 | char *find_command(char *cmd) |
73 | char *find_command(char *cmd) |
74 | { |
74 | { |
75 | char *path_orig, *path_tok; |
75 | char *path_orig, *path_tok; |
76 | char *path[PATH_MAX]; |
76 | char *path[PATH_MAX]; |
77 | int rc, n = 0, i = 0; |
77 | int n = 0, i = 0; |
78 | size_t x = strlen(cmd) + 2; |
78 | size_t x = strlen(cmd) + 2; |
79 | 79 | ||
80 | found = (char *)malloc(PATH_MAX); |
80 | found = (char *)malloc(PATH_MAX); |
81 | 81 | ||
82 | /* The user has specified the full path, just give it back. Don't test it, |
82 | /* The user has specified a full or relative path, just give it back. */ |
- | 83 | #ifdef HELENOS |
|
83 | * they seem to know what they're doing. */ |
84 | if (-1 != try_access(cmd)) |
- | 85 | #else |
|
84 | if (cmd[0] == '/' || cmd [0] == '.') |
86 | if (-1 != access(cmd, F_OK)) |
- | 87 | #endif |
|
- | 88 | { |
|
85 | return (char *)cmd; |
89 | return (char *) cmd; |
- | 90 | } |
|
86 | 91 | ||
87 | #ifdef HELENOS |
92 | #ifdef HELENOS |
88 | path_orig = PATH; |
93 | path_orig = PATH; |
89 | #else |
94 | #else |
90 | path_orig = getenv("PATH"); |
95 | path_orig = getenv("PATH"); |
91 | if (NULL == path_orig) |
96 | if (NULL == path_orig) |
92 | path_orig = PATH; |
97 | path_orig = PATH; |
93 | #endif |
98 | #endif |
94 | 99 | ||
95 | path_tok = cli_strdup(path_orig); |
100 | path_tok = cli_strdup(path_orig); |
96 | 101 | ||
97 | /* Extract the PATH env to a path[] array */ |
102 | /* Extract the PATH env to a path[] array */ |
98 | path[n] = cli_strtok(path_tok, PATH_DELIM); |
103 | path[n] = cli_strtok(path_tok, PATH_DELIM); |
99 | while (NULL != path[n]) { |
104 | while (NULL != path[n]) { |
100 | if ((strlen(path[n]) + x ) > PATH_MAX) { |
105 | if ((strlen(path[n]) + x ) > PATH_MAX) { |
101 | cli_error(CL_ENOTSUP, |
106 | cli_error(CL_ENOTSUP, |
102 | "Segment %d of path is too large, search ends at segment %d", |
107 | "Segment %d of path is too large, search ends at segment %d", |
103 | n, n-1); |
108 | n, n-1); |
104 | break; |
109 | break; |
105 | } |
110 | } |
106 | path[++n] = cli_strtok(NULL, PATH_DELIM); |
111 | path[++n] = cli_strtok(NULL, PATH_DELIM); |
107 | } |
112 | } |
108 | 113 | ||
109 | /* We now have n places to look for the command */ |
114 | /* We now have n places to look for the command */ |
110 | for (i=0; path[i]; i++) { |
115 | for (i=0; path[i]; i++) { |
111 | memset(found, 0, sizeof(found)); |
116 | memset(found, 0, sizeof(found)); |
112 | snprintf(found, PATH_MAX, "%s/%s", path[i], cmd); |
117 | snprintf(found, PATH_MAX, "%s/%s", path[i], cmd); |
113 | #ifdef HELENOS |
118 | #ifdef HELENOS |
114 | rc = try_access(found); |
119 | if (-1 != try_access(found)) |
115 | #else |
120 | #else |
116 | rc = access(found, F_OK); |
121 | if (-1 != access(found, F_OK)) |
117 | #endif |
122 | #endif |
118 | if (rc >= 0) { |
123 | { |
119 | /* We found it */ |
- | |
120 | free(path_tok); |
124 | free(path_tok); |
121 | return (char *) found; |
125 | return (char *) found; |
122 | } |
126 | } |
123 | } |
127 | } |
124 | 128 | ||
125 | /* We didn't find it, just give it back as-is. Could be an alias |
129 | /* We didn't find it, just give it back as-is. Could be an alias |
126 | * set in the parent shell */ |
130 | * set in the parent shell */ |
127 | free(path_tok); |
131 | free(path_tok); |
128 | return (char *) cmd; |
132 | return (char *) cmd; |
129 | } |
133 | } |
130 | 134 | ||
131 | #ifdef HELENOS |
135 | #ifdef HELENOS |
132 | task_id_t try_exec(char *cmd, char **argv) |
136 | task_id_t try_exec(char *cmd, char **argv) |
133 | { |
137 | { |
134 | task_id_t tid; |
138 | task_id_t tid; |
135 | char *tmp; |
139 | char *tmp; |
136 | 140 | ||
137 | tmp = cli_strdup(find_command(cmd)); |
141 | tmp = cli_strdup(find_command(cmd)); |
138 | free(found); |
142 | free(found); |
139 | 143 | ||
140 | tid = task_spawn((const char *)tmp, (const char **)argv); |
144 | tid = task_spawn((const char *)tmp, (const char **)argv); |
141 | free(tmp); |
145 | free(tmp); |
142 | 146 | ||
143 | if (tid == 0) |
147 | if (tid == 0) |
144 | /* HelenOS does not set errno, so all we can do is report |
148 | /* HelenOS does not set errno, so all we can do is report |
145 | * a task ID of 0 as a generic failure. */ |
149 | * a task ID of 0 as a generic failure. */ |
146 | cli_error(CL_EEXEC, "Can not spawn %s", cmd); |
150 | cli_error(CL_EEXEC, "Can not spawn %s", cmd); |
147 | 151 | ||
148 | return tid; |
152 | return tid; |
149 | } |
153 | } |
150 | 154 | ||
151 | #else |
155 | #else |
152 | int try_exec(char *cmd, char **argv) |
156 | int try_exec(char *cmd, char **argv) |
153 | { |
157 | { |
154 | char *tmp; |
158 | char *tmp; |
155 | pid_t pid; |
159 | pid_t pid; |
156 | int status; |
160 | int status; |
157 | 161 | ||
158 | /* Copy the result of allocated 'found' */ |
162 | /* Copy the result of allocated 'found' */ |
159 | tmp = cli_strdup(find_command(cmd)); |
163 | tmp = cli_strdup(find_command(cmd)); |
160 | /* free the pointer, no longer needed */ |
164 | /* free the pointer, no longer needed */ |
161 | free(found); |
165 | free(found); |
162 | 166 | ||
163 | if (-1 == (access(tmp, F_OK))) { |
167 | if (-1 == (access(tmp, F_OK))) { |
164 | cli_error(CL_EFAIL, |
168 | cli_error(CL_EFAIL, |
165 | "%s : No such external, modular or builtin command", tmp); |
169 | "%s : No such external, modular or builtin command", tmp); |
166 | free(tmp); |
170 | free(tmp); |
167 | return CL_EFAIL; |
171 | return CL_EFAIL; |
168 | } |
172 | } |
169 | 173 | ||
170 | /* Create a child to run the program */ |
174 | /* Create a child to run the program */ |
171 | pid = fork(); |
175 | pid = fork(); |
172 | if (pid == 0) { |
176 | if (pid == 0) { |
173 | execv(tmp, argv); |
177 | execv(tmp, argv); |
174 | exit(errno); |
178 | exit(errno); |
175 | } else if (pid > 0) { |
179 | } else if (pid > 0) { |
176 | /* Block until we get a PID (and result) */ |
180 | /* Block until we get a PID (and result) */ |
177 | wait(&status); |
181 | wait(&status); |
178 | status = status / 256; |
182 | status = status / 256; |
179 | } else { |
183 | } else { |
180 | /* Could not fork, ulimit or out of memory */ |
184 | /* Could not fork, ulimit or out of memory */ |
181 | cli_error(CL_ENOMEM, "Could not fork"); |
185 | cli_error(CL_ENOMEM, "Could not fork"); |
182 | free(tmp); |
186 | free(tmp); |
183 | return CL_ENOMEM; |
187 | return CL_ENOMEM; |
184 | } |
188 | } |
185 | 189 | ||
186 | free(tmp); |
190 | free(tmp); |
187 | 191 | ||
188 | /* No need to go any further if status == 0 */ |
- | |
189 | /* |
- | |
190 | if (status == 0) |
- | |
191 | return status; |
- | |
192 | */ |
- | |
193 | /* Decode any errors from execv() (these explain themselves) */ |
192 | /* Decode any errors from execv() (these explain themselves) */ |
194 | switch (status) { |
193 | switch (status) { |
195 | case ENOTDIR: |
194 | case ENOTDIR: |
196 | cli_error(CL_EFAIL, "%s : No such file or directory", tmp); |
195 | cli_error(CL_EFAIL, "%s : No such file or directory", tmp); |
197 | status = CL_EFAIL; |
196 | status = CL_EFAIL; |
198 | break; |
197 | break; |
199 | case EISDIR: |
198 | case EISDIR: |
200 | cli_error(CL_EFAIL, "%s : Command is a directory", tmp); |
199 | cli_error(CL_EFAIL, "%s : Command is a directory", tmp); |
201 | status = CL_EFAIL; |
200 | status = CL_EFAIL; |
202 | break; |
201 | break; |
203 | case EACCES: |
202 | case EACCES: |
204 | cli_error(CL_EPERM, "%s :", tmp); |
203 | cli_error(CL_EPERM, "%s :", tmp); |
205 | status = CL_EFAIL; |
204 | status = CL_EFAIL; |
206 | break; |
205 | break; |
207 | case ENOMEM: |
206 | case ENOMEM: |
208 | cli_error(CL_ENOMEM, "%s :", tmp); |
207 | cli_error(CL_ENOMEM, "%s :", tmp); |
209 | status = CL_EFAIL; |
208 | status = CL_EFAIL; |
210 | break; |
209 | break; |
211 | case ENAMETOOLONG: |
210 | case ENAMETOOLONG: |
212 | cli_error(CL_EFAIL, "Argument list too long"); |
211 | cli_error(CL_EFAIL, "Argument list too long"); |
213 | status = CL_EFAIL; |
212 | status = CL_EFAIL; |
214 | break; |
213 | break; |
215 | case EFAULT: |
214 | case EFAULT: |
216 | cli_error(CL_EFAIL, "Invalid argument pointer\n(please report " |
215 | cli_error(CL_EFAIL, "Invalid argument pointer\n(please report " |
217 | "this to %s)", PACKAGE_BUGREPORT); |
216 | "this to %s)", PACKAGE_BUGREPORT); |
218 | status = CL_EFAIL; |
217 | status = CL_EFAIL; |
219 | break; |
218 | break; |
220 | } |
219 | } |
221 | 220 | ||
222 | return status; |
221 | return status; |
223 | } |
222 | } |
224 | 223 | ||
225 | #endif /* HELENOS */ |
224 | #endif /* HELENOS */ |
226 | 225 |