Rev 3298 | Rev 3340 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3298 | Rev 3304 | ||
---|---|---|---|
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 |
- | |
44 | #include <linux/limits.h> |
- | |
45 | #include <sys/errno.h> |
- | |
46 | #include <sys/wait.h> |
- | |
47 | #endif |
- | |
48 | - | ||
49 | #include "config.h" |
43 | #include "config.h" |
50 | #include "util.h" |
44 | #include "util.h" |
51 | #include "exec.h" |
45 | #include "exec.h" |
52 | #include "errors.h" |
46 | #include "errors.h" |
53 | 47 | ||
54 | /* TODO: create exec, exev, execve wrappers for task_spawn() */ |
48 | /* TODO: create exec, exev, execve wrappers for task_spawn() */ |
55 | 49 | ||
56 | /* Easiest way to handle a shared + allocated string */ |
50 | /* Easiest way to handle a shared + allocated string */ |
57 | char *found; |
51 | char *found; |
58 | 52 | ||
59 | /* work-around for access() */ |
53 | /* work-around for access() */ |
60 | unsigned int try_access(const char *f) |
54 | unsigned int try_access(const char *f) |
61 | { |
55 | { |
62 | int fd; |
56 | int fd; |
63 | 57 | ||
64 | fd = open(f, O_RDONLY); |
58 | fd = open(f, O_RDONLY); |
65 | if (fd > -1) { |
59 | if (fd > -1) { |
66 | close(fd); |
60 | close(fd); |
67 | return 0; |
61 | return 0; |
68 | } else |
62 | } else |
69 | return -1; |
63 | return -1; |
70 | } |
64 | } |
71 | 65 | ||
72 | /* Returns the full path of "cmd" if cmd is found, else just hand back |
66 | /* Returns the full path of "cmd" if cmd is found, else just hand back |
73 | * cmd as it was presented */ |
67 | * cmd as it was presented */ |
74 | char *find_command(char *cmd) |
68 | char *find_command(char *cmd) |
75 | { |
69 | { |
76 | char *path_orig, *path_tok; |
70 | char *path_orig, *path_tok; |
77 | char *path[PATH_MAX]; |
71 | char *path[PATH_MAX]; |
78 | int n = 0, i = 0; |
72 | int n = 0, i = 0; |
79 | size_t x = strlen(cmd) + 2; |
73 | size_t x = strlen(cmd) + 2; |
80 | 74 | ||
81 | found = (char *)malloc(PATH_MAX); |
75 | found = (char *)malloc(PATH_MAX); |
82 | 76 | ||
83 | /* The user has specified a full or relative path, just give it back. */ |
77 | /* The user has specified a full or relative path, just give it back. */ |
84 | #ifdef HELENOS |
- | |
85 | if (-1 != try_access(cmd)) |
78 | if (-1 != try_access(cmd)) { |
86 | #else |
- | |
87 | if (-1 != access(cmd, F_OK)) |
- | |
88 | #endif |
- | |
89 | { |
- | |
90 | return (char *) cmd; |
79 | return (char *) cmd; |
91 | } |
80 | } |
92 | - | ||
93 | #ifdef HELENOS |
- | |
94 | path_orig = PATH; |
81 | path_orig = PATH; |
95 | #else |
- | |
96 | path_orig = getenv("PATH"); |
- | |
97 | if (NULL == path_orig) |
- | |
98 | path_orig = PATH; |
- | |
99 | #endif |
- | |
100 | - | ||
101 | path_tok = cli_strdup(path_orig); |
82 | path_tok = cli_strdup(path_orig); |
102 | 83 | ||
103 | /* Extract the PATH env to a path[] array */ |
84 | /* Extract the PATH env to a path[] array */ |
104 | path[n] = cli_strtok(path_tok, PATH_DELIM); |
85 | path[n] = cli_strtok(path_tok, PATH_DELIM); |
105 | while (NULL != path[n]) { |
86 | while (NULL != path[n]) { |
106 | if ((strlen(path[n]) + x ) > PATH_MAX) { |
87 | if ((strlen(path[n]) + x ) > PATH_MAX) { |
107 | cli_error(CL_ENOTSUP, |
88 | cli_error(CL_ENOTSUP, |
108 | "Segment %d of path is too large, search ends at segment %d", |
89 | "Segment %d of path is too large, search ends at segment %d", |
109 | n, n-1); |
90 | n, n-1); |
110 | break; |
91 | break; |
111 | } |
92 | } |
112 | path[++n] = cli_strtok(NULL, PATH_DELIM); |
93 | path[++n] = cli_strtok(NULL, PATH_DELIM); |
113 | } |
94 | } |
114 | 95 | ||
115 | /* We now have n places to look for the command */ |
96 | /* We now have n places to look for the command */ |
116 | for (i=0; path[i]; i++) { |
97 | for (i=0; path[i]; i++) { |
117 | memset(found, 0, sizeof(found)); |
98 | memset(found, 0, sizeof(found)); |
118 | snprintf(found, PATH_MAX, "%s/%s", path[i], cmd); |
99 | snprintf(found, PATH_MAX, "%s/%s", path[i], cmd); |
119 | #ifdef HELENOS |
- | |
120 | if (-1 != try_access(found)) |
100 | if (-1 != try_access(found)) { |
121 | #else |
- | |
122 | if (-1 != access(found, F_OK)) |
- | |
123 | #endif |
- | |
124 | { |
- | |
125 | free(path_tok); |
101 | free(path_tok); |
126 | return (char *) found; |
102 | return (char *) found; |
127 | } |
103 | } |
128 | } |
104 | } |
129 | 105 | ||
130 | /* We didn't find it, just give it back as-is. Could be an alias |
106 | /* We didn't find it, just give it back as-is. Could be an alias |
131 | * set in the parent shell */ |
107 | * set in the parent shell */ |
132 | free(path_tok); |
108 | free(path_tok); |
133 | return (char *) cmd; |
109 | return (char *) cmd; |
134 | } |
110 | } |
135 | 111 | ||
136 | #ifdef HELENOS |
- | |
137 | task_id_t try_exec(char *cmd, char **argv) |
112 | task_id_t try_exec(char *cmd, char **argv) |
138 | { |
113 | { |
139 | task_id_t tid; |
114 | task_id_t tid; |
140 | char *tmp; |
115 | char *tmp; |
141 | 116 | ||
142 | tmp = cli_strdup(find_command(cmd)); |
117 | tmp = cli_strdup(find_command(cmd)); |
143 | free(found); |
118 | free(found); |
144 | 119 | ||
145 | /* TODO: put the cwd in front of tmp if tmp[0] != root |
120 | /* TODO: put the cwd in front of tmp if tmp[0] != root |
146 | * which fixes relative paths fed to task_spawn */ |
121 | * which fixes relative paths fed to task_spawn */ |
147 | 122 | ||
148 | tid = task_spawn((const char *)tmp, (const char **)argv); |
123 | tid = task_spawn((const char *)tmp, (const char **)argv); |
149 | free(tmp); |
124 | free(tmp); |
150 | 125 | ||
151 | if (tid == 0) |
126 | if (tid == 0) |
152 | /* HelenOS does not set errno, so all we can do is report |
127 | /* HelenOS does not set errno, so all we can do is report |
153 | * a task ID of 0 as a generic failure. */ |
128 | * a task ID of 0 as a generic failure. */ |
154 | cli_error(CL_EEXEC, "Can not spawn %s", cmd); |
129 | cli_error(CL_EEXEC, "Can not spawn %s", cmd); |
155 | 130 | ||
156 | return tid; |
131 | return tid; |
157 | } |
132 | } |
158 | - | ||
159 | #else |
- | |
160 | int try_exec(char *cmd, char **argv) |
- | |
161 | { |
- | |
162 | char *tmp; |
- | |
163 | pid_t pid; |
- | |
164 | int status; |
- | |
165 | - | ||
166 | /* Copy the result of allocated 'found' */ |
- | |
167 | tmp = cli_strdup(find_command(cmd)); |
- | |
168 | /* free the pointer, no longer needed */ |
- | |
169 | free(found); |
- | |
170 | - | ||
171 | if (-1 == (access(tmp, F_OK))) { |
- | |
172 | cli_error(CL_EFAIL, |
- | |
173 | "%s : No such external, modular or builtin command", tmp); |
- | |
174 | free(tmp); |
- | |
175 | return CL_EFAIL; |
- | |
176 | } |
- | |
177 | - | ||
178 | /* Create a child to run the program */ |
- | |
179 | pid = fork(); |
- | |
180 | if (pid == 0) { |
- | |
181 | execv(tmp, argv); |
- | |
182 | exit(errno); |
- | |
183 | } else if (pid > 0) { |
- | |
184 | /* Block until we get a PID (and result) */ |
- | |
185 | wait(&status); |
- | |
186 | status = status / 256; |
- | |
187 | } else { |
- | |
188 | /* Could not fork, ulimit or out of memory */ |
- | |
189 | cli_error(CL_ENOMEM, "Could not fork"); |
- | |
190 | free(tmp); |
- | |
191 | return CL_ENOMEM; |
- | |
192 | } |
- | |
193 | - | ||
194 | free(tmp); |
- | |
195 | - | ||
196 | /* Decode any errors from execv() (these explain themselves) */ |
- | |
197 | switch (status) { |
- | |
198 | case ENOTDIR: |
- | |
199 | cli_error(CL_EFAIL, "%s : No such file or directory", tmp); |
- | |
200 | status = CL_EFAIL; |
- | |
201 | break; |
- | |
202 | case EISDIR: |
- | |
203 | cli_error(CL_EFAIL, "%s : Command is a directory", tmp); |
- | |
204 | status = CL_EFAIL; |
- | |
205 | break; |
- | |
206 | case EACCES: |
- | |
207 | cli_error(CL_EPERM, "%s :", tmp); |
- | |
208 | status = CL_EFAIL; |
- | |
209 | break; |
- | |
210 | case ENOMEM: |
- | |
211 | cli_error(CL_ENOMEM, "%s :", tmp); |
- | |
212 | status = CL_EFAIL; |
- | |
213 | break; |
- | |
214 | case ENAMETOOLONG: |
- | |
215 | cli_error(CL_EFAIL, "Argument list too long"); |
- | |
216 | status = CL_EFAIL; |
- | |
217 | break; |
- | |
218 | case EFAULT: |
- | |
219 | cli_error(CL_EFAIL, "Invalid argument pointer\n(please report " |
- | |
220 | "this to %s)", PACKAGE_BUGREPORT); |
- | |
221 | status = CL_EFAIL; |
- | |
222 | break; |
- | |
223 | } |
- | |
224 | - | ||
225 | return status; |
- | |
226 | } |
- | |
227 | - | ||
228 | #endif /* HELENOS */ |
- | |
229 | 133 |