public static int bgexec(String[] cmdarray, File workdir, File logfile, boolean inheritLogfile,
      Map<String, String> env) throws IOException {
    String commandShell =
        System.getProperty(GeodeGlossary.GEMFIRE_PREFIX + "commandShell", "bash");
    if (cmdarray.length == 0) {
      throw new java.lang.IndexOutOfBoundsException();
    }
    boolean isWindows = false;
    String os = System.getProperty("os.name");
    if (os != null) {
      if (os.indexOf("Windows") != -1) {
        isWindows = true;
      }
    }
    for (int i = 0; i < cmdarray.length; i++) {
      if (cmdarray[i] == null) {
        throw new NullPointerException();
      }
      if (isWindows) {
        if (i == 0) {
          // do the following before quotes get added.
          File cmd = new File(cmdarray[0]);
          if (!cmd.exists()) {
            cmd = new File(cmdarray[0] + ".exe");
            if (cmd.exists()) {
              cmdarray[0] = cmd.getPath();
            }
          }
        }
        String s = cmdarray[i];
        if (i != 0) {
          if (s.length() == 0) {
            cmdarray[i] = "\"\""; // fix for bug 22207
          } else if ((s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0)) {
            String unquotedS = s;
            if (s.indexOf('\"') != -1) {
              // Note that Windows provides no way to embed a double
              // quote in a double quoted string so need to remove
              // any internal quotes and let the outer quotes
              // preserve the whitespace.
              StringBuilder b = new StringBuilder(s);
              int quoteIdx = s.lastIndexOf('\"');
              while (quoteIdx != -1) {
                b.deleteCharAt(quoteIdx);
                quoteIdx = s.lastIndexOf('\"', quoteIdx - 1);
              }
              unquotedS = b.toString();
            }
            // It has whitespace and its not quoted
            cmdarray[i] = '"' + unquotedS + '"';
          }
        }
      }
    }
    File cmd = new File(cmdarray[0]);
    if (!cmd.exists()) {
      throw new IOException(String.format("the executable %s does not exist",
          cmd.getPath()));
    }
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
      security.checkExec(cmdarray[0]);
    }
    if (workdir != null && !workdir.isDirectory()) {
      String curDir = new File("").getAbsolutePath();
      System.out.println(
          String.format("WARNING: %s is not a directory. Defaulting to current directory %s.",
              workdir, curDir));
      workdir = null;
    }
    if (workdir == null) {
      workdir = new File("").getAbsoluteFile();
    }
    if (logfile == null) {
      logfile = File.createTempFile("bgexec", ".log", workdir);
    }
    if (!logfile.isAbsolute()) {
      // put it in the working directory
      logfile = new File(workdir, logfile.getPath());
    }
    // fix for bug 24575
    if (logfile.exists()) {
      // it already exists so make sure its a file and can be written
      if (!logfile.isFile()) {
        throw new IOException(String.format("The log file %s was not a normal file.",
            logfile.getPath()));
      }
      if (!logfile.canWrite()) {
        throw new IOException(String.format("Need write access for the log file %s.",
            logfile.getPath()));
      }
    } else {
      try {
        logfile.createNewFile();
      } catch (IOException io) {
        throw new IOException(String.format("Could not create log file %s because: %s.",
            logfile.getPath(), io.getMessage()));
      }
    }
    String trace = System.getProperty("org.apache.geode.logging.internal.OSProcess.trace");
    if (trace != null && trace.length() > 0) {
      for (int i = 0; i < cmdarray.length; i++) {
        System.out.println("cmdarray[" + i + "] = " + cmdarray[i]);
      }
      System.out.println("workdir=" + workdir.getPath());
      System.out.println("logfile=" + logfile.getPath());
    }
    int result = 0;

    StringBuilder sb = new StringBuilder();
    Vector<String> cmdVec = new Vector<>();
    // Add shell code to spawn a process silently
    if (isWindows) {
      cmdVec.add("cmd.exe");
      cmdVec.add("/c");
      sb.append("start /b \"\" ");
    } else {
      // to address issue with users that don't have bash shell installed
      if (commandShell.equals("bash")) {
        cmdVec.add("bash");
        cmdVec.add("--norc");
        cmdVec.add("-c");
      } else {
        cmdVec.add(commandShell);
      }
    }
    // Add the actual command
    for (int i = 0; i < cmdarray.length; i++) {
      if (i != 0) {
        sb.append(" ");
      }
      if (cmdarray[i].length() != 0 && cmdarray[i].charAt(0) == '\"') {
        // The token has already been quoted, see bug 40835
        sb.append(cmdarray[i]);
      } else {
        sb.append("\"");
        sb.append(cmdarray[i]);
        sb.append("\"");
      }
    }
    // Add the IO redirction code, this prevents hangs and IO blocking
    sb.append(" >> ");
    sb.append(logfile.getPath());
    sb.append(" 2>&1");
    if (isWindows) {
      sb.append(" <NUL");
    } else {
      sb.append(" </dev/null &");
    }
    cmdVec.add(sb.toString());

    String[] cmdStrings = cmdVec.toArray(new String[0]);
    if (trace != null && trace.length() > 0) {
      for (int i = 0; i < cmdStrings.length; i++) {
        System.out.println("cmdStrings[" + i + "] = " + cmdStrings[i]);
      }
      System.out.println("workdir=" + workdir.getPath());
      System.out.println("logfile=" + logfile.getPath());
    }
    final ProcessBuilder procBuilder = new ProcessBuilder(cmdStrings);
    if (env != null && env.size() > 0) {
      // adjust the environment variables inheriting from parent
      procBuilder.environment().putAll(env);
    }
    procBuilder.directory(workdir);
    final Process process = procBuilder.start();
    try {
      process.getInputStream().close();
    } catch (IOException ignore) {
    }
    try {
      process.getOutputStream().close();
    } catch (IOException ignore) {
    }
    try {
      process.getErrorStream().close();
    } catch (IOException ignore) {
    }
    try {
      // short count = 1000;
      boolean processIsStillRunning = true;
      while (processIsStillRunning) {
        Thread.sleep(10);
        try {
          process.exitValue();
          processIsStillRunning = false;
        } catch (IllegalThreadStateException itse) {
          // Ignore this, we are polling the exitStatus
          // instead of using the blocking Process#waitFor()
        }
      }
    } catch (InterruptedException ie) {
      Thread.currentThread().interrupt();
    }

    return result; // Always 0 for pureJava
  }
Starts execution of the specified command and arguments in a separate detached process in the
specified working directory writing output to the specified log file.
<p>
If there is a security manager, its <code>checkExec</code> method is called with the first
component of the array <code>cmdarray</code> as its argument. This may result in a security
exception.
<p>
Given an array of strings <code>cmdarray</code>, representing the tokens of a command line,
this method creates a new process in which to execute the specified command.

@param cmdarray array containing the command to call and its arguments.
@param workdir the current directory of the created process; null causes working directory to
       default to the current directory.
@param logfile the file the created process will write stdout and stderr to; null causes a
       default log file name to be used.
@param inheritLogfile can be set to false if the child process is willing to create its own log
       file. Setting to false can help on Windows because it keeps the child process from
       inheriting handles from the parent.
@param env any extra environment variables as key,value map; these will be in addition to those
       inherited from the parent process and will overwrite same keys
@return the process id of the created process; -1 on failure
@exception SecurityException if the current thread cannot create a subprocess.
@see java.lang.SecurityException
@see java.lang.SecurityManager#checkExec(java.lang.String)
geode-logging/src/main/java/org/apache/geode/logging/internal/OSProcess.java