This is osprg.c in view mode; [Download] [Up]
/* unix/osprg.c */ #include <sys/types.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include "elvis.h" #ifdef NEED_WAIT_H # include <sys/wait.h> #endif char id_osprg[] = "$Id: osprg.c,v 2.9 1996/05/23 00:03:51 steve Exp $"; #define TMPDIR (o_directory ? tochar8(o_directory) : "/tmp") #define SHELL (o_shell ? tochar8(o_shell) : "/bin/sh") static char *command; /* the command to run */ static char tempfname[100]; /* name of temp file */ static int writefd; /* fd used for writing to program's stdin */ static int readfd; /* fd used for reading program's stdout */ static int pid; /* process ID of program */ /* Declares which program we'll run, and what we'll be doing with it. * This function should return True if successful. If there is an error, * it should issue an error message via msg(), and return False. * * For UNIX, the behavior of this function depends on willwrite. * If willwrite, then the command is saved and a temporary file is * is created to store the data that will become the program's stdin, * and the function succeeds if the temp file was created successfully. * Else the program is forked (with stdout/stderr redirected to a pipe * if willread) and the function succedes if pipe() and fork() * succeed. */ BOOLEAN prgopen(cmd, willwrite, willread) char *cmd; /* command string */ BOOLEAN willwrite; /* if True, redirect command's stdin */ BOOLEAN willread; /* if True, redirect command's stdout */ { int r0w1[2]; /* two ends of a pipe */ /* Mark both fd's as being unused */ writefd = readfd = -1; /* Don't die if a write-pipe breaks */ signal(SIGPIPE, SIG_IGN); /* Next step depends on what I/O we expect to do with this program */ if (willwrite && willread) { /* save the command */ command = strdup(cmd); /* create a temporary file for feeding the program's stdin */ sprintf(tempfname, "%s/elvis%d.tmp", TMPDIR, (int)getpid()); writefd = open(tempfname, O_WRONLY|O_CREAT|O_EXCL, 0600); if (writefd < 0) { msg(MSG_ERROR, "can't make temporary file"); free(command); return False; } } else if (willwrite || willread) /* but not both */ { /* create a pipe */ if (pipe(r0w1) < 0) { msg(MSG_ERROR, "can't create pipe"); return False; } /* fork */ pid = fork(); if (pid < 0) /* error */ { msg(MSG_ERROR, "can't fork"); close(r0w1[0]); close(r0w1[1]); return False; } else if (pid == 0) /* child */ { if (willwrite) { /* close the write end of the pipe, and make * the read end become stdin. */ close(r0w1[1]); close(0); dup(r0w1[0]); close(r0w1[0]); } else { /* close the read end of the pipe, and make * the write end become stdout & stderr */ close(r0w1[0]); close(1); close(2); dup(r0w1[1]); dup(r0w1[1]); close(r0w1[1]); } /* run the program */ execl(SHELL, SHELL, "-c", cmd, NULL); /* if we get here, fail! */ exit(1); } else /* parent */ { if (willwrite) { /* close the read end of the pipe, and remember * the fd of the write end. */ close(r0w1[0]); writefd = r0w1[1]; } else { /* close the write end of the pipe, and * remember the fd of the read end. */ close(r0w1[1]); readfd = r0w1[0]; } } } else /* no redirection */ { /* fork */ pid = fork(); if (pid < 0) /* error */ { msg(MSG_ERROR, "can't fork"); return False; } else if (pid == 0) /* child */ { execl(SHELL, SHELL, "-c", cmd, NULL); /* if we get here, fail */ exit(1); } /* else parent, but parent doesn't need to do anything */ } /* if we get here, we must have succeeded */ return True; } /* Write the contents of buf to the program's stdin, and return nbytes * if successful, or -1 for error. Note that this text should * be subjected to the same kind of transformations as textwrite(). * In fact, it may use textwrite() internally. * * For UNIX, this is simply a write() to the temp file or pipe. */ int prgwrite(buf, nbytes) CHAR *buf; /* buffer, contains text to be written */ int nbytes; /* number of characters in buf */ { assert(writefd >= 0); return write(writefd, buf, (size_t)nbytes); } /* Marks the end of writing. Returns True if all is okay, or False if * error. * * For UNIX, the temp file is closed, and the program is forked. * (Since this function is only called when willwrite, the program * wasn't forked when prgopen() was called.) Returns True if the * fork was successful, or False if it failed. */ BOOLEAN prggo() { int r0w1[2]; /* If we weren't writing, then there's nothing to be done here */ if (writefd < 0) return True; /* If we're using a temp file, then close it for writing, and then * fork the program with its stdin redirected to come from file. */ if (command) { /* close the temp file for writing */ close(writefd); writefd = -1; /* make a pipe to use for reading stdout/stderr */ if (pipe(r0w1) < 0) { msg(MSG_ERROR, "can't create pipe"); } /* fork */ pid = fork(); if (pid < 0) /* error */ { msg(MSG_ERROR, "can't fork"); close(r0w1[0]); close(r0w1[1]); return False; } else if (pid == 0) /* child */ { /* redirect stdin to come from file */ close(0); open(tempfname, O_RDONLY); /* connect the write end of the pipe to stdout/stderr; * close the read end. */ close(1); dup(r0w1[1]); close(2); dup(r0w1[1]); close(r0w1[0]); close(r0w1[1]); /* exec the program */ execl(SHELL, SHELL, "-c", command, NULL); /* if we get here, fail! */ exit(1); } else /* parent */ { /* close the write end of the pipe; the read end * becomes readfd. */ close(r0w1[1]); readfd = r0w1[0]; /* don't need the command string any more. */ free(command); } } else /* writing but not reading */ { /* close the writefd */ close(writefd); writefd = -1; } return True; } /* Reads text from the program's stdout, and returns the number of * characters read. At EOF, it returns 0. Note that this text * should be subjected to the same kinds of transformations as * textread(). * * For UNIX, this is simply a read() from the pipe. */ int prgread(buf, nbytes) CHAR *buf; /* buffer where text should be placed */ int nbytes; /* maximum number of characters to read */ { assert(readfd >= 0); return read(readfd, buf, (size_t)nbytes); } /* Clean up, and return the program's exit status. The exit status * should be 0 normally. * * For UNIX, this involves closing the pipe, calling wait() to get the * program's exit status, and then deleting the temp file. */ int prgclose() { int status; /* close the readfd, if necessary */ if (readfd >= 0) { close(readfd); readfd = -1; } /* close the writefd, if necessary */ if (writefd >= 0) { close(writefd); writefd = -1; } /* wait for the program to die */ while (wait(&status) != pid) { } /* delete the temp file, if there was one */ if (*tempfname) { unlink(tempfname); *tempfname = '\0'; } return status; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.