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>
22 #include "__arosc_privdata.h"
28 #include <aros/debug.h>
29 #include <aros/startup.h>
31 BPTR
DupFHFromfd(int fd
, ULONG mode
);
32 void vfork_longjmp (jmp_buf env
, int val
);
33 LONG
exec_command(BPTR seglist
, char *taskname
, char *args
, ULONG stacksize
);
37 D(bug("launcher: Entered child launcher\n"));
39 struct Task
*this = FindTask(NULL
);
40 struct vfork_data
*udata
= this->tc_UserData
;
43 struct Library
*aroscbase
= NULL
;
45 GetIntETask(this)->iet_startup
= GetETask(this)->et_Result2
= AllocVec(sizeof(struct aros_startup
), MEMF_ANY
| MEMF_CLEAR
);
47 /* Allocate signal for parent->child communication */
48 child_signal
= udata
->child_signal
= AllocSignal(-1);
49 D(bug("launcher: Allocated child signal: %d\n", udata
->child_signal
));
50 if(udata
->child_signal
== -1)
53 udata
->child_errno
= ENOMEM
;
54 Signal(udata
->parent
, 1 << udata
->parent_signal
);
58 if(__register_init_fdarray(udata
->ppriv
->acpd_fd_array
, udata
->ppriv
->acpd_numslots
))
59 aroscbase
= OpenLibrary((STRPTR
) "arosc.library", 0);
62 FreeSignal(child_signal
);
63 udata
->child_errno
= ENOMEM
;
64 Signal(udata
->parent
, 1 << udata
->parent_signal
);
68 udata
->cpriv
= __get_arosc_privdata();
69 __get_arosc_privdata()->acpd_parent_does_upath
= udata
->ppriv
->acpd_doupath
;
70 __get_arosc_privdata()->acpd_flags
|= KEEP_OLD_ACPD
| DO_NOT_CLONE_ENV_VARS
;
72 /* Setup complete, signal parent */
73 D(bug("launcher: Signaling parent that we finished setup\n"));
74 Signal(udata
->parent
, 1 << udata
->parent_signal
);
76 D(bug("launcher: Child waiting for execve or exit\n"));
77 Wait(1 << udata
->child_signal
);
79 if(udata
->child_executed
)
81 D(bug("launcher: child executed\n"));
82 BPTR seglist
= udata
->exec_seglist
;
83 char *taskname
= udata
->exec_taskname
;
84 char *arguments
= udata
->exec_arguments
;
85 ULONG stacksize
= udata
->exec_stacksize
;
87 fdesc
*in
, *out
, *err
;
89 in
= __fd_array
[STDIN_FILENO
];
91 SelectInput(in
->fcb
->fh
);
93 out
= __fd_array
[STDOUT_FILENO
];
95 SelectOutput(out
->fcb
->fh
);
97 err
= __fd_array
[STDERR_FILENO
];
99 SelectError(err
->fcb
->fh
);
101 D(bug("launcher: informing parent that we won't use udata anymore\n"));
102 /* Inform parent that we won't use udata anymore */
103 Signal(udata
->parent
, 1 << udata
->parent_signal
);
105 D(bug("launcher: executing command\n"));
106 /* Run executed command */
114 D(bug("launcher: freeing taskname and arguments\n"));
118 __aros_startup_error
= ret
;
119 D(bug("launcher: exec_command returned %d\n", ret
));
123 D(bug("launcher: informing parent that we won't use udata anymore\n"));
124 /* Inform parent that we won't use udata anymore */
125 Signal(udata
->parent
, 1 << udata
->parent_signal
);
127 D(bug("launcher: freeing child_signal\n"));
128 FreeSignal(child_signal
);
129 CloseLibrary(aroscbase
);
133 void FreeAndJump(struct vfork_data
*udata
)
136 ULONG child_id
= udata
->child_id
;
137 bcopy(&udata
->vfork_jump
, env
, sizeof(jmp_buf));
138 D(bug("FreeAndJump: Restoring old vfork_data: %p\n", udata
->prev
));
139 __get_arosc_privdata()->acpd_vfork_data
= udata
->prev
;
140 __get_arosc_privdata()->acpd_flags
= udata
->old_acpd_flags
;
141 D(bug("FreeAndJump: freeing udata\n"));
142 FreeMem(udata
, sizeof(struct vfork_data
));
143 longjmp(env
, child_id
);
146 pid_t
__vfork(jmp_buf env
)
148 struct Task
*this = FindTask(NULL
);
149 struct vfork_data
*udata
= AllocMem(sizeof(struct vfork_data
), MEMF_ANY
| MEMF_CLEAR
);
155 D(bug("__vfork: allocated udata %p\n", udata
));
156 bcopy(env
, &udata
->vfork_jump
, sizeof(jmp_buf));
158 struct TagItem tags
[] =
160 { NP_Entry
, (IPTR
) launcher
},
161 { NP_CloseInput
, (IPTR
) FALSE
},
162 { NP_CloseOutput
, (IPTR
) FALSE
},
163 { NP_CloseError
, (IPTR
) FALSE
},
164 { NP_Cli
, (IPTR
) TRUE
},
165 { NP_Name
, (IPTR
) "vfork()" },
166 { NP_UserData
, (IPTR
) udata
},
167 { NP_NotifyOnDeath
, (IPTR
) TRUE
},
171 udata
->parent
= this;
172 /* Store parent's vfork_data to restore it later */
173 udata
->old_acpd_flags
= __get_arosc_privdata()->acpd_flags
;
174 udata
->prev
= __get_arosc_privdata()->acpd_vfork_data
;
175 D(bug("__vfork: Saved old parent's vfork_data: %p\n", udata
->prev
));
176 udata
->ppriv
= __get_arosc_privdata();
178 D(bug("__vfork: backuping startup buffer\n"));
179 /* Backup startup buffer */
180 CopyMem(&__aros_startup_jmp_buf
, &udata
->startup_jmp_buf
, sizeof(jmp_buf));
182 D(bug("__vfork: backuping current directory\n"));
183 udata
->parent_curdir
= CurrentDir(NULL
);
185 CurrentDir(DupLock(udata
->parent_curdir
));
187 D(bug("__vfork: backuping descriptor table\n"));
188 /* Backup parent fd descriptor table */
189 struct arosc_privdata
*ppriv
= GetIntETask(this)->iet_acpd
;
191 udata
->parent_acpd_fd_mempool
= ppriv
->acpd_fd_mempool
;
192 udata
->parent_acpd_numslots
= ppriv
->acpd_numslots
;
193 udata
->parent_acpd_fd_array
= ppriv
->acpd_fd_array
;
195 D(bug("__vfork: Allocating parent signal\n"));
196 /* Allocate signal for child->parent communication */
197 udata
->parent_signal
= AllocSignal(-1);
198 if(udata
->parent_signal
== -1)
200 /* Couldn't allocate the signal, return -1 */
201 FreeMem(udata
, sizeof(struct vfork_data
));
203 longjmp(udata
->vfork_jump
, -1);
206 D(bug("__vfork: Creating child\n"));
207 udata
->child
= (struct Task
*) CreateNewProc(tags
);
209 if(udata
->child
== NULL
)
211 /* Something went wrong, return -1 */
212 FreeMem(udata
, sizeof(struct vfork_data
));
213 errno
= ENOMEM
; /* Most likely */
216 D(bug("__vfork: Child created %p, waiting to finish setup\n", udata
->child
));
217 udata
->child_id
= GetETaskID(udata
->child
);
218 D(bug("__vfork: Got unique child id: %d\n", udata
->child_id
));
220 /* Wait for child to finish setup */
221 Wait(1 << udata
->parent_signal
);
223 if(udata
->child_errno
)
225 /* An error occured during child setup */
226 errno
= udata
->child_errno
;
230 D(bug("__vfork: Setting jmp_buf at %p in %p\n", __aros_startup
, &__aros_startup_jmp_buf
));
231 if(setjmp(__aros_startup_jmp_buf
))
233 D(bug("__vfork: child exited\n or executed\n"));
234 __get_arosc_privdata()->acpd_flags
&= ~PRETEND_CHILD
;
236 if(!GETUDATA
->child_executed
)
238 D(bug("__vfork: not executed\n"));
239 ((struct aros_startup
*) GetIntETask(GETUDATA
->child
)->iet_startup
)->as_startup_error
= __aros_startup_error
;
240 D(bug("__vfork: Signaling child\n"));
241 Signal(GETUDATA
->child
, 1 << GETUDATA
->child_signal
);
244 D(bug("__vfork: Waiting for child to finish using udata\n"));
245 /* Wait for child to finish using GETUDATA */
246 Wait(1 << GETUDATA
->parent_signal
);
248 D(bug("__vfork: fflushing\n"));
251 D(bug("__vfork: Restoring current directory\n"));
252 UnLock(CurrentDir(GETUDATA
->parent_curdir
));
254 D(bug("__vfork: restoring old fd_array\n"));
255 /* Restore parent's old fd_array */
256 ((struct arosc_privdata
*) GetIntETask(GETUDATA
->parent
)->iet_acpd
)->acpd_fd_mempool
= GETUDATA
->parent_acpd_fd_mempool
;
257 ((struct arosc_privdata
*) GetIntETask(GETUDATA
->parent
)->iet_acpd
)->acpd_numslots
= GETUDATA
->parent_acpd_numslots
;
258 ((struct arosc_privdata
*) GetIntETask(GETUDATA
->parent
)->iet_acpd
)->acpd_fd_array
= GETUDATA
->parent_acpd_fd_array
;
260 D(bug("__vfork: restoring startup buffer\n"));
261 /* Restore parent startup buffer */
262 CopyMem(&GETUDATA
->startup_jmp_buf
, &__aros_startup_jmp_buf
, sizeof(jmp_buf));
264 D(bug("__vfork: freeing parent signal\n"));
265 FreeSignal(GETUDATA
->parent_signal
);
267 FreeAndJump(GETUDATA
);
268 return (pid_t
) 1; /* not reached */
271 ppriv
->acpd_vfork_data
= udata
;
272 ppriv
->acpd_flags
|= PRETEND_CHILD
;
273 ppriv
->acpd_fd_mempool
= udata
->cpriv
->acpd_fd_mempool
;
274 ppriv
->acpd_numslots
= udata
->cpriv
->acpd_numslots
;
275 ppriv
->acpd_fd_array
= udata
->cpriv
->acpd_fd_array
;
277 D(bug("__vfork: Jumping to jmp_buf %p\n", &udata
->vfork_jump
));
278 D(bug("__vfork: ip: %p, stack: %p\n", udata
->vfork_jump
[0].retaddr
, udata
->vfork_jump
[0].regs
[_JMPLEN
- 1]));
279 vfork_longjmp(udata
->vfork_jump
, 0);
280 return (pid_t
) 0; /* not reached */