r6831@lvps87-230-33-50: verhaegs | 2008-02-03 14:08:57 +0100
[tangerine.git] / compiler / clib / __spawnv.c
blob75100663151f7a5e1e8fcb3be9c4ca852fedb9cd
1 /*
2 Copyright © 1995-2003, The AROS Development Team. All rights reserved.
3 $Id$
5 spavnv() function, used to spawn new processes.
6 */
8 #include "__arosc_privdata.h"
10 #include <proto/dos.h>
11 #include <proto/exec.h>
12 #include <dos/dos.h>
13 #include <dos/dosextens.h>
14 #include <dos/filesystem.h>
15 #include <aros/debug.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <sys/syscall.h>
23 #include "__errno.h"
25 typedef struct
27 BPTR command;
28 LONG returncode;
29 int parent_does_upath;
30 } childdata_t;
32 AROS_UFP3(static LONG, wait_entry,
33 AROS_UFPA(char *, argstr,A0),
34 AROS_UFPA(ULONG, argsize,D0),
35 AROS_UFPA(struct ExecBase *,SysBase,A6));
37 static BPTR DupFHFromfd(int fd, ULONG mode);
38 static char *join_args(char * const *argv);
39 /*****************************************************************************
41 NAME */
42 #include <process.h>
44 int __spawnv(
46 /* SYNOPSIS */
47 int mode,
48 BPTR seg,
49 char *const argv[])
51 /* FUNCTION
52 Spawn a child process, given a vector of arguments and an already LoadSeg()'d executable.
54 INPUTS
55 mode - the way the child process has to be loaded, and how the parent has to behave
56 after the child process is initiated. Specify one of the following values:
58 P_WAIT - the child program is loaded into memory, then it's executed while
59 the parent process waits for it to terminate, at which point the
60 patent process resumes execution.
62 P_NOWAIT - the parent program is executed concurrently with the new child process.
64 P_OVERLAY - teplace the parent program with the child program in memory and then
65 execute the child. The parent program will never be resumed. This
66 mode is equivalent to calling one of the exec*() functions.
68 seg - the LoadSeg()'s executable. The segment is UnloadSeg()'d by this function.
70 argv - a pointer to a NULL terminated array of strings representing arguments to pass
71 to the child process. The first entry in the array is conventionally the name of
72 the program to spawn, but in any case it must _never_ be NULL, and the argv
73 pointer itself must never be NULL either.
75 RESULT
77 If P_WAIT is specified, then the return code of the child program is returned.
78 If instead P_NOWAIT is used, then the pid of the newly created process is returned.
79 Finally, if P_OVERLAY is used, the function doesn't return unless an error has occurred,
80 in which case -1 is returned also for the other modes and the global errno variable will
81 hold the proper error code.
83 NOTES
85 The way the child process behaves regarding parent's file descriptors, signal handlers
86 and so on is the same way it would behave with one of the exec*(3) functions.
87 This, for one, means that all filedescriptors are inherited except the ones which have
88 the close-on-exec flag set.
90 EXAMPLE
92 BUGS
94 SEE ALSO
95 execl(), execle(), execlp(), execlpe(), execv(), execve(), execvp(), execvpe(), getenv(),
96 putenv(), setenv(), spawn(), spawnl(), spawnle(), spawnlp(), spawnlpe(), spawnp(),
97 spawnve(), spawnvp(), spawnvpe(), wait(), waitpid()
99 INTERNALS
101 For now only the stdin, stout and stderr file descriptors are inherited, and signals
102 are not handled yet.
104 ******************************************************************************/
106 int ret = -1;
108 if (seg == MKBADDR(NULL))
110 errno = IoErr2errno(IoErr());
112 return -1;
115 errno = 0;
117 switch (mode)
119 case P_WAIT:
121 BPTR in, out, err;
122 childdata_t childdata;
124 struct TagItem tags[] =
126 { NP_Entry, (IPTR)wait_entry },
127 { NP_Input, 0 }, /* 1 */
128 { NP_Output, 0 }, /* 2 */
129 { NP_Error, 0 }, /* 3 */
130 { NP_Arguments, 0 }, /* 4 */
131 { NP_CloseInput, FALSE },
132 { NP_CloseOutput, FALSE },
133 { NP_CloseError, FALSE },
134 { NP_FreeSeglist, FALSE },
135 { NP_Cli, TRUE },
136 { NP_Synchronous, TRUE },
137 { NP_Name, (IPTR)argv[0] },
138 { NP_UserData, (IPTR)&childdata },
139 { TAG_DONE, 0 }
142 /* The helper entry function takes the loadseg result in
143 the usedsata field of the task structure. */
144 childdata.command = seg;
146 tags[4].ti_Data = (IPTR)join_args(&argv[1]);
147 if (!tags[4].ti_Data)
148 break;
150 D(bug("Args joined = %s\n", (char *)tags[4].ti_Data));
152 in = DupFHFromfd(STDIN_FILENO, FMF_READ);
153 out = DupFHFromfd(STDOUT_FILENO, FMF_WRITE);
154 err = DupFHFromfd(STDERR_FILENO, FMF_WRITE);
156 D(bug("in = %p - out = %p - err = %p\n", BADDR(in), BADDR(out), BADDR(err)));
158 if (in) tags[1].ti_Data = (IPTR)in;
159 else tags[1].ti_Tag = TAG_IGNORE;
160 if (out) tags[2].ti_Data = (IPTR)out;
161 else tags[2].ti_Tag = TAG_IGNORE;
162 if (err) tags[3].ti_Data = (IPTR)err;
163 else tags[3].ti_Tag = TAG_IGNORE;
166 childdata.parent_does_upath = __doupath;
168 if (CreateNewProc(tags) != NULL)
169 ret = childdata.returncode;
170 else
171 ret = -1;
173 D(bug("Process created successfully: %s\n", ret == -1 ? "NO" : "YES"));
175 Close(in); Close(out); Close(err);
177 D(bug("Command unloaded\n"));
178 break;
181 default:
182 ret = -1;
183 errno = ENOSYS;
186 UnLoadSeg(seg);
188 if (ret == -1 && errno == 0)
189 errno = IoErr2errno(IoErr());
191 return ret;
195 AROS_UFH3(static LONG, wait_entry,
196 AROS_UFHA(char *, argstr,A0),
197 AROS_UFHA(ULONG, argsize,D0),
198 AROS_UFHA(struct ExecBase *,SysBase,A6))
200 AROS_USERFUNC_INIT
202 struct DosLibrary *DOSBase;
203 struct Library *aroscbase;
204 LONG rc = -1;
205 childdata_t *childdata = (childdata_t *)FindTask(NULL)->tc_UserData;
207 DOSBase = (struct DosLibrary *)OpenLibrary(DOSNAME, 39);
208 if (DOSBase == NULL)
209 goto err1;
211 aroscbase = OpenLibrary("arosc.library", 0);
212 if (aroscbase == NULL)
213 goto err2;
215 __get_arosc_privdata()->acpd_parent_does_upath = childdata->parent_does_upath;
216 __get_arosc_privdata()->acpd_spawned = 1;
218 rc = RunCommand
220 childdata->command, Cli()->cli_DefaultStack * CLI_DEFAULTSTACK_UNIT,
221 argstr, argsize
224 CloseLibrary(aroscbase);
226 err2:
227 CloseLibrary((struct Library *)DOSBase);
229 err1:
230 childdata->returncode = rc;
232 return rc;
234 AROS_USERFUNC_EXIT
237 #include "__open.h"
238 static BPTR DupFHFromfd(int fd, ULONG mode)
240 fdesc *fdesc = __getfdesc(fd);
241 BPTR ret = MKBADDR(NULL);
243 if (fdesc != NULL && fdesc->fh != MKBADDR(NULL))
245 BPTR olddir = CurrentDir(fdesc->fh);
246 ret = Open("", mode);
247 CurrentDir(olddir);
250 return ret;
253 /* Join all elements of an argv array so to build one big string with
254 all elements chained one after the other one.
256 The resulting string's pointer is valid only until a subsequent call
257 to this function.
259 NOTE: the algorithm used is not very efficient. */
260 static char *join_args(char * const *argv)
262 char *last_arg_ptr, *args;
263 size_t size = 0;
264 int argc;
266 if (!argv)
267 return NULL;
269 if (!argv[0])
270 return "";
272 if (!argv[1])
273 return argv[0];
276 for (argc = 0; argv[argc] != NULL; argc++)
277 /* " argument " */
278 size += 1 + strlen(argv[argc]) + 1;
280 #define __args (__get_arosc_privdata()->acpd_joined_args)
281 args = __args = realloc_nocopy(__args, size+argc);
282 if (!args)
283 return NULL;
285 last_arg_ptr = args;
286 for (argc = 0; argv[argc] != NULL; argc++)
288 int needs_quotes = strchr(argv[argc], ' ') != NULL;
290 size = strlen(argv[argc]);
292 if (needs_quotes)
293 last_arg_ptr++[0] ='"';
295 memcpy(last_arg_ptr, argv[argc], size);
296 last_arg_ptr += size + 1;
298 if (needs_quotes)
299 last_arg_ptr++[-1] ='"';
301 last_arg_ptr[-1] = ' ';
304 last_arg_ptr[-1] = '\0';
306 return args;