summaryrefslogtreecommitdiff
path: root/pith/osdep/pipe.c
diff options
context:
space:
mode:
authorEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
committerEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
commit094ca96844842928810f14844413109fc6cdd890 (patch)
treee60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /pith/osdep/pipe.c
downloadalpine-094ca96844842928810f14844413109fc6cdd890.tar.xz
Initial Alpine Version
Diffstat (limited to 'pith/osdep/pipe.c')
-rw-r--r--pith/osdep/pipe.c811
1 files changed, 811 insertions, 0 deletions
diff --git a/pith/osdep/pipe.c b/pith/osdep/pipe.c
new file mode 100644
index 00000000..2183f529
--- /dev/null
+++ b/pith/osdep/pipe.c
@@ -0,0 +1,811 @@
+#if !defined(lint) && !defined(DOS)
+static char rcsid[] = "$Id: pipe.c 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $";
+#endif
+
+/*
+ * ========================================================================
+ * Copyright 2006-2008 University of Washington
+ * Copyright 2013 Eduardo Chappa
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * ========================================================================
+ */
+
+#include <system.h>
+
+#include "err_desc.h"
+
+#include "canaccess.h"
+#include "temp_nam.h"
+#include "forkwait.h"
+#include "pipe.h"
+#include "../charconv/utf8.h"
+#include "../charconv/filesys.h"
+#include "../debug.h"
+
+#ifdef _WINDOWS
+#include "../../pico/osdep/mswin.h"
+#endif
+
+
+
+/*======================================================================
+ pipe
+
+ Initiate I/O to and from a process. These functions used to be
+ similar to popen and pclose, but both an incoming stream and an
+ output file are provided.
+
+ ====*/
+
+
+
+/*
+ * Global's to helpsignal handler tell us child's status has changed...
+ */
+static pid_t child_pid;
+
+
+/*
+ * Internal Protos
+ */
+void zot_pipe(PIPE_S **);
+#ifdef _WINDOWS
+int pipe_mswin_exec_wrapper(char *, PIPE_S *, unsigned,
+ void (*)(PIPE_S *, int, void *),
+ void (*)(char *));
+#else /* UNIX */
+char *pipe_error_msg(char *, char *, char *);
+RETSIGTYPE pipe_alarm(int);
+#endif /* UNIX */
+
+
+
+
+/*----------------------------------------------------------------------
+ Spawn a child process and optionally connect read/write pipes to it
+
+ Args: command -- string to hand the shell
+ outfile -- address of pointer containing file to receive output
+ errfile -- address of pointer containing file to receive error output
+ mode -- mode for type of shell, signal protection etc...
+ Returns: pointer to alloc'd PIPE_S on success, NULL otherwise
+
+ The outfile is either NULL, a pointer to a NULL value, or a pointer
+ to the requested name for the output file. In the pointer-to-NULL case
+ the caller doesn't care about the name, but wants to see the pipe's
+ results so we make one up. It's up to the caller to make sure the
+ free storage containing the name is cleaned up.
+
+ Mode bits serve several purposes.
+ PIPE_WRITE tells us we need to open a pipe to write the child's
+ stdin.
+ PIPE_READ tells us we need to open a pipe to read from the child's
+ stdout/stderr. *NOTE* Having neither of the above set means
+ we're not setting up any pipes, just forking the child and exec'ing
+ the command. Also, this takes precedence over any named outfile.
+ PIPE_STDERR means we're to tie the childs stderr to the same place
+ stdout is going. *NOTE* This only makes sense then if PIPE_READ
+ or an outfile is provided. Also, this takes precedence over any
+ named errfile.
+ PIPE_RESET means we reset the terminal mode to what it was before
+ we started pine and then exec the command. In PC-Pine, _RESET
+ was a shortcut for just executing a command. We'll try to pay
+ attention to the above flags to make sure we do the right thing.
+ PIPE_PROT means to protect the child from the usual nasty signals
+ that might cause premature death. Otherwise, the default signals are
+ set so the child can deal with the nasty signals in its own way.
+ NOT USED UNDER WINDOWS
+ PIPE_NOSHELL means we're to exec the command without the aid of
+ a system shell. *NOTE* This negates the affect of PIPE_USER.
+ NOT USED UNDER WINDOWS
+ PIPE_USER means we're to try executing the command in the user's
+ shell. Right now we only look in the environment, but that may get
+ more sophisticated later.
+ NOT USED UNDER WINDOWS
+ PIPE_RUNNOW was added for WINDOWS for the case pipe is called to run
+ a shell program (like for url viewing). This is the only option
+ where we don't wait for child termination, and is only obeyed if
+ PIPE_WRITE and PIPE_READ aren't set
+ ----*/
+PIPE_S *
+open_system_pipe(char *command, char **outfile, char **errfile, int mode,
+ int timeout, void (*pipecb_f)(PIPE_S *, int, void *),
+ void (*piperr_f)(char *))
+{
+ PIPE_S *syspipe = NULL;
+#ifdef _WINDOWS
+ int exit_code = 0;
+ char cmdbuf[1024];
+ unsigned flags = 0;
+#else
+ char shellpath[MAXPATH+1], *shell;
+ int p[2], oparentd = -1, ochildd = -1, iparentd = -1, ichildd = -1;
+#endif
+
+#ifdef _WINDOWS
+ if(mode & PIPE_STDERR)
+ flags |= MSWIN_EAW_CAPT_STDERR;
+ /*
+ * It'll be a lot more difficult to support READing and WRITing.
+ * This was never supported, and there don't look to be any cases
+ * that set both of these flags anymore for win32.
+ *
+ * errfile could probably be supported pretty easily
+ */
+
+ if(errfile){
+ if(piperr_f)
+ (*piperr_f)("Pipe arg not yet supported: Error File");
+
+ return(NULL);
+ }
+
+
+ if((mode & PIPE_RUNNOW)
+ && !(mode & (PIPE_WRITE | PIPE_READ | PIPE_STDERR))){
+ if(mswin_shell_exec(command, NULL) == 0
+ && (syspipe = (PIPE_S *) malloc(sizeof(PIPE_S))) != NULL){
+ memset(syspipe, 0, sizeof(PIPE_S));
+ return(syspipe);
+ }
+
+ return(NULL);
+ }
+
+ strncpy(cmdbuf, command, sizeof(cmdbuf));
+ cmdbuf[sizeof(cmdbuf)-1] = '\0';
+
+ if((syspipe = (PIPE_S *) malloc(sizeof(PIPE_S))) == NULL)
+ return(NULL);
+
+ memset(syspipe, 0, sizeof(PIPE_S));
+ syspipe->mode = mode;
+ if(!outfile){
+ syspipe->deloutfile = 1;
+ if(mode & PIPE_READ){
+ syspipe->outfile = temp_nam(NULL, "po");
+ our_unlink(syspipe->outfile);
+ }
+ }
+ else{
+ if(!*outfile) /* asked for, but not named? */
+ *outfile = temp_nam(NULL, "po");
+
+ our_unlink(*outfile);
+ syspipe->outfile = (char *) malloc((strlen(*outfile)+1)*sizeof(char));
+ snprintf(syspipe->outfile, strlen(*outfile)+1, "%s", *outfile);
+ }
+
+ if(mode & PIPE_WRITE){
+ /*
+ * Create tmp file to write, spawn child in close_pipe
+ * after tmp file's written...
+ */
+ syspipe->infile = temp_nam(NULL, "pw");
+ syspipe->out.f = our_fopen(syspipe->infile, "wb");
+ syspipe->command = (char *) malloc((strlen(cmdbuf)+1)*sizeof(char));
+ snprintf(syspipe->command, strlen(cmdbuf)+1, "%s", cmdbuf);
+ dprint((1, "pipe write: %s", cmdbuf));
+ }
+ else if(mode & PIPE_READ){
+ /*
+ * Create a tmp file for command result, exec the command
+ * here into temp file, and return file pointer to it...
+ */
+ syspipe->command = (char *) malloc((strlen(cmdbuf)+1)*sizeof(char));
+ snprintf(syspipe->command, strlen(cmdbuf)+1, "%s", cmdbuf);
+ dprint((1, "pipe read: %s", cmdbuf));
+ if(pipe_mswin_exec_wrapper("pipe command", syspipe,
+ flags, pipecb_f, piperr_f)){
+ if(syspipe->outfile){
+ free((void *) syspipe->outfile);
+ syspipe->outfile = NULL;
+ }
+
+ zot_pipe(&syspipe);
+ }
+ else{
+ syspipe->in.f = our_fopen(syspipe->outfile, "rb");
+ syspipe->exit_code = exit_code;
+ }
+ }
+ else{
+ /* we just run the command taking outfile into account */
+ syspipe->command = (char *) malloc((strlen(cmdbuf)+1)*sizeof(char));
+ snprintf(syspipe->command, strlen(cmdbuf)+1, "%s", cmdbuf);
+ if(pipe_mswin_exec_wrapper("pipe command", syspipe,
+ flags, pipecb_f, piperr_f)){
+ if(syspipe->outfile){
+ free((void *) syspipe->outfile);
+ syspipe->outfile = NULL;
+ }
+
+ zot_pipe(&syspipe);
+ }
+ else
+ syspipe->exit_code = exit_code;
+ }
+
+#else /* !_WINDOWS */
+
+ if((syspipe = (PIPE_S *) malloc(sizeof(PIPE_S))) == NULL)
+ return(NULL);
+
+ memset(syspipe, 0, sizeof(PIPE_S));
+
+ syspipe->mode = mode;
+
+ /*
+ * If we're not using the shell's command parsing smarts, build
+ * argv by hand...
+ */
+ if(mode & PIPE_NOSHELL){
+ char **ap, *p;
+ size_t n;
+
+ /* parse the arguments into argv */
+ for(p = command; *p && isspace((unsigned char)(*p)); p++)
+ ; /* swallow leading ws */
+
+ if(*p){
+ int l = strlen(p);
+
+ if((syspipe->args = (char *) malloc((l + 1) * sizeof(char))) != NULL){
+ strncpy(syspipe->args, p, l);
+ syspipe->args[l] = '\0';
+ }
+ else{
+ if(piperr_f)
+ (*piperr_f)(pipe_error_msg("<null>", "execute",
+ "Can't allocate command string"));
+ zot_pipe(&syspipe);
+ return(NULL);
+ }
+ }
+ else{
+ if(piperr_f)
+ (*piperr_f)(pipe_error_msg("<null>", "execute",
+ "No command name found"));
+ zot_pipe(&syspipe);
+ return(NULL);
+ }
+
+ for(p = syspipe->args, n = 2; *p; p++) /* count the args */
+ if(isspace((unsigned char)(*p))
+ && *(p+1) && !isspace((unsigned char)(*(p+1))))
+ n++;
+
+ if ((syspipe->argv = ap = (char **)malloc(n * sizeof(char *))) == NULL){
+ zot_pipe(&syspipe);
+ return(NULL);
+ }
+
+ memset(syspipe->argv, 0, n * sizeof(char *));
+
+ for(p = syspipe->args; *p; ){ /* collect args */
+ while(*p && isspace((unsigned char)(*p)))
+ *p++ = '\0';
+
+ *ap++ = (*p) ? p : NULL;
+ while(*p && !isspace((unsigned char)(*p)))
+ p++;
+ }
+
+ /* make sure argv[0] exists in $PATH */
+ if(can_access_in_path(getenv("PATH"), syspipe->argv[0],
+ EXECUTE_ACCESS) < 0){
+ if(piperr_f)
+ (*piperr_f)(pipe_error_msg(syspipe->argv[0], "access",
+ error_description(errno)));
+ zot_pipe(&syspipe);
+ return(NULL);
+ }
+ }
+
+ /* fill in any output filenames */
+ if(!(mode & PIPE_READ)){
+ if(outfile && !*outfile)
+ *outfile = temp_nam(NULL, "pine_p"); /* asked for, but not named? */
+
+ if(errfile && !*errfile)
+ *errfile = temp_nam(NULL, "pine_p"); /* ditto */
+ }
+
+ /* create pipes */
+ if(mode & (PIPE_WRITE | PIPE_READ)){
+ if(mode & PIPE_WRITE){
+ pipe(p); /* alloc pipe to write child */
+ oparentd = p[STDOUT_FILENO];
+ ichildd = p[STDIN_FILENO];
+ }
+
+ if(mode & PIPE_READ){
+ pipe(p); /* alloc pipe to read child */
+ iparentd = p[STDIN_FILENO];
+ ochildd = p[STDOUT_FILENO];
+ }
+ }
+
+ if(pipecb_f) /* let caller prep display */
+ (*pipecb_f)(syspipe, OSB_PRE_OPEN, NULL);
+
+
+ if((syspipe->pid = vfork()) == 0){
+ /* reset child's handlers in requested fashion... */
+ (void)signal(SIGINT, (mode & PIPE_PROT) ? SIG_IGN : SIG_DFL);
+ (void)signal(SIGQUIT, (mode & PIPE_PROT) ? SIG_IGN : SIG_DFL);
+ (void)signal(SIGHUP, (mode & PIPE_PROT) ? SIG_IGN : SIG_DFL);
+#ifdef SIGCHLD
+ (void) signal(SIGCHLD, SIG_DFL);
+#endif
+
+ /* if parent isn't reading, and we have a filename to write */
+ if(!(mode & PIPE_READ) && outfile){ /* connect output to file */
+ int output = our_creat(*outfile, 0600);
+ dup2(output, STDOUT_FILENO);
+ if(mode & PIPE_STDERR)
+ dup2(output, STDERR_FILENO);
+ else if(errfile)
+ dup2(our_creat(*errfile, 0600), STDERR_FILENO);
+ }
+
+ if(mode & PIPE_WRITE){ /* connect process input */
+ close(oparentd);
+ dup2(ichildd, STDIN_FILENO); /* tie stdin to pipe */
+ close(ichildd);
+ }
+
+ if(mode & PIPE_READ){ /* connect process output */
+ close(iparentd);
+ dup2(ochildd, STDOUT_FILENO); /* tie std{out,err} to pipe */
+ if(mode & PIPE_STDERR)
+ dup2(ochildd, STDERR_FILENO);
+ else if(errfile)
+ dup2(our_creat(*errfile, 0600), STDERR_FILENO);
+
+ close(ochildd);
+ }
+
+ if(mode & PIPE_NOSHELL){
+ execvp(syspipe->argv[0], syspipe->argv);
+ }
+ else{
+ if(mode & PIPE_USER){
+ char *env, *sh;
+ if((env = getenv("SHELL")) && (sh = strrchr(env, '/'))){
+ shell = sh + 1;
+ strncpy(shellpath, env, sizeof(shellpath)-1);
+ shellpath[sizeof(shellpath)-1] = '\0';
+ }
+ else{
+ shell = "csh";
+ strncpy(shellpath, "/bin/csh", sizeof(shellpath)-1);
+ shellpath[sizeof(shellpath)-1] = '\0';
+ }
+ }
+ else{
+ shell = "sh";
+ strncpy(shellpath, "/bin/sh", sizeof(shellpath)-1);
+ shellpath[sizeof(shellpath)-1] = '\0';
+ }
+
+ execl(shellpath, shell, command ? "-c" : (char *)NULL, fname_to_locale(command), (char *)NULL);
+ }
+
+ fprintf(stderr, "Can't exec %s\nReason: %s",
+ command, error_description(errno));
+ _exit(-1);
+ }
+
+ if((child_pid = syspipe->pid) > 0){
+ syspipe->isig = signal(SIGINT, SIG_IGN); /* Reset handlers to make */
+ syspipe->qsig = signal(SIGQUIT, SIG_IGN); /* sure we don't come to */
+ syspipe->hsig = signal(SIGHUP, SIG_IGN); /* a premature end... */
+ if((syspipe->timeout = timeout) != 0){
+ syspipe->alrm = signal(SIGALRM, pipe_alarm);
+ syspipe->old_timeo = alarm(timeout);
+ }
+
+ if(mode & PIPE_WRITE){
+ close(ichildd);
+ if(mode & PIPE_DESC)
+ syspipe->out.d = oparentd;
+ else
+ syspipe->out.f = fdopen(oparentd, "w");
+ }
+
+ if(mode & PIPE_READ){
+ close(ochildd);
+ if(mode & PIPE_DESC)
+ syspipe->in.d = iparentd;
+ else
+ syspipe->in.f = fdopen(iparentd, "r");
+ }
+ }
+ else{
+ if(mode & (PIPE_WRITE | PIPE_READ)){
+ if(mode & PIPE_WRITE){
+ close(oparentd);
+ close(ichildd);
+ }
+
+ if(mode & PIPE_READ){
+ close(iparentd);
+ close(ochildd);
+ }
+ }
+
+ if(pipecb_f) /* let caller fixup display */
+ (*pipecb_f)(syspipe, OSB_POST_OPEN, NULL);
+
+ if(outfile && *outfile){
+ our_unlink(*outfile);
+ free((void *) *outfile);
+ *outfile = NULL;
+ }
+
+ if(errfile && *errfile){
+ our_unlink(*errfile);
+ free((void *) *errfile);
+ *errfile = NULL;
+ }
+
+ if(piperr_f)
+ (*piperr_f)(pipe_error_msg(command, "fork",
+ error_description(errno)));
+ zot_pipe(&syspipe);
+ }
+
+#endif /* UNIX */
+
+ return(syspipe);
+}
+
+
+
+#ifndef _WINDOWS
+/*----------------------------------------------------------------------
+ Return appropriate error message
+
+ Args: cmd -- command we were trying to exec
+ op -- operation leading up to the exec
+ res -- result of that operation
+
+ ----*/
+char *
+pipe_error_msg(char *cmd, char *op, char *res)
+{
+ static char ebuf[512];
+
+ snprintf(ebuf, 256, "Pipe can't %.256s \"%.32sb\": %.223s",
+ op ? op : "?", cmd ? cmd : "?", res ? res : "?");
+
+ return(ebuf);
+}
+#endif /* !_WINDOWS */
+
+
+/*----------------------------------------------------------------------
+ Free resources associated with the given pipe struct
+
+ Args: syspipe -- address of pointer to struct to clean up
+
+ ----*/
+void
+zot_pipe(PIPE_S **syspipe)
+{
+ if((*syspipe)->args){
+ free((void *) (*syspipe)->args);
+ (*syspipe)->args = NULL;
+ }
+
+ if((*syspipe)->argv){
+ free((void *) (*syspipe)->argv);
+ (*syspipe)->argv = NULL;
+ }
+
+ if((*syspipe)->tmp){
+ free((void *) (*syspipe)->tmp);
+ (*syspipe)->tmp = NULL;
+ }
+
+#ifdef _WINDOWS
+
+ if((*syspipe)->outfile){
+ free((void *) (*syspipe)->outfile);
+ (*syspipe)->outfile = NULL;
+ }
+
+ if((*syspipe)->command){
+ free((void *) (*syspipe)->command);
+ (*syspipe)->command = NULL;
+ }
+
+#endif /* _WINDOWS */
+
+ free((void *) *syspipe);
+ *syspipe = NULL;
+}
+
+
+
+/*
+ * Returns: 0 if all went well, -1 otherwise
+ */
+int
+pipe_close_write(PIPE_S *syspipe)
+{
+ int rv = 0;
+
+ if(!syspipe || !syspipe->out.f)
+ return -1;
+
+#ifdef _WINDOWS
+
+ {
+ unsigned flags = 0;
+
+ if(syspipe->mode & PIPE_STDERR)
+ flags |= MSWIN_EAW_CAPT_STDERR;
+
+ rv = fclose(syspipe->out.f);
+ syspipe->out.f = NULL;
+ if(syspipe->mode & PIPE_WRITE){
+ /*
+ * PIPE_WRITE should always be set if we're trying to close
+ * the write end.
+ * PIPE_WRITE can't start process till now, all the others
+ * will have already run
+ */
+ if(pipe_mswin_exec_wrapper("pipe command", syspipe,
+ flags, NULL, NULL))
+ /* some horrible error just occurred */
+ rv = -1;
+ else
+ syspipe->in.f = our_fopen(syspipe->outfile, "rb");
+ }
+ else
+ rv = -1;
+ }
+
+#else /* UNIX */
+
+ rv = fclose(syspipe->out.f) ? -1 : 0;
+ syspipe->out.f = NULL;
+
+#endif
+ return(rv);
+}
+
+
+
+/*----------------------------------------------------------------------
+ Close pipe previously allocated and wait for child's death
+
+ Args: syspipe -- address of pointer to struct returned by open_system_pipe
+ exitval -- return exit status here.
+
+ Returns:
+ Two modes of return values for backcompat.
+ If exitval == NULL
+ returns exit status of child or -1 if invalid syspipe
+ If exitval != NULL
+ returns -1 if invalid syspipe or 0 if ok. In that case, exitval
+ of child is returned in exitval
+ ----*/
+int
+close_system_pipe(PIPE_S **syspipe, int *exitval, void (*pipecb_f) (PIPE_S *, int, void *))
+{
+#ifdef _WINDOWS
+ int rv = 0;
+ unsigned flags = 0;
+
+ if(!(syspipe && *syspipe))
+ return(-1);
+
+ if((*syspipe)->mode & PIPE_STDERR)
+ flags |= MSWIN_EAW_CAPT_STDERR;
+
+ if(((*syspipe)->mode & PIPE_WRITE) && (*syspipe)->out.f){
+ fclose((*syspipe)->out.f);
+ /*
+ * PIPE_WRITE can't start process till now, all the others
+ * will have already run
+ */
+ if(pipe_mswin_exec_wrapper("pipe command", (*syspipe),
+ flags, pipecb_f, NULL))
+ /* some horrible error just occurred */
+ rv = -1;
+ }
+ else if((*syspipe)->mode & PIPE_READ)
+ if((*syspipe)->in.f)
+ fclose((*syspipe)->in.f);
+
+ if(exitval){
+ *exitval = (*syspipe)->exit_code;
+ dprint((5, "Closed pipe: exitval=%d\n", *exitval));
+ }
+
+ if((*syspipe)->infile)
+ our_unlink((*syspipe)->infile);
+
+ if((*syspipe)->outfile && (*syspipe)->deloutfile)
+ our_unlink((*syspipe)->outfile);
+
+ if(rv != -1 && !exitval)
+ rv = (*syspipe)->exit_code;
+
+ zot_pipe(syspipe);
+
+#ifdef DEBUG
+ if(!exitval){
+ dprint((5, "Closed pipe: rv=%d\n", rv));
+ }
+#endif /* DEBUG */
+
+ return(rv);
+
+#else /* UNIX */
+ int status;
+
+ if(!(syspipe && *syspipe))
+ return -1;
+
+ if(((*syspipe)->mode) & PIPE_WRITE){
+ if(((*syspipe)->mode) & PIPE_DESC){
+ if((*syspipe)->out.d >= 0)
+ close((*syspipe)->out.d);
+ }
+ else if((*syspipe)->out.f)
+ fclose((*syspipe)->out.f);
+ }
+
+ if(((*syspipe)->mode) & PIPE_READ){
+ if(((*syspipe)->mode) & PIPE_DESC){
+ if((*syspipe)->in.d >= 0)
+ close((*syspipe)->in.d);
+ }
+ else if((*syspipe)->in.f)
+ fclose((*syspipe)->in.f);
+ }
+
+ if(pipecb_f)
+ (*pipecb_f)(*syspipe, OSB_PRE_CLOSE, NULL);
+
+ /* wait on the child */
+ (void) process_reap((*syspipe)->pid, &status, PR_NONE);
+
+ /* restore original handlers... */
+ (void) signal(SIGINT, (*syspipe)->isig);
+ (void) signal(SIGHUP, (*syspipe)->hsig);
+ (void) signal(SIGQUIT, (*syspipe)->qsig);
+
+ if((*syspipe)->timeout){
+ (void)signal(SIGALRM, (*syspipe)->alrm);
+ alarm((*syspipe)->old_timeo);
+ child_pid = 0;
+ }
+
+ if(pipecb_f)
+ (*pipecb_f)(*syspipe, OSB_POST_CLOSE, NULL);
+
+ zot_pipe(syspipe);
+
+ if(exitval){
+ *exitval = status;
+ return 0;
+ }
+ else{
+ return(status);
+ }
+#endif /* UNIX */
+}
+
+
+/*
+ * process_reap - manage child demise and return exit status
+ *
+ * Args: pid -- id of process to reap
+ * esp -- pointer to exist status
+ * flags -- special reaping considerations
+ *
+ * Returns:
+ * < 0 -- if there's a problem
+ * 0 -- if no child to reap
+ * > 0 -- process id of the child
+ */
+pid_t
+process_reap(pid_t pid, int *esp, int flags)
+{
+#ifdef _WINDOWS
+
+ return 0;
+
+#else /* UNIX */
+ WAITSTATUS_T wstatus;
+ pid_t rv;
+ int wflags;
+
+#if HAVE_WAITPID
+
+ wflags = 0;
+
+#ifdef WNOHANG
+ if(flags & PR_NOHANG)
+ wflags |= WNOHANG;
+#endif
+
+ while (((rv = waitpid(pid, &wstatus, wflags)) < 0) && (errno != ECHILD));
+
+#elif HAVE_WAIT4
+
+ wflags = 0;
+
+#ifdef WNOHANG
+ if(flags & PR_NOHANG)
+ wflags |= WNOHANG;
+#endif
+
+ while (((rv = wait4(pid,&wstatus,wflags,NULL)) < 0) && (errno != ECHILD));
+
+#elif HAVE_WAIT
+
+ while (((rv = wait(&wstatus)) != pid) && ((rv > 0) || (errno != ECHILD)));
+
+#else
+
+ /* BUG: BAIL */
+
+#endif
+
+ if(rv > 0)
+ *esp = (WIFEXITED(wstatus)) ? (int) WEXITSTATUS(wstatus) : -1;
+
+ return(rv);
+#endif /* UNIX */
+}
+
+
+#ifndef _WINDOWS
+RETSIGTYPE
+pipe_alarm(int sig)
+{
+ if(child_pid)
+ kill(child_pid, SIGINT);
+}
+#endif /* !_WINDOWS */
+
+
+#ifdef _WINDOWS
+/*
+ * Wrapper around mswin_exec_and_wait()
+ */
+int
+pipe_mswin_exec_wrapper(char *whatsit,
+ PIPE_S *syspipe, unsigned flags,
+ void (*pipecb_f)(PIPE_S *, int, void *),
+ void (*piperr_f)(char *))
+{
+ int rv;
+
+ flags |= MSWIN_EAW_CTRL_C_CANCELS;
+
+ if(pipecb_f)
+ (*pipecb_f)(syspipe, OSB_PRE_OPEN, NULL);
+
+ rv = mswin_exec_and_wait(whatsit, syspipe->command,
+ syspipe->infile, syspipe->outfile,
+ &syspipe->exit_code, flags);
+
+ if(pipecb_f)
+ (*pipecb_f)(syspipe, OSB_POST_OPEN, (void *)rv);
+
+ return rv;
+}
+#endif