summaryrefslogtreecommitdiff
path: root/amigaos4/amigaio.c
diff options
context:
space:
mode:
Diffstat (limited to 'amigaos4/amigaio.c')
-rw-r--r--amigaos4/amigaio.c229
1 files changed, 210 insertions, 19 deletions
diff --git a/amigaos4/amigaio.c b/amigaos4/amigaio.c
index 40e9835d0f..205e3d5eb4 100644
--- a/amigaos4/amigaio.c
+++ b/amigaos4/amigaio.c
@@ -21,6 +21,11 @@
#include <proto/utility.h>
#include <dos/dos.h>
+extern struct SignalSemaphore popen_sema;
+extern unsigned int pipenum;
+
+extern int32 myruncommand(BPTR seglist, int stack, char *command, int length, char **envp);
+
void amigaos_stdio_get(pTHX_ StdioStore *store)
{
store->astdin =
@@ -58,27 +63,212 @@ void amigaos_post_exec(int fd, int do_report)
}
}
+
+struct popen_data
+{
+ struct Task *parent;
+ STRPTR command;
+};
+
+static int popen_result = 0;
+
+int popen_child()
+{
+ struct Task *thisTask = IExec->FindTask(0);
+ struct popen_data *pd = (struct popen_data *)thisTask->tc_UserData;
+ const char *argv[4];
+
+ argv[0] = "sh";
+ argv[1] = "-c";
+ argv[2] = pd->command ? pd->command : NULL;
+ argv[3] = NULL;
+
+ // adebug("%s %ld %s\n",__FUNCTION__,__LINE__,command?command:"NULL");
+
+ /* We need to give this to sh via execvp, execvp expects filename,
+ * argv[]
+ */
+ IExec->ObtainSemaphore(&popen_sema);
+
+ IExec->Signal(pd->parent,SIGBREAKF_CTRL_F);
+
+ popen_result = myexecvp(FALSE, argv[0], (char **)argv);
+ if (pd->command)
+ IExec->FreeVec(pd->command);
+ IExec->FreeVec(pd);
+
+ IExec->ReleaseSemaphore(&popen_sema);
+ IExec->Forbid();
+ return 0;
+}
+
+
PerlIO *Perl_my_popen(pTHX_ const char *cmd, const char *mode)
{
+
PERL_FLUSHALL_FOR_CHILD;
- /* Call system's popen() to get a FILE *, then import it.
- * used 0 for 2nd parameter to PerlIO_importFILE;
- * apparently not used
- */
- // FILE *f=amigaos_popen(cmd,mode);
- // fprintf(stderr,"popen returned %d\n",f);
- return PerlIO_importFILE(amigaos_popen(cmd, mode), mode);
- // return PerlIO_importFILE(f, 0);
+ PerlIO *result = NULL;
+ char pipe_name[50];
+ char unix_pipe[50];
+ char ami_pipe[50];
+ BPTR input = 0;
+ BPTR output = 0;
+ struct Process *proc = NULL;
+ struct Task *thisTask = IExec->FindTask(0);
+ struct popen_data * pd = NULL;
+
+ /* First we need to check the mode
+ * We can only have unidirectional pipes
+ */
+ // adebug("%s %ld cmd %s mode %s \n",__FUNCTION__,__LINE__,cmd,
+ // mode);
+
+ switch (mode[0])
+ {
+ case 'r':
+ case 'w':
+ break;
+
+ default:
+
+ errno = EINVAL;
+ return result;
+ }
+
+ /* Make a unique pipe name
+ * we need a unix one and an amigaos version (of the same pipe!)
+ * as were linking with libunix.
+ */
+
+ sprintf(pipe_name, "%x%08lx/4096/0", pipenum++,
+ IUtility->GetUniqueID());
+ sprintf(unix_pipe, "/PIPE/%s", pipe_name);
+ sprintf(ami_pipe, "PIPE:%s", pipe_name);
+
+ /* Now we open the AmigaOs Filehandles That we wil pass to our
+ * Sub process
+ */
+
+ if (mode[0] == 'r')
+ {
+ /* A read mode pipe: Output from pipe input from Output() or NIL:*/
+ /* First attempt to DUP Output() */
+ input = IDOS->DupFileHandle(IDOS->Input());
+ if(input == 0)
+ {
+ input = IDOS->Open("NIL:", MODE_READWRITE);
+ }
+ if (input != 0)
+ {
+ output = IDOS->Open(ami_pipe, MODE_NEWFILE);
+ }
+ result = PerlIO_open(unix_pipe, mode);
+ }
+ else
+ {
+ /* Open the write end first! */
+
+ result = PerlIO_open(unix_pipe, mode);
+
+ input = IDOS->Open(ami_pipe, MODE_OLDFILE);
+ if (input != 0)
+ {
+ output = IDOS->DupFileHandle(IDOS->Output());
+ if(output == 0)
+ {
+ output = IDOS->Open("NIL:", MODE_READWRITE);
+ }
+ }
+ }
+ if ((input == 0) || (output == 0) || (result == NULL))
+ {
+ /* Ouch stream opening failed */
+ /* Close and bail */
+ if (input)
+ IDOS->Close(input);
+ if (output)
+ IDOS->Close(output);
+ if(result)
+ {
+ PerlIO_close(result);
+ result = NULL;
+ }
+ return result;
+ }
+
+ /* We have our streams now start our new process
+ * We're using a new process so that execve can modify the environment
+ * with messing things up for the shell that launched perl
+ * Copy cmd before we launch the subprocess as perl seems to waste
+ * no time in overwriting it! The subprocess will free the copy.
+ */
+
+ if((pd = (struct popen_data*)IExec->AllocVecTags(sizeof(struct popen_data),AVT_Type,MEMF_SHARED,TAG_DONE)))
+ {
+ pd->parent = thisTask;
+ if ((pd->command = mystrdup(cmd)))
+ {
+ // adebug("%s %ld
+ // %s\n",__FUNCTION__,__LINE__,cmd_copy?cmd_copy:"NULL");
+ proc = IDOS->CreateNewProcTags(
+ NP_Entry, popen_child, NP_Child, TRUE, NP_StackSize,
+ ((struct Process *)thisTask)->pr_StackSize, NP_Input, input,
+ NP_Output, output, NP_Error, IDOS->ErrorOutput(),
+ NP_CloseError, FALSE, NP_Cli, TRUE, NP_Name,
+ "Perl: popen process", NP_UserData, (int)pd,
+ TAG_DONE);
+ }
+ }
+ if(proc)
+ {
+ /* wait for the child be setup right */
+ IExec->Wait(SIGBREAKF_CTRL_F);
+ }
+ if (!proc)
+ {
+ /* New Process Failed to start
+ * Close and bail out
+ */
+ if(pd)
+ {
+ if(pd->command)
+ {
+ IExec->FreeVec(pd->command);
+ }
+ IExec->FreeVec(pd);
+ }
+ if (input)
+ IDOS->Close(input);
+ if (output)
+ IDOS->Close(output);
+ if(result)
+ {
+ PerlIO_close(result);
+ result = NULL;
+ }
+ }
+
+ /* Our new process is running and will close it streams etc
+ * once its done. All we need to is open the pipe via stdio
+ */
+
+ return result;
}
-I32 Perl_my_pclose(pTHX_ PerlIO *ptr)
+I32
+Perl_my_pclose(pTHX_ PerlIO *ptr)
{
- FILE * const f = PerlIO_findFILE(ptr);
- const I32 result = amigaos_pclose(f);
- PerlIO_releaseFILE(ptr,f);
+ int result = -1;
+ /* close the file before obtaining the semaphore else we might end up
+ hanging waiting for the child to read the last bit from the pipe */
+ PerlIO_close(ptr);
+ IExec->ObtainSemaphore(&popen_sema);
+ result = popen_result;
+ IExec->ReleaseSemaphore(&popen_sema);
return result;
}
+
#ifdef USE_ITHREADS
/* An arbitrary number to start with, should work out what the real max should
@@ -182,7 +372,7 @@ int amigaos_kill(Pid_t pid, int signal)
if (pseudo_children[i].ti_pid == pid)
{
realpid = (Pid_t)IDOS->GetPID(pseudo_children[i].ti_Process,GPID_PROCESS);
- if(pseudo_children[i].ti_Process == IExec->FindTask(NULL))
+ if(pseudo_children[i].ti_Process == (struct Process *)IExec->FindTask(NULL))
{
thistask = TRUE;
}
@@ -408,11 +598,11 @@ Pid_t amigaos_waitpid(pTHX_ int optype, Pid_t pid, void *argflags)
int result;
if (PL_signals & PERL_SIGNALS_UNSAFE_FLAG)
{
- result = pthread_join(pid, argflags);
+ result = pthread_join(pid, (void **)argflags);
}
else
{
- while ((result = pthread_join(pid, argflags)) == -1 &&
+ while ((result = pthread_join(pid, (void **)argflags)) == -1 &&
errno == EINTR)
{
// PERL_ASYNC_CHECK();
@@ -658,7 +848,7 @@ void *amigaos_system_child(void *userdata)
amigaos_stdio_restore(aTHX_ & store);
- return value;
+ return (void *)value;
}
static BOOL contains_whitespace(char *string)
@@ -804,7 +994,7 @@ int myexecve(bool isperlthread,
if (filename_conv)
size += strlen(filename_conv);
size += 1;
- full = (char *)IExec->AllocVec(size + 10, MEMF_ANY | MEMF_CLEAR);
+ full = (char *)IExec->AllocVecTags(size + 10, AVT_ClearWithValue, 0 ,TAG_DONE);
if (full)
{
if (interpreter)
@@ -848,9 +1038,10 @@ int myexecve(bool isperlthread,
if (esc > 0)
{
- char *buff = (char *)IExec->AllocVec(
+ char *buff = (char *)IExec->AllocVecTags(
strlen(*cur) + 4 + esc,
- MEMF_ANY | MEMF_CLEAR);
+ AVT_ClearWithValue,0,
+ TAG_DONE);
char *p = *cur;
char *q = buff;