home *** CD-ROM | disk | FTP | other *** search
- /*
- ** popen.c
- ** Written by Rick Schaeffer (ricks@isc-br.isc-br.com)
- **
- ** apoted for sendmail by wusel@hactar.hanse.de, Thu, 20 Feb 1992 07:26:26 +0100
- **
- ** FIXME: change the errno's ...
-
- NAME
- popen, pclose - initiate I/O to/from a process
-
- SYNOPSIS
- #include <stdio.h>
-
- FILE *popen(command, type)
- char *command, *type;
-
- pclose(stream)
- FILE *stream;
-
- DESCRIPTION
- The arguments to popen are pointers to null-terminated
- strings containing respectively a command line and an
- I/O mode, either "r" for reading or "w" for writing. It
- creates a pipe between the calling process and the command
- to be executed. The value returned is a stream pointer that
- can be used (as appropriate) to write to the standard input
- of the command or read from its standard output.
-
- A stream opened by popen **MUST** be closed by pclose, which
- waits for the associated process to terminate and returns
- the exit status of the command.
-
- Because stdio files are shared, a type "r" command may be
- used as an input filter, and a type "w" as an output filter.
-
- DIAGNOSTICS
- Popen returns a null pointer if files or processes cannot be
- created.
-
- Pclose returns -1 if stream is not associated with a
- `popened' command.
-
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <exec/libraries.h>
- #include <dos/dos.h>
- #include <dos/dosextens.h>
- #include <dos/record.h>
- #include <dos/dostags.h>
- #include <proto/exec.h>
- #include <proto/dos.h>
-
- static const char RCSId[] = "$Id: popen2.c,v 1.1 1993/12/25 23:38:29 simons Rel simons $";
-
- struct POmsg {
- struct Message POm;
- char *cmd;
- BPTR pipe;
- int rc;
- char rw;
- };
-
- struct pstruct {
- FILE *fptr;
- struct POmsg childmsg;
- };
-
- struct pstruct poarray[6];
-
- FILE *popen(char *cmd, char *mode)
- {
- char *pname, redir[60];
- short i;
- int pmode;
- int childprocess();
- struct TagItem nptags[] =
- {
- {NP_Entry, (Tag) childprocess},
- {NP_Input, 0},
- {NP_Output, 0},
- {NP_CloseInput, 0},
- {NP_CloseOutput, 0},
- {NP_StackSize, 50000},
- {NP_Cli, 1},
- #ifdef DEBUG
- {NP_CommandName, (Tag) "childtask()"},
- #endif
- {TAG_DONE, 0}
- };
- struct pstruct *poptr;
- BPTR pfd;
- struct Process *child;
- struct CommandLineInterface *cli;
- struct Process *thistask;
-
- /* First, get pointers to our process and cli structs */
- thistask = (struct Process *) FindTask(NULL);
- cli = Cli();
- poptr = NULL;
-
- /*
- * now find an open pipe (we currently only allow 6
- * simultaneously * open pipes)
- */
- for (i = 0; i < 6; i++) {
- if (poarray[i].fptr == NULL) {
- poptr = &poarray[i];
- break;
- }
- }
- if (poptr == NULL) {
- fprintf(stderr, "popen: Unable to find an open pipe.\n");
- return (errno = EPIPE, NULL);
- }
- if (!strcmp(mode, "r"))
- pmode = MODE_NEWFILE;
- else if (!strcmp(mode, "w"))
- pmode = MODE_OLDFILE;
- else {
- fprintf(stderr, "popen: Mode must be 'r' or 'w'.\n");
- return (errno = EINVAL, NULL);
- }
-
- /* Try to make a guaranteed unique file name for the pipe */
- sprintf(redir, "PIPE:popen.%08lx.%d", thistask, i);
- pname = redir; /* set up a PIPE: file name */
-
- #ifdef DEBUG
- printf("popen: Geh' in den Keller und rei▀ Dich zusammen, %s!\n", pname);
- nptags[7].ti_Data = (Tag) pname;
- #endif
-
- /* Now get the child's stack and priority set up */
- if (thistask->pr_CLI)
- nptags[5].ti_Data = cli->cli_DefaultStack << 2;
- else
- nptags[5].ti_Data = thistask->pr_StackSize;
-
- /* Open the side of the pipe for the child */
- pfd = Open(pname, pmode);
- if (pfd == 0) {
- fprintf(stderr, "popen: Unable to open pipe file (#%d, %s: %ld).\n", i, pname, IoErr());
- return (errno = ENOENT, NULL);
- }
-
- /* set up the tags for the new process */
- if (pmode == MODE_NEWFILE) { /* "r" */
- nptags[1].ti_Data = (Tag) Input();
- nptags[2].ti_Data = (Tag) pfd;
- nptags[3].ti_Data = FALSE;
- nptags[4].ti_Data = FALSE /* TRUE */ ;
- /* poptr->childmsg.pipe=NULL;*/
- }
- else { /* "w" */
- nptags[1].ti_Data = (Tag) pfd;
- nptags[2].ti_Data = (Tag) Output();
- nptags[3].ti_Data = FALSE /* TRUE */ ;
- nptags[4].ti_Data = FALSE;
- /* poptr->childmsg.pipe=pfd;*/
- }
- poptr->childmsg.pipe = pfd;
- poptr->childmsg.rw = *mode;
-
- /*
- * create the command. since the "System" function runs through
- * the default shell, we need to tell it not to fail so that we
- * ALWAYS get back the exit status. This wouldn't be necessary
- * if the CLI created by the System function inherited the
- * parent's FAILAT level
- */
- poptr->childmsg.cmd = malloc(strlen(cmd) + 15);
- if (!poptr->childmsg.cmd) {
- fprintf(stderr, "popen: Out of memory.\n");
- Close(pfd);
- return (errno = ENOMEM, NULL);
- }
- strcpy(poptr->childmsg.cmd, "failat 9999\n");
- strcat(poptr->childmsg.cmd, cmd);
-
- /* Create a port that we can get the child's exit status through */
- poptr->childmsg.POm.mn_ReplyPort = CreatePort(NULL, 0);
- poptr->childmsg.POm.mn_Node.ln_Type = NT_MESSAGE;
- poptr->childmsg.POm.mn_Node.ln_Pri = 0;
- poptr->childmsg.POm.mn_Length = sizeof(struct POmsg);
-
- if (!poptr->childmsg.POm.mn_ReplyPort) {
- fprintf(stderr, "popen: Couldn't create message port.\n");
- free(poptr->childmsg.cmd);
- Close(pfd);
- return (errno = EFAULT, NULL);
- }
-
- /*
- * Now we can start the new process. NOTE: this is actually
- * going to create a process consisting ONLY of the function
- * "childprocess" which can be seen below. childprocess() then
- * runs the command passed in the startup message.
- */
-
- #ifdef DEBUG
- PutStr("popen: Creating child process\n");
- Flush(Output());
- #endif
- child = CreateNewProc(nptags);
- #ifdef DEBUG
- printf("popen: created new process @ $%06lx.\n", child);
- fflush(stdout);
- #endif
- if (!child) {
- fprintf(stderr, "popen: CreateNewProc() failed.\n");
- free(poptr->childmsg.cmd);
- Close(pfd);
- return (errno = EFAULT, NULL);
- }
- /* now pass the child the startup message */
- PutMsg(&child->pr_MsgPort, (struct Message *) &poptr->childmsg);
-
- #ifdef DEBUG
- PutStr("popen: Sent startupmsg, now opening our side of the pipe\n");
- Flush(Output());
- #endif
- /* Now open our side of the pipe */
- poptr->fptr = fopen(pname, mode);
- #ifdef DEBUG
- printf("fopen(%s, %s)=$%06lx\n", pname, mode, poptr->fptr);
- #endif
-
- if (!poptr->fptr) {
- #ifdef DEBUG
- PutStr("popen: fopen() failed! Let's clean up and return NULL ...\n");
- Flush(Output());
- #endif
- fprintf(stderr, "popen: Unable to open pipe file %s.\n", pname);
- DeletePort(poptr->childmsg.POm.mn_ReplyPort);
- return (errno = ENOENT, NULL);
- }
-
- #ifdef DEBUG
- PutStr("popen: Returning FILE * to caller\n");
- Flush(Output());
- #endif
- return (poptr->fptr);
- }
-
- pclose(FILE * fptr)
- {
- short i;
-
- /* Figure out which pipe we used for this file */
- for (i = 0; i < 6; i++)
- if (poarray[i].fptr == fptr)
- break;
-
- if (i > 5) {
- fprintf(stderr, "popen: DISASTER - couldn't find file pointer in pclose().\n");
- return (-1);
- /* exit(1); */
- }
-
- #ifdef DEBUG
- PutStr("pclose: Closing pipe\n");
- Flush(Output());
- #endif
- /* Close the file */
- fclose(fptr);
-
- #ifdef DEBUG
- PutStr("pclose: Waiting for child to terminate\n");
- Flush(Output());
- #endif
- /* Now wait for the exit status */
- WaitPort(poarray[i].childmsg.POm.mn_ReplyPort);
-
- /* Clean things up */
- DeletePort(poarray[i].childmsg.POm.mn_ReplyPort);
- free(poarray[i].childmsg.cmd);
- #ifdef DEBUG
- PutStr("pclose: Returning rc\n");
- Flush(Output());
- #endif
- /* Finally, make this pipe available again ... */
- poarray[i].fptr = NULL;
- return (poarray[i].childmsg.rc);
- }
-
- int __saveds childprocess(void)
- {
- struct TagItem systags[] =
- {
- {SYS_UserShell, 0},
- {TAG_DONE, 0}
- };
- struct Process *me;
- struct POmsg *startupmsg;
- int i;
-
- /* Find our process structure */
- me = (struct Process *) FindTask(NULL);
-
- /* Wait for the parent to kick us off */
- WaitPort(&me->pr_MsgPort);
-
- /* Get the command to execute */
- startupmsg = (struct POmsg *) GetMsg(&me->pr_MsgPort);
-
- /* Now run the command. stdin and stdout are already set up */
- i = SystemTagList(startupmsg->cmd, systags);
-
- /* Store the rc for pclose() */
- startupmsg->rc = i;
-
- /*
- * ╖╖ Always ╖╖ try to dry the pipe; read until EOF, as
- * otherwise the calling process will be blocked - forever =:-(
- * this may cause some delay (if there are many bytes to junk),
- * but at least, it works. wusel, Sat, 16
- * May 1992 03:11:10 +0200
- */
- if (startupmsg->rw == 'w') {
- while (FGetC(startupmsg->pipe) != -1L) ;
- }
- Close(startupmsg->pipe);
- startupmsg->pipe = NULL;
-
- /* Pass the exit code back to the parent */
- ReplyMsg((struct Message *) startupmsg);
- return (0);
- }
-
- int oldchildprocess(void)
- {
- struct TagItem systags[] =
- {
- {SYS_UserShell, 0},
- {TAG_DONE, 0}
- };
- struct Process *me;
- struct POmsg *startupmsg;
- int i;
-
- /* find our process structure */
- me = (struct Process *) FindTask(NULL);
-
- /* Wait for the parent to kick us off */
- WaitPort(&me->pr_MsgPort);
-
- /* Get the command to execute */
- startupmsg = (struct POmsg *) GetMsg(&me->pr_MsgPort);
-
- /* Now run the command. stdin and stdout are already set up */
- i = SystemTagList(startupmsg->cmd, systags);
- startupmsg->rc = i;
-
- /* pass the exit code back to the parent */
- ReplyMsg((struct Message *) startupmsg);
- return (0);
- }
-
- int pexit(void)
- { /* close all open pipes ... */
- short i;
-
- for (i = 0; i < 6; i++)
- if (poarray[i].fptr)
- (void) pclose(poarray[i].fptr);
- return (0);
- }
-