Пример #1
0
static pid_t
spawn_staprun(char** args)
{
  pid_t pid = -1;
  posix_spawn_file_actions_t fa;

  int err;
  if ((err = posix_spawn_file_actions_init(&fa)) != 0)
    {
      reply ("ERROR: Can't initialize posix_spawn actions: %s\n", strerror(err));
      return -1;
    }

  // no stdin for staprun
  if ((err = posix_spawn_file_actions_addopen(&fa, 0, "/dev/null", O_RDONLY, 0)) != 0)
    {
      reply("ERROR: Can't set posix_spawn actions: %s\n", strerror(err));
      posix_spawn_file_actions_destroy(&fa);
      return -1;
    }

  if ((err = posix_spawn(&pid, args[0], &fa, NULL, args, environ)) != 0)
    {
      reply("ERROR: Can't launch stap backend: %s\n", strerror(err));
      posix_spawn_file_actions_destroy(&fa);
      return -1;
    }

  posix_spawn_file_actions_destroy(&fa);
  return pid;
}
Пример #2
0
static int
parent_main (void)
{
  FILE *fp;
  char *argv[3] = { CHILD_PROGRAM_FILENAME, "-child", NULL };
  posix_spawn_file_actions_t actions;
  bool actions_allocated;
  int err;
  pid_t child;
  int status;
  int exitstatus;

  /* Create a data file with specific contents.  */
  fp = fopen (DATA_FILENAME, "wb");
  if (fp == NULL)
    {
      perror ("cannot create data file");
      return 1;
    }
  fwrite ("Halle Potta", 1, 11, fp);
  if (fflush (fp) || fclose (fp))
    {
      perror ("cannot prepare data file");
      return 1;
    }

  /* Avoid reading from our stdin, as it could block.  */
  freopen ("/dev/null", "rb", stdin);

  /* Test whether posix_spawn_file_actions_addopen with this file name
     actually works, but spawning a child that reads from this file.  */
  actions_allocated = false;
  if ((err = posix_spawn_file_actions_init (&actions)) != 0
      || (actions_allocated = true,
          (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO, DATA_FILENAME, O_RDONLY, 0600)) != 0
          || (err = posix_spawn (&child, CHILD_PROGRAM_FILENAME, &actions, NULL, argv, environ)) != 0))
    {
      if (actions_allocated)
        posix_spawn_file_actions_destroy (&actions);
      errno = err;
      perror ("subprocess failed");
      return 1;
    }
  posix_spawn_file_actions_destroy (&actions);
  status = 0;
  while (waitpid (child, &status, 0) != child)
    ;
  if (!WIFEXITED (status))
    {
      fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
      return 1;
    }
  exitstatus = WEXITSTATUS (status);
  if (exitstatus != 0)
    {
      fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
      return 1;
    }
  return 0;
}
Пример #3
0
pid_t child_spawn1_internal (char const *prog, char const *const *argv, char const *const *envp, int *p, int to)
{
  posix_spawn_file_actions_t actions ;
  posix_spawnattr_t attr ;
  int e ;
  pid_t pid ;
  int haspath = !!env_get("PATH") ;
  if (coe(p[!(to & 1)]) < 0) { e = errno ; goto err ; }
  e = posix_spawnattr_init(&attr) ;
  if (e) goto err ;
  {
    sigset_t set ;
    sigemptyset(&set) ;
    e = posix_spawnattr_setsigmask(&attr, &set) ;
    if (e) goto errattr ;
    e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ;
    if (e) goto errattr ;
  }
  e = posix_spawn_file_actions_init(&actions) ;
  if (e) goto errattr ;
  e = posix_spawn_file_actions_adddup2(&actions, p[to & 1], to & 1) ;
  if (e) goto erractions ;
  e = posix_spawn_file_actions_addclose(&actions, p[to & 1]) ;
  if (e) goto erractions ;
  if (to & 2)
  {
    e = posix_spawn_file_actions_adddup2(&actions, to & 1, !(to & 1)) ;
    if (e) goto erractions ;
  }
  if (!haspath && (setenv("PATH", SKALIBS_DEFAULTPATH, 0) < 0)) { e = errno ; goto erractions ; }
  e = posix_spawnp(&pid, prog, &actions, &attr, (char *const *)argv, (char *const *)envp) ;
  if (!haspath) unsetenv("PATH") ;
  posix_spawn_file_actions_destroy(&actions) ;
  posix_spawnattr_destroy(&attr) ;
  fd_close(p[to & 1]) ;
  if (e) goto errp ;
  return pid ;

 erractions:
  posix_spawn_file_actions_destroy(&actions) ;
 errattr:
  posix_spawnattr_destroy(&attr) ;
 err:
  fd_close(p[to & 1]) ;
 errp:
  fd_close(p[!(to & 1)]) ;
  errno = e ;
  return 0 ;
}
Пример #4
0
/**
 * Wait for the forked process to finish.
 *
 * @param p handle returned by CPLSpawnAsync()
 * @param bWait set to TRUE to wait for the child to terminate. Otherwise the associated
 *              handles are just cleaned.
 * @param bKill set to TRUE to force child termination (unimplemented right now).
 *
 * @return the return code of the forked process if bWait == TRUE, 0 otherwise
 *
 * @since GDAL 1.10.0
 */
int CPLSpawnAsyncFinish(CPLSpawnedProcess* p, int bWait, CPL_UNUSED int bKill)
{
    int status = 0;

    if( bWait )
    {
        while(1)
        {
            status = -1;
            const int ret = waitpid (p->pid, &status, 0);
            if (ret < 0)
            {
                if (errno != EINTR)
                {
                    break;
                }
            }
            else
                break;
        }
    }

    CPLSpawnAsyncCloseInputFileHandle(p);
    CPLSpawnAsyncCloseOutputFileHandle(p);
    CPLSpawnAsyncCloseErrorFileHandle(p);
#ifdef HAVE_POSIX_SPAWNP
    if( p->bFreeActions )
        posix_spawn_file_actions_destroy(&p->actions);
#endif
    CPLFree(p);
    return status;
}
Пример #5
0
static void spawn_win32(void) {
  char module_name[WATCHMAN_NAME_MAX];
  GetModuleFileName(NULL, module_name, sizeof(module_name));
  char *argv[MAX_DAEMON_ARGS] = {
    module_name,
    "--foreground",
    NULL
  };
  posix_spawn_file_actions_t actions;
  posix_spawnattr_t attr;
  pid_t pid;
  int i;

  for (i = 0; daemon_argv[i]; i++) {
    append_argv(argv, daemon_argv[i]);
  }

  posix_spawnattr_init(&attr);
  posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP);
  posix_spawn_file_actions_init(&actions);
  posix_spawn_file_actions_addopen(&actions,
      STDIN_FILENO, "/dev/null", O_RDONLY, 0);
  posix_spawn_file_actions_addopen(&actions,
      STDOUT_FILENO, log_name, O_WRONLY|O_CREAT|O_APPEND, 0600);
  posix_spawn_file_actions_adddup2(&actions,
      STDOUT_FILENO, STDERR_FILENO);
  posix_spawnp(&pid, argv[0], &actions, &attr, argv, environ);
  posix_spawnattr_destroy(&attr);
  posix_spawn_file_actions_destroy(&actions);
}
Пример #6
0
TEST(spawn, posix_spawn_file_actions) {
  int fds[2];
  ASSERT_NE(-1, pipe(fds));

  posix_spawn_file_actions_t fa;
  ASSERT_EQ(0, posix_spawn_file_actions_init(&fa));

  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[0]));
  ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fds[1], 1));
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
  // Check that close(2) failures are ignored by closing the same fd again.
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
  ASSERT_EQ(0, posix_spawn_file_actions_addopen(&fa, 56, "/proc/version", O_RDONLY, 0));

  ExecTestHelper eth;
  eth.SetArgs({"ls", "-l", "/proc/self/fd", nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), &fa, nullptr, eth.GetArgs(), eth.GetEnv()));
  ASSERT_EQ(0, posix_spawn_file_actions_destroy(&fa));

  ASSERT_EQ(0, close(fds[1]));
  std::string content;
  ASSERT_TRUE(android::base::ReadFdToString(fds[0], &content));
  ASSERT_EQ(0, close(fds[0]));

  AssertChildExited(pid, 0);

  // We'll know the dup2 worked if we see any ls(1) output in our pipe.
  // The open we can check manually...
  bool open_to_fd_56_worked = false;
  for (const auto& line : android::base::Split(content, "\n")) {
    if (line.find(" 56 -> /proc/version") != std::string::npos) open_to_fd_56_worked = true;
  }
  ASSERT_TRUE(open_to_fd_56_worked);
}
Пример #7
0
static void spawn_via_gimli(void)
{
  char *argv[MAX_DAEMON_ARGS] = {
    GIMLI_MONITOR_PATH,
#ifdef WATCHMAN_STATE_DIR
    "--trace-dir=" WATCHMAN_STATE_DIR "/traces",
#endif
    "--pidfile", pid_file,
    "watchman",
    "--foreground",
    NULL
  };
  posix_spawn_file_actions_t actions;
  posix_spawnattr_t attr;
  pid_t pid;
  int i;

  for (i = 0; daemon_argv[i]; i++) {
    append_argv(argv, daemon_argv[i]);
  }

  close_random_fds();

  posix_spawnattr_init(&attr);
  posix_spawn_file_actions_init(&actions);
  posix_spawn_file_actions_addopen(&actions,
      STDOUT_FILENO, log_name, O_WRONLY|O_CREAT|O_APPEND, 0600);
  posix_spawn_file_actions_adddup2(&actions,
      STDOUT_FILENO, STDERR_FILENO);
  posix_spawnp(&pid, argv[0], &actions, &attr, argv, environ);
  posix_spawnattr_destroy(&attr);
  posix_spawn_file_actions_destroy(&actions);
}
Пример #8
0
void pipeline(const char *const *argv, struct pipeline *pl)
{
  posix_spawn_file_actions_t file_acts;

  int pipefds[2];
  if (pipe(pipefds)) {
    die_errno(errno, "pipe");
  }

  die_errno(posix_spawn_file_actions_init(&file_acts),
            "posix_spawn_file_actions_init");
  die_errno(posix_spawn_file_actions_adddup2(&file_acts, pipefds[0], 0),
            "posix_spawn_file_actions_adddup2");
  die_errno(posix_spawn_file_actions_addclose(&file_acts, pipefds[0]),
            "posix_spawn_file_actions_addclose");
  die_errno(posix_spawn_file_actions_addclose(&file_acts, pipefds[1]),
            "posix_spawn_file_actions_addclose");

  die_errno(posix_spawnp(&pl->pid, argv[0], &file_acts, NULL,
                         (char * const *)argv, environ),
            "posix_spawnp: %s", argv[0]);

  die_errno(posix_spawn_file_actions_destroy(&file_acts),
            "posix_spawn_file_actions_destroy");

  if (close(pipefds[0])) {
    die_errno(errno, "close");
  }

  pl->infd = pipefds[1];
}
Пример #9
0
static int l_posix_spawn_file_actions_destroy(lua_State *L) {
	int r;
	posix_spawn_file_actions_t *file_actions = luaL_checkudata(L, 1, "posix_spawn_file_actions_t");
	if (0 != (r = posix_spawn_file_actions_destroy(file_actions))) {
		lua_pushnil(L);
		lua_pushstring(L, strerror(r));
		lua_pushinteger(L, r);
		return 3;
	}
	lua_pushboolean(L, 1);
	return 1;
}
void do_bind_shell(char* env, int port) {
  char* bundle_root = bundle_path();
  
  char* shell_path = NULL;
  asprintf(&shell_path, "%s/iosbinpack64/bin/bash", bundle_root);
  
  char* argv[] = {shell_path, NULL};
  char* envp[] = {env, NULL};
  
  struct sockaddr_in sa;
  sa.sin_len = 0;
  sa.sin_family = AF_INET;
  sa.sin_port = htons(port);
  sa.sin_addr.s_addr = INADDR_ANY;
  
  int sock = socket(PF_INET, SOCK_STREAM, 0);
  bind(sock, (struct sockaddr*)&sa, sizeof(sa));
  listen(sock, 1);
  
  printf("shell listening on port %d\n", port);
  
  for(;;) {
    int conn = accept(sock, 0, 0);
    
    posix_spawn_file_actions_t actions;
    
    posix_spawn_file_actions_init(&actions);
    posix_spawn_file_actions_adddup2(&actions, conn, 0);
    posix_spawn_file_actions_adddup2(&actions, conn, 1);
    posix_spawn_file_actions_adddup2(&actions, conn, 2);
    

    pid_t spawned_pid = 0;
    int spawn_err = posix_spawn(&spawned_pid, shell_path, &actions, NULL, argv, envp);
    
    if (spawn_err != 0){
      perror("shell spawn error");
    } else {
      printf("shell posix_spawn success!\n");
    }
    
    posix_spawn_file_actions_destroy(&actions);
    
    printf("our pid: %d\n", getpid());
    printf("spawned_pid: %d\n", spawned_pid);
    
    int wl = 0;
    while (waitpid(spawned_pid, &wl, 0) == -1 && errno == EINTR);
  }
  
  free(shell_path);
}
Пример #11
0
static int
do_test (void)
{
  /* Try to eliminate the file descriptor limit.  */
  {
    struct rlimit limit;
    if (getrlimit (RLIMIT_NOFILE, &limit) < 0)
      {
        printf ("error: getrlimit: %m\n");
        return 1;
      }
    limit.rlim_cur = RLIM_INFINITY;
    if (setrlimit (RLIMIT_NOFILE, &limit) < 0)
      printf ("warning: setrlimit: %m\n");
  }

  maxfd = sysconf (_SC_OPEN_MAX);
  printf ("info: _SC_OPEN_MAX: %ld\n", maxfd);

  invalid_fd = dup (0);
  if (invalid_fd < 0)
    {
      printf ("error: dup: %m\n");
      return 1;
    }
  if (close (invalid_fd) < 0)
    {
      printf ("error: close: %m\n");
      return 1;
    }

  int ret = posix_spawn_file_actions_init (&actions);
  if (ret != 0)
    {
      errno = ret;
      printf ("error: posix_spawn_file_actions_init: %m\n");
      return 1;
    }

  all_functions ();

  ret = posix_spawn_file_actions_destroy (&actions);
  if (ret != 0)
    {
      errno = ret;
      printf ("error: posix_spawn_file_actions_destroy: %m\n");
      return 1;
    }

  return errors;
}
Пример #12
0
// Spawn watchman via a site-specific spawn helper program.
// We'll pass along any daemon-appropriate arguments that
// we noticed during argument parsing.
static void spawn_site_specific(const char *spawner)
{
  char *argv[MAX_DAEMON_ARGS] = {
    (char*)spawner,
    NULL
  };
  posix_spawn_file_actions_t actions;
  posix_spawnattr_t attr;
  pid_t pid;
  int i;
  int res, err;

  for (i = 0; daemon_argv[i]; i++) {
    append_argv(argv, daemon_argv[i]);
  }

  close_random_fds();

  posix_spawnattr_init(&attr);
  posix_spawn_file_actions_init(&actions);
  posix_spawn_file_actions_addopen(&actions,
      STDOUT_FILENO, log_name, O_WRONLY|O_CREAT|O_APPEND, 0600);
  posix_spawn_file_actions_adddup2(&actions,
      STDOUT_FILENO, STDERR_FILENO);
  res = posix_spawnp(&pid, argv[0], &actions, &attr, argv, environ);
  err = errno;

  posix_spawnattr_destroy(&attr);
  posix_spawn_file_actions_destroy(&actions);

  if (res) {
    w_log(W_LOG_FATAL, "Failed to spawn watchman via `%s': %s\n", spawner,
          strerror(err));
  }

  if (waitpid(pid, &res, 0) == -1) {
    w_log(W_LOG_FATAL, "Failed waiting for %s: %s\n", spawner, strerror(errno));
  }

  if (WIFEXITED(res) && WEXITSTATUS(res) == 0) {
    return;
  }

  if (WIFEXITED(res)) {
    w_log(W_LOG_FATAL, "%s: exited with status %d\n", spawner,
          WEXITSTATUS(res));
  } else if (WIFSIGNALED(res)) {
    w_log(W_LOG_FATAL, "%s: signaled with %d\n", spawner, WTERMSIG(res));
  }
  w_log(W_LOG_ERR, "%s: failed to start, exit status %d\n", spawner, res);
}
Пример #13
0
/**
* @fn                   : tc_libc_spawn_posix_spawn_file_actions_init
* @brief                : Initializes the object referenced by file_action
* @scenario             : initializes the object referenced by st_fileactions, to an empty set of file actions for subsequent use
* @API's covered        : posix_spawn_file_actions_init, posix_spawn_file_actions_destroy
* @Preconditions        : none
* @Postconditions       : posix_spawn_file_actions_destroy
* @Return               : void
*/
static void tc_libc_spawn_posix_spawn_file_actions_init(void)
{
	posix_spawn_file_actions_t st_fileactions;
	int ret_chk = ERROR;

	ret_chk = posix_spawn_file_actions_init(&st_fileactions);
	TC_ASSERT_EQ("posix_spawn_file_actions_init", ret_chk, OK);
	TC_ASSERT_EQ("posix_spawn_file_actions_init", st_fileactions, NULL);

	ret_chk = posix_spawn_file_actions_destroy(&st_fileactions);
	TC_ASSERT_EQ("posix_spawn_file_actions_destroy", ret_chk, OK);

	TC_SUCCESS_RESULT();
}
Пример #14
0
// based on stap_spawn_piped from util.cxx
static pid_t
spawn_staprun_piped(char** args)
{
  pid_t pid = -1;
  int outfd[2], errfd[2];
  posix_spawn_file_actions_t fa;

  int err;
  if ((err = posix_spawn_file_actions_init(&fa)) != 0)
    {
      reply("ERROR: Can't initialize posix_spawn actions: %s\n", strerror(err));
      return -1;
    }
  if ((err = pipe_child_fd(&fa, outfd, 1)) != 0)
    {
      reply("ERROR: Can't create pipe for stdout: %s\n",
            err > 0 ? strerror(err) : "pipe_child_fd");
      goto cleanup_fa;
    }
  if ((err = pipe_child_fd(&fa, errfd, 2)) != 0)
    {
      reply("ERROR: Can't create pipe for stderr: %s\n",
            err > 0 ? strerror(err) : "pipe_child_fd");
      goto cleanup_out;
    }

  posix_spawn(&pid, args[0], &fa, NULL, args, environ);

  if (pid > 0)
    fd_staprun_err = errfd[0];
  else
    close(errfd[0]);
  close(errfd[1]);

cleanup_out:

  if (pid > 0)
    fd_staprun_out = outfd[0];
  else
    close(outfd[0]);
  close(outfd[1]);

cleanup_fa:

  posix_spawn_file_actions_destroy(&fa);
  return pid;
}
Пример #15
0
/**
* @fn                   : tc_libc_spawn_posix_spawn_file_actions_destroy
* @brief                : destroy the object referenced by st_fileactions
* @scenario             : destroys the object referenced by st_fileactions which was previously intialized
* @API's covered        : posix_spawn_file_actions_init, posix_spawn_file_actions_addopen ,posix_spawn_file_actions_destroy
* @Preconditions        : posix_spawn_file_actions_init ,posix_spawn_file_actions_addopen
* @Postconditions       : none
* @Return               : void
*/
static void tc_libc_spawn_posix_spawn_file_actions_destroy(void)
{
	const char szfilepath[] = "./testdata.txt";
	posix_spawn_file_actions_t st_fileactions;
	int ret_chk = ERROR;

	ret_chk = posix_spawn_file_actions_init(&st_fileactions);
	TC_ASSERT_EQ("posix_spawn_file_actions_init", ret_chk, OK);

	ret_chk = posix_spawn_file_actions_addopen(&st_fileactions, 1, szfilepath, O_WRONLY, 0644);
	TC_ASSERT_EQ("posix_spawn_file_actions_addopen", ret_chk, OK);
	TC_ASSERT_NOT_NULL("posix_spawn_file_actions_addopen", st_fileactions);

	ret_chk = posix_spawn_file_actions_destroy(&st_fileactions);
	TC_ASSERT_EQ("posix_spawn_file_actions_destroy", ret_chk, OK);
	TC_ASSERT_EQ("posix_spawn_file_actions_destroy", st_fileactions, NULL);

	TC_SUCCESS_RESULT();
}
Пример #16
0
int main()
{
	int ret_err = 0;
	pid_t pid_child;
	char buf_err[64];
	posix_spawn_file_actions_t posix_faction;
	char *argv_child[] = { "forkexec_child", NULL };
	printf("Parent[%d]: Start\n", getpid());
	if ((ret_err = posix_spawn_file_actions_init(&posix_faction)) != 0)
	{
		strerror_r(ret_err, buf_err, sizeof(buf_err));
		fprintf(stderr, "Fail: file_actions_addopen: %s\n", buf_err);
		exit(EXIT_FAILURE);
	}

	if ((ret_err = posix_spawn_file_actions_addopen(&posix_faction,
					3, "pspawn.log", O_WRONLY | O_CREAT | O_APPEND, 0664)) != 0)
	{
		strerror_r(ret_err, buf_err, sizeof(buf_err));
		fprintf(stderr, "Fail: file_actions_addopen: %s\n", buf_err);
		exit(EXIT_FAILURE);
	}

	ret_err = posix_spawn( &pid_child,
			argv_child[0],
			&posix_faction,
			NULL,
			argv_child,
			NULL);
	if ((ret_err = posix_spawn_file_actions_destroy(&posix_faction)) != 0)
	{
		strerror_r(ret_err, buf_err, sizeof(buf_err));
		fprintf(stderr, "Fail: file_actions_destroy: %s\n", buf_err);
		exit(EXIT_FAILURE);
	}

	printf("Parent[%d]: Wait for child(%d) \n", getpid(), (int)pid_child);
	(void)wait(NULL);
	printf("Parent[%d]: Exit\n", getpid());
	return 0;
}
Пример #17
0
/**
* @fn                   : tc_libc_spawn_add_file_action
* @brief                : Add the file action
* @scenario             : Add the file action to the end for the file action list
* @API's covered        : posix_spawn_file_actions_init, posix_spawn_file_actions_addopen, add_file_action
* @Preconditions        : posix_spawn_file_actions_init,posix_spawn_file_actions_addopen
* @Postconditions       : posix_spawn_file_actions_destroy
* @Return               : void
*/
static void tc_libc_spawn_add_file_action(void)
{
	const char szfilepath[] = "./testdata.txt";
	posix_spawn_file_actions_t st_fileactions;
	struct spawn_open_file_action_s *entry1;
	struct spawn_open_file_action_s *entry2;
	size_t length;
	size_t alloc_num;
	int ret_chk = ERROR;

	ret_chk = posix_spawn_file_actions_init(&st_fileactions);
	TC_ASSERT_EQ("posix_spawn_file_actions_init", ret_chk, OK);

	ret_chk = posix_spawn_file_actions_addopen(&st_fileactions, 1, szfilepath, O_WRONLY, 0644);
	TC_ASSERT_EQ("posix_spawn_file_actions_addopen", ret_chk, OK);

	length = strlen(szfilepath);
	alloc_num = SIZEOF_OPEN_FILE_ACTION_S(length);

	/* Allocate the action list entry of this size */

	entry1 = (struct spawn_open_file_action_s *)zalloc(alloc_num);
	TC_ASSERT_NOT_NULL("zalloc", entry1);

	/* And add it to the file action list */

	add_file_action(st_fileactions, (struct spawn_general_file_action_s *)entry1);

	entry2 = (struct spawn_open_file_action_s *)zalloc(alloc_num);
	TC_ASSERT_NOT_NULL("zalloc", entry2);

	/* And add it to the file action list */

	add_file_action(st_fileactions, (struct spawn_general_file_action_s *)entry2);
	TC_ASSERT_EQ("add_file_action", entry1->flink, (struct spawn_general_file_action_s *)entry2);

	ret_chk = posix_spawn_file_actions_destroy(&st_fileactions);
	TC_ASSERT_EQ("posix_spawn_file_actions_destroy", ret_chk, OK);

	TC_SUCCESS_RESULT();
}
Пример #18
0
static void CatFileToString(posix_spawnattr_t* sa, const char* path, std::string* content) {
  int fds[2];
  ASSERT_NE(-1, pipe(fds));

  posix_spawn_file_actions_t fa;
  ASSERT_EQ(0, posix_spawn_file_actions_init(&fa));
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[0]));
  ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fds[1], 1));
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));

  ExecTestHelper eth;
  eth.SetArgs({"cat", path, nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), &fa, sa, eth.GetArgs(), nullptr));
  ASSERT_EQ(0, posix_spawn_file_actions_destroy(&fa));

  ASSERT_EQ(0, close(fds[1]));
  ASSERT_TRUE(android::base::ReadFdToString(fds[0], content));
  ASSERT_EQ(0, close(fds[0]));
  AssertChildExited(pid, 0);
}
Пример #19
0
//GetExitCodeProcess
void Process::cleanup() {

#ifdef WIN32

	if (!piProcInfo.hProcess) return;

	CloseHandle(piProcInfo.hProcess);
	CloseHandle(piProcInfo.hThread);

	if (p_stdin)
		close(p_stdin);
	if (p_stdout)
		close(p_stdout);
	if (p_stderr)
		close(p_stderr);

	CloseHandle(handle_IN_Rd);
	CloseHandle(handle_IN_Wr);
	CloseHandle(handle_OUT_Rd);
	CloseHandle(handle_OUT_Wr);
	CloseHandle(handle_ERR_Rd);
	CloseHandle(handle_ERR_Wr);

#else
	if (!pid) return;

    close(out[0]);
    close(err[0]);
    close(in[1]);
    close(out[1]);
    close(err[1]);
    close(in[0]);

    posix_spawn_file_actions_destroy(&action);

#endif

}
Пример #20
0
int spawn_param_execute(struct spawn_params *p)
{
  lua_State *L = p->L;
  int ret;
  struct process *proc;
  if (!p->argv) {
    p->argv = lua_newuserdata(L, 2 * sizeof *p->argv);
    p->argv[0] = p->command;
    p->argv[1] = 0;
  }
  if (!p->envp)
    p->envp = (const char **)environ;
  proc = lua_newuserdata(L, sizeof *proc);
  luaL_getmetatable(L, PROCESS_HANDLE);
  lua_setmetatable(L, -2);
  proc->status = -1;
  errno = 0;
  ret = posix_spawnp(&proc->pid, p->command, &p->redirect, &p->attr,
                     (char *const *)p->argv, (char *const *)p->envp);
  posix_spawn_file_actions_destroy(&p->redirect);
  posix_spawnattr_destroy(&p->attr);
  return ret != 0 || errno != 0 ? push_error(L) : 1;
}
Пример #21
0
/**
* @fn                   : tc_libc_spawn_posix_spawn_file_actions_addOpenClose
* @brief                : adds an open action to the object referenced by fact_p that causes the file named by path to be opened
* @scenario             : Files that need to be opened for use by the spawned process can alternatively be handled either by having the
*                         calling process open or by passing filenames to the spawned process
* @API's covered        : posix_spawnattr_init,posix_spawn_file_actions_init,posix_spawn_file_actions_addopen
* @Preconditions        : posix_spawnattr_init,posix_spawn_file_actions_init
* @Postconditions       : posix_spawn_file_actions_destroy
* @Return               : void
*/
static void tc_libc_spawn_posix_spawn_file_actions_addopenclose(void)
{
	const char szfilepath[] = "./testdata.txt";
	posix_spawn_file_actions_t st_fileactions;
	posix_spawnattr_t st_attr;
	int ret_chk = ERROR;

	ret_chk = posix_spawnattr_init(&st_attr);
	TC_ASSERT_EQ("posix_spawnattr_init", ret_chk, OK);

	ret_chk = posix_spawn_file_actions_init(&st_fileactions);
	TC_ASSERT_EQ("posix_spawn_file_actions_init", ret_chk, OK);

	ret_chk = posix_spawn_file_actions_addopen(&st_fileactions, 0, szfilepath, O_RDONLY, 0644);
	TC_ASSERT_EQ("posix_spawn_file_actions_addopen", ret_chk, OK);

	ret_chk = posix_spawn_file_actions_addclose(&st_fileactions, 0);
	TC_ASSERT_EQ("posix_spawn_file_actions_addclose", ret_chk, OK);

	ret_chk = posix_spawn_file_actions_destroy(&st_fileactions);
	TC_ASSERT_EQ("posix_spawn_file_actions_destroy", ret_chk, OK);

	TC_SUCCESS_RESULT();
}
Пример #22
0
int exec_builtin(FAR const char *appname, FAR char * const *argv,
                 FAR const char *redirfile, int oflags)
{
  FAR const struct builtin_s *builtin;
  posix_spawnattr_t attr;
  posix_spawn_file_actions_t file_actions;
  struct sched_param param;
  pid_t pid;
  int index;
  int ret;

  /* Verify that an application with this name exists */

  index = builtin_isavail(appname);
  if (index < 0)
    {
      ret = ENOENT;
      goto errout_with_errno;
    }

  /* Get information about the builtin */

  builtin = builtin_for_index(index);
  if (builtin == NULL)
    { 
      ret = ENOENT;
      goto errout_with_errno;
    }

  /* Initialize attributes for task_spawn(). */

  ret = posix_spawnattr_init(&attr);
  if (ret != 0)
    {
      goto errout_with_errno;
    }

  ret = posix_spawn_file_actions_init(&file_actions);
  if (ret != 0)
    {
      goto errout_with_attrs;
    }

  /* Set the correct task size and priority */

  param.sched_priority = builtin->priority;
  ret = posix_spawnattr_setschedparam(&attr, &param);
  if (ret != 0)
    {
      goto errout_with_actions;
    }

  ret = task_spawnattr_setstacksize(&attr, builtin->stacksize);
  if (ret != 0)
    {
      goto errout_with_actions;
    }

   /* If robin robin scheduling is enabled, then set the scheduling policy
    * of the new task to SCHED_RR before it has a chance to run.
    */

#if CONFIG_RR_INTERVAL > 0
  ret = posix_spawnattr_setschedpolicy(&attr, SCHED_RR);
  if (ret != 0)
    {
      goto errout_with_actions;
    }

  ret = posix_spawnattr_setflags(&attr,
                                 POSIX_SPAWN_SETSCHEDPARAM |
                                 POSIX_SPAWN_SETSCHEDULER);
  if (ret != 0)
    {
      goto errout_with_actions;
    }
#else
  ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSCHEDPARAM);
  if (ret != 0)
    {
      goto errout_with_actions;
    }
#endif

  /* Is output being redirected? */

  if (redirfile)
    {
      /* Set up to close open redirfile and set to stdout (1) */

      ret = posix_spawn_file_actions_addopen(&file_actions, 1,
                                             redirfile, O_WRONLY, 0644);
      if (ret != 0)
        {
          sdbg("ERROR: posix_spawn_file_actions_addopen failed: %d\n", ret);
          goto errout_with_actions;
        }
    }

  /* Start the built-in */

  ret = task_spawn(&pid, builtin->name, builtin->main, &file_actions,
                   &attr, (argv) ? &argv[1] : (FAR char * const *)NULL,
                   (FAR char * const *)NULL);
  if (ret != 0)
    {
      sdbg("ERROR: task_spawn failed: %d\n", ret);
      goto errout_with_actions;
    }

  /* Free attibutes and file actions.  Ignoring return values in the case
   * of an error.
   */

  /* Return the task ID of the new task if the task was sucessfully
   * started.  Otherwise, ret will be ERROR (and the errno value will
   * be set appropriately).
   */

  (void)posix_spawn_file_actions_destroy(&file_actions);
  (void)posix_spawnattr_destroy(&attr);
  return pid;

errout_with_actions:
  (void)posix_spawn_file_actions_destroy(&file_actions);

errout_with_attrs:
  (void)posix_spawnattr_destroy(&attr);

errout_with_errno:
  set_errno(ret);
  return ERROR;
}
Пример #23
0
RTR3DECL(int)   RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
                               PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,
                               const char *pszPassword, PRTPROCESS phProcess)
{
    int rc;

    /*
     * Input validation
     */
    AssertPtrReturn(pszExec, VERR_INVALID_POINTER);
    AssertReturn(*pszExec, VERR_INVALID_PARAMETER);
    AssertReturn(!(fFlags & ~RTPROC_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
    AssertReturn(!(fFlags & RTPROC_FLAGS_DETACHED) || !phProcess, VERR_INVALID_PARAMETER);
    AssertReturn(hEnv != NIL_RTENV, VERR_INVALID_PARAMETER);
    AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER);
    AssertPtrNullReturn(pszAsUser, VERR_INVALID_POINTER);
    AssertReturn(!pszAsUser || *pszAsUser, VERR_INVALID_PARAMETER);
    AssertReturn(!pszPassword || pszAsUser, VERR_INVALID_PARAMETER);
    AssertPtrNullReturn(pszPassword, VERR_INVALID_POINTER);
#if defined(RT_OS_OS2)
    if (fFlags & RTPROC_FLAGS_DETACHED)
        return VERR_PROC_DETACH_NOT_SUPPORTED;
#endif

    /*
     * Get the file descriptors for the handles we've been passed.
     */
    PCRTHANDLE  paHandles[3] = { phStdIn, phStdOut, phStdErr };
    int         aStdFds[3]   = {      -1,       -1,       -1 };
    for (int i = 0; i < 3; i++)
    {
        if (paHandles[i])
        {
            AssertPtrReturn(paHandles[i], VERR_INVALID_POINTER);
            switch (paHandles[i]->enmType)
            {
                case RTHANDLETYPE_FILE:
                    aStdFds[i] = paHandles[i]->u.hFile != NIL_RTFILE
                               ? (int)RTFileToNative(paHandles[i]->u.hFile)
                               : -2 /* close it */;
                    break;

                case RTHANDLETYPE_PIPE:
                    aStdFds[i] = paHandles[i]->u.hPipe != NIL_RTPIPE
                               ? (int)RTPipeToNative(paHandles[i]->u.hPipe)
                               : -2 /* close it */;
                    break;

                case RTHANDLETYPE_SOCKET:
                    aStdFds[i] = paHandles[i]->u.hSocket != NIL_RTSOCKET
                               ? (int)RTSocketToNative(paHandles[i]->u.hSocket)
                               : -2 /* close it */;
                    break;

                default:
                    AssertMsgFailedReturn(("%d: %d\n", i, paHandles[i]->enmType), VERR_INVALID_PARAMETER);
            }
            /** @todo check the close-on-execness of these handles?  */
        }
    }

    for (int i = 0; i < 3; i++)
        if (aStdFds[i] == i)
            aStdFds[i] = -1;

    for (int i = 0; i < 3; i++)
        AssertMsgReturn(aStdFds[i] < 0 || aStdFds[i] > i,
                        ("%i := %i not possible because we're lazy\n", i, aStdFds[i]),
                        VERR_NOT_SUPPORTED);

    /*
     * Resolve the user id if specified.
     */
    uid_t uid = ~(uid_t)0;
    gid_t gid = ~(gid_t)0;
    if (pszAsUser)
    {
        rc = rtCheckCredentials(pszAsUser, pszPassword, &gid, &uid);
        if (RT_FAILURE(rc))
            return rc;
    }

    /*
     * Create the child environment if either RTPROC_FLAGS_PROFILE or
     * RTPROC_FLAGS_ENV_CHANGE_RECORD are in effect.
     */
    RTENV hEnvToUse = hEnv;
    if (   (fFlags & (RTPROC_FLAGS_ENV_CHANGE_RECORD | RTPROC_FLAGS_PROFILE))
        && (   (fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD)
            || hEnv == RTENV_DEFAULT) )
    {
        if (fFlags & RTPROC_FLAGS_PROFILE)
            rc = rtProcPosixCreateProfileEnv(&hEnvToUse, pszAsUser);
        else
            rc = RTEnvClone(&hEnvToUse, RTENV_DEFAULT);
        if (RT_SUCCESS(rc))
        {
            if ((fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD) && hEnv != RTENV_DEFAULT)
                rc = RTEnvApplyChanges(hEnvToUse, hEnv);
            if (RT_FAILURE(rc))
                RTEnvDestroy(hEnvToUse);
        }
        if (RT_FAILURE(rc))
            return rc;
    }

    /*
     * Check for execute access to the file.
     */
    char szRealExec[RTPATH_MAX];
    if (access(pszExec, X_OK))
    {
        rc = errno;
        if (   !(fFlags & RTPROC_FLAGS_SEARCH_PATH)
            || rc != ENOENT
            || RTPathHavePath(pszExec) )
            rc = RTErrConvertFromErrno(rc);
        else
        {
            /* search */
            char *pszPath = RTEnvDupEx(hEnvToUse, "PATH");
            rc = RTPathTraverseList(pszPath, ':', rtPathFindExec, (void *)pszExec, &szRealExec[0]);
            RTStrFree(pszPath);
            if (RT_SUCCESS(rc))
                pszExec = szRealExec;
            else
                rc = rc == VERR_END_OF_STRING ? VERR_FILE_NOT_FOUND : rc;
        }

        if (RT_FAILURE(rc))
            return rtProcPosixCreateReturn(rc, hEnvToUse, hEnv);
    }

    pid_t pid = -1;
    const char * const *papszEnv = RTEnvGetExecEnvP(hEnvToUse);
    AssertPtrReturn(papszEnv, rtProcPosixCreateReturn(VERR_INVALID_HANDLE, hEnvToUse, hEnv));


    /*
     * Take care of detaching the process.
     *
     * HACK ALERT! Put the process into a new process group with pgid = pid
     * to make sure it differs from that of the parent process to ensure that
     * the IPRT waitpid call doesn't race anyone (read XPCOM) doing group wide
     * waits. setsid() includes the setpgid() functionality.
     * 2010-10-11 XPCOM no longer waits for anything, but it cannot hurt.
     */
#ifndef RT_OS_OS2
    if (fFlags & RTPROC_FLAGS_DETACHED)
    {
# ifdef RT_OS_SOLARIS
        int templateFd = -1;
        if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
        {
            templateFd = rtSolarisContractPreFork();
            if (templateFd == -1)
                return rtProcPosixCreateReturn(VERR_OPEN_FAILED, hEnvToUse, hEnv);
        }
# endif /* RT_OS_SOLARIS */
        pid = fork();
        if (!pid)
        {
# ifdef RT_OS_SOLARIS
            if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
                rtSolarisContractPostForkChild(templateFd);
# endif
            setsid(); /* see comment above */

            pid = -1;
            /* Child falls through to the actual spawn code below. */
        }
        else
        {
# ifdef RT_OS_SOLARIS
            if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
                rtSolarisContractPostForkParent(templateFd, pid);
# endif
            if (pid > 0)
            {
                /* Must wait for the temporary process to avoid a zombie. */
                int status = 0;
                pid_t pidChild = 0;

                /* Restart if we get interrupted. */
                do
                {
                    pidChild = waitpid(pid, &status, 0);
                } while (   pidChild == -1
                         && errno == EINTR);

                /* Assume that something wasn't found. No detailed info. */
                if (status)
                    return rtProcPosixCreateReturn(VERR_PROCESS_NOT_FOUND, hEnvToUse, hEnv);
                if (phProcess)
                    *phProcess = 0;
                return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv);
            }
            return rtProcPosixCreateReturn(RTErrConvertFromErrno(errno), hEnvToUse, hEnv);
        }
    }
#endif

    /*
     * Spawn the child.
     *
     * Any spawn code MUST not execute any atexit functions if it is for a
     * detached process. It would lead to running the atexit functions which
     * make only sense for the parent. libORBit e.g. gets confused by multiple
     * execution. Remember, there was only a fork() so far, and until exec()
     * is successfully run there is nothing which would prevent doing anything
     * silly with the (duplicated) file descriptors.
     */
#ifdef HAVE_POSIX_SPAWN
    /** @todo OS/2: implement DETACHED (BACKGROUND stuff), see VbglR3Daemonize.  */
    if (   uid == ~(uid_t)0
        && gid == ~(gid_t)0)
    {
        /* Spawn attributes. */
        posix_spawnattr_t Attr;
        rc = posix_spawnattr_init(&Attr);
        if (!rc)
        {
            /* Indicate that process group and signal mask are to be changed,
               and that the child should use default signal actions. */
            rc = posix_spawnattr_setflags(&Attr, POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF);
            Assert(rc == 0);

            /* The child starts in its own process group. */
            if (!rc)
            {
                rc = posix_spawnattr_setpgroup(&Attr, 0 /* pg == child pid */);
                Assert(rc == 0);
            }

            /* Unmask all signals. */
            if (!rc)
            {
                sigset_t SigMask;
                sigemptyset(&SigMask);
                rc = posix_spawnattr_setsigmask(&Attr, &SigMask); Assert(rc == 0);
            }

            /* File changes. */
            posix_spawn_file_actions_t  FileActions;
            posix_spawn_file_actions_t *pFileActions = NULL;
            if ((aStdFds[0] != -1 || aStdFds[1] != -1 || aStdFds[2] != -1) && !rc)
            {
                rc = posix_spawn_file_actions_init(&FileActions);
                if (!rc)
                {
                    pFileActions = &FileActions;
                    for (int i = 0; i < 3; i++)
                    {
                        int fd = aStdFds[i];
                        if (fd == -2)
                            rc = posix_spawn_file_actions_addclose(&FileActions, i);
                        else if (fd >= 0 && fd != i)
                        {
                            rc = posix_spawn_file_actions_adddup2(&FileActions, fd, i);
                            if (!rc)
                            {
                                for (int j = i + 1; j < 3; j++)
                                    if (aStdFds[j] == fd)
                                    {
                                        fd = -1;
                                        break;
                                    }
                                if (fd >= 0)
                                    rc = posix_spawn_file_actions_addclose(&FileActions, fd);
                            }
                        }
                        if (rc)
                            break;
                    }
                }
            }

            if (!rc)
                rc = posix_spawn(&pid, pszExec, pFileActions, &Attr, (char * const *)papszArgs,
                                 (char * const *)papszEnv);

            /* cleanup */
            int rc2 = posix_spawnattr_destroy(&Attr); Assert(rc2 == 0); NOREF(rc2);
            if (pFileActions)
            {
                rc2 = posix_spawn_file_actions_destroy(pFileActions);
                Assert(rc2 == 0);
            }

            /* return on success.*/
            if (!rc)
            {
                /* For a detached process this happens in the temp process, so
                 * it's not worth doing anything as this process must exit. */
                if (fFlags & RTPROC_FLAGS_DETACHED)
                    _Exit(0);
                if (phProcess)
                    *phProcess = pid;
                return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv);
            }
        }
        /* For a detached process this happens in the temp process, so
         * it's not worth doing anything as this process must exit. */
        if (fFlags & RTPROC_FLAGS_DETACHED)
            _Exit(124);
    }
    else
#endif
    {
#ifdef RT_OS_SOLARIS
        int templateFd = -1;
        if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
        {
            templateFd = rtSolarisContractPreFork();
            if (templateFd == -1)
                return rtProcPosixCreateReturn(VERR_OPEN_FAILED, hEnvToUse, hEnv);
        }
#endif /* RT_OS_SOLARIS */
        pid = fork();
        if (!pid)
        {
#ifdef RT_OS_SOLARIS
            if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
                rtSolarisContractPostForkChild(templateFd);
#endif /* RT_OS_SOLARIS */
            if (!(fFlags & RTPROC_FLAGS_DETACHED))
                setpgid(0, 0); /* see comment above */

            /*
             * Change group and user if requested.
             */
#if 1 /** @todo This needs more work, see suplib/hardening. */
            if (pszAsUser)
            {
                int ret = initgroups(pszAsUser, gid);
                if (ret)
                {
                    if (fFlags & RTPROC_FLAGS_DETACHED)
                        _Exit(126);
                    else
                        exit(126);
                }
            }
            if (gid != ~(gid_t)0)
            {
                if (setgid(gid))
                {
                    if (fFlags & RTPROC_FLAGS_DETACHED)
                        _Exit(126);
                    else
                        exit(126);
                }
            }

            if (uid != ~(uid_t)0)
            {
                if (setuid(uid))
                {
                    if (fFlags & RTPROC_FLAGS_DETACHED)
                        _Exit(126);
                    else
                        exit(126);
                }
            }
#endif

            /*
             * Some final profile environment tweaks, if running as user.
             */
            if (   (fFlags & RTPROC_FLAGS_PROFILE)
                && pszAsUser
                && (   (fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD)
                    || hEnv == RTENV_DEFAULT) )
            {
                rc = rtProcPosixAdjustProfileEnvFromChild(hEnvToUse, fFlags, hEnv);
                papszEnv = RTEnvGetExecEnvP(hEnvToUse);
                if (RT_FAILURE(rc) || !papszEnv)
                {
                    if (fFlags & RTPROC_FLAGS_DETACHED)
                        _Exit(126);
                    else
                        exit(126);
                }
            }

            /*
             * Unset the signal mask.
             */
            sigset_t SigMask;
            sigemptyset(&SigMask);
            rc = sigprocmask(SIG_SETMASK, &SigMask, NULL);
            Assert(rc == 0);

            /*
             * Apply changes to the standard file descriptor and stuff.
             */
            for (int i = 0; i < 3; i++)
            {
                int fd = aStdFds[i];
                if (fd == -2)
                    close(i);
                else if (fd >= 0)
                {
                    int rc2 = dup2(fd, i);
                    if (rc2 != i)
                    {
                        if (fFlags & RTPROC_FLAGS_DETACHED)
                            _Exit(125);
                        else
                            exit(125);
                    }
                    for (int j = i + 1; j < 3; j++)
                        if (aStdFds[j] == fd)
                        {
                            fd = -1;
                            break;
                        }
                    if (fd >= 0)
                        close(fd);
                }
            }

            /*
             * Finally, execute the requested program.
             */
            rc = execve(pszExec, (char * const *)papszArgs, (char * const *)papszEnv);
            if (errno == ENOEXEC)
            {
                /* This can happen when trying to start a shell script without the magic #!/bin/sh */
                RTAssertMsg2Weak("Cannot execute this binary format!\n");
            }
            else
                RTAssertMsg2Weak("execve returns %d errno=%d\n", rc, errno);
            RTAssertReleasePanic();
            if (fFlags & RTPROC_FLAGS_DETACHED)
                _Exit(127);
            else
                exit(127);
        }
#ifdef RT_OS_SOLARIS
        if (!(fFlags & RTPROC_FLAGS_SAME_CONTRACT))
            rtSolarisContractPostForkParent(templateFd, pid);
#endif /* RT_OS_SOLARIS */
        if (pid > 0)
        {
            /* For a detached process this happens in the temp process, so
             * it's not worth doing anything as this process must exit. */
            if (fFlags & RTPROC_FLAGS_DETACHED)
                _Exit(0);
            if (phProcess)
                *phProcess = pid;
            return rtProcPosixCreateReturn(VINF_SUCCESS, hEnvToUse, hEnv);
        }
        /* For a detached process this happens in the temp process, so
         * it's not worth doing anything as this process must exit. */
        if (fFlags & RTPROC_FLAGS_DETACHED)
            _Exit(124);
        return rtProcPosixCreateReturn(RTErrConvertFromErrno(errno), hEnvToUse, hEnv);
    }

    return rtProcPosixCreateReturn(VERR_NOT_IMPLEMENTED, hEnvToUse, hEnv);
}
Пример #24
0
/* Open a pipe connected to a child process.
 *
 *           write       system                read
 *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child       if pipe_stdin
 *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child       if pipe_stdout
 *           read        system                write
 *
 * At least one of pipe_stdin, pipe_stdout must be true.
 * pipe_stdin and prog_stdin together determine the child's standard input.
 * pipe_stdout and prog_stdout together determine the child's standard output.
 * If pipe_stdin is true, prog_stdin is ignored.
 * If pipe_stdout is true, prog_stdout is ignored.
 */
static pid_t
create_pipe (const char *progname,
             const char *prog_path, char **prog_argv,
             bool pipe_stdin, bool pipe_stdout,
             const char *prog_stdin, const char *prog_stdout,
             bool null_stderr,
             bool slave_process, bool exit_on_error,
             int fd[2])
{
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__

  /* Native Windows API.
     This uses _pipe(), dup2(), and spawnv().  It could also be implemented
     using the low-level functions CreatePipe(), DuplicateHandle(),
     CreateProcess() and _open_osfhandle(); see the GNU make and GNU clisp
     and cvs source code.  */
  int ifd[2];
  int ofd[2];
  int orig_stdin;
  int orig_stdout;
  int orig_stderr;
  int child;
  int nulloutfd;
  int stdinfd;
  int stdoutfd;
  int saved_errno;

  /* FIXME: Need to free memory allocated by prepare_spawn.  */
  prog_argv = prepare_spawn (prog_argv);

  if (pipe_stdout)
    if (pipe2_safer (ifd, O_BINARY | O_CLOEXEC) < 0)
      error (EXIT_FAILURE, errno, _("cannot create pipe"));
  if (pipe_stdin)
    if (pipe2_safer (ofd, O_BINARY | O_CLOEXEC) < 0)
      error (EXIT_FAILURE, errno, _("cannot create pipe"));
/* Data flow diagram:
 *
 *           write        system         read
 *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
 *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
 *           read         system         write
 *
 */

  /* Save standard file handles of parent process.  */
  if (pipe_stdin || prog_stdin != NULL)
    orig_stdin = dup_safer_noinherit (STDIN_FILENO);
  if (pipe_stdout || prog_stdout != NULL)
    orig_stdout = dup_safer_noinherit (STDOUT_FILENO);
  if (null_stderr)
    orig_stderr = dup_safer_noinherit (STDERR_FILENO);
  child = -1;

  /* Create standard file handles of child process.  */
  nulloutfd = -1;
  stdinfd = -1;
  stdoutfd = -1;
  if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
      && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
      && (!null_stderr
          || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
              && (nulloutfd == STDERR_FILENO
                  || (dup2 (nulloutfd, STDERR_FILENO) >= 0
                      && close (nulloutfd) >= 0))))
      && (pipe_stdin
          || prog_stdin == NULL
          || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
              && (stdinfd == STDIN_FILENO
                  || (dup2 (stdinfd, STDIN_FILENO) >= 0
                      && close (stdinfd) >= 0))))
      && (pipe_stdout
          || prog_stdout == NULL
          || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
              && (stdoutfd == STDOUT_FILENO
                  || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
                      && close (stdoutfd) >= 0)))))
    /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
       but it inherits all open()ed or dup2()ed file handles (which is what
       we want in the case of STD*_FILENO).  */
    /* Use spawnvpe and pass the environment explicitly.  This is needed if
       the program has modified the environment using putenv() or [un]setenv().
       On Windows, programs have two environments, one in the "environment
       block" of the process and managed through SetEnvironmentVariable(), and
       one inside the process, in the location retrieved by the 'environ'
       macro.  When using spawnvp() without 'e', the child process inherits a
       copy of the environment block - ignoring the effects of putenv() and
       [un]setenv().  */
    {
      child = spawnvpe (P_NOWAIT, prog_path, (const char **) prog_argv,
                        (const char **) environ);
      if (child < 0 && errno == ENOEXEC)
        {
          /* prog is not a native executable.  Try to execute it as a
             shell script.  Note that prepare_spawn() has already prepended
             a hidden element "sh.exe" to prog_argv.  */
          --prog_argv;
          child = spawnvpe (P_NOWAIT, prog_argv[0], (const char **) prog_argv,
                            (const char **) environ);
        }
    }
  if (child == -1)
    saved_errno = errno;
  if (stdinfd >= 0)
    close (stdinfd);
  if (stdoutfd >= 0)
    close (stdoutfd);
  if (nulloutfd >= 0)
    close (nulloutfd);

  /* Restore standard file handles of parent process.  */
  if (null_stderr)
    undup_safer_noinherit (orig_stderr, STDERR_FILENO);
  if (pipe_stdout || prog_stdout != NULL)
    undup_safer_noinherit (orig_stdout, STDOUT_FILENO);
  if (pipe_stdin || prog_stdin != NULL)
    undup_safer_noinherit (orig_stdin, STDIN_FILENO);

  if (pipe_stdin)
    close (ofd[0]);
  if (pipe_stdout)
    close (ifd[1]);
  if (child == -1)
    {
      if (exit_on_error || !null_stderr)
        error (exit_on_error ? EXIT_FAILURE : 0, saved_errno,
               _("%s subprocess failed"), progname);
      if (pipe_stdout)
        close (ifd[0]);
      if (pipe_stdin)
        close (ofd[1]);
      errno = saved_errno;
      return -1;
    }

  if (pipe_stdout)
    fd[0] = ifd[0];
  if (pipe_stdin)
    fd[1] = ofd[1];
  return child;

#else

  /* Unix API.  */
  int ifd[2];
  int ofd[2];
  sigset_t blocked_signals;
  posix_spawn_file_actions_t actions;
  bool actions_allocated;
  posix_spawnattr_t attrs;
  bool attrs_allocated;
  int err;
  pid_t child;

  if (pipe_stdout)
    if (pipe_safer (ifd) < 0)
      error (EXIT_FAILURE, errno, _("cannot create pipe"));
  if (pipe_stdin)
    if (pipe_safer (ofd) < 0)
      error (EXIT_FAILURE, errno, _("cannot create pipe"));
/* Data flow diagram:
 *
 *           write        system         read
 *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
 *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
 *           read         system         write
 *
 */

  if (slave_process)
    {
      sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
      block_fatal_signals ();
    }
  actions_allocated = false;
  attrs_allocated = false;
  if ((err = posix_spawn_file_actions_init (&actions)) != 0
      || (actions_allocated = true,
          (pipe_stdin
           && (err = posix_spawn_file_actions_adddup2 (&actions,
                                                       ofd[0], STDIN_FILENO))
              != 0)
          || (pipe_stdout
              && (err = posix_spawn_file_actions_adddup2 (&actions,
                                                          ifd[1], STDOUT_FILENO))
                 != 0)
          || (pipe_stdin
              && (err = posix_spawn_file_actions_addclose (&actions, ofd[0]))
                 != 0)
          || (pipe_stdout
              && (err = posix_spawn_file_actions_addclose (&actions, ifd[1]))
                 != 0)
          || (pipe_stdin
              && (err = posix_spawn_file_actions_addclose (&actions, ofd[1]))
                 != 0)
          || (pipe_stdout
              && (err = posix_spawn_file_actions_addclose (&actions, ifd[0]))
                 != 0)
          || (null_stderr
              && (err = posix_spawn_file_actions_addopen (&actions,
                                                          STDERR_FILENO,
                                                          "/dev/null", O_RDWR,
                                                          0))
                 != 0)
          || (!pipe_stdin
              && prog_stdin != NULL
              && (err = posix_spawn_file_actions_addopen (&actions,
                                                          STDIN_FILENO,
                                                          prog_stdin, O_RDONLY,
                                                          0))
                 != 0)
          || (!pipe_stdout
              && prog_stdout != NULL
              && (err = posix_spawn_file_actions_addopen (&actions,
                                                          STDOUT_FILENO,
                                                          prog_stdout, O_WRONLY,
                                                          0))
                 != 0)
          || (slave_process
              && ((err = posix_spawnattr_init (&attrs)) != 0
                  || (attrs_allocated = true,
                      (err = posix_spawnattr_setsigmask (&attrs,
                                                         &blocked_signals))
                      != 0
                      || (err = posix_spawnattr_setflags (&attrs,
                                                        POSIX_SPAWN_SETSIGMASK))
                         != 0)))
          ))
    {
      if (actions_allocated)
        posix_spawn_file_actions_destroy (&actions);
      if (attrs_allocated)
        posix_spawnattr_destroy (&attrs);
      if (slave_process)
        unblock_fatal_signals ();
      if (exit_on_error || !null_stderr)
        error (exit_on_error ? EXIT_FAILURE : 0, err,
               _("%s subprocess failed"), progname);
      if (pipe_stdout)
        {
          close (ifd[0]);
          close (ifd[1]);
        }
      if (pipe_stdin)
        {
          close (ofd[0]);
          close (ofd[1]);
        }
      errno = err;
      return -1;
    }
  posix_spawn_file_actions_destroy (&actions);
  if (attrs_allocated)
    posix_spawnattr_destroy (&attrs);
  if (slave_process)
    {
      register_slave_subprocess (child);
      unblock_fatal_signals ();
    }
  if (pipe_stdin)
    close (ofd[0]);
  if (pipe_stdout)
    close (ifd[1]);

  if (pipe_stdout)
    fd[0] = ifd[0];
  if (pipe_stdin)
    fd[1] = ofd[1];
  return child;

#endif
}
Пример #25
0
/**
 * Runs an executable in another process (or fork the current process)
 * and return immediately.
 *
 * This function launches an executable and returns immediately, while letting
 * the sub-process to run asynchronously.
 *
 * It is implemented as CreateProcess() on Windows platforms, and fork()/exec()
 * on other platforms.
 *
 * On Unix, a pointer of function can be provided to run in the child process,
 * without exec()'ing a new executable.
 *
 * @param pfnMain the function to run in the child process (Unix only).
 * @param papszArgv argument list of the executable to run. papszArgv[0] is the
 *                  name of the executable.
 * @param bCreateInputPipe set to TRUE to create a pipe for the child input stream.
 * @param bCreateOutputPipe set to TRUE to create a pipe for the child output stream.
 * @param bCreateErrorPipe set to TRUE to create a pipe for the child error stream.
 *
 * @return a handle, that must be freed with CPLSpawnAsyncFinish()
 *
 * @since GDAL 1.10.0
 */
CPLSpawnedProcess* CPLSpawnAsync(int (*pfnMain)(CPL_FILE_HANDLE, CPL_FILE_HANDLE),
                                 const char * const papszArgv[],
                                 int bCreateInputPipe,
                                 int bCreateOutputPipe,
                                 int bCreateErrorPipe,
                                 CPL_UNUSED char** papszOptions)
{
    int pipe_in[2] = { -1, -1 };
    int pipe_out[2] = { -1, -1 };
    int pipe_err[2] = { -1, -1 };
    bool bDup2In = CPL_TO_BOOL(bCreateInputPipe);
    bool bDup2Out = CPL_TO_BOOL(bCreateOutputPipe);
    bool bDup2Err = CPL_TO_BOOL(bCreateErrorPipe);

    if ((bCreateInputPipe && pipe(pipe_in)) ||
        (bCreateOutputPipe && pipe(pipe_out)) ||
        (bCreateErrorPipe && pipe(pipe_err)))
    {
        CPLError(CE_Failure, CPLE_AppDefined, "Could not create pipe");
        return NULL;
    }

    char** papszArgvDup = CSLDuplicate( const_cast<char **>( papszArgv ) );

    /* If we don't do any file actions, posix_spawnp() might be implemented */
    /* efficiently as a vfork()/exec() pair (or if it is not available, we */
    /* can use vfork()/exec()), so if the child is cooperative */
    /* we pass the pipe handles as commandline arguments */
    if( papszArgv != NULL )
    {
        for( int i=0; papszArgvDup[i] != NULL; i++ )
        {
            if( bCreateInputPipe && strcmp(papszArgvDup[i], "{pipe_in}") == 0 )
            {
                CPLFree(papszArgvDup[i]);
                papszArgvDup[i] = CPLStrdup(CPLSPrintf("%d,%d",
                    pipe_in[IN_FOR_PARENT], pipe_in[OUT_FOR_PARENT]));
                bDup2In = false;
            }
            else if( bCreateOutputPipe && strcmp(papszArgvDup[i], "{pipe_out}") == 0 )
            {
                CPLFree(papszArgvDup[i]);
                papszArgvDup[i] = CPLStrdup(CPLSPrintf("%d,%d",
                    pipe_out[OUT_FOR_PARENT], pipe_out[IN_FOR_PARENT]));
                bDup2Out = false;
            }
            else if( bCreateErrorPipe && strcmp(papszArgvDup[i], "{pipe_err}") == 0 )
            {
                CPLFree(papszArgvDup[i]);
                papszArgvDup[i] = CPLStrdup(CPLSPrintf("%d,%d",
                    pipe_err[OUT_FOR_PARENT], pipe_err[IN_FOR_PARENT]));
                bDup2Err = false;
            }
        }
    }

#ifdef HAVE_POSIX_SPAWNP
    if( papszArgv != NULL )
    {
        bool bHasActions = false;
        posix_spawn_file_actions_t actions;

        if( bDup2In )
        {
            if( !bHasActions ) posix_spawn_file_actions_init(&actions);
            posix_spawn_file_actions_adddup2(&actions, pipe_in[IN_FOR_PARENT], fileno(stdin));
            posix_spawn_file_actions_addclose(&actions, pipe_in[OUT_FOR_PARENT]);
            bHasActions = true;
        }

        if( bDup2Out )
        {
            if( !bHasActions ) posix_spawn_file_actions_init(&actions);
            posix_spawn_file_actions_adddup2(&actions, pipe_out[OUT_FOR_PARENT], fileno(stdout));
            posix_spawn_file_actions_addclose(&actions, pipe_out[IN_FOR_PARENT]);
            bHasActions = true;
        }

        if( bDup2Err )
        {
            if( !bHasActions ) posix_spawn_file_actions_init(&actions);
            posix_spawn_file_actions_adddup2(&actions, pipe_err[OUT_FOR_PARENT], fileno(stderr));
            posix_spawn_file_actions_addclose(&actions, pipe_err[IN_FOR_PARENT]);
            bHasActions = true;
        }

        pid_t pid;
        if( posix_spawnp(&pid, papszArgvDup[0],
                         bHasActions ? &actions : NULL,
                         NULL,
                         reinterpret_cast<char* const*>( papszArgvDup ),
                         environ) != 0 )
        {
            if( bHasActions )
                posix_spawn_file_actions_destroy(&actions);
            CPLError(CE_Failure, CPLE_AppDefined, "posix_spawnp() failed");
            goto err;
        }

        CSLDestroy(papszArgvDup);

        /* Close unused end of pipe */
        if( bCreateInputPipe )
            close(pipe_in[IN_FOR_PARENT]);
        if( bCreateOutputPipe )
            close(pipe_out[OUT_FOR_PARENT]);
        if( bCreateErrorPipe )
            close(pipe_err[OUT_FOR_PARENT]);

        /* Ignore SIGPIPE */
    #ifdef SIGPIPE
        std::signal( SIGPIPE, SIG_IGN );
    #endif
        CPLSpawnedProcess *p = static_cast<CPLSpawnedProcess *>(
            CPLMalloc( sizeof(CPLSpawnedProcess) ) );
        if( bHasActions )
            memcpy(&p->actions, &actions, sizeof(actions));
        p->bFreeActions = bHasActions;
        p->pid = pid;
        p->fin = pipe_out[IN_FOR_PARENT];
        p->fout = pipe_in[OUT_FOR_PARENT];
        p->ferr = pipe_err[IN_FOR_PARENT];
        return p;
    }
#endif // #ifdef HAVE_POSIX_SPAWNP

    pid_t pid;
#ifdef HAVE_VFORK
    /* coverity[dead_error_line] */
    if( papszArgv != NULL && !bDup2In && !bDup2Out && !bDup2Err )
    {
        /* Workaround clang static analyzer warning about unsafe use of vfork */
        pid_t (*p_vfork)(void) = vfork;
        pid = p_vfork();
    }
    else
#endif
        pid = fork();
    if (pid == 0)
    {
        /* Close unused end of pipe */
        if( bDup2In )
            close(pipe_in[OUT_FOR_PARENT]);
        if( bDup2Out )
            close(pipe_out[IN_FOR_PARENT]);
        if( bDup2Err )
            close(pipe_err[IN_FOR_PARENT]);

#ifndef HAVE_POSIX_SPAWNP
        if( papszArgv != NULL )
        {
            if( bDup2In )
                dup2(pipe_in[IN_FOR_PARENT], fileno(stdin));
            if( bDup2Out )
                dup2(pipe_out[OUT_FOR_PARENT], fileno(stdout));
            if( bDup2Err )
                dup2(pipe_err[OUT_FOR_PARENT], fileno(stderr));

            execvp(papszArgvDup[0], (char* const*) papszArgvDup);

            _exit(1);
        }
        else
#endif // HAVE_POSIX_SPAWNP
        {
            if( bCreateErrorPipe )
                close(pipe_err[OUT_FOR_PARENT]);

            int nRet = 0;
            if (pfnMain != NULL)
                nRet = pfnMain((bCreateInputPipe) ? pipe_in[IN_FOR_PARENT] : fileno(stdin),
                               (bCreateOutputPipe) ? pipe_out[OUT_FOR_PARENT] : fileno(stdout));
            _exit(nRet);
        }
    }
    else if( pid > 0 )
    {
        CSLDestroy(papszArgvDup);

        /* Close unused end of pipe */
        if( bCreateInputPipe )
            close(pipe_in[IN_FOR_PARENT]);
        if( bCreateOutputPipe )
            close(pipe_out[OUT_FOR_PARENT]);
        if( bCreateErrorPipe )
            close(pipe_err[OUT_FOR_PARENT]);

        /* Ignore SIGPIPE */
#ifdef SIGPIPE
        std::signal( SIGPIPE, SIG_IGN );
#endif
        CPLSpawnedProcess* p = static_cast<CPLSpawnedProcess *>(
            CPLMalloc( sizeof(CPLSpawnedProcess) ) );
#ifdef HAVE_POSIX_SPAWNP
        p->bFreeActions = FALSE;
#endif
        p->pid = pid;
        p->fin = pipe_out[IN_FOR_PARENT];
        p->fout = pipe_in[OUT_FOR_PARENT];
        p->ferr = pipe_err[IN_FOR_PARENT];
        return p;
    }
    else
    {
        CPLError(CE_Failure, CPLE_AppDefined, "Fork failed");
        goto err;
    }

err:
    CSLDestroy(papszArgvDup);
    for( int i = 0; i < 2; i++ )
    {
        if (pipe_in[i] >= 0)
            close(pipe_in[i]);
        if (pipe_out[i] >= 0)
            close(pipe_out[i]);
        if (pipe_err[i] >= 0)
            close(pipe_err[i]);
    }

    return NULL;
}
Пример #26
0
int					/* O - Process ID or 0 */
cupsdStartProcess(
    const char  *command,		/* I - Full path to command */
    char        *argv[],		/* I - Command-line arguments */
    char        *envp[],		/* I - Environment */
    int         infd,			/* I - Standard input file descriptor */
    int         outfd,			/* I - Standard output file descriptor */
    int         errfd,			/* I - Standard error file descriptor */
    int         backfd,			/* I - Backchannel file descriptor */
    int         sidefd,			/* I - Sidechannel file descriptor */
    int         root,			/* I - Run as root? */
    void        *profile,		/* I - Security profile to use */
    cupsd_job_t *job,			/* I - Job associated with process */
    int         *pid)			/* O - Process ID */
{
  int		i;			/* Looping var */
  const char	*exec_path = command;	/* Command to be exec'd */
  char		*real_argv[110],	/* Real command-line arguments */
		cups_exec[1024],	/* Path to "cups-exec" program */
		user_str[16],		/* User string */
		group_str[16],		/* Group string */
		nice_str[16];		/* FilterNice string */
  uid_t		user;			/* Command UID */
  cupsd_proc_t	*proc;			/* New process record */
#if USE_POSIX_SPAWN
  posix_spawn_file_actions_t actions;	/* Spawn file actions */
  posix_spawnattr_t attrs;		/* Spawn attributes */
  sigset_t	defsignals;		/* Default signals */
#elif defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction action;		/* POSIX signal handler */
#endif /* USE_POSIX_SPAWN */
#if defined(__APPLE__)
  char		processPath[1024],	/* CFProcessPath environment variable */
		linkpath[1024];		/* Link path for symlinks... */
  int		linkbytes;		/* Bytes for link path */
#endif /* __APPLE__ */


  *pid = 0;

 /*
  * Figure out the UID for the child process...
  */

  if (RunUser)
    user = RunUser;
  else if (root)
    user = 0;
  else
    user = User;

 /*
  * Check the permissions of the command we are running...
  */

  if (_cupsFileCheck(command, _CUPS_FILE_CHECK_PROGRAM, !RunUser,
                     cupsdLogFCMessage, job ? job->printer : NULL))
    return (0);

#if defined(__APPLE__)
  if (envp)
  {
   /*
    * Add special voodoo magic for OS X - this allows OS X programs to access
    * their bundle resources properly...
    */

    if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
    {
     /*
      * Yes, this is a symlink to the actual program, nul-terminate and
      * use it...
      */

      linkpath[linkbytes] = '\0';

      if (linkpath[0] == '/')
	snprintf(processPath, sizeof(processPath), "CFProcessPath=%s",
		 linkpath);
      else
	snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
		 dirname((char *)command), linkpath);
    }
    else
      snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command);

    envp[0] = processPath;		/* Replace <CFProcessPath> string */
  }
#endif	/* __APPLE__ */

 /*
  * Use helper program when we have a sandbox profile...
  */

#if !USE_POSIX_SPAWN
  if (profile)
#endif /* !USE_POSIX_SPAWN */
  {
    snprintf(cups_exec, sizeof(cups_exec), "%s/daemon/cups-exec", ServerBin);
    snprintf(user_str, sizeof(user_str), "%d", user);
    snprintf(group_str, sizeof(group_str), "%d", Group);
    snprintf(nice_str, sizeof(nice_str), "%d", FilterNice);

    real_argv[0] = cups_exec;
    real_argv[1] = (char *)"-g";
    real_argv[2] = group_str;
    real_argv[3] = (char *)"-n";
    real_argv[4] = nice_str;
    real_argv[5] = (char *)"-u";
    real_argv[6] = user_str;
    real_argv[7] = profile ? profile : "none";
    real_argv[8] = (char *)command;

    for (i = 0;
         i < (int)(sizeof(real_argv) / sizeof(real_argv[0]) - 10) && argv[i];
	 i ++)
      real_argv[i + 9] = argv[i];

    real_argv[i + 9] = NULL;

    argv      = real_argv;
    exec_path = cups_exec;
  }

  if (LogLevel == CUPSD_LOG_DEBUG2)
  {
    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: Preparing to start \"%s\", arguments:", command);

    for (i = 0; argv[i]; i ++)
      cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: argv[%d] = \"%s\"", i, argv[i]);
  }

#if USE_POSIX_SPAWN
 /*
  * Setup attributes and file actions for the spawn...
  */

  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: Setting spawn attributes.");
  sigemptyset(&defsignals);
  sigaddset(&defsignals, SIGTERM);
  sigaddset(&defsignals, SIGCHLD);
  sigaddset(&defsignals, SIGPIPE);

  posix_spawnattr_init(&attrs);
  posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF);
  posix_spawnattr_setpgroup(&attrs, 0);
  posix_spawnattr_setsigdefault(&attrs, &defsignals);

  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: Setting file actions.");
  posix_spawn_file_actions_init(&actions);
  if (infd != 0)
  {
    if (infd < 0)
      posix_spawn_file_actions_addopen(&actions, 0, "/dev/null", O_RDONLY, 0);
    else
      posix_spawn_file_actions_adddup2(&actions, infd, 0);
  }

  if (outfd != 1)
  {
    if (outfd < 0)
      posix_spawn_file_actions_addopen(&actions, 1, "/dev/null", O_WRONLY, 0);
    else
      posix_spawn_file_actions_adddup2(&actions, outfd, 1);
  }

  if (errfd != 2)
  {
    if (errfd < 0)
      posix_spawn_file_actions_addopen(&actions, 2, "/dev/null", O_WRONLY, 0);
    else
      posix_spawn_file_actions_adddup2(&actions, errfd, 2);
  }

  if (backfd != 3 && backfd >= 0)
    posix_spawn_file_actions_adddup2(&actions, backfd, 3);

  if (sidefd != 4 && sidefd >= 0)
    posix_spawn_file_actions_adddup2(&actions, sidefd, 4);

  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: Calling posix_spawn.");

  if (posix_spawn(pid, exec_path, &actions, &attrs, argv, envp ? envp : environ))
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork %s - %s.", command, strerror(errno));

    *pid = 0;
  }
  else
    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: pid=%d", (int)*pid);

  posix_spawn_file_actions_destroy(&actions);
  posix_spawnattr_destroy(&attrs);

#else
 /*
  * Block signals before forking...
  */

  cupsdHoldSignals();

  if ((*pid = fork()) == 0)
  {
   /*
    * Child process goes here; update stderr as needed...
    */

    if (errfd != 2)
    {
      if (errfd < 0)
        errfd = open("/dev/null", O_WRONLY);

      if (errfd != 2)
      {
        dup2(errfd, 2);
	close(errfd);
      }
    }

   /*
    * Put this process in its own process group so that we can kill any child
    * processes it creates.
    */

#  ifdef HAVE_SETPGID
    if (!RunUser && setpgid(0, 0))
      exit(errno + 100);
#  else
    if (!RunUser && setpgrp())
      exit(errno + 100);
#  endif /* HAVE_SETPGID */

   /*
    * Update the remaining file descriptors as needed...
    */

    if (infd != 0)
    {
      if (infd < 0)
        infd = open("/dev/null", O_RDONLY);

      if (infd != 0)
      {
        dup2(infd, 0);
	close(infd);
      }
    }

    if (outfd != 1)
    {
      if (outfd < 0)
        outfd = open("/dev/null", O_WRONLY);

      if (outfd != 1)
      {
        dup2(outfd, 1);
	close(outfd);
      }
    }

    if (backfd != 3 && backfd >= 0)
    {
      dup2(backfd, 3);
      close(backfd);
      fcntl(3, F_SETFL, O_NDELAY);
    }

    if (sidefd != 4 && sidefd >= 0)
    {
      dup2(sidefd, 4);
      close(sidefd);
      fcntl(4, F_SETFL, O_NDELAY);
    }

   /*
    * Change the priority of the process based on the FilterNice setting.
    * (this is not done for root processes...)
    */

    if (!root)
      nice(FilterNice);

   /*
    * Reset group membership to just the main one we belong to.
    */

    if (!RunUser && setgid(Group))
      exit(errno + 100);

    if (!RunUser && setgroups(1, &Group))
      exit(errno + 100);

   /*
    * Change user to something "safe"...
    */

    if (!RunUser && user && setuid(user))
      exit(errno + 100);

   /*
    * Change umask to restrict permissions on created files...
    */

    umask(077);

   /*
    * Unblock signals before doing the exec...
    */

#  ifdef HAVE_SIGSET
    sigset(SIGTERM, SIG_DFL);
    sigset(SIGCHLD, SIG_DFL);
    sigset(SIGPIPE, SIG_DFL);
#  elif defined(HAVE_SIGACTION)
    memset(&action, 0, sizeof(action));

    sigemptyset(&action.sa_mask);
    action.sa_handler = SIG_DFL;

    sigaction(SIGTERM, &action, NULL);
    sigaction(SIGCHLD, &action, NULL);
    sigaction(SIGPIPE, &action, NULL);
#  else
    signal(SIGTERM, SIG_DFL);
    signal(SIGCHLD, SIG_DFL);
    signal(SIGPIPE, SIG_DFL);
#  endif /* HAVE_SIGSET */

    cupsdReleaseSignals();

   /*
    * Execute the command; if for some reason this doesn't work, log an error
    * exit with a non-zero value...
    */

    if (envp)
      execve(exec_path, argv, envp);
    else
      execv(exec_path, argv);

    exit(errno + 100);
  }
  else if (*pid < 0)
  {
   /*
    * Error - couldn't fork a new process!
    */

    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork %s - %s.", command,
                    strerror(errno));

    *pid = 0;
  }

  cupsdReleaseSignals();
#endif /* USE_POSIX_SPAWN */

  if (*pid)
  {
    if (!process_array)
      process_array = cupsArrayNew((cups_array_func_t)compare_procs, NULL);

    if (process_array)
    {
      if ((proc = calloc(1, sizeof(cupsd_proc_t) + strlen(command))) != NULL)
      {
        proc->pid    = *pid;
	proc->job_id = job ? job->id : 0;
	_cups_strcpy(proc->name, command);

	cupsArrayAdd(process_array, proc);
      }
    }
  }

  cupsdLogMessage(CUPSD_LOG_DEBUG2,
		  "cupsdStartProcess(command=\"%s\", argv=%p, envp=%p, "
		  "infd=%d, outfd=%d, errfd=%d, backfd=%d, sidefd=%d, root=%d, "
		  "profile=%p, job=%p(%d), pid=%p) = %d",
		  command, argv, envp, infd, outfd, errfd, backfd, sidefd,
		  root, profile, job, job ? job->id : 0, pid, *pid);

  return (*pid);
}
Пример #27
0
int swift_posix_spawn_file_actions_destroy(
    posix_spawn_file_actions_t *file_actions) {
  return posix_spawn_file_actions_destroy(file_actions);
}
Пример #28
0
int
main ()
{
  char *argv[3] = { "/bin/sh", CHILD_PROGRAM_FILENAME, NULL };
  int ofd[2];
  sigset_t blocked_signals;
  sigset_t fatal_signal_set;
  posix_spawn_file_actions_t actions;
  bool actions_allocated;
  posix_spawnattr_t attrs;
  bool attrs_allocated;
  int err;
  pid_t child;
  int fd;
  FILE *fp;
  int written;
  int status;
  int exitstatus;

  if (pipe (ofd) < 0 || (ofd[1] = fd_safer (ofd[1])) < 0)
    {
      perror ("cannot create pipe");
      exit (1);
    }
  sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
  sigemptyset (&fatal_signal_set);
  sigaddset (&fatal_signal_set, SIGINT);
  sigaddset (&fatal_signal_set, SIGTERM);
  sigaddset (&fatal_signal_set, SIGHUP);
  sigaddset (&fatal_signal_set, SIGPIPE);
  sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
  actions_allocated = false;
  attrs_allocated = false;
  if ((err = posix_spawn_file_actions_init (&actions)) != 0
      || (actions_allocated = true,
          (err = posix_spawn_file_actions_adddup2 (&actions, ofd[0], STDIN_FILENO)) != 0
          || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0
          || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0
          || (err = posix_spawnattr_init (&attrs)) != 0
          || (attrs_allocated = true,
              (err = posix_spawnattr_setsigmask (&attrs, &blocked_signals)) != 0
              || (err = posix_spawnattr_setflags (&attrs, POSIX_SPAWN_SETSIGMASK)) != 0)
          || (err = posix_spawnp (&child, "/bin/sh", &actions, &attrs, argv, environ)) != 0))
    {
      if (actions_allocated)
        posix_spawn_file_actions_destroy (&actions);
      if (attrs_allocated)
        posix_spawnattr_destroy (&attrs);
      sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
      errno = err;
      perror ("subprocess failed");
      exit (1);
    }
  posix_spawn_file_actions_destroy (&actions);
  posix_spawnattr_destroy (&attrs);
  sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
  close (ofd[0]);
  fd = ofd[1];
  fp = fdopen (fd, "w");
  if (fp == NULL)
    {
      fprintf (stderr, "fdopen() failed\n");
      exit (1);
    }
  written = fwrite ("Halle Potta\n", 1, 12, fp);
  if (written < 12)
    {
      fprintf (stderr, "could not write input\n");
      exit (1);
    }
  fclose (fp);
  status = 0;
  while (waitpid (child, &status, 0) != child)
    ;
  if (!WIFEXITED (status))
    {
      fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
      exit (1);
    }
  exitstatus = WEXITSTATUS (status);
  if (exitstatus != 0)
    {
      fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
      exit (1);
    }
  return 0;
}
Пример #29
0
static int dropbox_update(void *data)
{
	struct dropbox_section *section = data;
	char *argv[] = {"dropbox.py", "status", NULL};
	posix_spawn_file_actions_t file_actions;
	posix_spawnattr_t attr;
	int status = -1;
	sigset_t mask;
	int pipefd[2] = {-1, -1};
	pid_t pid;
	int ret;

	section->running = false;

	errno = posix_spawn_file_actions_init(&file_actions);
	if (errno) {
		perror("posix_spawn_file_actions_init");
		return -1;
	}

	errno = posix_spawnattr_init(&attr);
	if (errno) {
		perror("posix_spawnattr_init");
		goto out_file_actions;
	}

	ret = pipe(pipefd);
	if (ret) {
		perror("pipe2");
		goto out_spawnattr;
	}

	errno = posix_spawn_file_actions_addclose(&file_actions, pipefd[0]);
	if (errno) {
		perror("posix_spawn_file_actions_addclose");
		goto out;
	}

	errno = posix_spawn_file_actions_adddup2(&file_actions, pipefd[1],
						 STDOUT_FILENO);
	if (errno) {
		perror("posix_spawn_file_actions_adddup2");
		goto out;
	}

	sigemptyset(&mask);
	errno = posix_spawnattr_setsigmask(&attr, &mask);
	if (errno) {
		perror("posix_spawnattr_setsigmask");
		goto out;
	}

	errno = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK);
	if (errno) {
		perror("posix_spawnattr_setflags");
		goto out;
	}

	errno = posix_spawnp(&pid, "dropbox-cli", &file_actions, &attr, argv,
			     environ);
	if (errno) {
		perror("posix_spawnp");
		status = 0;
		goto out;
	}

	close(pipefd[1]);
	ret = read_all_output(section, pid, pipefd[0]);
	if (ret) {
		if (errno == ENOMEM)
			status = -1;
		else
			status = 0;
		goto out;
	}

	if (strcmp(section->status.buf, "Dropbox isn't running!\n") != 0)
		section->running = true;

	if (strcmp(section->status.buf, "Up to date\n") == 0 ||
	    strcmp(section->status.buf, "Idle\n") == 0)
		section->uptodate = true;
	else
		section->uptodate = false;

	status = 0;
out:
	close(pipefd[0]);
	close(pipefd[1]);
out_spawnattr:
	posix_spawnattr_destroy(&attr);
out_file_actions:
	posix_spawn_file_actions_destroy(&file_actions);
	return status;
}
Пример #30
0
static void spawn_command(w_root_t *root,
  struct watchman_trigger_command *cmd,
  w_query_res *res,
  struct w_clockspec *since_spec)
{
  char **envp = NULL;
  uint32_t i = 0;
  int ret;
  int stdin_fd = -1;
  json_t *args;
  char **argv = NULL;
  uint32_t env_size;
  posix_spawn_file_actions_t actions;
  posix_spawnattr_t attr;
  sigset_t mask;
  long arg_max;
  uint32_t argspace_remaining;
  bool file_overflow = false;
  int result_log_level;
  char clockbuf[128];
  const char *cwd = NULL;

  arg_max = sysconf(_SC_ARG_MAX);

  if (arg_max <= 0) {
    argspace_remaining = UINT_MAX;
  } else {
    argspace_remaining = (uint32_t)arg_max;
  }

  // Allow some misc working overhead
  argspace_remaining -= 32;

  stdin_fd = prepare_stdin(cmd, res);

  // Assumption: that only one thread will be executing on a given
  // cmd instance so that mutation of cmd->envht is safe.
  // This is guaranteed in the current architecture.

  if (cmd->max_files_stdin > 0 && res->num_results > cmd->max_files_stdin) {
    file_overflow = true;
  }

  // It is way too much of a hassle to try to recreate the clock value if it's
  // not a relative clock spec, and it's only going to happen on the first run
  // anyway, so just skip doing that entirely.
  if (since_spec && since_spec->tag == w_cs_clock &&
      clock_id_string(since_spec->clock.root_number, since_spec->clock.ticks,
                      clockbuf, sizeof(clockbuf))) {
    w_envp_set_cstring(cmd->envht, "WATCHMAN_SINCE", clockbuf);
  } else {
    w_envp_unset(cmd->envht, "WATCHMAN_SINCE");
  }

  if (clock_id_string(res->root_number, res->ticks,
        clockbuf, sizeof(clockbuf))) {
    w_envp_set_cstring(cmd->envht, "WATCHMAN_CLOCK", clockbuf);
  } else {
    w_envp_unset(cmd->envht, "WATCHMAN_CLOCK");
  }

  if (cmd->query->relative_root) {
    w_envp_set(cmd->envht, "WATCHMAN_RELATIVE_ROOT", cmd->query->relative_root);
  } else {
    w_envp_unset(cmd->envht, "WATCHMAN_RELATIVE_ROOT");
  }

  // Compute args
  args = json_deep_copy(cmd->command);

  if (cmd->append_files) {
    // Measure how much space the base args take up
    for (i = 0; i < json_array_size(args); i++) {
      const char *ele = json_string_value(json_array_get(args, i));

      argspace_remaining -= strlen(ele) + 1 + sizeof(char*);
    }

    // Dry run with env to compute space
    envp = w_envp_make_from_ht(cmd->envht, &env_size);
    free(envp);
    envp = NULL;
    argspace_remaining -= env_size;

    for (i = 0; i < res->num_results; i++) {
      // also: NUL terminator and entry in argv
      uint32_t size = res->results[i].relname->len + 1 + sizeof(char*);

      if (argspace_remaining < size) {
        file_overflow = true;
        break;
      }
      argspace_remaining -= size;

      json_array_append_new(
        args,
        json_string_nocheck(res->results[i].relname->buf)
      );
    }
  }

  argv = w_argv_copy_from_json(args, 0);
  json_decref(args);
  args = NULL;

  w_envp_set_bool(cmd->envht, "WATCHMAN_FILES_OVERFLOW", file_overflow);

  envp = w_envp_make_from_ht(cmd->envht, &env_size);

  posix_spawnattr_init(&attr);
  sigemptyset(&mask);
  posix_spawnattr_setsigmask(&attr, &mask);
  posix_spawnattr_setflags(&attr,
      POSIX_SPAWN_SETSIGMASK|
#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
      // Darwin: close everything except what we put in file actions
      POSIX_SPAWN_CLOEXEC_DEFAULT|
#endif
      POSIX_SPAWN_SETPGROUP);

  posix_spawn_file_actions_init(&actions);

  posix_spawn_file_actions_adddup2(&actions, stdin_fd, STDIN_FILENO);
  if (cmd->stdout_name) {
    posix_spawn_file_actions_addopen(&actions, STDOUT_FILENO,
        cmd->stdout_name, cmd->stdout_flags, 0666);
  } else {
    posix_spawn_file_actions_adddup2(&actions, STDOUT_FILENO, STDOUT_FILENO);
  }

  if (cmd->stderr_name) {
    posix_spawn_file_actions_addopen(&actions, STDERR_FILENO,
        cmd->stderr_name, cmd->stderr_flags, 0666);
  } else {
    posix_spawn_file_actions_adddup2(&actions, STDERR_FILENO, STDERR_FILENO);
  }

  pthread_mutex_lock(&spawn_lock);
  if (cmd->query->relative_root) {
    ignore_result(chdir(cmd->query->relative_root->buf));
  } else {
    ignore_result(chdir(root->root_path->buf));
  }

  json_unpack(cmd->definition, "{s:s}", "chdir", &cwd);
  if (cwd) {
    ignore_result(chdir(cwd));
  }

  ret = posix_spawnp(&cmd->current_proc, argv[0], &actions, &attr, argv, envp);
  if (ret == 0) {
    w_root_addref(root);
    insert_running_pid(cmd->current_proc, root);
  } else {
    // On Darwin (at least), posix_spawn can fail but will still populate the
    // pid.  Since we use the pid to gate future spawns, we need to ensure
    // that we clear out the pid on failure, otherwise the trigger would be
    // effectively disabled for the rest of the watch lifetime
    cmd->current_proc = 0;
  }
  ignore_result(chdir("/"));
  pthread_mutex_unlock(&spawn_lock);

  // If failed, we want to make sure we log enough info to figure out why
  result_log_level = res == 0 ? W_LOG_DBG : W_LOG_ERR;

  w_log(result_log_level, "posix_spawnp:\n");
  for (i = 0; argv[i]; i++) {
    w_log(result_log_level, "argv[%d] %s\n", i, argv[i]);
  }
  for (i = 0; envp[i]; i++) {
    w_log(result_log_level, "envp[%d] %s\n", i, envp[i]);
  }

  w_log(result_log_level, "trigger %.*s:%s pid=%d ret=%d %s\n",
      (int)root->root_path->len,
      root->root_path->buf,
      cmd->triggername->buf, (int)cmd->current_proc, ret, strerror(ret));

  free(argv);
  free(envp);

  posix_spawnattr_destroy(&attr);
  posix_spawn_file_actions_destroy(&actions);

  if (stdin_fd != -1) {
    close(stdin_fd);
  }
}