2 Copyright © 1995-2003, The AROS Development Team. All rights reserved.
5 spavnv() function, used to spawn new processes.
8 #include "__arosc_privdata.h"
10 #include <proto/dos.h>
11 #include <proto/exec.h>
13 #include <dos/dosextens.h>
14 #include <dos/filesystem.h>
15 #include <aros/debug.h>
21 #include <sys/syscall.h>
29 int parent_does_upath
;
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 /*****************************************************************************
52 Spawn a child process, given a vector of arguments and an already LoadSeg()'d executable.
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.
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.
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.
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()
101 For now only the stdin, stout and stderr file descriptors are inherited, and signals
104 ******************************************************************************/
108 if (seg
== MKBADDR(NULL
))
110 errno
= IoErr2errno(IoErr());
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
},
136 { NP_Synchronous
, TRUE
},
137 { NP_Name
, (IPTR
)argv
[0] },
138 { NP_UserData
, (IPTR
)&childdata
},
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
)
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
;
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"));
188 if (ret
== -1 && errno
== 0)
189 errno
= IoErr2errno(IoErr());
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
))
202 struct DosLibrary
*DOSBase
;
203 struct Library
*aroscbase
;
205 childdata_t
*childdata
= (childdata_t
*)FindTask(NULL
)->tc_UserData
;
207 DOSBase
= (struct DosLibrary
*)OpenLibrary(DOSNAME
, 39);
211 aroscbase
= OpenLibrary("arosc.library", 0);
212 if (aroscbase
== NULL
)
215 __get_arosc_privdata()->acpd_parent_does_upath
= childdata
->parent_does_upath
;
216 __get_arosc_privdata()->acpd_spawned
= 1;
220 childdata
->command
, Cli()->cli_DefaultStack
* CLI_DEFAULTSTACK_UNIT
,
224 CloseLibrary(aroscbase
);
227 CloseLibrary((struct Library
*)DOSBase
);
230 childdata
->returncode
= rc
;
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
);
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
259 NOTE: the algorithm used is not very efficient. */
260 static char *join_args(char * const *argv
)
262 char *last_arg_ptr
, *args
;
276 for (argc
= 0; argv
[argc
] != NULL
; argc
++)
278 size
+= 1 + strlen(argv
[argc
]) + 1;
280 #define __args (__get_arosc_privdata()->acpd_joined_args)
281 args
= __args
= realloc_nocopy(__args
, size
+argc
);
286 for (argc
= 0; argv
[argc
] != NULL
; argc
++)
288 int needs_quotes
= strchr(argv
[argc
], ' ') != NULL
;
290 size
= strlen(argv
[argc
]);
293 last_arg_ptr
++[0] ='"';
295 memcpy(last_arg_ptr
, argv
[argc
], size
);
296 last_arg_ptr
+= size
+ 1;
299 last_arg_ptr
++[-1] ='"';
301 last_arg_ptr
[-1] = ' ';
304 last_arg_ptr
[-1] = '\0';