xref: /openbsd-src/gnu/usr.bin/perl/amigaos4/amigaio.c (revision e068048151d29f2562a32185e21a8ba885482260)
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