Subversion Repositories HelenOS

Rev

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