2 Copyright © 2008-2009, The AROS Development Team. All rights reserved.
6 #include <proto/exec.h>
9 #include <exec/tasks.h>
11 #include <dos/filesystem.h>
14 #include <sys/types.h>
23 #include "__arosc_privdata.h"
30 #include <aros/debug.h>
31 #include <aros/startup.h>
33 BPTR
DupFHFromfd(int fd
, ULONG mode
);
34 void vfork_longjmp (jmp_buf env
, int val
);
35 LONG
exec_command(BPTR seglist
, char *taskname
, char *args
, ULONG stacksize
);
39 D(bug("launcher: Entered child launcher\n"));
41 struct Task
*this = FindTask(NULL
);
42 struct vfork_data
*udata
= this->tc_UserData
;
44 struct Library
*aroscbase
= NULL
;
46 GetIntETask(this)->iet_startup
= GetETask(this)->et_Result2
= AllocVec(sizeof(struct aros_startup
), MEMF_ANY
| MEMF_CLEAR
);
48 /* Allocate signal for parent->child communication */
49 child_signal
= udata
->child_signal
= AllocSignal(-1);
50 D(bug("launcher: Allocated child signal: %d\n", udata
->child_signal
));
51 if(udata
->child_signal
== -1)
54 udata
->child_errno
= ENOMEM
;
55 Signal(udata
->parent
, 1 << udata
->parent_signal
);
59 if(__register_init_fdarray(udata
->ppriv
->acpd_fd_array
, udata
->ppriv
->acpd_numslots
))
60 aroscbase
= OpenLibrary((STRPTR
) "arosc.library", 0);
63 FreeSignal(child_signal
);
64 udata
->child_errno
= ENOMEM
;
65 Signal(udata
->parent
, 1 << udata
->parent_signal
);
69 udata
->cpriv
= __get_arosc_privdata();
70 udata
->cpriv
->acpd_parent_does_upath
= udata
->ppriv
->acpd_doupath
;
71 udata
->cpriv
->acpd_flags
|= DO_NOT_CLONE_ENV_VARS
;
73 if(setjmp(__aros_startup_jmp_buf
) == 0)
75 /* Setup complete, signal parent */
76 D(bug("launcher: Signaling parent that we finished setup\n"));
77 Signal(udata
->parent
, 1 << udata
->parent_signal
);
79 D(bug("launcher: Child waiting for exec or exit\n"));
80 Wait(1 << udata
->child_signal
);
82 if(udata
->child_executed
)
87 D(bug("launcher: child executed\n"));
89 /* Set current dir to parent's current dir */
90 dir
= DupLock(((struct Process
*)udata
->parent
)->pr_CurrentDir
);
91 UnLock(CurrentDir(dir
));
92 /* Don't mind updating aroscbase->acb_startup_cd_changed as we will
93 exit from process after __exec_do has finished */
95 /* Filenames passed from parent obey parent's __doupath */
96 __doupath
= udata
->cpriv
->acpd_parent_does_upath
;
97 D(bug("launcher: __doupath == %d for __exec_prepare()\n", __doupath
));
99 exec_id
= udata
->exec_id
= __exec_prepare(
100 udata
->exec_filename
,
101 udata
->exec_searchpath
,
106 udata
->child_errno
= errno
;
108 /* Clear __doupath again, command will set it if wanted */
111 D(bug("launcher: informing parent that we have run __exec_prepare\n"));
112 /* Inform parent that we have run __exec_prepare */
113 Signal(udata
->parent
, 1 << udata
->parent_signal
);
115 /* Wait 'till __exec_do() is called on parent process */
116 D(bug("launcher: Waiting parent to get the result\n"));
117 Wait(1 << udata
->child_signal
);
119 D(bug("launcher: informing parent that we won't use udata anymore\n"));
120 /* Inform parent that we won't use udata anymore */
121 Signal(udata
->parent
, 1 << udata
->parent_signal
);
125 D(bug("launcher: executing command\n"));
128 assert(0); /* Should not be reached */
132 D(bug("launcher: exit because execve returned with an error\n"));
138 D(bug("launcher: informing parent that we won't use udata anymore\n"));
139 /* Inform parent that we won't use udata anymore */
140 Signal(udata
->parent
, 1 << udata
->parent_signal
);
145 D(bug("launcher: freeing child_signal\n"));
146 FreeSignal(child_signal
);
147 CloseLibrary(aroscbase
);
153 void FreeAndJump(struct vfork_data
*udata
)
155 D(bug("FreeAndJump(udata = %p)\n", udata
));
157 ULONG child_id
= udata
->child_id
;
158 D(bug("FreeAndJump: Child ID=%d\n", child_id
));
159 bcopy(&udata
->vfork_jump
, env
, sizeof(jmp_buf));
160 D(bug("FreeAndJump: Restoring old vfork_data: %p\n", udata
->prev
));
161 __get_arosc_privdata()->acpd_vfork_data
= udata
->prev
;
162 if(udata
->prev
== NULL
)
163 __get_arosc_privdata()->acpd_flags
&= ~PRETEND_CHILD
;
164 D(bug("FreeAndJump: freeing udata\n"));
165 FreeMem(udata
, sizeof(struct vfork_data
));
166 D(bug("FreeAndJump: Jumping to jmp_buf %p\n", &env
));
167 D(bug("FreeAndJump: ip: %p, stack: %p\n", env
->retaddr
, env
->regs
[_JMPLEN
- 1]));
168 vfork_longjmp(env
, child_id
);
171 pid_t
__vfork(jmp_buf env
)
173 struct Task
*this = FindTask(NULL
);
174 struct vfork_data
*udata
= AllocMem(sizeof(struct vfork_data
), MEMF_ANY
| MEMF_CLEAR
);
180 D(bug("__vfork: allocated udata %p\n", udata
));
181 bcopy(env
, &udata
->vfork_jump
, sizeof(jmp_buf));
183 struct TagItem tags
[] =
185 { NP_Entry
, (IPTR
) launcher
},
186 { NP_CloseInput
, (IPTR
) FALSE
},
187 { NP_CloseOutput
, (IPTR
) FALSE
},
188 { NP_CloseError
, (IPTR
) FALSE
},
189 { NP_Cli
, (IPTR
) TRUE
},
190 { NP_Name
, (IPTR
) "vfork()" },
191 { NP_UserData
, (IPTR
) udata
},
192 { NP_NotifyOnDeath
, (IPTR
) TRUE
},
196 udata
->parent
= this;
198 struct arosc_privdata
*ppriv
= __get_arosc_privdata();
199 udata
->ppriv
= ppriv
;
201 /* Store parent's vfork_data to restore it later */
202 udata
->prev
= __get_arosc_privdata()->acpd_vfork_data
;
203 D(bug("__vfork: Saved old parent's vfork_data: %p\n", udata
->prev
));
205 D(bug("__vfork: backuping startup buffer\n"));
206 /* Backup startup buffer */
207 CopyMem(&__aros_startup_jmp_buf
, &udata
->startup_jmp_buf
, sizeof(jmp_buf));
209 D(bug("__vfork: Allocating parent signal\n"));
210 /* Allocate signal for child->parent communication */
211 udata
->parent_signal
= AllocSignal(-1);
212 if(udata
->parent_signal
== -1)
214 /* Couldn't allocate the signal, return -1 */
215 FreeMem(udata
, sizeof(struct vfork_data
));
217 longjmp(udata
->vfork_jump
, -1);
220 D(bug("__vfork: Creating child\n"));
221 udata
->child
= (struct Task
*) CreateNewProc(tags
);
223 if(udata
->child
== NULL
)
225 /* Something went wrong, return -1 */
226 FreeMem(udata
, sizeof(struct vfork_data
));
227 errno
= ENOMEM
; /* Most likely */
230 D(bug("__vfork: Child created %p, waiting to finish setup\n", udata
->child
));
231 udata
->child_id
= GetETaskID(udata
->child
);
232 D(bug("__vfork: Got unique child id: %d\n", udata
->child_id
));
234 /* Wait for child to finish setup */
235 Wait(1 << udata
->parent_signal
);
237 if(udata
->child_errno
)
239 /* An error occured during child setup */
240 errno
= udata
->child_errno
;
244 D(bug("__vfork: Setting jmp_buf at %p in %p\n", __aros_startup
, &__aros_startup_jmp_buf
));
245 if(setjmp(__aros_startup_jmp_buf
))
247 D(bug("__vfork: child exited\n or executed\n"));
249 if(!GETUDATA
->child_executed
)
251 D(bug("__vfork: not executed\n"));
252 ((struct aros_startup
*) GetIntETask(GETUDATA
->child
)->iet_startup
)->as_startup_error
= __aros_startup_error
;
253 D(bug("__vfork: Signaling child\n"));
254 Signal(GETUDATA
->child
, 1 << GETUDATA
->child_signal
);
257 D(bug("__vfork: Waiting for child to finish using udata\n"));
258 /* Wait for child to finish using GETUDATA */
259 Wait(1 << GETUDATA
->parent_signal
);
261 D(bug("__vfork: fflushing\n"));
264 D(bug("__vfork: restoring old fd_array\n"));
265 /* Restore parent's old fd_array */
266 ((struct arosc_privdata
*) GetIntETask(GETUDATA
->parent
)->iet_acpd
)->acpd_fd_mempool
= GETUDATA
->parent_acpd_fd_mempool
;
267 ((struct arosc_privdata
*) GetIntETask(GETUDATA
->parent
)->iet_acpd
)->acpd_numslots
= GETUDATA
->parent_acpd_numslots
;
268 ((struct arosc_privdata
*) GetIntETask(GETUDATA
->parent
)->iet_acpd
)->acpd_fd_array
= GETUDATA
->parent_acpd_fd_array
;
270 D(bug("__vfork: restoring startup buffer\n"));
271 /* Restore parent startup buffer */
272 CopyMem(&GETUDATA
->startup_jmp_buf
, &__aros_startup_jmp_buf
, sizeof(jmp_buf));
274 D(bug("__vfork: freeing parent signal\n"));
275 FreeSignal(GETUDATA
->parent_signal
);
277 errno
= GETUDATA
->child_errno
;
279 FreeAndJump(GETUDATA
);
280 assert(0); /* not reached */
284 /* Remember parent fd descriptor table */
285 udata
->parent_acpd_fd_mempool
= ppriv
->acpd_fd_mempool
;
286 udata
->parent_acpd_numslots
= ppriv
->acpd_numslots
;
287 udata
->parent_acpd_fd_array
= ppriv
->acpd_fd_array
;
289 /* Pretend to be running as the child created by vfork */
290 ppriv
->acpd_vfork_data
= udata
;
291 ppriv
->acpd_flags
|= PRETEND_CHILD
;
292 ppriv
->acpd_fd_mempool
= udata
->cpriv
->acpd_fd_mempool
;
293 ppriv
->acpd_numslots
= udata
->cpriv
->acpd_numslots
;
294 ppriv
->acpd_fd_array
= udata
->cpriv
->acpd_fd_array
;
296 D(bug("__vfork: Jumping to jmp_buf %p\n", &udata
->vfork_jump
));
297 D(bug("__vfork: ip: %p, stack: %p\n", udata
->vfork_jump
[0].retaddr
, udata
->vfork_jump
[0].regs
[_JMPLEN
- 1]));
298 vfork_longjmp(udata
->vfork_jump
, 0);
299 assert(0); /* not reached */