|  | @@ -142,236 +142,6 @@ tor_join_win_cmdline(const char *argv[])
 | 
	
		
			
				|  |  |    return joined_argv;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#ifndef _WIN32
 | 
	
		
			
				|  |  | -/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in
 | 
	
		
			
				|  |  | - * <b>hex_errno</b>.  Called between fork and _exit, so must be signal-handler
 | 
	
		
			
				|  |  | - * safe.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * <b>hex_errno</b> must have at least HEX_ERRNO_SIZE+1 bytes available.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded
 | 
	
		
			
				|  |  | - * with spaces. CHILD_STATE indicates where
 | 
	
		
			
				|  |  | - * in the process of starting the child process did the failure occur (see
 | 
	
		
			
				|  |  | - * CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of
 | 
	
		
			
				|  |  | - * errno when the failure occurred.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * On success return the number of characters added to hex_errno, not counting
 | 
	
		
			
				|  |  | - * the terminating NUL; return -1 on error.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -STATIC int
 | 
	
		
			
				|  |  | -format_helper_exit_status(unsigned char child_state, int saved_errno,
 | 
	
		
			
				|  |  | -                          char *hex_errno)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  unsigned int unsigned_errno;
 | 
	
		
			
				|  |  | -  int written, left;
 | 
	
		
			
				|  |  | -  char *cur;
 | 
	
		
			
				|  |  | -  size_t i;
 | 
	
		
			
				|  |  | -  int res = -1;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Fill hex_errno with spaces, and a trailing newline (memset may
 | 
	
		
			
				|  |  | -     not be signal handler safe, so we can't use it) */
 | 
	
		
			
				|  |  | -  for (i = 0; i < (HEX_ERRNO_SIZE - 1); i++)
 | 
	
		
			
				|  |  | -    hex_errno[i] = ' ';
 | 
	
		
			
				|  |  | -  hex_errno[HEX_ERRNO_SIZE - 1] = '\n';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Convert errno to be unsigned for hex conversion */
 | 
	
		
			
				|  |  | -  if (saved_errno < 0) {
 | 
	
		
			
				|  |  | -    // Avoid overflow on the cast to unsigned int when result is INT_MIN
 | 
	
		
			
				|  |  | -    // by adding 1 to the signed int negative value,
 | 
	
		
			
				|  |  | -    // then, after it has been negated and cast to unsigned,
 | 
	
		
			
				|  |  | -    // adding the original 1 back (the double-addition is intentional).
 | 
	
		
			
				|  |  | -    // Otherwise, the cast to signed could cause a temporary int
 | 
	
		
			
				|  |  | -    // to equal INT_MAX + 1, which is undefined.
 | 
	
		
			
				|  |  | -    unsigned_errno = ((unsigned int) -(saved_errno + 1)) + 1;
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    unsigned_errno = (unsigned int) saved_errno;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /*
 | 
	
		
			
				|  |  | -   * Count how many chars of space we have left, and keep a pointer into the
 | 
	
		
			
				|  |  | -   * current point in the buffer.
 | 
	
		
			
				|  |  | -   */
 | 
	
		
			
				|  |  | -  left = HEX_ERRNO_SIZE+1;
 | 
	
		
			
				|  |  | -  cur = hex_errno;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Emit child_state */
 | 
	
		
			
				|  |  | -  written = format_hex_number_sigsafe(child_state, cur, left);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (written <= 0)
 | 
	
		
			
				|  |  | -    goto err;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Adjust left and cur */
 | 
	
		
			
				|  |  | -  left -= written;
 | 
	
		
			
				|  |  | -  cur += written;
 | 
	
		
			
				|  |  | -  if (left <= 0)
 | 
	
		
			
				|  |  | -    goto err;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Now the '/' */
 | 
	
		
			
				|  |  | -  *cur = '/';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Adjust left and cur */
 | 
	
		
			
				|  |  | -  ++cur;
 | 
	
		
			
				|  |  | -  --left;
 | 
	
		
			
				|  |  | -  if (left <= 0)
 | 
	
		
			
				|  |  | -    goto err;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Need minus? */
 | 
	
		
			
				|  |  | -  if (saved_errno < 0) {
 | 
	
		
			
				|  |  | -    *cur = '-';
 | 
	
		
			
				|  |  | -    ++cur;
 | 
	
		
			
				|  |  | -    --left;
 | 
	
		
			
				|  |  | -    if (left <= 0)
 | 
	
		
			
				|  |  | -      goto err;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Emit unsigned_errno */
 | 
	
		
			
				|  |  | -  written = format_hex_number_sigsafe(unsigned_errno, cur, left);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (written <= 0)
 | 
	
		
			
				|  |  | -    goto err;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Adjust left and cur */
 | 
	
		
			
				|  |  | -  left -= written;
 | 
	
		
			
				|  |  | -  cur += written;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Check that we have enough space left for a newline and a NUL */
 | 
	
		
			
				|  |  | -  if (left <= 1)
 | 
	
		
			
				|  |  | -    goto err;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Emit the newline and NUL */
 | 
	
		
			
				|  |  | -  *cur++ = '\n';
 | 
	
		
			
				|  |  | -  *cur++ = '\0';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  res = (int)(cur - hex_errno - 1);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  goto done;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | - err:
 | 
	
		
			
				|  |  | -  /*
 | 
	
		
			
				|  |  | -   * In error exit, just write a '\0' in the first char so whatever called
 | 
	
		
			
				|  |  | -   * this at least won't fall off the end.
 | 
	
		
			
				|  |  | -   */
 | 
	
		
			
				|  |  | -  *hex_errno = '\0';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | - done:
 | 
	
		
			
				|  |  | -  return res;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -#endif /* !defined(_WIN32) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/* Maximum number of file descriptors, if we cannot get it via sysconf() */
 | 
	
		
			
				|  |  | -#define DEFAULT_MAX_FD 256
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Terminate the process of <b>process_handle</b>, if that process has not
 | 
	
		
			
				|  |  | - * already exited.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Return 0 if we succeeded in terminating the process (or if the process
 | 
	
		
			
				|  |  | - * already exited), and -1 if we tried to kill the process but failed.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Based on code originally borrowed from Python's os.kill. */
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -tor_terminate_process(process_handle_t *process_handle)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -  if (tor_get_exit_code(process_handle, 0, NULL) == PROCESS_EXIT_RUNNING) {
 | 
	
		
			
				|  |  | -    HANDLE handle = process_handle->pid.hProcess;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (!TerminateProcess(handle, 0))
 | 
	
		
			
				|  |  | -      return -1;
 | 
	
		
			
				|  |  | -    else
 | 
	
		
			
				|  |  | -      return 0;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -#else /* !(defined(_WIN32)) */
 | 
	
		
			
				|  |  | -  if (process_handle->waitpid_cb) {
 | 
	
		
			
				|  |  | -    /* We haven't got a waitpid yet, so we can just kill off the process. */
 | 
	
		
			
				|  |  | -    return kill(process_handle->pid, SIGTERM);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -#endif /* defined(_WIN32) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return 0; /* We didn't need to kill the process, so report success */
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Return the Process ID of <b>process_handle</b>. */
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -tor_process_get_pid(process_handle_t *process_handle)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -  return (int) process_handle->pid.dwProcessId;
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -  return (int) process_handle->pid;
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -HANDLE
 | 
	
		
			
				|  |  | -tor_process_get_stdout_pipe(process_handle_t *process_handle)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  return process_handle->stdout_pipe;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -#else /* !(defined(_WIN32)) */
 | 
	
		
			
				|  |  | -/* DOCDOC tor_process_get_stdout_pipe */
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -tor_process_get_stdout_pipe(process_handle_t *process_handle)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  return process_handle->stdout_pipe;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -#endif /* defined(_WIN32) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/* DOCDOC process_handle_new */
 | 
	
		
			
				|  |  | -static process_handle_t *
 | 
	
		
			
				|  |  | -process_handle_new(void)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  process_handle_t *out = tor_malloc_zero(sizeof(process_handle_t));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -  out->stdin_pipe = INVALID_HANDLE_VALUE;
 | 
	
		
			
				|  |  | -  out->stdout_pipe = INVALID_HANDLE_VALUE;
 | 
	
		
			
				|  |  | -  out->stderr_pipe = INVALID_HANDLE_VALUE;
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -  out->stdin_pipe = -1;
 | 
	
		
			
				|  |  | -  out->stdout_pipe = -1;
 | 
	
		
			
				|  |  | -  out->stderr_pipe = -1;
 | 
	
		
			
				|  |  | -#endif /* defined(_WIN32) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return out;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifndef _WIN32
 | 
	
		
			
				|  |  | -/** Invoked when a process that we've launched via tor_spawn_background() has
 | 
	
		
			
				|  |  | - * been found to have terminated.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -static void
 | 
	
		
			
				|  |  | -process_handle_waitpid_cb(int status, void *arg)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  process_handle_t *process_handle = arg;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  process_handle->waitpid_exit_status = status;
 | 
	
		
			
				|  |  | -  clear_waitpid_callback(process_handle->waitpid_cb);
 | 
	
		
			
				|  |  | -  if (process_handle->status == PROCESS_STATUS_RUNNING)
 | 
	
		
			
				|  |  | -    process_handle->status = PROCESS_STATUS_NOTRUNNING;
 | 
	
		
			
				|  |  | -  process_handle->waitpid_cb = 0;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -#endif /* !defined(_WIN32) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @name child-process states
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Each of these values represents a possible state that a child process can
 | 
	
		
			
				|  |  | - * be in.  They're used to determine what to say when telling the parent how
 | 
	
		
			
				|  |  | - * far along we were before failure.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * @{
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -#define CHILD_STATE_INIT 0
 | 
	
		
			
				|  |  | -#define CHILD_STATE_PIPE 1
 | 
	
		
			
				|  |  | -#define CHILD_STATE_MAXFD 2
 | 
	
		
			
				|  |  | -#define CHILD_STATE_FORK 3
 | 
	
		
			
				|  |  | -#define CHILD_STATE_DUPOUT 4
 | 
	
		
			
				|  |  | -#define CHILD_STATE_DUPERR 5
 | 
	
		
			
				|  |  | -#define CHILD_STATE_DUPIN 6
 | 
	
		
			
				|  |  | -#define CHILD_STATE_CLOSEFD 7
 | 
	
		
			
				|  |  | -#define CHILD_STATE_EXEC 8
 | 
	
		
			
				|  |  | -#define CHILD_STATE_FAILEXEC 9
 | 
	
		
			
				|  |  | -/** @} */
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  |   * Boolean.  If true, then Tor may call execve or CreateProcess via
 | 
	
		
			
				|  |  |   * tor_spawn_background.
 | 
	
	
		
			
				|  | @@ -386,851 +156,3 @@ tor_disable_spawning_background_processes(void)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    may_spawn_background_process = 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -/** Start a program in the background. If <b>filename</b> contains a '/', then
 | 
	
		
			
				|  |  | - * it will be treated as an absolute or relative path.  Otherwise, on
 | 
	
		
			
				|  |  | - * non-Windows systems, the system path will be searched for <b>filename</b>.
 | 
	
		
			
				|  |  | - * On Windows, only the current directory will be searched. Here, to search the
 | 
	
		
			
				|  |  | - * system path (as well as the application directory, current working
 | 
	
		
			
				|  |  | - * directory, and system directories), set filename to NULL.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * The strings in <b>argv</b> will be passed as the command line arguments of
 | 
	
		
			
				|  |  | - * the child program (following convention, argv[0] should normally be the
 | 
	
		
			
				|  |  | - * filename of the executable, and this must be the case if <b>filename</b> is
 | 
	
		
			
				|  |  | - * NULL). The last element of argv must be NULL. A handle to the child process
 | 
	
		
			
				|  |  | - * will be returned in process_handle (which must be non-NULL). Read
 | 
	
		
			
				|  |  | - * process_handle.status to find out if the process was successfully launched.
 | 
	
		
			
				|  |  | - * For convenience, process_handle.status is returned by this function.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Some parts of this code are based on the POSIX subprocess module from
 | 
	
		
			
				|  |  | - * Python, and example code from
 | 
	
		
			
				|  |  | - * http://msdn.microsoft.com/en-us/library/ms682499%28v=vs.85%29.aspx.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -tor_spawn_background(const char *const filename, const char **argv,
 | 
	
		
			
				|  |  | -                     process_environment_t *env,
 | 
	
		
			
				|  |  | -                     process_handle_t **process_handle_out)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  if (BUG(may_spawn_background_process == 0)) {
 | 
	
		
			
				|  |  | -    /* We should never reach this point if we're forbidden to spawn
 | 
	
		
			
				|  |  | -     * processes. Instead we should have caught the attempt earlier. */
 | 
	
		
			
				|  |  | -    return PROCESS_STATUS_ERROR;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -  HANDLE stdout_pipe_read = NULL;
 | 
	
		
			
				|  |  | -  HANDLE stdout_pipe_write = NULL;
 | 
	
		
			
				|  |  | -  HANDLE stderr_pipe_read = NULL;
 | 
	
		
			
				|  |  | -  HANDLE stderr_pipe_write = NULL;
 | 
	
		
			
				|  |  | -  HANDLE stdin_pipe_read = NULL;
 | 
	
		
			
				|  |  | -  HANDLE stdin_pipe_write = NULL;
 | 
	
		
			
				|  |  | -  process_handle_t *process_handle;
 | 
	
		
			
				|  |  | -  int status;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  STARTUPINFOA siStartInfo;
 | 
	
		
			
				|  |  | -  BOOL retval = FALSE;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  SECURITY_ATTRIBUTES saAttr;
 | 
	
		
			
				|  |  | -  char *joined_argv;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
 | 
	
		
			
				|  |  | -  saAttr.bInheritHandle = TRUE;
 | 
	
		
			
				|  |  | -  /* TODO: should we set explicit security attributes? (#2046, comment 5) */
 | 
	
		
			
				|  |  | -  saAttr.lpSecurityDescriptor = NULL;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Assume failure to start process */
 | 
	
		
			
				|  |  | -  status = PROCESS_STATUS_ERROR;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Set up pipe for stdout */
 | 
	
		
			
				|  |  | -  if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, &saAttr, 0)) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -      "Failed to create pipe for stdout communication with child process: %s",
 | 
	
		
			
				|  |  | -      format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -    return status;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (!SetHandleInformation(stdout_pipe_read, HANDLE_FLAG_INHERIT, 0)) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -      "Failed to configure pipe for stdout communication with child "
 | 
	
		
			
				|  |  | -      "process: %s", format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -    return status;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Set up pipe for stderr */
 | 
	
		
			
				|  |  | -  if (!CreatePipe(&stderr_pipe_read, &stderr_pipe_write, &saAttr, 0)) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -      "Failed to create pipe for stderr communication with child process: %s",
 | 
	
		
			
				|  |  | -      format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -    return status;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (!SetHandleInformation(stderr_pipe_read, HANDLE_FLAG_INHERIT, 0)) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -      "Failed to configure pipe for stderr communication with child "
 | 
	
		
			
				|  |  | -      "process: %s", format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -    return status;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Set up pipe for stdin */
 | 
	
		
			
				|  |  | -  if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, &saAttr, 0)) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -      "Failed to create pipe for stdin communication with child process: %s",
 | 
	
		
			
				|  |  | -      format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -    return status;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (!SetHandleInformation(stdin_pipe_write, HANDLE_FLAG_INHERIT, 0)) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -      "Failed to configure pipe for stdin communication with child "
 | 
	
		
			
				|  |  | -      "process: %s", format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -    return status;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Create the child process */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Windows expects argv to be a whitespace delimited string, so join argv up
 | 
	
		
			
				|  |  | -   */
 | 
	
		
			
				|  |  | -  joined_argv = tor_join_win_cmdline(argv);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  process_handle = process_handle_new();
 | 
	
		
			
				|  |  | -  process_handle->status = status;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  ZeroMemory(&(process_handle->pid), sizeof(PROCESS_INFORMATION));
 | 
	
		
			
				|  |  | -  ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
 | 
	
		
			
				|  |  | -  siStartInfo.cb = sizeof(STARTUPINFO);
 | 
	
		
			
				|  |  | -  siStartInfo.hStdError = stderr_pipe_write;
 | 
	
		
			
				|  |  | -  siStartInfo.hStdOutput = stdout_pipe_write;
 | 
	
		
			
				|  |  | -  siStartInfo.hStdInput = stdin_pipe_read;
 | 
	
		
			
				|  |  | -  siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Create the child process */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  retval = CreateProcessA(filename,      // module name
 | 
	
		
			
				|  |  | -                 joined_argv,   // command line
 | 
	
		
			
				|  |  | -  /* TODO: should we set explicit security attributes? (#2046, comment 5) */
 | 
	
		
			
				|  |  | -                 NULL,          // process security attributes
 | 
	
		
			
				|  |  | -                 NULL,          // primary thread security attributes
 | 
	
		
			
				|  |  | -                 TRUE,          // handles are inherited
 | 
	
		
			
				|  |  | -  /*(TODO: set CREATE_NEW CONSOLE/PROCESS_GROUP to make GetExitCodeProcess()
 | 
	
		
			
				|  |  | -   * work?) */
 | 
	
		
			
				|  |  | -                 CREATE_NO_WINDOW,             // creation flags
 | 
	
		
			
				|  |  | -                 (env==NULL) ? NULL : env->windows_environment_block,
 | 
	
		
			
				|  |  | -                 NULL,          // use parent's current directory
 | 
	
		
			
				|  |  | -                 &siStartInfo,  // STARTUPINFO pointer
 | 
	
		
			
				|  |  | -                 &(process_handle->pid));  // receives PROCESS_INFORMATION
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  tor_free(joined_argv);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!retval) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -      "Failed to create child process %s: %s", filename?filename:argv[0],
 | 
	
		
			
				|  |  | -      format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -    tor_free(process_handle);
 | 
	
		
			
				|  |  | -  } else  {
 | 
	
		
			
				|  |  | -    /* TODO: Close hProcess and hThread in process_handle->pid? */
 | 
	
		
			
				|  |  | -    process_handle->stdout_pipe = stdout_pipe_read;
 | 
	
		
			
				|  |  | -    process_handle->stderr_pipe = stderr_pipe_read;
 | 
	
		
			
				|  |  | -    process_handle->stdin_pipe = stdin_pipe_write;
 | 
	
		
			
				|  |  | -    status = process_handle->status = PROCESS_STATUS_RUNNING;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* TODO: Close pipes on exit */
 | 
	
		
			
				|  |  | -  *process_handle_out = process_handle;
 | 
	
		
			
				|  |  | -  return status;
 | 
	
		
			
				|  |  | -#else /* !(defined(_WIN32)) */
 | 
	
		
			
				|  |  | -  pid_t pid;
 | 
	
		
			
				|  |  | -  int stdout_pipe[2];
 | 
	
		
			
				|  |  | -  int stderr_pipe[2];
 | 
	
		
			
				|  |  | -  int stdin_pipe[2];
 | 
	
		
			
				|  |  | -  int fd, retval;
 | 
	
		
			
				|  |  | -  process_handle_t *process_handle;
 | 
	
		
			
				|  |  | -  int status;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  const char *error_message = SPAWN_ERROR_MESSAGE;
 | 
	
		
			
				|  |  | -  size_t error_message_length;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Represents where in the process of spawning the program is;
 | 
	
		
			
				|  |  | -     this is used for printing out the error message */
 | 
	
		
			
				|  |  | -  unsigned char child_state = CHILD_STATE_INIT;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  char hex_errno[HEX_ERRNO_SIZE + 2]; /* + 1 should be sufficient actually */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  static int max_fd = -1;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  status = PROCESS_STATUS_ERROR;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* We do the strlen here because strlen() is not signal handler safe,
 | 
	
		
			
				|  |  | -     and we are not allowed to use unsafe functions between fork and exec */
 | 
	
		
			
				|  |  | -  error_message_length = strlen(error_message);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // child_state = CHILD_STATE_PIPE;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Set up pipe for redirecting stdout, stderr, and stdin of child */
 | 
	
		
			
				|  |  | -  retval = pipe(stdout_pipe);
 | 
	
		
			
				|  |  | -  if (-1 == retval) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -      "Failed to set up pipe for stdout communication with child process: %s",
 | 
	
		
			
				|  |  | -       strerror(errno));
 | 
	
		
			
				|  |  | -    return status;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  retval = pipe(stderr_pipe);
 | 
	
		
			
				|  |  | -  if (-1 == retval) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -      "Failed to set up pipe for stderr communication with child process: %s",
 | 
	
		
			
				|  |  | -      strerror(errno));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    close(stdout_pipe[0]);
 | 
	
		
			
				|  |  | -    close(stdout_pipe[1]);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return status;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  retval = pipe(stdin_pipe);
 | 
	
		
			
				|  |  | -  if (-1 == retval) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -      "Failed to set up pipe for stdin communication with child process: %s",
 | 
	
		
			
				|  |  | -       strerror(errno));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    close(stdout_pipe[0]);
 | 
	
		
			
				|  |  | -    close(stdout_pipe[1]);
 | 
	
		
			
				|  |  | -    close(stderr_pipe[0]);
 | 
	
		
			
				|  |  | -    close(stderr_pipe[1]);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return status;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // child_state = CHILD_STATE_MAXFD;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifdef _SC_OPEN_MAX
 | 
	
		
			
				|  |  | -  if (-1 == max_fd) {
 | 
	
		
			
				|  |  | -    max_fd = (int) sysconf(_SC_OPEN_MAX);
 | 
	
		
			
				|  |  | -    if (max_fd == -1) {
 | 
	
		
			
				|  |  | -      max_fd = DEFAULT_MAX_FD;
 | 
	
		
			
				|  |  | -      log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -               "Cannot find maximum file descriptor, assuming %d", max_fd);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -#else /* !(defined(_SC_OPEN_MAX)) */
 | 
	
		
			
				|  |  | -  max_fd = DEFAULT_MAX_FD;
 | 
	
		
			
				|  |  | -#endif /* defined(_SC_OPEN_MAX) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // child_state = CHILD_STATE_FORK;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  pid = fork();
 | 
	
		
			
				|  |  | -  if (0 == pid) {
 | 
	
		
			
				|  |  | -    /* In child */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
 | 
	
		
			
				|  |  | -    /* Attempt to have the kernel issue a SIGTERM if the parent
 | 
	
		
			
				|  |  | -     * goes away. Certain attributes of the binary being execve()ed
 | 
	
		
			
				|  |  | -     * will clear this during the execve() call, but it's better
 | 
	
		
			
				|  |  | -     * than nothing.
 | 
	
		
			
				|  |  | -     */
 | 
	
		
			
				|  |  | -    prctl(PR_SET_PDEATHSIG, SIGTERM);
 | 
	
		
			
				|  |  | -#endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    child_state = CHILD_STATE_DUPOUT;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* Link child stdout to the write end of the pipe */
 | 
	
		
			
				|  |  | -    retval = dup2(stdout_pipe[1], STDOUT_FILENO);
 | 
	
		
			
				|  |  | -    if (-1 == retval)
 | 
	
		
			
				|  |  | -        goto error;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    child_state = CHILD_STATE_DUPERR;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* Link child stderr to the write end of the pipe */
 | 
	
		
			
				|  |  | -    retval = dup2(stderr_pipe[1], STDERR_FILENO);
 | 
	
		
			
				|  |  | -    if (-1 == retval)
 | 
	
		
			
				|  |  | -        goto error;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    child_state = CHILD_STATE_DUPIN;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* Link child stdin to the read end of the pipe */
 | 
	
		
			
				|  |  | -    retval = dup2(stdin_pipe[0], STDIN_FILENO);
 | 
	
		
			
				|  |  | -    if (-1 == retval)
 | 
	
		
			
				|  |  | -      goto error;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // child_state = CHILD_STATE_CLOSEFD;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    close(stderr_pipe[0]);
 | 
	
		
			
				|  |  | -    close(stderr_pipe[1]);
 | 
	
		
			
				|  |  | -    close(stdout_pipe[0]);
 | 
	
		
			
				|  |  | -    close(stdout_pipe[1]);
 | 
	
		
			
				|  |  | -    close(stdin_pipe[0]);
 | 
	
		
			
				|  |  | -    close(stdin_pipe[1]);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* Close all other fds, including the read end of the pipe */
 | 
	
		
			
				|  |  | -    /* XXX: We should now be doing enough FD_CLOEXEC setting to make
 | 
	
		
			
				|  |  | -     * this needless. */
 | 
	
		
			
				|  |  | -    for (fd = STDERR_FILENO + 1; fd < max_fd; fd++) {
 | 
	
		
			
				|  |  | -      close(fd);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // child_state = CHILD_STATE_EXEC;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* Call the requested program. We need the cast because
 | 
	
		
			
				|  |  | -       execvp doesn't define argv as const, even though it
 | 
	
		
			
				|  |  | -       does not modify the arguments */
 | 
	
		
			
				|  |  | -    if (env)
 | 
	
		
			
				|  |  | -      execve(filename, (char *const *) argv, env->unixoid_environment_block);
 | 
	
		
			
				|  |  | -    else {
 | 
	
		
			
				|  |  | -      static char *new_env[] = { NULL };
 | 
	
		
			
				|  |  | -      execve(filename, (char *const *) argv, new_env);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* If we got here, the exec or open(/dev/null) failed */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    child_state = CHILD_STATE_FAILEXEC;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  error:
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -      /* XXX: are we leaking fds from the pipe? */
 | 
	
		
			
				|  |  | -      int n, err=0;
 | 
	
		
			
				|  |  | -      ssize_t nbytes;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      n = format_helper_exit_status(child_state, errno, hex_errno);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      if (n >= 0) {
 | 
	
		
			
				|  |  | -        /* Write the error message. GCC requires that we check the return
 | 
	
		
			
				|  |  | -           value, but there is nothing we can do if it fails */
 | 
	
		
			
				|  |  | -        /* TODO: Don't use STDOUT, use a pipe set up just for this purpose */
 | 
	
		
			
				|  |  | -        nbytes = write(STDOUT_FILENO, error_message, error_message_length);
 | 
	
		
			
				|  |  | -        err = (nbytes < 0);
 | 
	
		
			
				|  |  | -        nbytes = write(STDOUT_FILENO, hex_errno, n);
 | 
	
		
			
				|  |  | -        err += (nbytes < 0);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      _exit(err?254:255); // exit ok: in child.
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* Never reached, but avoids compiler warning */
 | 
	
		
			
				|  |  | -    return status; // LCOV_EXCL_LINE
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* In parent */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (-1 == pid) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL, "Failed to fork child process: %s", strerror(errno));
 | 
	
		
			
				|  |  | -    close(stdin_pipe[0]);
 | 
	
		
			
				|  |  | -    close(stdin_pipe[1]);
 | 
	
		
			
				|  |  | -    close(stdout_pipe[0]);
 | 
	
		
			
				|  |  | -    close(stdout_pipe[1]);
 | 
	
		
			
				|  |  | -    close(stderr_pipe[0]);
 | 
	
		
			
				|  |  | -    close(stderr_pipe[1]);
 | 
	
		
			
				|  |  | -    return status;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  process_handle = process_handle_new();
 | 
	
		
			
				|  |  | -  process_handle->status = status;
 | 
	
		
			
				|  |  | -  process_handle->pid = pid;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* TODO: If the child process forked but failed to exec, waitpid it */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Return read end of the pipes to caller, and close write end */
 | 
	
		
			
				|  |  | -  process_handle->stdout_pipe = stdout_pipe[0];
 | 
	
		
			
				|  |  | -  retval = close(stdout_pipe[1]);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (-1 == retval) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -            "Failed to close write end of stdout pipe in parent process: %s",
 | 
	
		
			
				|  |  | -            strerror(errno));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  process_handle->waitpid_cb = set_waitpid_callback(pid,
 | 
	
		
			
				|  |  | -                                                    process_handle_waitpid_cb,
 | 
	
		
			
				|  |  | -                                                    process_handle);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  process_handle->stderr_pipe = stderr_pipe[0];
 | 
	
		
			
				|  |  | -  retval = close(stderr_pipe[1]);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (-1 == retval) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -            "Failed to close write end of stderr pipe in parent process: %s",
 | 
	
		
			
				|  |  | -            strerror(errno));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Return write end of the stdin pipe to caller, and close the read end */
 | 
	
		
			
				|  |  | -  process_handle->stdin_pipe = stdin_pipe[1];
 | 
	
		
			
				|  |  | -  retval = close(stdin_pipe[0]);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (-1 == retval) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -            "Failed to close read end of stdin pipe in parent process: %s",
 | 
	
		
			
				|  |  | -            strerror(errno));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  status = process_handle->status = PROCESS_STATUS_RUNNING;
 | 
	
		
			
				|  |  | -  /* Set stdin/stdout/stderr pipes to be non-blocking */
 | 
	
		
			
				|  |  | -  if (fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK) < 0 ||
 | 
	
		
			
				|  |  | -      fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK) < 0 ||
 | 
	
		
			
				|  |  | -      fcntl(process_handle->stdin_pipe, F_SETFL, O_NONBLOCK) < 0) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL, "Failed to set stderror/stdout/stdin pipes "
 | 
	
		
			
				|  |  | -             "nonblocking in parent process: %s", strerror(errno));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  *process_handle_out = process_handle;
 | 
	
		
			
				|  |  | -  return status;
 | 
	
		
			
				|  |  | -#endif /* defined(_WIN32) */
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Destroy all resources allocated by the process handle in
 | 
	
		
			
				|  |  | - *  <b>process_handle</b>.
 | 
	
		
			
				|  |  | - *  If <b>also_terminate_process</b> is true, also terminate the
 | 
	
		
			
				|  |  | - *  process of the process handle. */
 | 
	
		
			
				|  |  | -MOCK_IMPL(void,
 | 
	
		
			
				|  |  | -tor_process_handle_destroy,(process_handle_t *process_handle,
 | 
	
		
			
				|  |  | -                            int also_terminate_process))
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  if (!process_handle)
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (also_terminate_process) {
 | 
	
		
			
				|  |  | -    if (tor_terminate_process(process_handle) < 0) {
 | 
	
		
			
				|  |  | -      const char *errstr =
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -        format_win32_error(GetLastError());
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -        strerror(errno);
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -      log_notice(LD_GENERAL, "Failed to terminate process with "
 | 
	
		
			
				|  |  | -                 "PID '%d' ('%s').", tor_process_get_pid(process_handle),
 | 
	
		
			
				|  |  | -                 errstr);
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      log_info(LD_GENERAL, "Terminated process with PID '%d'.",
 | 
	
		
			
				|  |  | -               tor_process_get_pid(process_handle));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  process_handle->status = PROCESS_STATUS_NOTRUNNING;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -  if (process_handle->stdout_pipe)
 | 
	
		
			
				|  |  | -    CloseHandle(process_handle->stdout_pipe);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (process_handle->stderr_pipe)
 | 
	
		
			
				|  |  | -    CloseHandle(process_handle->stderr_pipe);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (process_handle->stdin_pipe)
 | 
	
		
			
				|  |  | -    CloseHandle(process_handle->stdin_pipe);
 | 
	
		
			
				|  |  | -#else /* !(defined(_WIN32)) */
 | 
	
		
			
				|  |  | -  close(process_handle->stdout_pipe);
 | 
	
		
			
				|  |  | -  close(process_handle->stderr_pipe);
 | 
	
		
			
				|  |  | -  close(process_handle->stdin_pipe);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  clear_waitpid_callback(process_handle->waitpid_cb);
 | 
	
		
			
				|  |  | -#endif /* defined(_WIN32) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  memset(process_handle, 0x0f, sizeof(process_handle_t));
 | 
	
		
			
				|  |  | -  tor_free(process_handle);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Get the exit code of a process specified by <b>process_handle</b> and store
 | 
	
		
			
				|  |  | - * it in <b>exit_code</b>, if set to a non-NULL value.  If <b>block</b> is set
 | 
	
		
			
				|  |  | - * to true, the call will block until the process has exited.  Otherwise if
 | 
	
		
			
				|  |  | - * the process is still running, the function will return
 | 
	
		
			
				|  |  | - * PROCESS_EXIT_RUNNING, and exit_code will be left unchanged. Returns
 | 
	
		
			
				|  |  | - * PROCESS_EXIT_EXITED if the process did exit. If there is a failure,
 | 
	
		
			
				|  |  | - * PROCESS_EXIT_ERROR will be returned and the contents of exit_code (if
 | 
	
		
			
				|  |  | - * non-NULL) will be undefined. N.B. Under *nix operating systems, this will
 | 
	
		
			
				|  |  | - * probably not work in Tor, because waitpid() is called in main.c to reap any
 | 
	
		
			
				|  |  | - * terminated child processes.*/
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -tor_get_exit_code(process_handle_t *process_handle,
 | 
	
		
			
				|  |  | -                  int block, int *exit_code)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -  DWORD retval;
 | 
	
		
			
				|  |  | -  BOOL success;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (block) {
 | 
	
		
			
				|  |  | -    /* Wait for the process to exit */
 | 
	
		
			
				|  |  | -    retval = WaitForSingleObject(process_handle->pid.hProcess, INFINITE);
 | 
	
		
			
				|  |  | -    if (retval != WAIT_OBJECT_0) {
 | 
	
		
			
				|  |  | -      log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s",
 | 
	
		
			
				|  |  | -              (int)retval, format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -      return PROCESS_EXIT_ERROR;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    retval = WaitForSingleObject(process_handle->pid.hProcess, 0);
 | 
	
		
			
				|  |  | -    if (WAIT_TIMEOUT == retval) {
 | 
	
		
			
				|  |  | -      /* Process has not exited */
 | 
	
		
			
				|  |  | -      return PROCESS_EXIT_RUNNING;
 | 
	
		
			
				|  |  | -    } else if (retval != WAIT_OBJECT_0) {
 | 
	
		
			
				|  |  | -      log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s",
 | 
	
		
			
				|  |  | -               (int)retval, format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -      return PROCESS_EXIT_ERROR;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (exit_code != NULL) {
 | 
	
		
			
				|  |  | -    success = GetExitCodeProcess(process_handle->pid.hProcess,
 | 
	
		
			
				|  |  | -                                 (PDWORD)exit_code);
 | 
	
		
			
				|  |  | -    if (!success) {
 | 
	
		
			
				|  |  | -      log_warn(LD_GENERAL, "GetExitCodeProcess() failed: %s",
 | 
	
		
			
				|  |  | -               format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -      return PROCESS_EXIT_ERROR;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -#else /* !(defined(_WIN32)) */
 | 
	
		
			
				|  |  | -  int stat_loc;
 | 
	
		
			
				|  |  | -  int retval;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (process_handle->waitpid_cb) {
 | 
	
		
			
				|  |  | -    /* We haven't processed a SIGCHLD yet. */
 | 
	
		
			
				|  |  | -    retval = waitpid(process_handle->pid, &stat_loc, block?0:WNOHANG);
 | 
	
		
			
				|  |  | -    if (retval == process_handle->pid) {
 | 
	
		
			
				|  |  | -      clear_waitpid_callback(process_handle->waitpid_cb);
 | 
	
		
			
				|  |  | -      process_handle->waitpid_cb = NULL;
 | 
	
		
			
				|  |  | -      process_handle->waitpid_exit_status = stat_loc;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    /* We already got a SIGCHLD for this process, and handled it. */
 | 
	
		
			
				|  |  | -    retval = process_handle->pid;
 | 
	
		
			
				|  |  | -    stat_loc = process_handle->waitpid_exit_status;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!block && 0 == retval) {
 | 
	
		
			
				|  |  | -    /* Process has not exited */
 | 
	
		
			
				|  |  | -    return PROCESS_EXIT_RUNNING;
 | 
	
		
			
				|  |  | -  } else if (retval != process_handle->pid) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL, "waitpid() failed for PID %d: %s",
 | 
	
		
			
				|  |  | -             (int)process_handle->pid, strerror(errno));
 | 
	
		
			
				|  |  | -    return PROCESS_EXIT_ERROR;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!WIFEXITED(stat_loc)) {
 | 
	
		
			
				|  |  | -    log_warn(LD_GENERAL, "Process %d did not exit normally",
 | 
	
		
			
				|  |  | -             (int)process_handle->pid);
 | 
	
		
			
				|  |  | -    return PROCESS_EXIT_ERROR;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (exit_code != NULL)
 | 
	
		
			
				|  |  | -    *exit_code = WEXITSTATUS(stat_loc);
 | 
	
		
			
				|  |  | -#endif /* defined(_WIN32) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return PROCESS_EXIT_EXITED;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes.  If
 | 
	
		
			
				|  |  | - * <b>hProcess</b> is NULL, the function will return immediately if there is
 | 
	
		
			
				|  |  | - * nothing more to read. Otherwise <b>hProcess</b> should be set to the handle
 | 
	
		
			
				|  |  | - * to the process owning the <b>h</b>. In this case, the function will exit
 | 
	
		
			
				|  |  | - * only once the process has exited, or <b>count</b> bytes are read. Returns
 | 
	
		
			
				|  |  | - * the number of bytes read, or -1 on error. */
 | 
	
		
			
				|  |  | -ssize_t
 | 
	
		
			
				|  |  | -tor_read_all_handle(HANDLE h, char *buf, size_t count,
 | 
	
		
			
				|  |  | -                    const process_handle_t *process)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  size_t numread = 0;
 | 
	
		
			
				|  |  | -  BOOL retval;
 | 
	
		
			
				|  |  | -  DWORD byte_count;
 | 
	
		
			
				|  |  | -  BOOL process_exited = FALSE;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (count > SIZE_T_CEILING || count > SSIZE_MAX)
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  while (numread < count) {
 | 
	
		
			
				|  |  | -    /* Check if there is anything to read */
 | 
	
		
			
				|  |  | -    retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL);
 | 
	
		
			
				|  |  | -    if (!retval) {
 | 
	
		
			
				|  |  | -      log_warn(LD_GENERAL,
 | 
	
		
			
				|  |  | -        "Failed to peek from handle: %s",
 | 
	
		
			
				|  |  | -        format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -      return -1;
 | 
	
		
			
				|  |  | -    } else if (0 == byte_count) {
 | 
	
		
			
				|  |  | -      /* Nothing available: process exited or it is busy */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      /* Exit if we don't know whether the process is running */
 | 
	
		
			
				|  |  | -      if (NULL == process)
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      /* The process exited and there's nothing left to read from it */
 | 
	
		
			
				|  |  | -      if (process_exited)
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      /* If process is not running, check for output one more time in case
 | 
	
		
			
				|  |  | -         it wrote something after the peek was performed. Otherwise keep on
 | 
	
		
			
				|  |  | -         waiting for output */
 | 
	
		
			
				|  |  | -      tor_assert(process != NULL);
 | 
	
		
			
				|  |  | -      byte_count = WaitForSingleObject(process->pid.hProcess, 0);
 | 
	
		
			
				|  |  | -      if (WAIT_TIMEOUT != byte_count)
 | 
	
		
			
				|  |  | -        process_exited = TRUE;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      continue;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* There is data to read; read it */
 | 
	
		
			
				|  |  | -    retval = ReadFile(h, buf+numread, count-numread, &byte_count, NULL);
 | 
	
		
			
				|  |  | -    tor_assert(byte_count + numread <= count);
 | 
	
		
			
				|  |  | -    if (!retval) {
 | 
	
		
			
				|  |  | -      log_warn(LD_GENERAL, "Failed to read from handle: %s",
 | 
	
		
			
				|  |  | -        format_win32_error(GetLastError()));
 | 
	
		
			
				|  |  | -      return -1;
 | 
	
		
			
				|  |  | -    } else if (0 == byte_count) {
 | 
	
		
			
				|  |  | -      /* End of file */
 | 
	
		
			
				|  |  | -      break;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    numread += byte_count;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return (ssize_t)numread;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -#else /* !(defined(_WIN32)) */
 | 
	
		
			
				|  |  | -/** Read from a handle <b>fd</b> into <b>buf</b>, up to <b>count</b> bytes.  If
 | 
	
		
			
				|  |  | - * <b>process</b> is NULL, the function will return immediately if there is
 | 
	
		
			
				|  |  | - * nothing more to read. Otherwise data will be read until end of file, or
 | 
	
		
			
				|  |  | - * <b>count</b> bytes are read.  Returns the number of bytes read, or -1 on
 | 
	
		
			
				|  |  | - * error. Sets <b>eof</b> to true if <b>eof</b> is not NULL and the end of the
 | 
	
		
			
				|  |  | - * file has been reached. */
 | 
	
		
			
				|  |  | -ssize_t
 | 
	
		
			
				|  |  | -tor_read_all_handle(int fd, char *buf, size_t count,
 | 
	
		
			
				|  |  | -                    const process_handle_t *process,
 | 
	
		
			
				|  |  | -                    int *eof)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  size_t numread = 0;
 | 
	
		
			
				|  |  | -  ssize_t result;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (eof)
 | 
	
		
			
				|  |  | -    *eof = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (count > SIZE_T_CEILING || count > SSIZE_MAX)
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  while (numread < count) {
 | 
	
		
			
				|  |  | -    result = read(fd, buf+numread, count-numread);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (result == 0) {
 | 
	
		
			
				|  |  | -      log_debug(LD_GENERAL, "read() reached end of file");
 | 
	
		
			
				|  |  | -      if (eof)
 | 
	
		
			
				|  |  | -        *eof = 1;
 | 
	
		
			
				|  |  | -      break;
 | 
	
		
			
				|  |  | -    } else if (result < 0 && errno == EAGAIN) {
 | 
	
		
			
				|  |  | -      if (process)
 | 
	
		
			
				|  |  | -        continue;
 | 
	
		
			
				|  |  | -      else
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    } else if (result < 0) {
 | 
	
		
			
				|  |  | -      log_warn(LD_GENERAL, "read() failed: %s", strerror(errno));
 | 
	
		
			
				|  |  | -      return -1;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    numread += result;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  log_debug(LD_GENERAL, "read() read %d bytes from handle", (int)numread);
 | 
	
		
			
				|  |  | -  return (ssize_t)numread;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -#endif /* defined(_WIN32) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Read from stdout of a process until the process exits. */
 | 
	
		
			
				|  |  | -ssize_t
 | 
	
		
			
				|  |  | -tor_read_all_from_process_stdout(const process_handle_t *process_handle,
 | 
	
		
			
				|  |  | -                                 char *buf, size_t count)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -  return tor_read_all_handle(process_handle->stdout_pipe, buf, count,
 | 
	
		
			
				|  |  | -                             process_handle);
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -  return tor_read_all_handle(process_handle->stdout_pipe, buf, count,
 | 
	
		
			
				|  |  | -                             process_handle, NULL);
 | 
	
		
			
				|  |  | -#endif /* defined(_WIN32) */
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Read from stdout of a process until the process exits. */
 | 
	
		
			
				|  |  | -ssize_t
 | 
	
		
			
				|  |  | -tor_read_all_from_process_stderr(const process_handle_t *process_handle,
 | 
	
		
			
				|  |  | -                                 char *buf, size_t count)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -  return tor_read_all_handle(process_handle->stderr_pipe, buf, count,
 | 
	
		
			
				|  |  | -                             process_handle);
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -  return tor_read_all_handle(process_handle->stderr_pipe, buf, count,
 | 
	
		
			
				|  |  | -                             process_handle, NULL);
 | 
	
		
			
				|  |  | -#endif /* defined(_WIN32) */
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Return a string corresponding to <b>stream_status</b>. */
 | 
	
		
			
				|  |  | -const char *
 | 
	
		
			
				|  |  | -stream_status_to_string(enum stream_status stream_status)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  switch (stream_status) {
 | 
	
		
			
				|  |  | -    case IO_STREAM_OKAY:
 | 
	
		
			
				|  |  | -      return "okay";
 | 
	
		
			
				|  |  | -    case IO_STREAM_EAGAIN:
 | 
	
		
			
				|  |  | -      return "temporarily unavailable";
 | 
	
		
			
				|  |  | -    case IO_STREAM_TERM:
 | 
	
		
			
				|  |  | -      return "terminated";
 | 
	
		
			
				|  |  | -    case IO_STREAM_CLOSED:
 | 
	
		
			
				|  |  | -      return "closed";
 | 
	
		
			
				|  |  | -    default:
 | 
	
		
			
				|  |  | -      tor_fragile_assert();
 | 
	
		
			
				|  |  | -      return "unknown";
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Split buf into lines, and add to smartlist. The buffer <b>buf</b> will be
 | 
	
		
			
				|  |  | - * modified. The resulting smartlist will consist of pointers to buf, so there
 | 
	
		
			
				|  |  | - * is no need to free the contents of sl. <b>buf</b> must be a NUL-terminated
 | 
	
		
			
				|  |  | - * string. <b>len</b> should be set to the length of the buffer excluding the
 | 
	
		
			
				|  |  | - * NUL. Non-printable characters (including NUL) will be replaced with "." */
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -tor_split_lines(smartlist_t *sl, char *buf, int len)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  /* Index in buf of the start of the current line */
 | 
	
		
			
				|  |  | -  int start = 0;
 | 
	
		
			
				|  |  | -  /* Index in buf of the current character being processed */
 | 
	
		
			
				|  |  | -  int cur = 0;
 | 
	
		
			
				|  |  | -  /* Are we currently in a line */
 | 
	
		
			
				|  |  | -  char in_line = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Loop over string */
 | 
	
		
			
				|  |  | -  while (cur < len) {
 | 
	
		
			
				|  |  | -    /* Loop until end of line or end of string */
 | 
	
		
			
				|  |  | -    for (; cur < len; cur++) {
 | 
	
		
			
				|  |  | -      if (in_line) {
 | 
	
		
			
				|  |  | -        if ('\r' == buf[cur] || '\n' == buf[cur]) {
 | 
	
		
			
				|  |  | -          /* End of line */
 | 
	
		
			
				|  |  | -          buf[cur] = '\0';
 | 
	
		
			
				|  |  | -          /* Point cur to the next line */
 | 
	
		
			
				|  |  | -          cur++;
 | 
	
		
			
				|  |  | -          /* Line starts at start and ends with a nul */
 | 
	
		
			
				|  |  | -          break;
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -          if (!TOR_ISPRINT(buf[cur]))
 | 
	
		
			
				|  |  | -            buf[cur] = '.';
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        if ('\r' == buf[cur] || '\n' == buf[cur]) {
 | 
	
		
			
				|  |  | -          /* Skip leading vertical space */
 | 
	
		
			
				|  |  | -          ;
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -          in_line = 1;
 | 
	
		
			
				|  |  | -          start = cur;
 | 
	
		
			
				|  |  | -          if (!TOR_ISPRINT(buf[cur]))
 | 
	
		
			
				|  |  | -            buf[cur] = '.';
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    /* We are at the end of the line or end of string. If in_line is true there
 | 
	
		
			
				|  |  | -     * is a line which starts at buf+start and ends at a NUL. cur points to
 | 
	
		
			
				|  |  | -     * the character after the NUL. */
 | 
	
		
			
				|  |  | -    if (in_line)
 | 
	
		
			
				|  |  | -      smartlist_add(sl, (void *)(buf+start));
 | 
	
		
			
				|  |  | -    in_line = 0;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return smartlist_len(sl);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifdef _WIN32
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Return a smartlist containing lines outputted from
 | 
	
		
			
				|  |  | - *  <b>handle</b>. Return NULL on error, and set
 | 
	
		
			
				|  |  | - *  <b>stream_status_out</b> appropriately. */
 | 
	
		
			
				|  |  | -MOCK_IMPL(smartlist_t *,
 | 
	
		
			
				|  |  | -tor_get_lines_from_handle, (HANDLE *handle,
 | 
	
		
			
				|  |  | -                            enum stream_status *stream_status_out))
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  int pos;
 | 
	
		
			
				|  |  | -  char stdout_buf[600] = {0};
 | 
	
		
			
				|  |  | -  smartlist_t *lines = NULL;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  tor_assert(stream_status_out);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  *stream_status_out = IO_STREAM_TERM;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  pos = tor_read_all_handle(handle, stdout_buf, sizeof(stdout_buf) - 1, NULL);
 | 
	
		
			
				|  |  | -  if (pos < 0) {
 | 
	
		
			
				|  |  | -    *stream_status_out = IO_STREAM_TERM;
 | 
	
		
			
				|  |  | -    return NULL;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (pos == 0) {
 | 
	
		
			
				|  |  | -    *stream_status_out = IO_STREAM_EAGAIN;
 | 
	
		
			
				|  |  | -    return NULL;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* End with a null even if there isn't a \r\n at the end */
 | 
	
		
			
				|  |  | -  /* TODO: What if this is a partial line? */
 | 
	
		
			
				|  |  | -  stdout_buf[pos] = '\0';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Split up the buffer */
 | 
	
		
			
				|  |  | -  lines = smartlist_new();
 | 
	
		
			
				|  |  | -  tor_split_lines(lines, stdout_buf, pos);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Currently 'lines' is populated with strings residing on the
 | 
	
		
			
				|  |  | -     stack. Replace them with their exact copies on the heap: */
 | 
	
		
			
				|  |  | -  SMARTLIST_FOREACH(lines, char *, line,
 | 
	
		
			
				|  |  | -                    SMARTLIST_REPLACE_CURRENT(lines, line, tor_strdup(line)));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  *stream_status_out = IO_STREAM_OKAY;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return lines;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#else /* !(defined(_WIN32)) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Return a smartlist containing lines outputted from
 | 
	
		
			
				|  |  | - *  <b>fd</b>. Return NULL on error, and set
 | 
	
		
			
				|  |  | - *  <b>stream_status_out</b> appropriately. */
 | 
	
		
			
				|  |  | -MOCK_IMPL(smartlist_t *,
 | 
	
		
			
				|  |  | -tor_get_lines_from_handle, (int fd, enum stream_status *stream_status_out))
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  enum stream_status stream_status;
 | 
	
		
			
				|  |  | -  char stdout_buf[400];
 | 
	
		
			
				|  |  | -  smartlist_t *lines = NULL;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  while (1) {
 | 
	
		
			
				|  |  | -    memset(stdout_buf, 0, sizeof(stdout_buf));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    stream_status = get_string_from_pipe(fd,
 | 
	
		
			
				|  |  | -                                         stdout_buf, sizeof(stdout_buf) - 1);
 | 
	
		
			
				|  |  | -    if (stream_status != IO_STREAM_OKAY)
 | 
	
		
			
				|  |  | -      goto done;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (!lines) lines = smartlist_new();
 | 
	
		
			
				|  |  | -    smartlist_split_string(lines, stdout_buf, "\n", 0, 0);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | - done:
 | 
	
		
			
				|  |  | -  *stream_status_out = stream_status;
 | 
	
		
			
				|  |  | -  return lines;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#endif /* defined(_WIN32) */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Reads from <b>fd</b> and stores input in <b>buf_out</b> making
 | 
	
		
			
				|  |  | - *  sure it's below <b>count</b> bytes.
 | 
	
		
			
				|  |  | - *  If the string has a trailing newline, we strip it off.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * This function is specifically created to handle input from managed
 | 
	
		
			
				|  |  | - * proxies, according to the pluggable transports spec. Make sure it
 | 
	
		
			
				|  |  | - * fits your needs before using it.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Returns:
 | 
	
		
			
				|  |  | - * IO_STREAM_CLOSED: If the stream is closed.
 | 
	
		
			
				|  |  | - * IO_STREAM_EAGAIN: If there is nothing to read and we should check back
 | 
	
		
			
				|  |  | - *  later.
 | 
	
		
			
				|  |  | - * IO_STREAM_TERM: If something is wrong with the stream.
 | 
	
		
			
				|  |  | - * IO_STREAM_OKAY: If everything went okay and we got a string
 | 
	
		
			
				|  |  | - *  in <b>buf_out</b>. */
 | 
	
		
			
				|  |  | -enum stream_status
 | 
	
		
			
				|  |  | -get_string_from_pipe(int fd, char *buf_out, size_t count)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  ssize_t ret;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  tor_assert(count <= INT_MAX);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  ret = read(fd, buf_out, count);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (ret == 0)
 | 
	
		
			
				|  |  | -    return IO_STREAM_CLOSED;
 | 
	
		
			
				|  |  | -  else if (ret < 0 && errno == EAGAIN)
 | 
	
		
			
				|  |  | -    return IO_STREAM_EAGAIN;
 | 
	
		
			
				|  |  | -  else if (ret < 0)
 | 
	
		
			
				|  |  | -    return IO_STREAM_TERM;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (buf_out[ret - 1] == '\n') {
 | 
	
		
			
				|  |  | -    /* Remove the trailing newline */
 | 
	
		
			
				|  |  | -    buf_out[ret - 1] = '\0';
 | 
	
		
			
				|  |  | -  } else
 | 
	
		
			
				|  |  | -    buf_out[ret] = '\0';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return IO_STREAM_OKAY;
 | 
	
		
			
				|  |  | -}
 |