Subversion Repositories HelenOS

Rev

Rev 3470 | Rev 3536 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3470 Rev 3471
1
/*
1
/*
2
 * Copyright (c) 2008 Jiri Svoboda
2
 * Copyright (c) 2008 Jiri Svoboda
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup libc
29
/** @addtogroup libc
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <ipc/ipc.h>
35
#include <ipc/ipc.h>
36
#include <ipc/loader.h>
36
#include <ipc/loader.h>
37
#include <libc.h>
37
#include <libc.h>
38
#include <string.h>
38
#include <string.h>
39
#include <stdlib.h>
39
#include <stdlib.h>
40
#include <async.h>
40
#include <async.h>
41
#include <errno.h>
41
#include <errno.h>
42
#include <vfs/vfs.h>
42
#include <vfs/vfs.h>
43
#include <loader/loader.h>
43
#include <loader/loader.h>
44
 
44
 
45
/** Connect to a new program loader.
45
/** Connect to a new program loader.
46
 *
46
 *
47
 * Spawns a new program loader task and returns the connection structure.
47
 * Spawns a new program loader task and returns the connection structure.
48
 * @return  Pointer to the loader connection structure (should be
48
 * @return  Pointer to the loader connection structure (should be
49
 *      de-allocated using free() after use).
49
 *      de-allocated using free() after use).
50
 */
50
 */
51
loader_t *loader_spawn(void)
51
loader_t *loader_spawn(void)
52
{
52
{
53
    int phone_id, rc;
53
    int phone_id, rc;
54
    loader_t *ldr;
54
    loader_t *ldr;
55
 
55
 
56
    /*
56
    /*
57
     * Ask kernel to spawn a new loader task.
57
     * Ask kernel to spawn a new loader task.
58
     */
58
     */
59
    rc = __SYSCALL1(SYS_PROGRAM_SPAWN_LOADER, (sysarg_t) &phone_id);
59
    rc = __SYSCALL1(SYS_PROGRAM_SPAWN_LOADER, (sysarg_t) &phone_id);
60
    if (rc != 0)
60
    if (rc != 0)
61
        return NULL;
61
        return NULL;
62
 
62
 
63
    /*
63
    /*
64
     * Say hello so that the loader knows the incoming connection's
64
     * Say hello so that the loader knows the incoming connection's
65
     * phone hash.
65
     * phone hash.
66
     */
66
     */
67
    rc = async_req_0_0(phone_id, LOADER_HELLO);
67
    rc = async_req_0_0(phone_id, LOADER_HELLO);
68
    if (rc != EOK)
68
    if (rc != EOK)
69
        return NULL;
69
        return NULL;
70
 
70
 
71
    ldr = malloc(sizeof(loader_t));
71
    ldr = malloc(sizeof(loader_t));
72
    if (ldr == NULL)
72
    if (ldr == NULL)
73
        return NULL;
73
        return NULL;
74
 
74
 
75
    ldr->phone_id = phone_id;
75
    ldr->phone_id = phone_id;
76
    return ldr;
76
    return ldr;
77
}
77
}
78
 
78
 
79
/** Get ID of the new task.
79
/** Get ID of the new task.
80
 *
80
 *
81
 * Retrieves the ID of the new task from the loader.
81
 * Retrieves the ID of the new task from the loader.
82
 *
82
 *
83
 * @param ldr       Loader connection structure.
83
 * @param ldr       Loader connection structure.
84
 * @param task_id   Points to a variable where the ID should be stored.
84
 * @param task_id   Points to a variable where the ID should be stored.
85
 * @return      Zero on success or negative error code.
85
 * @return      Zero on success or negative error code.
86
 */
86
 */
87
int loader_get_task_id(loader_t *ldr, task_id_t *task_id)
87
int loader_get_task_id(loader_t *ldr, task_id_t *task_id)
88
{
88
{
89
    ipc_call_t answer;
89
    ipc_call_t answer;
90
    aid_t req;
90
    aid_t req;
91
    int rc;
91
    int rc;
92
    ipcarg_t retval;
92
    ipcarg_t retval;
93
 
93
 
94
    /* Get task ID. */
94
    /* Get task ID. */
95
    req = async_send_0(ldr->phone_id, LOADER_GET_TASKID, &answer);
95
    req = async_send_0(ldr->phone_id, LOADER_GET_TASKID, &answer);
96
    rc = ipc_data_read_start(ldr->phone_id, task_id, sizeof(task_id));
96
    rc = ipc_data_read_start(ldr->phone_id, task_id, sizeof(task_id));
97
    if (rc != EOK) {
97
    if (rc != EOK) {
98
        async_wait_for(req, NULL);
98
        async_wait_for(req, NULL);
99
        return rc;
99
        return rc;
100
    }
100
    }
101
 
101
 
102
    async_wait_for(req, &retval);
102
    async_wait_for(req, &retval);
103
    return (int)retval;
103
    return (int)retval;
104
}
104
}
105
 
105
 
106
/** Set pathname of the program to load.
106
/** Set pathname of the program to load.
107
 *
107
 *
108
 * Sets the name of the program file to load. The name can be relative
108
 * Sets the name of the program file to load. The name can be relative
109
 * to the current working directory (it will be absolutized before
109
 * to the current working directory (it will be absolutized before
110
 * sending to the loader).
110
 * sending to the loader).
111
 *
111
 *
112
 * @param ldr       Loader connection structure.
112
 * @param ldr       Loader connection structure.
113
 * @param path      Pathname of the program file.
113
 * @param path      Pathname of the program file.
114
 * @return      Zero on success or negative error code.
114
 * @return      Zero on success or negative error code.
115
 */
115
 */
116
int loader_set_pathname(loader_t *ldr, const char *path)
116
int loader_set_pathname(loader_t *ldr, const char *path)
117
{
117
{
118
    ipc_call_t answer;
118
    ipc_call_t answer;
119
    aid_t req;
119
    aid_t req;
120
    int rc;
120
    int rc;
121
    ipcarg_t retval;
121
    ipcarg_t retval;
122
 
122
 
123
    char *pa;
123
    char *pa;
124
    size_t pa_len;
124
    size_t pa_len;
125
 
125
 
126
    pa = absolutize(path, &pa_len);
126
    pa = absolutize(path, &pa_len);
127
    if (!pa)
127
    if (!pa)
128
        return 0;
128
        return 0;
129
 
129
 
130
    /* Send program pathname */
130
    /* Send program pathname */
131
    req = async_send_0(ldr->phone_id, LOADER_SET_PATHNAME, &answer);
131
    req = async_send_0(ldr->phone_id, LOADER_SET_PATHNAME, &answer);
132
    rc = ipc_data_write_start(ldr->phone_id, (void *)pa, pa_len);
132
    rc = ipc_data_write_start(ldr->phone_id, (void *)pa, pa_len);
133
    if (rc != EOK) {
133
    if (rc != EOK) {
134
        async_wait_for(req, NULL);
134
        async_wait_for(req, NULL);
135
        return rc;
135
        return rc;
136
    }
136
    }
137
 
137
 
138
    free(pa);
138
    free(pa);
139
 
139
 
140
    async_wait_for(req, &retval);
140
    async_wait_for(req, &retval);
141
    return (int)retval;
141
    return (int)retval;
142
}
142
}
143
 
143
 
144
 
144
 
145
/** Set command-line arguments for the program.
145
/** Set command-line arguments for the program.
146
 *
146
 *
147
 * Sets the vector of command-line arguments to be passed to the loaded
147
 * Sets the vector of command-line arguments to be passed to the loaded
148
 * program. By convention, the very first argument is typically the same as
148
 * program. By convention, the very first argument is typically the same as
149
 * the command used to execute the program.
149
 * the command used to execute the program.
150
 *
150
 *
151
 * @param ldr       Loader connection structure.
151
 * @param ldr       Loader connection structure.
152
 * @param argv      NULL-terminated array of pointers to arguments.
152
 * @param argv      NULL-terminated array of pointers to arguments.
153
 * @return      Zero on success or negative error code.
153
 * @return      Zero on success or negative error code.
154
 */
154
 */
155
int loader_set_args(loader_t *ldr, char *const argv[])
155
int loader_set_args(loader_t *ldr, char *const argv[])
156
{
156
{
157
    aid_t req;
157
    aid_t req;
158
    ipc_call_t answer;
158
    ipc_call_t answer;
159
    ipcarg_t rc;
159
    ipcarg_t rc;
160
 
160
 
161
    char *const *ap;
161
    char *const *ap;
162
    char *dp;
162
    char *dp;
163
    char *arg_buf;
163
    char *arg_buf;
164
    size_t buffer_size;
164
    size_t buffer_size;
165
 
165
 
166
    /*
166
    /*
167
     * Serialize the arguments into a single array. First
167
     * Serialize the arguments into a single array. First
168
     * compute size of the buffer needed.
168
     * compute size of the buffer needed.
169
     */
169
     */
170
    ap = argv;
170
    ap = argv;
171
    buffer_size = 0;
171
    buffer_size = 0;
172
    while (*ap != NULL) {
172
    while (*ap != NULL) {
173
        buffer_size += strlen(*ap) + 1;
173
        buffer_size += strlen(*ap) + 1;
174
        ++ap;
174
        ++ap;
175
    }
175
    }
176
 
176
 
177
    arg_buf = malloc(buffer_size);
177
    arg_buf = malloc(buffer_size);
178
    if (arg_buf == NULL) return ENOMEM;
178
    if (arg_buf == NULL) return ENOMEM;
179
 
179
 
180
    /* Now fill the buffer with null-terminated argument strings */
180
    /* Now fill the buffer with null-terminated argument strings */
181
    ap = argv;
181
    ap = argv;
182
    dp = arg_buf;
182
    dp = arg_buf;
183
    while (*ap != NULL) {
183
    while (*ap != NULL) {
184
        strcpy(dp, *ap);
184
        strcpy(dp, *ap);
185
        dp += strlen(*ap) + 1;
185
        dp += strlen(*ap) + 1;
186
 
186
 
187
        ++ap;
187
        ++ap;
188
    }
188
    }
189
 
189
 
190
    /* Send serialized arguments to the loader */
190
    /* Send serialized arguments to the loader */
191
 
191
 
192
    req = async_send_0(ldr->phone_id, LOADER_SET_ARGS, &answer);
192
    req = async_send_0(ldr->phone_id, LOADER_SET_ARGS, &answer);
193
    rc = ipc_data_write_start(ldr->phone_id, (void *)arg_buf, buffer_size);
193
    rc = ipc_data_write_start(ldr->phone_id, (void *)arg_buf, buffer_size);
194
    if (rc != EOK) {
194
    if (rc != EOK) {
195
        async_wait_for(req, NULL);
195
        async_wait_for(req, NULL);
196
        return rc;
196
        return rc;
197
    }
197
    }
198
 
198
 
199
    async_wait_for(req, &rc);
199
    async_wait_for(req, &rc);
200
    if (rc != EOK) return rc;
200
    if (rc != EOK) return rc;
201
 
201
 
202
    /* Free temporary buffer */
202
    /* Free temporary buffer */
203
    free(arg_buf);
203
    free(arg_buf);
204
 
204
 
205
    return EOK;
205
    return EOK;
206
}
206
}
207
 
207
 
208
/** Instruct loader to load the program.
208
/** Instruct loader to load the program.
209
 *
209
 *
210
 * If this function succeeds, the program has been successfully loaded
210
 * If this function succeeds, the program has been successfully loaded
211
 * and is ready to be executed.
211
 * and is ready to be executed.
212
 *
212
 *
213
 * @param ldr       Loader connection structure.
213
 * @param ldr       Loader connection structure.
214
 * @return      Zero on success or negative error code.
214
 * @return      Zero on success or negative error code.
215
 */
215
 */
216
int loader_load_program(loader_t *ldr)
216
int loader_load_program(loader_t *ldr)
217
{
217
{
218
    int rc;
218
    int rc;
219
 
219
 
220
    rc = async_req_0_0(ldr->phone_id, LOADER_LOAD);
220
    rc = async_req_0_0(ldr->phone_id, LOADER_LOAD);
221
    if (rc != EOK)
221
    if (rc != EOK)
222
        return rc;
222
        return rc;
223
 
223
 
224
    return EOK;
224
    return EOK;
225
}
225
}
226
 
226
 
227
/** Instruct loader to execute the program.
227
/** Instruct loader to execute the program.
228
 *
228
 *
229
 * Note that this function blocks until the loader actually replies
229
 * Note that this function blocks until the loader actually replies
230
 * so you cannot expect this function to return if you are debugging
230
 * so you cannot expect this function to return if you are debugging
231
 * the task and its thread is stopped.
231
 * the task and its thread is stopped.
232
 *
232
 *
233
 * After using this function, no further operations must be performed
233
 * After using this function, no further operations must be performed
234
 * on the loader structure. It should be de-allocated using free().
234
 * on the loader structure. It should be de-allocated using free().
235
 *
235
 *
236
 * @param ldr       Loader connection structure.
236
 * @param ldr       Loader connection structure.
237
 * @return      Zero on success or negative error code.
237
 * @return      Zero on success or negative error code.
238
 */
238
 */
239
int loader_run(loader_t *ldr)
239
int loader_run(loader_t *ldr)
240
{
240
{
241
    int rc;
241
    int rc;
242
 
242
 
243
    rc = async_req_0_0(ldr->phone_id, LOADER_RUN);
243
    rc = async_req_0_0(ldr->phone_id, LOADER_RUN);
244
    if (rc != EOK)
244
    if (rc != EOK)
245
        return rc;
245
        return rc;
246
 
246
 
247
    return EOK;
247
    return EOK;
248
}
248
}
249
 
249
 
250
/** Cancel the loader session.
250
/** Cancel the loader session.
251
 *
251
 *
252
 * Tells the loader not to load any program and terminate.
252
 * Tells the loader not to load any program and terminate.
253
 * After using this function, no further operations must be performed
253
 * After using this function, no further operations must be performed
254
 * on the loader structure. It should be de-allocated using free().
254
 * on the loader structure. It should be de-allocated using free().
255
 *
255
 *
256
 * @param ldr       Loader connection structure.
256
 * @param ldr       Loader connection structure.
257
 * @return      Zero on success or negative error code.
257
 * @return      Zero on success or negative error code.
258
 */
258
 */
259
void loader_abort(loader_t *ldr)
259
void loader_abort(loader_t *ldr)
260
{
260
{
261
    ipc_hangup(ldr->phone_id);
261
    ipc_hangup(ldr->phone_id);
262
    ldr->phone_id = 0;
262
    ldr->phone_id = 0;
263
}
263
}
264
 
264
 
265
/** @}
265
/** @}
266
 */
266
 */
267
 
267