home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 2: PC
/
frozenfish_august_1995.bin
/
bbs
/
d09xx
/
d0980.lha
/
APipe
/
pgmpipe.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-04
|
25KB
|
860 lines
/*
** Pgmpipe.c --- main module of APipe-Handler
**
** Copyright (C) 1991 by Per Bojsen. All Rights Reserved.
**
** Permission is granted to any individual or institution to use, copy,
** modify, and distribute this software, provided that this complete
** copyright and permission notice is maintained, intact, in all copies
** and supporting documentation.
**
** This software is provided on an "as is" basis without express or
** implied warranty.
**
** NOTE: The code is reentrant. Be careful when modifying it.
**
** $Id: pgmpipe.c,v 1.7 92/09/12 16:49:11 bojsen Exp Locker: bojsen $
**
** $Log: pgmpipe.c,v $
** Revision 1.7 92/09/12 16:49:11 bojsen
** Improved cloning of file handles so that reading/writing will start
** from current position.
**
** Revision 1.6 92/02/20 23:46:11 bojsen
** Fixed bug in handling multiple outstanding read packets add EOF.
**
** Revision 1.5 91/11/24 17:01:25 bojsen
** Made extraction of command line from file name more robust; the code now
** handles the case where the handler name is not prepended.
**
** Revision 1.4 91/11/24 02:22:39 bojsen
** First released version. Changed references to ChildProcess() to
** _ChildProcess().
**
** Revision 1.3 91/10/01 02:35:30 bojsen
** Added code to clone current dir of requester process. Changed code
** to obtain pointer to requester process.
**
** Revision 1.2 91/09/24 23:59:44 bojsen
** Fixed typo in #include line.
**
** Revision 1.1 91/09/24 23:54:06 bojsen
** Initial revision
**
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <utility/tagitem.h>
#include <clib/macros.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <dos/var.h>
#ifdef __SASC
#include <proto/exec.h>
#include <proto/dos.h>
#endif /* __SASC */
#include <string.h>
#include "APipe-Handler_rev.h"
/*
* Version tagging.
*/
STATIC char VersionTag[] = VERSTAG;
/*
* Debugging.
*/
#ifdef DEBUG
#define DPrintF(args) do { KPrintF args; } while (0)
#else /* !DEBUG */
#define DPrintF(args)
#endif /* !DEBUG */
#define AbsExecBase 4L
#define LIB_VERSION_SUPPORTED 37L
#define PIPEBUFFER_SIZE 4096
/* defines for read/write status */
#define PPIPE_NOTOPEN 0
#define PPIPE_OPEN 4
#define PPIPE_READ 1
#define PPIPE_READOPEN (PGMPIPE_READ | PGMPIPE_OPEN)
#define PPIPE_WRITE 2
#define PPIPE_WRITEOPEN (PGMPIPE_WRITE | PGMPIPE_OPEN)
#define PPIPE_RWMASK 3
/* defines for fh_Arg1 field of filehandles */
#define PPIPE_READER 1
#define PPIPE_WRITER 2
/* defines for closing variable */
#define PPIPE_C_OPEN 0
#define PPIPE_C_RDRCLOSING 1
#define PPIPE_C_WRTCLOSING 2
#define PPIPE_C_CLOSINGMASK 3
#define PPIPE_C_RDRCLOSED 4
#define PPIPE_C_WRTCLOSED 8
#define PPIPE_C_CLOSEDMASK 0xC
/*
* Parameter packet to child process.
*/
struct ChildMsg
{
struct Message ExecMsg;
char *CmdLine; /* the command line to execute */
LONG StackSize; /* use this stacksize for child's child */
BPTR PathList; /* path list for child */
ULONG Flags; /* flags for child */
LONG RC; /* return code from child process */
};
/* Defines for ChildMsg.Flags */
#define CHMF_PIPE 1L /* stdin of child is a pipe (of PIPE: type) */
#define CHMF_PATH 2L /* path is passed in in PathList */
/*
* Command path element.
*/
struct PathEntry
{
BPTR pe_NextPathEntry;
BPTR pe_PathLock;
};
/*
* The library bases must be global by AmigaOS programming standards,
* and the pragma libcall requires them.
*/
struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
/*
* Prototypes for external functions.
*/
extern int _ChildProcess(void);
/*
* Prototypes for local functions.
*/
ULONG CopyFromFIFO(UBYTE *FIFO, ULONG FIFOSize, UBYTE **Start, UBYTE *End,
ULONG *FIFOFill, UBYTE *Dest, ULONG NumBytes);
ULONG CopyToFIFO(UBYTE *FIFO, ULONG FIFOSize, UBYTE **Start, UBYTE **End,
ULONG *FIFOFill, UBYTE *Src, ULONG NumBytes);
STRPTR GetCommandLine(STRPTR FileSpec, BSTR HandlerName);
LONG ExecCommand(char *CmdLine, struct MsgPort **ParentPort,
struct Process *Requester, struct FileHandle *ChildIO,
LONG IoDirection);
BPTR CloneProcessIO(struct Process *Friend, LONG IoDirection);
BPTR ClonePathList(struct CommandLineInterface *Peer);
void FreePathList(BPTR);
void
PgmPipe()
{
struct DosLibrary *l_DOSBase;
SysBase = *((struct ExecBase **) AbsExecBase); /* `open' exec.library */
if (l_DOSBase =
(struct DosLibrary *) OpenLibrary("dos.library", LIB_VERSION_SUPPORTED))
{
struct Process *ourProc, *theirProc;
struct DosList *ourDevNode;
struct DosPacket *packet, *writePkt = NULL, *readPkt = NULL;
struct DosPacket *writeCls = NULL, *readCls = NULL;
struct MsgPort *childPort = NULL;
struct MsgPort *oldConTask = NULL;
struct ChildMsg *childMsg = NULL;
struct FileHandle *fhIncoming, *fhOutgoing;
UBYTE *pipeBuffer;
UBYTE *pbStart, *pbEnd;
ULONG bytesReady, bytesR = 0, bytesW = 0;
UWORD closing = PPIPE_C_RDRCLOSED | PPIPE_C_WRTCLOSED;
UWORD readwrite = PPIPE_NOTOPEN;
ULONG waitSigMask;
struct MinList readQ, writeQ;
#ifdef DEBUG
ULONG packetNum = 0;
#endif /* DEBUG */
NewList((struct List *) &readQ);
NewList((struct List *) &writeQ);
DOSBase = l_DOSBase; /* patch the global library base */
ourProc = (struct Process *) FindTask(NULL);
waitSigMask = 1L << ourProc->pr_MsgPort.mp_SigBit;
packet = WaitPkt(); /* get parameter packet */
if ((pipeBuffer = AllocMem(PIPEBUFFER_SIZE, 0)) == NULL)
ReplyPkt(packet, DOSFALSE, ERROR_NO_FREE_STORE);
else
{
pbStart = pbEnd = pipeBuffer;
bytesReady = 0;
/*
* Currently we don't use the parameters provided in the parameter
* packet. Since we want a new process for each instance of reference
* to our handler we don't patch the DeviceList node, but use the
* node to get the handler name.
*/
ourDevNode = (struct DosList *) BADDR(packet->dp_Arg3);
ReplyPkt(packet, DOSTRUE, packet->dp_Arg2);
do
{
struct Node *node;
char *cmdLine;
LONG ioerr;
if (readPkt && bytesReady == 0 && writePkt == NULL &&
closing & PPIPE_C_WRTCLOSED)
{
ReplyPkt(readPkt, bytesR, 0);
while (readPkt = (struct DosPacket *)
(node = RemHead((struct List *) &readQ),
node ? node->ln_Name : NULL))
ReplyPkt(readPkt, 0, 0);
}
#ifdef DEBUG
if (readPkt || writePkt)
DPrintF(("Event loop: readPkt == 0x%08lx writePkt == 0x%08lx\n",
readPkt, writePkt));
#endif /* DEBUG */
if (packet = WaitPkt())
{
DPrintF(("Packet %ld, port 0x%08lx: ", ++packetNum, packet->dp_Port));
switch (packet->dp_Type)
{
struct TagItem adoTags[2];
case ACTION_FINDINPUT:
DPrintF(("ACTION_FINDINPUT 0x%08lx 0x%08lx %s\n",
packet->dp_Arg1 << 2, packet->dp_Arg2 << 2,
(char *) (packet->dp_Arg3 << 2) + 1));
if (readwrite != PPIPE_NOTOPEN)
{
ReplyPkt(packet, DOSFALSE, ERROR_OBJECT_IN_USE);
break;
}
else
readwrite = PPIPE_READ;
case ACTION_FINDOUTPUT:
#ifdef DEBUG
if (packet->dp_Type == ACTION_FINDOUTPUT)
DPrintF(("ACTION_FINDOUTPUT 0x%08lx 0x%08lx %s\n",
packet->dp_Arg1 << 2, packet->dp_Arg2 << 2,
(char *) (packet->dp_Arg3 << 2) + 1));
#endif /* DEBUG */
if (readwrite & PPIPE_OPEN)
{
ReplyPkt(packet, DOSFALSE, ERROR_OBJECT_IN_USE);
break;
}
else if (readwrite != PPIPE_READ)
readwrite = PPIPE_WRITE;
fhIncoming = (struct FileHandle *) BADDR(packet->dp_Arg1);
/*
* Obtain command line to execute.
*/
cmdLine = GetCommandLine((STRPTR) BADDR(packet->dp_Arg3) + 1,
ourDevNode->dol_Name);
/*
* Find out who sent the packet.
*/
if ((packet->dp_Port->mp_Flags & PF_ACTION) == PA_SIGNAL)
theirProc = (struct Process *) packet->dp_Port->mp_SigTask;
else
{
ReplyPkt(packet, DOSFALSE, ERROR_BAD_STREAM_NAME);
readwrite = PPIPE_NOTOPEN;
break;
}
adoTags[0].ti_Tag = ADO_FH_Mode;
adoTags[0].ti_Data =
readwrite == PPIPE_READ ? MODE_NEWFILE : MODE_OLDFILE;
adoTags[1].ti_Tag = TAG_DONE;
if ((fhOutgoing = AllocDosObject(DOS_FILEHANDLE, adoTags))
== NULL)
{
ReplyPkt(packet, DOSFALSE, ERROR_NO_FREE_STORE);
readwrite = PPIPE_NOTOPEN;
break;
}
fhOutgoing->fh_Link = NULL;
fhOutgoing->fh_Port = fhIncoming->fh_Port = (struct MsgPort *) 0;
fhOutgoing->fh_Type = &ourProc->pr_MsgPort;
if (readwrite == PPIPE_READ)
{
fhIncoming->fh_Arg1 = PPIPE_READER;
fhOutgoing->fh_Arg1 = PPIPE_WRITER;
}
else
{
fhIncoming->fh_Arg1 = PPIPE_WRITER;
fhOutgoing->fh_Arg1 = PPIPE_READER;
}
oldConTask = SetConsoleTask(theirProc->pr_ConsoleTask);
DPrintF(("Getting ready to spawn child . . . "));
if (ioerr = ExecCommand(cmdLine, &childPort, theirProc,
fhOutgoing, readwrite))
{
SetConsoleTask(oldConTask);
ReplyPkt(packet, DOSFALSE, ioerr);
FreeDosObject(DOS_FILEHANDLE, fhOutgoing);
readwrite = PPIPE_NOTOPEN;
break;
}
SetConsoleTask(oldConTask);
DPrintF(("Child spawned.\n"));
waitSigMask |= 1L << childPort->mp_SigBit;
closing = PPIPE_C_OPEN;
readwrite |= PPIPE_OPEN;
ReplyPkt(packet, DOSTRUE, packet->dp_Res2);
break;
case ACTION_READ:
DPrintF(("ACTION_READ %ld 0x%08lx %ld\n", packet->dp_Arg1,
packet->dp_Arg2, packet->dp_Arg3));
if (packet->dp_Arg2 == NULL || packet->dp_Arg3 < 0)
ReplyPkt(packet, DOSFALSE, ERROR_BAD_NUMBER);
else if (closing & PPIPE_C_RDRCLOSED)
ReplyPkt(packet, DOSFALSE, ERROR_INVALID_LOCK);
else if (packet->dp_Arg1 == PPIPE_WRITER)
ReplyPkt(packet, 0, 0);
else if (readPkt == NULL)
{
readPkt = packet;
bytesR = 0;
}
else
AddTail((struct List *) &readQ,
(struct Node *) packet->dp_Link);
break;
case ACTION_WRITE:
DPrintF(("ACTION_WRITE %ld 0x%08lx %ld\n", packet->dp_Arg1,
packet->dp_Arg2, packet->dp_Arg3));
if (packet->dp_Arg2 == NULL || packet->dp_Arg3 < 0)
ReplyPkt(packet, DOSFALSE, ERROR_BAD_NUMBER);
else if (closing & PPIPE_C_WRTCLOSED)
ReplyPkt(packet, DOSFALSE, ERROR_INVALID_LOCK);
else if (packet->dp_Arg1 == PPIPE_READER)
ReplyPkt(packet, 0, 0);
else if (writePkt == NULL)
{
writePkt = packet;
bytesW = 0;
}
else
AddTail((struct List *) &writeQ,
(struct Node *) packet->dp_Link);
break;
case ACTION_END:
DPrintF(("ACTION_END %ld\n", packet->dp_Arg1));
if (packet->dp_Arg1 == PPIPE_READER &&
(closing & PPIPE_C_RDRCLOSED) == 0)
{
closing |= PPIPE_C_RDRCLOSING;
readCls = packet;
}
else if (packet->dp_Arg1 == PPIPE_WRITER &&
(closing & PPIPE_C_WRTCLOSED) == 0)
{
closing |= PPIPE_C_WRTCLOSING;
writeCls = packet;
}
else
ReplyPkt(packet, DOSTRUE, 0);
break;
case ACTION_IS_FILESYSTEM:
DPrintF(("ACTION_IS_FILESYSTEM\n"));
ReplyPkt(packet, DOSFALSE, 0);
break;
default:
DPrintF(("%ld\n", packet->dp_Type));
ReplyPkt(packet, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
}
DPrintF(("\n"));
}
do
{
if (readPkt)
{
if (bytesReady > 0)
bytesR += CopyFromFIFO(pipeBuffer, PIPEBUFFER_SIZE, &pbStart,
pbEnd, &bytesReady,
(UBYTE *) readPkt->dp_Arg2 + bytesR,
readPkt->dp_Arg3 - bytesR);
if (bytesR < readPkt->dp_Arg3 && writePkt)
{
ULONG bytes = MIN(writePkt->dp_Arg3 - bytesW,
readPkt->dp_Arg3 - bytesR);
CopyMem((UBYTE *) writePkt->dp_Arg2 + bytesW,
(UBYTE *) readPkt->dp_Arg2 + bytesR, bytes);
bytesR += bytes;
if ((bytesW += bytes) == writePkt->dp_Arg3)
{
ReplyPkt(writePkt, writePkt->dp_Arg3, 0);
writePkt = NULL;
}
}
if (bytesR == readPkt->dp_Arg3)
{
ReplyPkt(readPkt, readPkt->dp_Arg3, 0);
readPkt = NULL;
}
}
if (readPkt == NULL &&
(readPkt = (struct DosPacket *)
(node = RemHead((struct List *) &readQ),
node ? node->ln_Name : NULL)))
{
bytesR = 0;
}
if (writePkt == NULL &&
(writePkt = (struct DosPacket *)
(node = RemHead((struct List *) &writeQ),
node ? node->ln_Name : NULL)))
{
bytesW = 0;
}
}
while (readPkt && (writePkt || bytesReady > 0));
if (readPkt == NULL && closing & PPIPE_C_RDRCLOSING)
{
closing &= ~PPIPE_C_RDRCLOSING;
closing |= PPIPE_C_RDRCLOSED;
}
while (writePkt &&
(closing & PPIPE_C_RDRCLOSED ||
PIPEBUFFER_SIZE - bytesReady >= writePkt->dp_Arg3 - bytesW))
{
if (closing & PPIPE_C_RDRCLOSED)
{
ReplyPkt(writePkt, writePkt->dp_Arg3, 0);
writePkt = NULL;
}
else
{
ULONG bytes = CopyToFIFO(pipeBuffer, PIPEBUFFER_SIZE, &pbStart,
&pbEnd, &bytesReady,
(UBYTE *) writePkt->dp_Arg2 + bytesW,
writePkt->dp_Arg3 - bytesW);
if ((bytesW += bytes) == writePkt->dp_Arg3)
{
ReplyPkt(writePkt, writePkt->dp_Arg3, 0);
writePkt = NULL;
}
}
if (writePkt == NULL &&
(writePkt = (struct DosPacket *)
(node = RemHead((struct List *) &writeQ),
node ? node->ln_Name : NULL)))
{
bytesW = 0;
}
}
if (writePkt == NULL && closing & PPIPE_C_WRTCLOSING)
{
closing &= ~PPIPE_C_WRTCLOSING;
closing |= PPIPE_C_WRTCLOSED;
}
}
while ((closing & PPIPE_C_RDRCLOSED) == 0 ||
(closing & PPIPE_C_WRTCLOSED) == 0);
/* clean up from child process */
if (childPort)
{
waitSigMask = 1L << childPort->mp_SigBit;
while ((childMsg = (struct ChildMsg *) GetMsg(childPort)) == NULL)
Wait(waitSigMask);
DeleteMsgPort(childPort);
}
if (childMsg) /* means the child process existed */
{
if (readCls)
ReplyPkt(readCls, DOSTRUE, 0);
if (writeCls)
ReplyPkt(writeCls, DOSTRUE, 0);
FreePathList(childMsg->PathList);
FreeVec(childMsg); /* no use for return code currently */
}
FreeMem(pipeBuffer, PIPEBUFFER_SIZE);
}
CloseLibrary((struct Library *) l_DOSBase);
DPrintF(("Handler exiting.\n"));
}
} /* PgmPipe */
STATIC ULONG
CopyFromFIFO(UBYTE *FIFO, ULONG FIFOSize, UBYTE **Start, UBYTE *End,
ULONG *FIFOFill, UBYTE *Dest, ULONG NumBytes)
{
ULONG bytesCopied = 0, bytes;
DPrintF(("CopyFromFIFO: 0x%08lx %ld", Dest, NumBytes));
if (*FIFOFill > 0 && NumBytes > 0)
{
bytes = *Start >= End ? FIFO + FIFOSize - *Start : *FIFOFill;
CopyMem(*Start, Dest, bytesCopied = MIN(bytes, NumBytes));
NumBytes -= bytesCopied;
*Start += bytesCopied;
*FIFOFill -= bytesCopied;
}
if (*FIFOFill > 0 && NumBytes > 0)
{
bytes = End - FIFO; /* invariant: *Start == FIFO + FIFOSize */
CopyMem(FIFO, Dest + bytesCopied, bytes = MIN(bytes, NumBytes));
*Start = FIFO + bytes;
*FIFOFill -= bytes;
bytesCopied += bytes;
}
DPrintF((" %ld\n\n", bytesCopied));
return bytesCopied;
} /* CopyFromFIFO */
STATIC ULONG
CopyToFIFO(UBYTE *FIFO, ULONG FIFOSize, UBYTE **Start, UBYTE **End,
ULONG *FIFOFill, UBYTE *Src, ULONG NumBytes)
{
ULONG bytesCopied = 0, bytes;
DPrintF(("CopyToFIFO: 0x%08lx %ld", Src, NumBytes));
if (*FIFOFill == 0)
*Start = *End = FIFO; /* normalize for efficiency */
if (*FIFOFill < FIFOSize && NumBytes > 0)
{
bytes = *End <= *Start ? FIFOSize - *FIFOFill : FIFO + FIFOSize - *End;
CopyMem(Src, *End, bytesCopied = MIN(bytes, NumBytes));
NumBytes -= bytesCopied;
*End += bytesCopied;
*FIFOFill += bytesCopied;
}
if (*FIFOFill < FIFOSize && NumBytes > 0)
{
bytes = *Start - FIFO; /* invariant: *End == FIFO + FIFOSize */
CopyMem(Src + bytesCopied, FIFO, bytes = MIN(bytes, NumBytes));
*End = FIFO + bytes;
*FIFOFill += bytes;
bytesCopied += bytes;
}
DPrintF((" %ld\n\n", bytesCopied));
return bytesCopied;
} /* CopyFromFIFO */
#define GetCICh(String, Char) \
((Char) = *(String), (Char) += (Char) >= 'A' && (Char) <= 'Z' ? 0x20 : 0)
STATIC STRPTR
GetCommandLine(STRPTR FileSpec, BSTR HandlerName)
{
UBYTE *cp1 = FileSpec, *cp2 = BADDR(HandlerName);
LONG hNmLen = *cp2++;
LONG ch1, ch2;
while (hNmLen-- > 0 && GetCICh(cp1, ch1) == GetCICh(cp2, ch2))
cp1++, cp2++;
return hNmLen < 0 && *cp1 == ':' ? cp1 + 1 : FileSpec;
} /* GetCommandLine */
#define FAILATCMD "FailAt 2147483647\n"
#define STRLEN_FAILATCMD 18
/*
* Run a command asynchronously.
*/
STATIC LONG
ExecCommand(char *CmdLine, struct MsgPort **ParentPort,
struct Process *Requester, struct FileHandle *ChildIO,
LONG IoDirection)
{
char *commandLine;
struct ChildMsg *childMsg;
struct TagItem processTags[9];
struct Process *child, *thisProcess = (struct Process *) FindTask(NULL);
struct CommandLineInterface *cli = BADDR(Requester->pr_CLI);
BPTR childOI;
struct LocalVar *pVar;
BPTR pathList, homeDir;
LONG ioErr;
/*
* Copy shell variables, aliases, and path from requester process.
* NOTE: This is not completely safe!
*/
Forbid();
for (pVar = (struct LocalVar *) Requester->pr_LocalVars.mlh_TailPred;
pVar->lv_Node.ln_Pred;
pVar = (struct LocalVar *) pVar->lv_Node.ln_Pred)
{
if (FindVar(pVar->lv_Node.ln_Name, pVar->lv_Node.ln_Type) == NULL)
SetVar(pVar->lv_Node.ln_Name, pVar->lv_Value, pVar->lv_Len,
pVar->lv_Flags | pVar->lv_Node.ln_Type & ~LVF_IGNORE);
}
pathList = ClonePathList(cli);
Permit();
if ((childOI = CloneProcessIO(Requester, IoDirection)) == NULL)
{
ioErr = IoErr();
FreePathList(pathList);
return ioErr;
}
if ((homeDir = DupLock(Requester->pr_CurrentDir)) == NULL)
{
ioErr = IoErr();
Close(childOI);
FreePathList(pathList);
return ioErr;
}
/*
* Create parent's port.
*/
if ((*ParentPort = CreateMsgPort()) == NULL)
{
UnLock(homeDir);
Close(childOI);
FreePathList(pathList);
return ERROR_NO_FREE_STORE;
}
/*
* Build command line from argument vector. First count the length.
*
* We insert a `FailAt 2147483647' (0x7fffffff) so the shell doesn't
* print `Command foo failed' when we call System() to execute the
* command.
*/
if ((childMsg = AllocVec(sizeof(struct ChildMsg) + strlen(CmdLine) +
STRLEN_FAILATCMD + 1, MEMF_PUBLIC)) == NULL)
{
DeleteMsgPort(*ParentPort);
*ParentPort = NULL;
UnLock(homeDir);
Close(childOI);
FreePathList(pathList);
return ERROR_NO_FREE_STORE;
}
childMsg->ExecMsg.mn_Node.ln_Type = NT_MESSAGE;
childMsg->ExecMsg.mn_Node.ln_Pri = 0;
childMsg->ExecMsg.mn_ReplyPort = *ParentPort;
childMsg->ExecMsg.mn_Length = sizeof(struct ChildMsg);
childMsg->CmdLine = commandLine = (char *) (childMsg + 1);
/* Setup the grandchild's [sic] stack */
childMsg->StackSize = cli ? cli->cli_DefaultStack << 2 :
Requester->pr_StackSize;
childMsg->PathList = pathList;
childMsg->Flags = pathList ? CHMF_PATH : 0;
childMsg->RC = 0;
strcpy(commandLine, FAILATCMD);
strcpy(commandLine + STRLEN_FAILATCMD, CmdLine);
processTags[0].ti_Tag = NP_Entry;
processTags[0].ti_Data = (Tag) _ChildProcess;
processTags[1].ti_Tag = NP_Input;
processTags[2].ti_Tag = NP_Output;
processTags[3].ti_Tag = NP_StackSize;
processTags[3].ti_Data = thisProcess->pr_StackSize;
processTags[4].ti_Tag = NP_Cli;
processTags[4].ti_Data = TRUE;
processTags[5].ti_Tag = NP_Name;
processTags[5].ti_Data = (Tag) "Kicker Process";
processTags[6].ti_Tag = NP_Priority;
processTags[6].ti_Data = Requester->pr_Task.tc_Node.ln_Pri;
processTags[7].ti_Tag = NP_CurrentDir;
processTags[7].ti_Data = homeDir;
processTags[8].ti_Tag = TAG_DONE;
if (IoDirection == PPIPE_READ)
{
processTags[1].ti_Data = childOI;
processTags[2].ti_Data = MKBADDR(ChildIO);
}
else /* IoDirection == PPIPE_WRITE */
{
processTags[1].ti_Data = MKBADDR(ChildIO);
processTags[2].ti_Data = childOI;
}
/*
* Start our `kicker' process. This process consists of the _ChildProcess()
* function above. The _ChildProcess() function then executes the command.
*/
if ((child = CreateNewProc(processTags)) == NULL)
{
FreeVec(childMsg);
DeleteMsgPort(*ParentPort);
*ParentPort = NULL;
UnLock(homeDir);
Close(childOI);
FreePathList(pathList);
return ERROR_NO_FREE_STORE;
}
/* now pass the child the startup message */
PutMsg(&child->pr_MsgPort, (struct Message *) childMsg);
return 0;
} /* ExecCommand */
STATIC BPTR
CloneProcessIO(struct Process *Friend, LONG IoDirection)
{
BPTR origFH;
BPTR lock;
BPTR fh = NULL;
LONG pos = -1;
if (IoDirection == PPIPE_READ)
origFH = Friend->pr_CIS;
else
origFH = Friend->pr_COS;
if (origFH)
{
pos = Seek(origFH, 0, OFFSET_CURRENT);
if (IoErr()) /* Handle V36/37 Seek() bug. */
pos = -1;
}
if ((lock = DupLockFromFH(origFH)) == NULL ||
(fh = OpenFromLock(lock)) == NULL)
{
if (lock)
UnLock(lock);
fh = Open("CONSOLE:", MODE_OLDFILE);
}
else if (fh && pos > 0)
Seek(fh, pos, OFFSET_BEGINNING);
return fh;
} /* CloneProcessIO */
/*
* NOTE: This routine should be called from within a Forbid();
* but it is still unsafe due to the call to DupLock().
*/
STATIC BPTR
ClonePathList(struct CommandLineInterface *Peer)
{
BPTR pathList = NULL;
struct PathEntry *pathEntry, *pathET;
if (Peer)
{
for (pathEntry = BADDR(Peer->cli_CommandDir),
pathET = (struct PathEntry *) &pathList;
pathEntry;
pathEntry = BADDR(pathEntry->pe_NextPathEntry))
{
struct PathEntry *newPE;
if (newPE = AllocMem(sizeof(struct PathEntry), MEMF_PUBLIC))
{
newPE->pe_NextPathEntry = NULL;
newPE->pe_PathLock = DupLock(pathEntry->pe_PathLock);
pathET->pe_NextPathEntry = MKBADDR(newPE);
pathET = newPE;
}
else
break;
}
}
return pathList;
} /* ClonePathList */
STATIC void
FreePathList(BPTR PathList)
{
struct PathEntry *pathEntry;
while (pathEntry = BADDR(PathList))
{
PathList = pathEntry->pe_NextPathEntry;
UnLock(pathEntry->pe_PathLock);
FreeMem(pathEntry, sizeof(struct PathEntry));
}
} /* FreePathList */