text: /*
   * Copyright (C) by Argonne National Laboratory
   *     See COPYRIGHT in top-level directory
   */
  
  #include "hydra_spawn.h"
  #include "hydra_err.h"
  #include "hydra_sock.h"
  #include "hydra_topo.h"
  
  HYD_status HYD_spawn(char **client_arg, int envcount, char *const *const env, int *in, int *out,
                       int *err, int *pid, int idx)
  {
      int inpipe[2], outpipe[2], errpipe[2], tpid, i;
      char *str;
      HYD_status status = HYD_SUCCESS;
  
      HYD_FUNC_ENTER();
  
      if (in && (pipe(inpipe) < 0))
          HYD_ERR_SETANDJUMP(status, HYD_ERR_SOCK, "pipe error (%s)\n", MPL_strerror(errno));
  
      if (out && (pipe(outpipe) < 0))
          HYD_ERR_SETANDJUMP(status, HYD_ERR_SOCK, "pipe error (%s)\n", MPL_strerror(errno));
  
      if (err && (pipe(errpipe) < 0))
          HYD_ERR_SETANDJUMP(status, HYD_ERR_SOCK, "pipe error (%s)\n", MPL_strerror(errno));
  
      /* Fork off the process */
      tpid = fork();
      if (tpid == 0) {    /* Child process */
  
  #if defined HAVE_SETSID
          setsid();
  #endif /* HAVE_SETSID */
  
          close(STDIN_FILENO);
          if (in) {
              close(inpipe[1]);
              if (inpipe[0] != STDIN_FILENO && dup2(inpipe[0], STDIN_FILENO) < 0)
                  HYD_ERR_SETANDJUMP(status, HYD_ERR_SOCK, "dup2 error (%s)\n", MPL_strerror(errno));
          }
  
          close(STDOUT_FILENO);
          if (out) {
              close(outpipe[0]);
              if (outpipe[1] != STDOUT_FILENO && dup2(outpipe[1], STDOUT_FILENO) < 0)
                  HYD_ERR_SETANDJUMP(status, HYD_ERR_SOCK, "dup2 error (%s)\n", MPL_strerror(errno));
          }
  
          close(STDERR_FILENO);
          if (err) {
              close(errpipe[0]);
              if (errpipe[1] != STDERR_FILENO && dup2(errpipe[1], STDERR_FILENO) < 0)
                  HYD_ERR_SETANDJUMP(status, HYD_ERR_SOCK, "dup2 error (%s)\n", MPL_strerror(errno));
          }
  
          /* Forced environment overwrites existing environment */
          for (i = 0; i < envcount; i++) {
              str = MPL_strdup(env[i]);
              putenv(str);
          }
  
          if (idx >= 0) {
              status = HYD_topo_bind(idx);
              HYD_ERR_POP(status, "bind process failed\n");
          }
  
          if (execvp(client_arg[0], client_arg) < 0) {
              /* The child process should never get back to the proxy
               * code; if there is an error, just throw it here and
               * exit. */
              HYD_ERR_PRINT("execvp error on file %s (%s)\n", client_arg[0], MPL_strerror(errno));
              exit(-1);
          }
      } else {    /* Parent process */
          if (out)
              close(outpipe[1]);
          if (err)
              close(errpipe[1]);
          if (in) {
              close(inpipe[0]);
              *in = inpipe[1];
  
              status = HYD_sock_cloexec(*in);
              HYD_ERR_POP(status, "unable to set close on exec\n");
          }
          if (out)
              *out = outpipe[0];
          if (err)
              *err = errpipe[0];
      }
  
      if (pid)
          *pid = tpid;
  
    fn_exit:
      HYD_FUNC_EXIT();
      return status;
  
    fn_fail:
      goto fn_exit;
  }
  