1b8851fccSafresh1 /* amigaio.c mixes amigaos and perl APIs,
2b8851fccSafresh1 * as opposed to amigaos.c which is pure amigaos */
3b8851fccSafresh1
4b8851fccSafresh1 #include "EXTERN.h"
5b8851fccSafresh1 #include "perl.h"
6b8851fccSafresh1
7b8851fccSafresh1 #include "amigaos4/amigaio.h"
8b8851fccSafresh1 #include "amigaos.h"
9b8851fccSafresh1
10b8851fccSafresh1 #ifdef WORD
11b8851fccSafresh1 # undef WORD
12b8851fccSafresh1 # define WORD int16
13b8851fccSafresh1 #endif
14b8851fccSafresh1
15b8851fccSafresh1 #include <stdio.h>
16b8851fccSafresh1
17b8851fccSafresh1 #include <exec/semaphores.h>
18b8851fccSafresh1 #include <exec/exectags.h>
19b8851fccSafresh1 #include <proto/exec.h>
20b8851fccSafresh1 #include <proto/dos.h>
21b8851fccSafresh1 #include <proto/utility.h>
22b8851fccSafresh1 #include <dos/dos.h>
23b8851fccSafresh1
24b8851fccSafresh1 extern struct SignalSemaphore popen_sema;
25b8851fccSafresh1 extern unsigned int pipenum;
26b8851fccSafresh1
27b8851fccSafresh1 extern int32 myruncommand(BPTR seglist, int stack, char *command, int length, char **envp);
28b8851fccSafresh1
amigaos_stdio_get(pTHX_ StdioStore * store)29b8851fccSafresh1 void amigaos_stdio_get(pTHX_ StdioStore *store)
30b8851fccSafresh1 {
31b8851fccSafresh1 store->astdin =
32b8851fccSafresh1 amigaos_get_file(PerlIO_fileno(IoIFP(GvIO(PL_stdingv))));
33b8851fccSafresh1 store->astderr =
34b8851fccSafresh1 amigaos_get_file(PerlIO_fileno(IoIFP(GvIO(PL_stderrgv))));
35b8851fccSafresh1 store->astdout = amigaos_get_file(
36b8851fccSafresh1 PerlIO_fileno(IoIFP(GvIO(gv_fetchpv("STDOUT", TRUE, SVt_PVIO)))));
37b8851fccSafresh1 }
38b8851fccSafresh1
amigaos_stdio_save(pTHX_ StdioStore * store)39b8851fccSafresh1 void amigaos_stdio_save(pTHX_ StdioStore *store)
40b8851fccSafresh1 {
41b8851fccSafresh1 amigaos_stdio_get(aTHX_ store);
42b8851fccSafresh1 store->oldstdin = IDOS->SelectInput(store->astdin);
43b8851fccSafresh1 store->oldstderr = IDOS->SelectErrorOutput(store->astderr);
44b8851fccSafresh1 store->oldstdout = IDOS->SelectOutput(store->astdout);
45b8851fccSafresh1 }
46b8851fccSafresh1
amigaos_stdio_restore(pTHX_ const StdioStore * store)47b8851fccSafresh1 void amigaos_stdio_restore(pTHX_ const StdioStore *store)
48b8851fccSafresh1 {
49b8851fccSafresh1 IDOS->SelectInput(store->oldstdin);
50b8851fccSafresh1 IDOS->SelectErrorOutput(store->oldstderr);
51b8851fccSafresh1 IDOS->SelectOutput(store->oldstdout);
52b8851fccSafresh1 }
53b8851fccSafresh1
amigaos_post_exec(int fd,int do_report)54b8851fccSafresh1 void amigaos_post_exec(int fd, int do_report)
55b8851fccSafresh1 {
56b8851fccSafresh1 /* We *must* write something to our pipe or else
57b8851fccSafresh1 * the other end hangs */
58b8851fccSafresh1 if (do_report)
59b8851fccSafresh1 {
60b8851fccSafresh1 int e = errno;
61b8851fccSafresh1 PerlLIO_write(fd, (void *)&e, sizeof(e));
62b8851fccSafresh1 PerlLIO_close(fd);
63b8851fccSafresh1 }
64b8851fccSafresh1 }
65b8851fccSafresh1
66b8851fccSafresh1
67b8851fccSafresh1 struct popen_data
68b8851fccSafresh1 {
69b8851fccSafresh1 struct Task *parent;
70b8851fccSafresh1 STRPTR command;
71b8851fccSafresh1 };
72b8851fccSafresh1
73b8851fccSafresh1 static int popen_result = 0;
74b8851fccSafresh1
popen_child()75b8851fccSafresh1 int popen_child()
76b8851fccSafresh1 {
77b8851fccSafresh1 struct Task *thisTask = IExec->FindTask(0);
78b8851fccSafresh1 struct popen_data *pd = (struct popen_data *)thisTask->tc_UserData;
79b8851fccSafresh1 const char *argv[4];
80b8851fccSafresh1
81b8851fccSafresh1 argv[0] = "sh";
82b8851fccSafresh1 argv[1] = "-c";
83b8851fccSafresh1 argv[2] = pd->command ? pd->command : NULL;
84b8851fccSafresh1 argv[3] = NULL;
85b8851fccSafresh1
86b8851fccSafresh1 // adebug("%s %ld %s\n",__FUNCTION__,__LINE__,command?command:"NULL");
87b8851fccSafresh1
88b8851fccSafresh1 /* We need to give this to sh via execvp, execvp expects filename,
89b8851fccSafresh1 * argv[]
90b8851fccSafresh1 */
91b8851fccSafresh1 IExec->ObtainSemaphore(&popen_sema);
92b8851fccSafresh1
93b8851fccSafresh1 IExec->Signal(pd->parent,SIGBREAKF_CTRL_F);
94b8851fccSafresh1
95b8851fccSafresh1 popen_result = myexecvp(FALSE, argv[0], (char **)argv);
96b8851fccSafresh1 if (pd->command)
97b8851fccSafresh1 IExec->FreeVec(pd->command);
98b8851fccSafresh1 IExec->FreeVec(pd);
99b8851fccSafresh1
100b8851fccSafresh1 IExec->ReleaseSemaphore(&popen_sema);
101b8851fccSafresh1 IExec->Forbid();
102b8851fccSafresh1 return 0;
103b8851fccSafresh1 }
104b8851fccSafresh1
105b8851fccSafresh1
Perl_my_popen(pTHX_ const char * cmd,const char * mode)106b8851fccSafresh1 PerlIO *Perl_my_popen(pTHX_ const char *cmd, const char *mode)
107b8851fccSafresh1 {
108b8851fccSafresh1
109b8851fccSafresh1 PERL_FLUSHALL_FOR_CHILD;
110b8851fccSafresh1 PerlIO *result = NULL;
111b8851fccSafresh1 char pipe_name[50];
112b8851fccSafresh1 char unix_pipe[50];
113b8851fccSafresh1 char ami_pipe[50];
114b8851fccSafresh1 BPTR input = 0;
115b8851fccSafresh1 BPTR output = 0;
116b8851fccSafresh1 struct Process *proc = NULL;
117b8851fccSafresh1 struct Task *thisTask = IExec->FindTask(0);
118b8851fccSafresh1 struct popen_data * pd = NULL;
119b8851fccSafresh1
120b8851fccSafresh1 /* First we need to check the mode
121b8851fccSafresh1 * We can only have unidirectional pipes
122b8851fccSafresh1 */
123b8851fccSafresh1 // adebug("%s %ld cmd %s mode %s \n",__FUNCTION__,__LINE__,cmd,
124b8851fccSafresh1 // mode);
125b8851fccSafresh1
126b8851fccSafresh1 switch (mode[0])
127b8851fccSafresh1 {
128b8851fccSafresh1 case 'r':
129b8851fccSafresh1 case 'w':
130b8851fccSafresh1 break;
131b8851fccSafresh1
132b8851fccSafresh1 default:
133b8851fccSafresh1
134b8851fccSafresh1 errno = EINVAL;
135b8851fccSafresh1 return result;
136b8851fccSafresh1 }
137b8851fccSafresh1
138b8851fccSafresh1 /* Make a unique pipe name
139b8851fccSafresh1 * we need a unix one and an amigaos version (of the same pipe!)
140b8851fccSafresh1 * as were linking with libunix.
141b8851fccSafresh1 */
142b8851fccSafresh1
143b8851fccSafresh1 sprintf(pipe_name, "%x%08lx/4096/0", pipenum++,
144b8851fccSafresh1 IUtility->GetUniqueID());
145b8851fccSafresh1 sprintf(unix_pipe, "/PIPE/%s", pipe_name);
146b8851fccSafresh1 sprintf(ami_pipe, "PIPE:%s", pipe_name);
147b8851fccSafresh1
148b8851fccSafresh1 /* Now we open the AmigaOs Filehandles That we wil pass to our
149b8851fccSafresh1 * Sub process
150b8851fccSafresh1 */
151b8851fccSafresh1
152b8851fccSafresh1 if (mode[0] == 'r')
153b8851fccSafresh1 {
154b8851fccSafresh1 /* A read mode pipe: Output from pipe input from Output() or NIL:*/
155b8851fccSafresh1 /* First attempt to DUP Output() */
156b8851fccSafresh1 input = IDOS->DupFileHandle(IDOS->Input());
157b8851fccSafresh1 if(input == 0)
158b8851fccSafresh1 {
159b8851fccSafresh1 input = IDOS->Open("NIL:", MODE_READWRITE);
160b8851fccSafresh1 }
161b8851fccSafresh1 if (input != 0)
162b8851fccSafresh1 {
163b8851fccSafresh1 output = IDOS->Open(ami_pipe, MODE_NEWFILE);
164b8851fccSafresh1 }
165b8851fccSafresh1 result = PerlIO_open(unix_pipe, mode);
166b8851fccSafresh1 }
167b8851fccSafresh1 else
168b8851fccSafresh1 {
169b8851fccSafresh1 /* Open the write end first! */
170b8851fccSafresh1
171b8851fccSafresh1 result = PerlIO_open(unix_pipe, mode);
172b8851fccSafresh1
173b8851fccSafresh1 input = IDOS->Open(ami_pipe, MODE_OLDFILE);
174b8851fccSafresh1 if (input != 0)
175b8851fccSafresh1 {
176b8851fccSafresh1 output = IDOS->DupFileHandle(IDOS->Output());
177b8851fccSafresh1 if(output == 0)
178b8851fccSafresh1 {
179b8851fccSafresh1 output = IDOS->Open("NIL:", MODE_READWRITE);
180b8851fccSafresh1 }
181b8851fccSafresh1 }
182b8851fccSafresh1 }
183b8851fccSafresh1 if ((input == 0) || (output == 0) || (result == NULL))
184b8851fccSafresh1 {
185b8851fccSafresh1 /* Ouch stream opening failed */
186b8851fccSafresh1 /* Close and bail */
187b8851fccSafresh1 if (input)
188b8851fccSafresh1 IDOS->Close(input);
189b8851fccSafresh1 if (output)
190b8851fccSafresh1 IDOS->Close(output);
191b8851fccSafresh1 if(result)
192b8851fccSafresh1 {
193b8851fccSafresh1 PerlIO_close(result);
194b8851fccSafresh1 result = NULL;
195b8851fccSafresh1 }
196b8851fccSafresh1 return result;
197b8851fccSafresh1 }
198b8851fccSafresh1
199b8851fccSafresh1 /* We have our streams now start our new process
200b8851fccSafresh1 * We're using a new process so that execve can modify the environment
201b8851fccSafresh1 * with messing things up for the shell that launched perl
202b8851fccSafresh1 * Copy cmd before we launch the subprocess as perl seems to waste
203b8851fccSafresh1 * no time in overwriting it! The subprocess will free the copy.
204b8851fccSafresh1 */
205b8851fccSafresh1
206b8851fccSafresh1 if((pd = (struct popen_data*)IExec->AllocVecTags(sizeof(struct popen_data),AVT_Type,MEMF_SHARED,TAG_DONE)))
207b8851fccSafresh1 {
208b8851fccSafresh1 pd->parent = thisTask;
209b8851fccSafresh1 if ((pd->command = mystrdup(cmd)))
210b8851fccSafresh1 {
211b8851fccSafresh1 // adebug("%s %ld
212b8851fccSafresh1 // %s\n",__FUNCTION__,__LINE__,cmd_copy?cmd_copy:"NULL");
213b8851fccSafresh1 proc = IDOS->CreateNewProcTags(
214b8851fccSafresh1 NP_Entry, popen_child, NP_Child, TRUE, NP_StackSize,
215b8851fccSafresh1 ((struct Process *)thisTask)->pr_StackSize, NP_Input, input,
216b8851fccSafresh1 NP_Output, output, NP_Error, IDOS->ErrorOutput(),
217b8851fccSafresh1 NP_CloseError, FALSE, NP_Cli, TRUE, NP_Name,
218b8851fccSafresh1 "Perl: popen process", NP_UserData, (int)pd,
219b8851fccSafresh1 TAG_DONE);
220b8851fccSafresh1 }
221b8851fccSafresh1 }
222b8851fccSafresh1 if(proc)
223b8851fccSafresh1 {
224b8851fccSafresh1 /* wait for the child be setup right */
225b8851fccSafresh1 IExec->Wait(SIGBREAKF_CTRL_F);
226b8851fccSafresh1 }
227b8851fccSafresh1 if (!proc)
228b8851fccSafresh1 {
229b8851fccSafresh1 /* New Process Failed to start
230b8851fccSafresh1 * Close and bail out
231b8851fccSafresh1 */
232b8851fccSafresh1 if(pd)
233b8851fccSafresh1 {
234b8851fccSafresh1 if(pd->command)
235b8851fccSafresh1 {
236b8851fccSafresh1 IExec->FreeVec(pd->command);
237b8851fccSafresh1 }
238b8851fccSafresh1 IExec->FreeVec(pd);
239b8851fccSafresh1 }
240b8851fccSafresh1 if (input)
241b8851fccSafresh1 IDOS->Close(input);
242b8851fccSafresh1 if (output)
243b8851fccSafresh1 IDOS->Close(output);
244b8851fccSafresh1 if(result)
245b8851fccSafresh1 {
246b8851fccSafresh1 PerlIO_close(result);
247b8851fccSafresh1 result = NULL;
248b8851fccSafresh1 }
249b8851fccSafresh1 }
250b8851fccSafresh1
251b8851fccSafresh1 /* Our new process is running and will close it streams etc
252*e0680481Safresh1 * once it's done. All we need to is open the pipe via stdio
253b8851fccSafresh1 */
254b8851fccSafresh1
255b8851fccSafresh1 return result;
256b8851fccSafresh1 }
257b8851fccSafresh1
258b8851fccSafresh1 I32
Perl_my_pclose(pTHX_ PerlIO * ptr)259b8851fccSafresh1 Perl_my_pclose(pTHX_ PerlIO *ptr)
260b8851fccSafresh1 {
261b8851fccSafresh1 int result = -1;
262b8851fccSafresh1 /* close the file before obtaining the semaphore else we might end up
263b8851fccSafresh1 hanging waiting for the child to read the last bit from the pipe */
264b8851fccSafresh1 PerlIO_close(ptr);
265b8851fccSafresh1 IExec->ObtainSemaphore(&popen_sema);
266b8851fccSafresh1 result = popen_result;
267b8851fccSafresh1 IExec->ReleaseSemaphore(&popen_sema);
268b8851fccSafresh1 return result;
269b8851fccSafresh1 }
270b8851fccSafresh1
271b8851fccSafresh1
272b8851fccSafresh1 #ifdef USE_ITHREADS
273b8851fccSafresh1
274b8851fccSafresh1 /* An arbitrary number to start with, should work out what the real max should
275b8851fccSafresh1 * be */
276b8851fccSafresh1
277b8851fccSafresh1 #ifndef MAX_THREADS
278b8851fccSafresh1 # define MAX_THREADS 64
279b8851fccSafresh1 #endif
280b8851fccSafresh1
281b8851fccSafresh1 #define REAPED 0
282b8851fccSafresh1 #define ACTIVE 1
283b8851fccSafresh1 #define EXITED -1
284b8851fccSafresh1
285b8851fccSafresh1 struct thread_info
286b8851fccSafresh1 {
287b8851fccSafresh1 pthread_t ti_pid;
288b8851fccSafresh1 int ti_children;
289b8851fccSafresh1 pthread_t ti_parent;
290b8851fccSafresh1 struct MsgPort *ti_port;
291b8851fccSafresh1 struct Process *ti_Process;
292b8851fccSafresh1 };
293b8851fccSafresh1
294b8851fccSafresh1 static struct thread_info pseudo_children[MAX_THREADS];
295b8851fccSafresh1 static int num_pseudo_children = 0;
296b8851fccSafresh1 static struct SignalSemaphore fork_array_sema;
297b8851fccSafresh1
amigaos4_init_fork_array()298b8851fccSafresh1 void amigaos4_init_fork_array()
299b8851fccSafresh1 {
300b8851fccSafresh1 IExec->InitSemaphore(&fork_array_sema);
301b8851fccSafresh1 pseudo_children[0].ti_pid = (pthread_t)IExec->FindTask(0);
302b8851fccSafresh1 pseudo_children[0].ti_parent = -1;
303b8851fccSafresh1 pseudo_children[0].ti_port =
304b8851fccSafresh1 (struct MsgPort *)IExec->AllocSysObjectTags(ASOT_PORT, TAG_DONE);
305b8851fccSafresh1 }
306b8851fccSafresh1
amigaos4_dispose_fork_array()307b8851fccSafresh1 void amigaos4_dispose_fork_array()
308b8851fccSafresh1 {
309b8851fccSafresh1 while (pseudo_children[0].ti_children > 0)
310b8851fccSafresh1 {
311b8851fccSafresh1 void *msg;
312b8851fccSafresh1 IExec->WaitPort(pseudo_children[0].ti_port);
313b8851fccSafresh1 msg = IExec->GetMsg(pseudo_children[0].ti_port);
314b8851fccSafresh1 if (msg)
315b8851fccSafresh1 IExec->FreeSysObject(ASOT_MESSAGE, msg);
316b8851fccSafresh1 pseudo_children[0].ti_children--;
317b8851fccSafresh1 }
318b8851fccSafresh1 IExec->FreeSysObject(ASOT_PORT, pseudo_children[0].ti_port);
319b8851fccSafresh1 }
320b8851fccSafresh1
321b8851fccSafresh1 struct thread_exit_message
322b8851fccSafresh1 {
323b8851fccSafresh1 struct Message tem_Message;
324b8851fccSafresh1 pthread_t tem_pid;
325b8851fccSafresh1 int tem_status;
326b8851fccSafresh1 };
327b8851fccSafresh1
getnextchild()328b8851fccSafresh1 int getnextchild()
329b8851fccSafresh1 {
330b8851fccSafresh1 int i;
331b8851fccSafresh1 for (i = 0; i < MAX_THREADS; i++)
332b8851fccSafresh1 {
333b8851fccSafresh1 if (pseudo_children[i].ti_pid == 0)
334b8851fccSafresh1 return i;
335b8851fccSafresh1 }
336b8851fccSafresh1 return -1;
337b8851fccSafresh1 }
338b8851fccSafresh1
findparent(pthread_t pid)339b8851fccSafresh1 int findparent(pthread_t pid)
340b8851fccSafresh1 {
341b8851fccSafresh1 int i;
342b8851fccSafresh1 for (i = 0; i < MAX_THREADS; i++)
343b8851fccSafresh1 {
344b8851fccSafresh1 if (pseudo_children[i].ti_pid == pid)
345b8851fccSafresh1 return i;
346b8851fccSafresh1 }
347b8851fccSafresh1 return -1;
348b8851fccSafresh1 }
349b8851fccSafresh1
350b8851fccSafresh1 struct child_arg
351b8851fccSafresh1 {
352b8851fccSafresh1 struct Task *ca_parent_task;
353b8851fccSafresh1 pthread_t ca_parent;
354b8851fccSafresh1 PerlInterpreter *ca_interp;
355b8851fccSafresh1 };
356b8851fccSafresh1
357b8851fccSafresh1 #undef kill
358b8851fccSafresh1
359b8851fccSafresh1 /* FIXME: Is here's a chance, albeit it small of a clash between our pseudo pid */
360b8851fccSafresh1 /* derived from the pthread API and the dos.library pid that newlib kill uses? */
361b8851fccSafresh1 /* clib2 used the Process address so there was no issue */
362b8851fccSafresh1
amigaos_kill(Pid_t pid,int signal)363b8851fccSafresh1 int amigaos_kill(Pid_t pid, int signal)
364b8851fccSafresh1 {
365b8851fccSafresh1 int i;
366b8851fccSafresh1 BOOL thistask = FALSE;
367b8851fccSafresh1 Pid_t realpid = pid; // Perhaps we have a real pid from else where?
368b8851fccSafresh1 /* Look for our DOS pid */
369b8851fccSafresh1 IExec->ObtainSemaphore(&fork_array_sema);
370b8851fccSafresh1 for (i = 0; i < MAX_THREADS; i++)
371b8851fccSafresh1 {
372b8851fccSafresh1 if (pseudo_children[i].ti_pid == pid)
373b8851fccSafresh1 {
374b8851fccSafresh1 realpid = (Pid_t)IDOS->GetPID(pseudo_children[i].ti_Process,GPID_PROCESS);
375b8851fccSafresh1 if(pseudo_children[i].ti_Process == (struct Process *)IExec->FindTask(NULL))
376b8851fccSafresh1 {
377b8851fccSafresh1 thistask = TRUE;
378b8851fccSafresh1 }
379b8851fccSafresh1 break;
380b8851fccSafresh1 }
381b8851fccSafresh1 }
382b8851fccSafresh1 IExec->ReleaseSemaphore(&fork_array_sema);
383b8851fccSafresh1 /* Allow the C library to work out which signals are realy valid */
384b8851fccSafresh1 if(thistask)
385b8851fccSafresh1 {
386b8851fccSafresh1 /* A quirk in newlib kill handling means it's better to call raise() rather than kill on out own task. */
387b8851fccSafresh1 return raise(signal);
388b8851fccSafresh1 }
389b8851fccSafresh1 else
390b8851fccSafresh1 {
391b8851fccSafresh1 return kill(realpid,signal);
392b8851fccSafresh1 }
393b8851fccSafresh1 }
394b8851fccSafresh1
amigaos4_start_child(void * arg)395b8851fccSafresh1 static THREAD_RET_TYPE amigaos4_start_child(void *arg)
396b8851fccSafresh1 {
397b8851fccSafresh1
398b8851fccSafresh1 PerlInterpreter *my_perl =
399b8851fccSafresh1 (PerlInterpreter *)((struct child_arg *)arg)->ca_interp;
400b8851fccSafresh1 ;
401b8851fccSafresh1
402b8851fccSafresh1 GV *tmpgv;
403b8851fccSafresh1 int status;
404b8851fccSafresh1 int parent;
405b8851fccSafresh1 int nextchild;
406b8851fccSafresh1 pthread_t pseudo_id = pthread_self();
407b8851fccSafresh1
408b8851fccSafresh1 #ifdef PERL_SYNC_FORK
409b8851fccSafresh1 static long sync_fork_id = 0;
410b8851fccSafresh1 long id = ++sync_fork_id;
411b8851fccSafresh1 #endif
412b8851fccSafresh1
413b8851fccSafresh1 /* before we do anything set up our process semaphore and add
414b8851fccSafresh1 a new entry to the pseudochildren */
415b8851fccSafresh1
416b8851fccSafresh1 /* get next available slot */
417b8851fccSafresh1 /* should not fail here! */
418b8851fccSafresh1
419b8851fccSafresh1 IExec->ObtainSemaphore(&fork_array_sema);
420b8851fccSafresh1
421b8851fccSafresh1 nextchild = getnextchild();
422b8851fccSafresh1
423b8851fccSafresh1 pseudo_children[nextchild].ti_pid = pseudo_id;
424b8851fccSafresh1 pseudo_children[nextchild].ti_Process = (struct Process *)IExec->FindTask(NULL);
425b8851fccSafresh1 pseudo_children[nextchild].ti_parent =
426b8851fccSafresh1 ((struct child_arg *)arg)->ca_parent;
427b8851fccSafresh1 pseudo_children[nextchild].ti_port =
428b8851fccSafresh1 (struct MsgPort *)IExec->AllocSysObjectTags(ASOT_PORT, TAG_DONE);
429b8851fccSafresh1
430b8851fccSafresh1 num_pseudo_children++;
431b8851fccSafresh1 IExec->ReleaseSemaphore(&fork_array_sema);
432b8851fccSafresh1
433b8851fccSafresh1 /* We're set up let the parent continue */
434b8851fccSafresh1
435b8851fccSafresh1 IExec->Signal(((struct child_arg *)arg)->ca_parent_task,
436b8851fccSafresh1 SIGBREAKF_CTRL_F);
437b8851fccSafresh1
438b8851fccSafresh1 PERL_SET_THX(my_perl);
439b8851fccSafresh1 if ((tmpgv = gv_fetchpv("$", TRUE, SVt_PV)))
440b8851fccSafresh1 {
441b8851fccSafresh1 SV *sv = GvSV(tmpgv);
442b8851fccSafresh1 SvREADONLY_off(sv);
443b8851fccSafresh1 sv_setiv(sv, (IV)pseudo_id);
444b8851fccSafresh1 SvREADONLY_on(sv);
445b8851fccSafresh1 }
446b8851fccSafresh1 hv_clear(PL_pidstatus);
447b8851fccSafresh1
448b8851fccSafresh1 /* push a zero on the stack (we are the child) */
449b8851fccSafresh1 {
450b8851fccSafresh1 dSP;
451b8851fccSafresh1 dTARGET;
452b8851fccSafresh1 PUSHi(0);
453b8851fccSafresh1 PUTBACK;
454b8851fccSafresh1 }
455b8851fccSafresh1
456b8851fccSafresh1 /* continue from next op */
457b8851fccSafresh1 PL_op = PL_op->op_next;
458b8851fccSafresh1
459b8851fccSafresh1 {
460b8851fccSafresh1 dJMPENV;
461b8851fccSafresh1 volatile int oldscope = PL_scopestack_ix;
462b8851fccSafresh1
463b8851fccSafresh1 restart:
464b8851fccSafresh1 JMPENV_PUSH(status);
465b8851fccSafresh1 switch (status)
466b8851fccSafresh1 {
467b8851fccSafresh1 case 0:
468b8851fccSafresh1 CALLRUNOPS(aTHX);
469b8851fccSafresh1 status = 0;
470b8851fccSafresh1 break;
471b8851fccSafresh1 case 2:
472b8851fccSafresh1 while (PL_scopestack_ix > oldscope)
473b8851fccSafresh1 {
474b8851fccSafresh1 LEAVE;
475b8851fccSafresh1 }
476b8851fccSafresh1 FREETMPS;
477b8851fccSafresh1 PL_curstash = PL_defstash;
478b8851fccSafresh1 if (PL_endav && !PL_minus_c)
479b8851fccSafresh1 call_list(oldscope, PL_endav);
480b8851fccSafresh1 status = STATUS_EXIT;
481b8851fccSafresh1 break;
482b8851fccSafresh1 case 3:
483b8851fccSafresh1 if (PL_restartop)
484b8851fccSafresh1 {
485b8851fccSafresh1 POPSTACK_TO(PL_mainstack);
486b8851fccSafresh1 PL_op = PL_restartop;
487b8851fccSafresh1 PL_restartop = (OP *)NULL;
488b8851fccSafresh1 ;
489b8851fccSafresh1 goto restart;
490b8851fccSafresh1 }
491b8851fccSafresh1 PerlIO_printf(Perl_error_log, "panic: restartop\n");
492b8851fccSafresh1 FREETMPS;
493b8851fccSafresh1 status = 1;
494b8851fccSafresh1 break;
495b8851fccSafresh1 }
496b8851fccSafresh1 JMPENV_POP;
497b8851fccSafresh1
498b8851fccSafresh1 /* XXX hack to avoid perl_destruct() freeing optree */
499b8851fccSafresh1 PL_main_root = (OP *)NULL;
500b8851fccSafresh1 }
501b8851fccSafresh1
502b8851fccSafresh1 {
503b8851fccSafresh1 do_close(PL_stdingv, FALSE);
504b8851fccSafresh1 do_close(gv_fetchpv("STDOUT", TRUE, SVt_PVIO),
505b8851fccSafresh1 FALSE); /* PL_stdoutgv - ISAGN */
506b8851fccSafresh1 do_close(PL_stderrgv, FALSE);
507b8851fccSafresh1 }
508b8851fccSafresh1
509b8851fccSafresh1 /* destroy everything (waits for any pseudo-forked children) */
510b8851fccSafresh1
511b8851fccSafresh1 /* wait for any remaining children */
512b8851fccSafresh1
513b8851fccSafresh1 while (pseudo_children[nextchild].ti_children > 0)
514b8851fccSafresh1 {
515b8851fccSafresh1 if (IExec->WaitPort(pseudo_children[nextchild].ti_port))
516b8851fccSafresh1 {
517b8851fccSafresh1 void *msg =
518b8851fccSafresh1 IExec->GetMsg(pseudo_children[nextchild].ti_port);
519b8851fccSafresh1 IExec->FreeSysObject(ASOT_MESSAGE, msg);
520b8851fccSafresh1 pseudo_children[nextchild].ti_children--;
521b8851fccSafresh1 }
522b8851fccSafresh1 }
523b8851fccSafresh1 if (PL_scopestack_ix <= 1)
524b8851fccSafresh1 {
525b8851fccSafresh1 perl_destruct(my_perl);
526b8851fccSafresh1 }
527b8851fccSafresh1 perl_free(my_perl);
528b8851fccSafresh1
529b8851fccSafresh1 IExec->ObtainSemaphore(&fork_array_sema);
530b8851fccSafresh1 parent = findparent(pseudo_children[nextchild].ti_parent);
531b8851fccSafresh1 pseudo_children[nextchild].ti_pid = 0;
532b8851fccSafresh1 pseudo_children[nextchild].ti_parent = 0;
533b8851fccSafresh1 IExec->FreeSysObject(ASOT_PORT, pseudo_children[nextchild].ti_port);
534b8851fccSafresh1 pseudo_children[nextchild].ti_port = NULL;
535b8851fccSafresh1
536b8851fccSafresh1 IExec->ReleaseSemaphore(&fork_array_sema);
537b8851fccSafresh1
538b8851fccSafresh1 {
539b8851fccSafresh1 if (parent >= 0)
540b8851fccSafresh1 {
541b8851fccSafresh1 struct thread_exit_message *tem =
542b8851fccSafresh1 (struct thread_exit_message *)
543b8851fccSafresh1 IExec->AllocSysObjectTags(
544b8851fccSafresh1 ASOT_MESSAGE, ASOMSG_Size,
545b8851fccSafresh1 sizeof(struct thread_exit_message),
546b8851fccSafresh1 ASOMSG_Length,
547b8851fccSafresh1 sizeof(struct thread_exit_message));
548b8851fccSafresh1 if (tem)
549b8851fccSafresh1 {
550b8851fccSafresh1 tem->tem_pid = pseudo_id;
551b8851fccSafresh1 tem->tem_status = status;
552b8851fccSafresh1 IExec->PutMsg(pseudo_children[parent].ti_port,
553b8851fccSafresh1 (struct Message *)tem);
554b8851fccSafresh1 }
555b8851fccSafresh1 }
556b8851fccSafresh1 }
557b8851fccSafresh1 #ifdef PERL_SYNC_FORK
558b8851fccSafresh1 return id;
559b8851fccSafresh1 #else
560b8851fccSafresh1 return (void *)status;
561b8851fccSafresh1 #endif
562b8851fccSafresh1 }
563b8851fccSafresh1
564b8851fccSafresh1 #endif /* USE_ITHREADS */
565b8851fccSafresh1
amigaos_fork()566b8851fccSafresh1 Pid_t amigaos_fork()
567b8851fccSafresh1 {
568b8851fccSafresh1 dTHX;
569b8851fccSafresh1 pthread_t id;
570b8851fccSafresh1 int handle;
571b8851fccSafresh1 struct child_arg arg;
572b8851fccSafresh1 if (num_pseudo_children >= MAX_THREADS)
573b8851fccSafresh1 {
574b8851fccSafresh1 errno = EAGAIN;
575b8851fccSafresh1 return -1;
576b8851fccSafresh1 }
577b8851fccSafresh1 arg.ca_interp = perl_clone((PerlInterpreter *)aTHX, CLONEf_COPY_STACKS);
578b8851fccSafresh1 arg.ca_parent_task = IExec->FindTask(NULL);
579b8851fccSafresh1 arg.ca_parent =
580b8851fccSafresh1 pthread_self() ? pthread_self() : (pthread_t)IExec->FindTask(0);
581b8851fccSafresh1
582b8851fccSafresh1 handle = pthread_create(&id, NULL, amigaos4_start_child, (void *)&arg);
583b8851fccSafresh1 pseudo_children[findparent(arg.ca_parent)].ti_children++;
584b8851fccSafresh1
585b8851fccSafresh1 IExec->Wait(SIGBREAKF_CTRL_F);
586b8851fccSafresh1
587b8851fccSafresh1 PERL_SET_THX(aTHX); /* XXX perl_clone*() set TLS */
588b8851fccSafresh1 if (handle)
589b8851fccSafresh1 {
590b8851fccSafresh1 errno = EAGAIN;
591b8851fccSafresh1 return -1;
592b8851fccSafresh1 }
593b8851fccSafresh1 return id;
594b8851fccSafresh1 }
595b8851fccSafresh1
amigaos_waitpid(pTHX_ int optype,Pid_t pid,void * argflags)596b8851fccSafresh1 Pid_t amigaos_waitpid(pTHX_ int optype, Pid_t pid, void *argflags)
597b8851fccSafresh1 {
598b8851fccSafresh1 int result;
599b8851fccSafresh1 if (PL_signals & PERL_SIGNALS_UNSAFE_FLAG)
600b8851fccSafresh1 {
601b8851fccSafresh1 result = pthread_join(pid, (void **)argflags);
602b8851fccSafresh1 }
603b8851fccSafresh1 else
604b8851fccSafresh1 {
605b8851fccSafresh1 while ((result = pthread_join(pid, (void **)argflags)) == -1 &&
606b8851fccSafresh1 errno == EINTR)
607b8851fccSafresh1 {
608b8851fccSafresh1 // PERL_ASYNC_CHECK();
609b8851fccSafresh1 }
610b8851fccSafresh1 }
611b8851fccSafresh1 return result;
612b8851fccSafresh1 }
613b8851fccSafresh1
amigaos_fork_set_userdata(pTHX_ struct UserData * userdata,I32 did_pipes,int pp,SV ** sp,SV ** mark)614b8851fccSafresh1 void amigaos_fork_set_userdata(
615b8851fccSafresh1 pTHX_ struct UserData *userdata, I32 did_pipes, int pp, SV **sp, SV **mark)
616b8851fccSafresh1 {
617b8851fccSafresh1 userdata->parent = IExec->FindTask(0);
618b8851fccSafresh1 userdata->did_pipes = did_pipes;
619b8851fccSafresh1 userdata->pp = pp;
620b8851fccSafresh1 userdata->sp = sp;
621b8851fccSafresh1 userdata->mark = mark;
622b8851fccSafresh1 userdata->my_perl = aTHX;
623b8851fccSafresh1 }
624b8851fccSafresh1
625b8851fccSafresh1 /* AmigaOS specific versions of #?exec#? solely for use in amigaos_system_child
626b8851fccSafresh1 */
627b8851fccSafresh1
S_exec_failed(pTHX_ const char * cmd,int fd,int do_report)628b8851fccSafresh1 static void S_exec_failed(pTHX_ const char *cmd, int fd, int do_report)
629b8851fccSafresh1 {
630b8851fccSafresh1 const int e = errno;
631b8851fccSafresh1 // PERL_ARGS_ASSERT_EXEC_FAILED;
632b8851fccSafresh1 if (e)
633b8851fccSafresh1 {
634b8851fccSafresh1 if (ckWARN(WARN_EXEC))
635b8851fccSafresh1 Perl_warner(aTHX_ packWARN(WARN_EXEC),
636b8851fccSafresh1 "Can't exec \"%s\": %s", cmd, Strerror(e));
637b8851fccSafresh1 }
638b8851fccSafresh1 if (do_report)
639b8851fccSafresh1 {
640b8851fccSafresh1 /* XXX silently ignore failures */
641b8851fccSafresh1 PERL_UNUSED_RESULT(PerlLIO_write(fd, (void *)&e, sizeof(int)));
642b8851fccSafresh1 PerlLIO_close(fd);
643b8851fccSafresh1 }
644b8851fccSafresh1 }
645b8851fccSafresh1
S_do_amigaos_exec3(pTHX_ const char * incmd,int fd,int do_report)646b8851fccSafresh1 static I32 S_do_amigaos_exec3(pTHX_ const char *incmd, int fd, int do_report)
647b8851fccSafresh1 {
6485759b3d2Safresh1 const char **argv, **a;
649b8851fccSafresh1 char *s;
650b8851fccSafresh1 char *buf;
651b8851fccSafresh1 char *cmd;
652b8851fccSafresh1 /* Make a copy so we can change it */
653b8851fccSafresh1 const Size_t cmdlen = strlen(incmd) + 1;
654b8851fccSafresh1 I32 result = -1;
655b8851fccSafresh1
656b8851fccSafresh1 PERL_ARGS_ASSERT_DO_EXEC3;
657b8851fccSafresh1
6585759b3d2Safresh1 ENTER;
659b8851fccSafresh1 Newx(buf, cmdlen, char);
6605759b3d2Safresh1 SAVEFREEPV(buf);
661b8851fccSafresh1 cmd = buf;
662b8851fccSafresh1 memcpy(cmd, incmd, cmdlen);
663b8851fccSafresh1
664b8851fccSafresh1 while (*cmd && isSPACE(*cmd))
665b8851fccSafresh1 cmd++;
666b8851fccSafresh1
667b8851fccSafresh1 /* see if there are shell metacharacters in it */
668b8851fccSafresh1
669b8851fccSafresh1 if (*cmd == '.' && isSPACE(cmd[1]))
670b8851fccSafresh1 goto doshell;
671b8851fccSafresh1
6725759b3d2Safresh1 if (strBEGINs(cmd, "exec") && isSPACE(cmd[4]))
673b8851fccSafresh1 goto doshell;
674b8851fccSafresh1
675b8851fccSafresh1 s = cmd;
676b8851fccSafresh1 while (isWORDCHAR(*s))
677b8851fccSafresh1 s++; /* catch VAR=val gizmo */
678b8851fccSafresh1 if (*s == '=')
679b8851fccSafresh1 goto doshell;
680b8851fccSafresh1
681b8851fccSafresh1 for (s = cmd; *s; s++)
682b8851fccSafresh1 {
683b8851fccSafresh1 if (*s != ' ' && !isALPHA(*s) &&
68456d68f1eSafresh1 memCHRs("$&*(){}[]'\";\\|?<>~`\n", *s))
685b8851fccSafresh1 {
686b8851fccSafresh1 if (*s == '\n' && !s[1])
687b8851fccSafresh1 {
688b8851fccSafresh1 *s = '\0';
689b8851fccSafresh1 break;
690b8851fccSafresh1 }
691b8851fccSafresh1 /* handle the 2>&1 construct at the end */
692b8851fccSafresh1 if (*s == '>' && s[1] == '&' && s[2] == '1' &&
693b8851fccSafresh1 s > cmd + 1 && s[-1] == '2' && isSPACE(s[-2]) &&
694b8851fccSafresh1 (!s[3] || isSPACE(s[3])))
695b8851fccSafresh1 {
696b8851fccSafresh1 const char *t = s + 3;
697b8851fccSafresh1
698b8851fccSafresh1 while (*t && isSPACE(*t))
699b8851fccSafresh1 ++t;
700b8851fccSafresh1 if (!*t && (PerlLIO_dup2(1, 2) != -1))
701b8851fccSafresh1 {
702b8851fccSafresh1 s[-2] = '\0';
703b8851fccSafresh1 break;
704b8851fccSafresh1 }
705b8851fccSafresh1 }
706b8851fccSafresh1 doshell:
707b8851fccSafresh1 PERL_FPU_PRE_EXEC
708b8851fccSafresh1 result = myexecl(FALSE, PL_sh_path, "sh", "-c", cmd,
709b8851fccSafresh1 (char *)NULL);
710b8851fccSafresh1 PERL_FPU_POST_EXEC
711b8851fccSafresh1 S_exec_failed(aTHX_ PL_sh_path, fd, do_report);
712b8851fccSafresh1 amigaos_post_exec(fd, do_report);
7135759b3d2Safresh1 goto leave;
714b8851fccSafresh1 }
715b8851fccSafresh1 }
716b8851fccSafresh1
7175759b3d2Safresh1 Newx(argv, (s - cmd) / 2 + 2, const char *);
7185759b3d2Safresh1 SAVEFREEPV(argv);
7195759b3d2Safresh1 cmd = savepvn(cmd, s - cmd);
7205759b3d2Safresh1 SAVEFREEPV(cmd);
7215759b3d2Safresh1 a = argv;
7225759b3d2Safresh1 for (s = cmd; *s;)
723b8851fccSafresh1 {
724b8851fccSafresh1 while (isSPACE(*s))
725b8851fccSafresh1 s++;
726b8851fccSafresh1 if (*s)
727b8851fccSafresh1 *(a++) = s;
728b8851fccSafresh1 while (*s && !isSPACE(*s))
729b8851fccSafresh1 s++;
730b8851fccSafresh1 if (*s)
731b8851fccSafresh1 *s++ = '\0';
732b8851fccSafresh1 }
733b8851fccSafresh1 *a = NULL;
7345759b3d2Safresh1 if (argv[0])
735b8851fccSafresh1 {
736b8851fccSafresh1 PERL_FPU_PRE_EXEC
7375759b3d2Safresh1 result = myexecvp(FALSE, argv[0], EXEC_ARGV_CAST(argv));
738b8851fccSafresh1 PERL_FPU_POST_EXEC
7395759b3d2Safresh1 if (errno == ENOEXEC) /* for system V NIH syndrome */
740b8851fccSafresh1 goto doshell;
7415759b3d2Safresh1 S_exec_failed(aTHX_ argv[0], fd, do_report);
742b8851fccSafresh1 amigaos_post_exec(fd, do_report);
743b8851fccSafresh1 }
7445759b3d2Safresh1 leave:
7455759b3d2Safresh1 LEAVE;
746b8851fccSafresh1 return result;
747b8851fccSafresh1 }
748b8851fccSafresh1
S_do_amigaos_aexec5(pTHX_ SV * really,SV ** mark,SV ** sp,int fd,int do_report)749b8851fccSafresh1 I32 S_do_amigaos_aexec5(
750b8851fccSafresh1 pTHX_ SV *really, SV **mark, SV **sp, int fd, int do_report)
751b8851fccSafresh1 {
752b8851fccSafresh1 I32 result = -1;
753b8851fccSafresh1 PERL_ARGS_ASSERT_DO_AEXEC5;
7545759b3d2Safresh1 ENTER;
755b8851fccSafresh1 if (sp > mark)
756b8851fccSafresh1 {
7575759b3d2Safresh1 const char **argv, **a;
758b8851fccSafresh1 const char *tmps = NULL;
7595759b3d2Safresh1 Newx(argv, sp - mark + 1, const char *);
7605759b3d2Safresh1 SAVEFREEPV(argv);
7615759b3d2Safresh1 a = argv;
762b8851fccSafresh1
763b8851fccSafresh1 while (++mark <= sp)
764b8851fccSafresh1 {
7655759b3d2Safresh1 if (*mark) {
7665759b3d2Safresh1 char *arg = savepv(SvPV_nolen_const(*mark));
7675759b3d2Safresh1 SAVEFREEPV(arg);
7685759b3d2Safresh1 *a++ = arg;
7695759b3d2Safresh1 } else
770b8851fccSafresh1 *a++ = "";
771b8851fccSafresh1 }
772b8851fccSafresh1 *a = NULL;
7735759b3d2Safresh1 if (really) {
7745759b3d2Safresh1 tmps = savepv(SvPV_nolen_const(really));
7755759b3d2Safresh1 SAVEFREEPV(tmps);
7765759b3d2Safresh1 }
7775759b3d2Safresh1 if ((!really && *argv[0] != '/') ||
778b8851fccSafresh1 (really && *tmps != '/')) /* will execvp use PATH? */
779b8851fccSafresh1 TAINT_ENV(); /* testing IFS here is overkill, probably
780b8851fccSafresh1 */
781b8851fccSafresh1 PERL_FPU_PRE_EXEC
782b8851fccSafresh1 if (really && *tmps)
783b8851fccSafresh1 {
7845759b3d2Safresh1 result = myexecvp(FALSE, tmps, EXEC_ARGV_CAST(argv));
785b8851fccSafresh1 }
786b8851fccSafresh1 else
787b8851fccSafresh1 {
7885759b3d2Safresh1 result = myexecvp(FALSE, argv[0], EXEC_ARGV_CAST(argv));
789b8851fccSafresh1 }
790b8851fccSafresh1 PERL_FPU_POST_EXEC
7915759b3d2Safresh1 S_exec_failed(aTHX_(really ? tmps : argv[0]), fd, do_report);
792b8851fccSafresh1 }
793b8851fccSafresh1 amigaos_post_exec(fd, do_report);
7945759b3d2Safresh1 LEAVE;
795b8851fccSafresh1 return result;
796b8851fccSafresh1 }
797b8851fccSafresh1
amigaos_system_child(void * userdata)798b8851fccSafresh1 void *amigaos_system_child(void *userdata)
799b8851fccSafresh1 {
800b8851fccSafresh1 struct Task *parent;
801b8851fccSafresh1 I32 did_pipes;
802b8851fccSafresh1 int pp;
803b8851fccSafresh1 I32 value;
804b8851fccSafresh1 STRLEN n_a;
805b8851fccSafresh1 /* these next are declared by macros else where but I may be
806eac174f2Safresh1 * passing modified values here so declare them explicitly but
807b8851fccSafresh1 * still referred to by macro below */
808b8851fccSafresh1
809b8851fccSafresh1 register SV **sp;
810b8851fccSafresh1 register SV **mark;
811b8851fccSafresh1 register PerlInterpreter *my_perl;
812b8851fccSafresh1
813b8851fccSafresh1 StdioStore store;
814b8851fccSafresh1
815b8851fccSafresh1 struct UserData *ud = (struct UserData *)userdata;
816b8851fccSafresh1
817b8851fccSafresh1 did_pipes = ud->did_pipes;
818b8851fccSafresh1 parent = ud->parent;
819b8851fccSafresh1 pp = ud->pp;
820b8851fccSafresh1 SP = ud->sp;
821b8851fccSafresh1 MARK = ud->mark;
822b8851fccSafresh1 my_perl = ud->my_perl;
823b8851fccSafresh1 PERL_SET_THX(my_perl);
824b8851fccSafresh1
825b8851fccSafresh1 amigaos_stdio_save(aTHX_ & store);
826b8851fccSafresh1
827b8851fccSafresh1 if (did_pipes)
828b8851fccSafresh1 {
829b8851fccSafresh1 // PerlLIO_close(pp[0]);
830b8851fccSafresh1 }
831b8851fccSafresh1 if (PL_op->op_flags & OPf_STACKED)
832b8851fccSafresh1 {
833b8851fccSafresh1 SV *really = *++MARK;
834b8851fccSafresh1 value = (I32)S_do_amigaos_aexec5(aTHX_ really, MARK, SP, pp,
835b8851fccSafresh1 did_pipes);
836b8851fccSafresh1 }
837b8851fccSafresh1 else if (SP - MARK != 1)
838b8851fccSafresh1 {
839b8851fccSafresh1 value = (I32)S_do_amigaos_aexec5(aTHX_ NULL, MARK, SP, pp,
840b8851fccSafresh1 did_pipes);
841b8851fccSafresh1 }
842b8851fccSafresh1 else
843b8851fccSafresh1 {
844b8851fccSafresh1 value = (I32)S_do_amigaos_exec3(
845b8851fccSafresh1 aTHX_ SvPVx(sv_mortalcopy(*SP), n_a), pp, did_pipes);
846b8851fccSafresh1 }
847b8851fccSafresh1
848b8851fccSafresh1 // Forbid();
849b8851fccSafresh1 // Signal(parent, SIGBREAKF_CTRL_F);
850b8851fccSafresh1
851b8851fccSafresh1 amigaos_stdio_restore(aTHX_ & store);
852b8851fccSafresh1
853b8851fccSafresh1 return (void *)value;
854b8851fccSafresh1 }
855b8851fccSafresh1
contains_whitespace(char * string)856b8851fccSafresh1 static BOOL contains_whitespace(char *string)
857b8851fccSafresh1 {
858b8851fccSafresh1
859b8851fccSafresh1 if (string)
860b8851fccSafresh1 {
861b8851fccSafresh1
862b8851fccSafresh1 if (strchr(string, ' '))
863b8851fccSafresh1 return TRUE;
864b8851fccSafresh1 if (strchr(string, '\t'))
865b8851fccSafresh1 return TRUE;
866b8851fccSafresh1 if (strchr(string, '\n'))
867b8851fccSafresh1 return TRUE;
868b8851fccSafresh1 if (strchr(string, 0xA0))
869b8851fccSafresh1 return TRUE;
870b8851fccSafresh1 if (strchr(string, '"'))
871b8851fccSafresh1 return TRUE;
872b8851fccSafresh1 }
873b8851fccSafresh1 return FALSE;
874b8851fccSafresh1 }
875b8851fccSafresh1
no_of_escapes(char * string)876b8851fccSafresh1 static int no_of_escapes(char *string)
877b8851fccSafresh1 {
878b8851fccSafresh1 int cnt = 0;
879b8851fccSafresh1 char *p;
880b8851fccSafresh1 for (p = string; p < string + strlen(string); p++)
881b8851fccSafresh1 {
882b8851fccSafresh1 if (*p == '"')
883b8851fccSafresh1 cnt++;
884b8851fccSafresh1 if (*p == '*')
885b8851fccSafresh1 cnt++;
886b8851fccSafresh1 if (*p == '\n')
887b8851fccSafresh1 cnt++;
888b8851fccSafresh1 if (*p == '\t')
889b8851fccSafresh1 cnt++;
890b8851fccSafresh1 }
891b8851fccSafresh1 return cnt;
892b8851fccSafresh1 }
893b8851fccSafresh1
894b8851fccSafresh1 struct command_data
895b8851fccSafresh1 {
896b8851fccSafresh1 STRPTR args;
897b8851fccSafresh1 BPTR seglist;
898b8851fccSafresh1 struct Task *parent;
899b8851fccSafresh1 };
900b8851fccSafresh1
901b8851fccSafresh1 #undef fopen
902b8851fccSafresh1 #undef fgetc
903b8851fccSafresh1 #undef fgets
904b8851fccSafresh1 #undef fclose
905b8851fccSafresh1
906b8851fccSafresh1 #define __USE_RUNCOMMAND__
907b8851fccSafresh1
myexecve(bool isperlthread,const char * filename,char * argv[],char * envp[])908b8851fccSafresh1 int myexecve(bool isperlthread,
909b8851fccSafresh1 const char *filename,
910b8851fccSafresh1 char *argv[],
911b8851fccSafresh1 char *envp[])
912b8851fccSafresh1 {
913b8851fccSafresh1 FILE *fh;
914b8851fccSafresh1 char buffer[1000];
915b8851fccSafresh1 int size = 0;
916b8851fccSafresh1 char **cur;
917b8851fccSafresh1 char *interpreter = 0;
918b8851fccSafresh1 char *interpreter_args = 0;
919b8851fccSafresh1 char *full = 0;
920b8851fccSafresh1 char *filename_conv = 0;
921b8851fccSafresh1 char *interpreter_conv = 0;
922b8851fccSafresh1 // char *tmp = 0;
923b8851fccSafresh1 char *fname;
924b8851fccSafresh1 // int tmpint;
925b8851fccSafresh1 // struct Task *thisTask = IExec->FindTask(0);
926b8851fccSafresh1 int result = -1;
927b8851fccSafresh1
928b8851fccSafresh1 StdioStore store;
929b8851fccSafresh1
930b8851fccSafresh1 pTHX = NULL;
931b8851fccSafresh1
932b8851fccSafresh1 if (isperlthread)
933b8851fccSafresh1 {
934b8851fccSafresh1 aTHX = PERL_GET_THX;
935b8851fccSafresh1 /* Save away our stdio */
936b8851fccSafresh1 amigaos_stdio_save(aTHX_ & store);
937b8851fccSafresh1 }
938b8851fccSafresh1
939b8851fccSafresh1 // adebug("%s %ld %s\n",__FUNCTION__,__LINE__,filename?filename:"NULL");
940b8851fccSafresh1
941b8851fccSafresh1 /* Calculate the size of filename and all args, including spaces and
942b8851fccSafresh1 * quotes */
943b8851fccSafresh1 size = 0; // strlen(filename) + 1;
944b8851fccSafresh1 for (cur = (char **)argv /* +1 */; *cur; cur++)
945b8851fccSafresh1 {
946b8851fccSafresh1 size +=
947b8851fccSafresh1 strlen(*cur) + 1 +
948b8851fccSafresh1 (contains_whitespace(*cur) ? (2 + no_of_escapes(*cur)) : 0);
949b8851fccSafresh1 }
950b8851fccSafresh1 /* Check if it's a script file */
951b8851fccSafresh1 IExec->DebugPrintF("%s %ld %08lx %c %c\n",__FILE__,__LINE__,filename,filename[0],filename[1]);
952b8851fccSafresh1 fh = fopen(filename, "r");
953b8851fccSafresh1 if (fh)
954b8851fccSafresh1 {
955b8851fccSafresh1 if (fgetc(fh) == '#' && fgetc(fh) == '!')
956b8851fccSafresh1 {
957b8851fccSafresh1 char *p;
958b8851fccSafresh1 char *q;
959b8851fccSafresh1 fgets(buffer, 999, fh);
960b8851fccSafresh1 p = buffer;
961b8851fccSafresh1 while (*p == ' ' || *p == '\t')
962b8851fccSafresh1 p++;
963b8851fccSafresh1 if (buffer[strlen(buffer) - 1] == '\n')
964b8851fccSafresh1 buffer[strlen(buffer) - 1] = '\0';
965b8851fccSafresh1 if ((q = strchr(p, ' ')))
966b8851fccSafresh1 {
967b8851fccSafresh1 *q++ = '\0';
968b8851fccSafresh1 if (*q != '\0')
969b8851fccSafresh1 {
970b8851fccSafresh1 interpreter_args = mystrdup(q);
971b8851fccSafresh1 }
972b8851fccSafresh1 }
973b8851fccSafresh1 else
974b8851fccSafresh1 interpreter_args = mystrdup("");
975b8851fccSafresh1
976b8851fccSafresh1 interpreter = mystrdup(p);
977b8851fccSafresh1 size += strlen(interpreter) + 1;
978b8851fccSafresh1 size += strlen(interpreter_args) + 1;
979b8851fccSafresh1 }
980b8851fccSafresh1
981b8851fccSafresh1 fclose(fh);
982b8851fccSafresh1 }
983b8851fccSafresh1 else
984b8851fccSafresh1 {
985b8851fccSafresh1 /* We couldn't open this why not? */
986b8851fccSafresh1 if (errno == ENOENT)
987b8851fccSafresh1 {
988b8851fccSafresh1 /* file didn't exist! */
989b8851fccSafresh1 goto out;
990b8851fccSafresh1 }
991b8851fccSafresh1 }
992b8851fccSafresh1
993b8851fccSafresh1 /* Allocate the command line */
994b8851fccSafresh1 filename_conv = convert_path_u2a(filename);
995b8851fccSafresh1
996b8851fccSafresh1 if (filename_conv)
997b8851fccSafresh1 size += strlen(filename_conv);
998b8851fccSafresh1 size += 1;
999b8851fccSafresh1 full = (char *)IExec->AllocVecTags(size + 10, AVT_ClearWithValue, 0 ,TAG_DONE);
1000b8851fccSafresh1 if (full)
1001b8851fccSafresh1 {
1002b8851fccSafresh1 if (interpreter)
1003b8851fccSafresh1 {
1004b8851fccSafresh1 interpreter_conv = convert_path_u2a(interpreter);
1005b8851fccSafresh1 #if !defined(__USE_RUNCOMMAND__)
1006b8851fccSafresh1 #warning(using system!)
1007b8851fccSafresh1 sprintf(full, "%s %s %s ", interpreter_conv,
1008b8851fccSafresh1 interpreter_args, filename_conv);
1009b8851fccSafresh1 #else
1010b8851fccSafresh1 sprintf(full, "%s %s ", interpreter_args,
1011b8851fccSafresh1 filename_conv);
1012b8851fccSafresh1 #endif
1013b8851fccSafresh1 IExec->FreeVec(interpreter);
1014b8851fccSafresh1 IExec->FreeVec(interpreter_args);
1015b8851fccSafresh1
1016b8851fccSafresh1 if (filename_conv)
1017b8851fccSafresh1 IExec->FreeVec(filename_conv);
1018b8851fccSafresh1 fname = mystrdup(interpreter_conv);
1019b8851fccSafresh1
1020b8851fccSafresh1 if (interpreter_conv)
1021b8851fccSafresh1 IExec->FreeVec(interpreter_conv);
1022b8851fccSafresh1 }
1023b8851fccSafresh1 else
1024b8851fccSafresh1 {
1025b8851fccSafresh1 #ifndef __USE_RUNCOMMAND__
1026b8851fccSafresh1 sprintf(full, "%s ", filename_conv);
1027b8851fccSafresh1 #else
1028b8851fccSafresh1 sprintf(full, "");
1029b8851fccSafresh1 #endif
1030b8851fccSafresh1 fname = mystrdup(filename_conv);
1031b8851fccSafresh1 if (filename_conv)
1032b8851fccSafresh1 IExec->FreeVec(filename_conv);
1033b8851fccSafresh1 }
1034b8851fccSafresh1
1035b8851fccSafresh1 for (cur = (char **)(argv + 1); *cur != 0; cur++)
1036b8851fccSafresh1 {
1037b8851fccSafresh1 if (contains_whitespace(*cur))
1038b8851fccSafresh1 {
1039b8851fccSafresh1 int esc = no_of_escapes(*cur);
1040b8851fccSafresh1
1041b8851fccSafresh1 if (esc > 0)
1042b8851fccSafresh1 {
1043b8851fccSafresh1 char *buff = (char *)IExec->AllocVecTags(
1044b8851fccSafresh1 strlen(*cur) + 4 + esc,
1045b8851fccSafresh1 AVT_ClearWithValue,0,
1046b8851fccSafresh1 TAG_DONE);
1047b8851fccSafresh1 char *p = *cur;
1048b8851fccSafresh1 char *q = buff;
1049b8851fccSafresh1
1050b8851fccSafresh1 *q++ = '"';
1051b8851fccSafresh1 while (*p != '\0')
1052b8851fccSafresh1 {
1053b8851fccSafresh1
1054b8851fccSafresh1 if (*p == '\n')
1055b8851fccSafresh1 {
1056b8851fccSafresh1 *q++ = '*';
1057b8851fccSafresh1 *q++ = 'N';
1058b8851fccSafresh1 p++;
1059b8851fccSafresh1 continue;
1060b8851fccSafresh1 }
1061b8851fccSafresh1 else if (*p == '"')
1062b8851fccSafresh1 {
1063b8851fccSafresh1 *q++ = '*';
1064b8851fccSafresh1 *q++ = '"';
1065b8851fccSafresh1 p++;
1066b8851fccSafresh1 continue;
1067b8851fccSafresh1 }
1068b8851fccSafresh1 else if (*p == '*')
1069b8851fccSafresh1 {
1070b8851fccSafresh1 *q++ = '*';
1071b8851fccSafresh1 }
1072b8851fccSafresh1 *q++ = *p++;
1073b8851fccSafresh1 }
1074b8851fccSafresh1 *q++ = '"';
1075b8851fccSafresh1 *q++ = ' ';
1076b8851fccSafresh1 *q = '\0';
1077b8851fccSafresh1 strcat(full, buff);
1078b8851fccSafresh1 IExec->FreeVec(buff);
1079b8851fccSafresh1 }
1080b8851fccSafresh1 else
1081b8851fccSafresh1 {
1082b8851fccSafresh1 strcat(full, "\"");
1083b8851fccSafresh1 strcat(full, *cur);
1084b8851fccSafresh1 strcat(full, "\" ");
1085b8851fccSafresh1 }
1086b8851fccSafresh1 }
1087b8851fccSafresh1 else
1088b8851fccSafresh1 {
1089b8851fccSafresh1 strcat(full, *cur);
1090b8851fccSafresh1 strcat(full, " ");
1091b8851fccSafresh1 }
1092b8851fccSafresh1 }
1093b8851fccSafresh1 strcat(full, "\n");
1094b8851fccSafresh1
1095b8851fccSafresh1 // if(envp)
1096b8851fccSafresh1 // createvars(envp);
1097b8851fccSafresh1
1098b8851fccSafresh1 #ifndef __USE_RUNCOMMAND__
1099b8851fccSafresh1 result = IDOS->SystemTags(
1100b8851fccSafresh1 full, SYS_UserShell, TRUE, NP_StackSize,
1101b8851fccSafresh1 ((struct Process *)thisTask)->pr_StackSize, SYS_Input,
1102b8851fccSafresh1 ((struct Process *)thisTask)->pr_CIS, SYS_Output,
1103b8851fccSafresh1 ((struct Process *)thisTask)->pr_COS, SYS_Error,
1104b8851fccSafresh1 ((struct Process *)thisTask)->pr_CES, TAG_DONE);
1105b8851fccSafresh1 #else
1106b8851fccSafresh1
1107b8851fccSafresh1 if (fname)
1108b8851fccSafresh1 {
1109b8851fccSafresh1 BPTR seglist = IDOS->LoadSeg(fname);
1110b8851fccSafresh1 if (seglist)
1111b8851fccSafresh1 {
1112b8851fccSafresh1 /* check if we have an executable! */
1113b8851fccSafresh1 struct PseudoSegList *ps = NULL;
1114b8851fccSafresh1 if (!IDOS->GetSegListInfoTags(
1115b8851fccSafresh1 seglist, GSLI_Native, &ps, TAG_DONE))
1116b8851fccSafresh1 {
1117b8851fccSafresh1 IDOS->GetSegListInfoTags(
1118b8851fccSafresh1 seglist, GSLI_68KPS, &ps, TAG_DONE);
1119b8851fccSafresh1 }
1120b8851fccSafresh1 if (ps != NULL)
1121b8851fccSafresh1 {
1122b8851fccSafresh1 // adebug("%s %ld %s
1123b8851fccSafresh1 // %s\n",__FUNCTION__,__LINE__,fname,full);
1124b8851fccSafresh1 IDOS->SetCliProgramName(fname);
1125b8851fccSafresh1 // result=RunCommand(seglist,8*1024,full,strlen(full));
1126b8851fccSafresh1 // result=myruncommand(seglist,8*1024,full,strlen(full),envp);
1127b8851fccSafresh1 result = myruncommand(seglist, 8 * 1024,
1128b8851fccSafresh1 full, -1, envp);
1129b8851fccSafresh1 errno = 0;
1130b8851fccSafresh1 }
1131b8851fccSafresh1 else
1132b8851fccSafresh1 {
1133b8851fccSafresh1 errno = ENOEXEC;
1134b8851fccSafresh1 }
1135b8851fccSafresh1 IDOS->UnLoadSeg(seglist);
1136b8851fccSafresh1 }
1137b8851fccSafresh1 else
1138b8851fccSafresh1 {
1139b8851fccSafresh1 errno = ENOEXEC;
1140b8851fccSafresh1 }
1141b8851fccSafresh1 IExec->FreeVec(fname);
1142b8851fccSafresh1 }
1143b8851fccSafresh1
1144b8851fccSafresh1 #endif /* USE_RUNCOMMAND */
1145b8851fccSafresh1
1146b8851fccSafresh1 IExec->FreeVec(full);
1147b8851fccSafresh1 if (errno == ENOEXEC)
1148b8851fccSafresh1 {
1149b8851fccSafresh1 result = -1;
1150b8851fccSafresh1 }
1151b8851fccSafresh1 goto out;
1152b8851fccSafresh1 }
1153b8851fccSafresh1
1154b8851fccSafresh1 if (interpreter)
1155b8851fccSafresh1 IExec->FreeVec(interpreter);
1156b8851fccSafresh1 if (filename_conv)
1157b8851fccSafresh1 IExec->FreeVec(filename_conv);
1158b8851fccSafresh1
1159b8851fccSafresh1 errno = ENOMEM;
1160b8851fccSafresh1
1161b8851fccSafresh1 out:
1162b8851fccSafresh1 if (isperlthread)
1163b8851fccSafresh1 {
1164b8851fccSafresh1 amigaos_stdio_restore(aTHX_ & store);
1165b8851fccSafresh1 STATUS_NATIVE_CHILD_SET(result);
1166b8851fccSafresh1 PL_exit_flags |= PERL_EXIT_EXPECTED;
1167b8851fccSafresh1 if (result != -1)
1168b8851fccSafresh1 my_exit(result);
1169b8851fccSafresh1 }
1170b8851fccSafresh1 return (result);
1171b8851fccSafresh1 }
1172