pid_t VG_REPLACE_FUNCTION_ZU(libastZdsoZd1, spawnveg)(const char *command,
                                                      char **argv,
                                                      char **envp,
                                                      pid_t pgid)
{
   int err = 0;
   pid_t pid;
   posix_spawnattr_t attr;
   int attr_init_done = 0;

   err = posix_spawnattr_init(&attr);
   if (err != 0)
      goto out;
   attr_init_done = 1;

   err = posix_spawnattr_init(&attr);
   if (err != 0)
      goto out;

   if (pgid != 0) {
      if (pgid <= 1)
         pgid = 0;
      err = posix_spawnattr_setpgroup(&attr, pgid);
      if (err != 0)
         goto out;
      err = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP);
      if (err != 0)
         goto out;
   }

   err = posix_spawn(&pid, command, NULL, &attr, argv, envp ? envp : environ);

out:
   if (attr_init_done)
      posix_spawnattr_destroy(&attr);
   if (err != 0) {
      errno = err;
      return -1;
   }
   return pid;
}
TInt CTestSendsignal::TestNegativeKill2 (  )
	{  
	int ret1 = KErrGeneral, pid, pid1, Signum, ret, status;
	char **argv=(char**)malloc(3*sizeof(char*));
	ret = GetIntFromConfig(ConfigSection(), _L("Signum"), Signum);
	if(ret == 0)
		{
		ERR_PRINTF1(_L("Failed to read the signal number")) ;
		goto close; 
		}
	argv[0]=(char*)malloc(34*sizeof(char));
	argv[1]= 0;
	strcpy(argv[0], "z:\\sys\\bin\\receivesignal.exe");
	ret = posix_spawn(&pid, "z:\\sys\\bin\\receivesignal.exe", NULL, NULL, argv, (char**)NULL);
	if(ret != 0)
		{
		ERR_PRINTF2(_L("Error in posix spawn and errno is set to %d"),errno);
		goto close;
		}
	INFO_PRINTF2( _L("the value of pid returned by posix_spawn is %d"),  pid);
	ret = kill(pid,Signum);
	INFO_PRINTF1(_L("Negative test on Kill()"));
	if((ret != -1) || (errno != EINVAL))
		{
		ERR_PRINTF1(_L("Failed to set the return value"));	
		goto close;
		}
	pid1 = waitpid(pid, &status, WUNTRACED);
	if (pid1 != pid)
		{
		ERR_PRINTF1(_L("waitpid failed..."));	
		goto close;
		}	
	INFO_PRINTF1(_L("Both the return and expected value of kill() are same"));
	ret1 = KErrNone;
	
	close:
	free((void*)argv[0]);
	free((void*)argv);
	return ret1;
	}
Exemple #3
0
GF_EXPORT
GF_Err gf_move_file(const char *fileName, const char *newFileName)
{
#if defined(_WIN32_WCE)
	TCHAR swzName[MAX_PATH];
	TCHAR swzNewName[MAX_PATH];
	CE_CharToWide((char*)fileName, swzName);
	CE_CharToWide((char*)newFileName, swzNewName);
	return (MoveFile(swzName, swzNewName) == 0 ) ? GF_IO_ERR : GF_OK;
#elif defined(WIN32)
	/* success if != 0 */
	return (MoveFile(fileName, newFileName) == 0 ) ? GF_IO_ERR : GF_OK;
#else
	GF_Err e = GF_IO_ERR;
	char cmd[1024], *arg1, *arg2;
	if (!fileName || !newFileName)
		return GF_IO_ERR;
	arg1 = gf_sanetize_single_quoted_string(fileName);
	arg2 = gf_sanetize_single_quoted_string(newFileName);
	if (snprintf(cmd, sizeof cmd, "mv %s %s", arg1, arg2) >= sizeof cmd) goto error;

#if defined(GPAC_IPHONE) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)
	{
		pid_t pid;
		char *argv[3];
		argv[0] = "mv";
		argv[1] = cmd;
		argv[2] = NULL;
		posix_spawn(&pid, argv[0], NULL, NULL, argv, environ);
		waitpid(pid, NULL, 0);
	}
#else
	e = (system(cmd) == 0) ? GF_OK : GF_IO_ERR;
#endif
	
error:
	gf_free(arg1);
	gf_free(arg2);
	return e;
#endif
}
TInt CTestSendsignal::TestNegativeSigqueue1 (  )
	{   
	int ret1 = KErrGeneral, pid, pid1, ret, status;
	union sigval sival;
	char **argv=(char**)malloc(3*sizeof(char*));
	argv[0]=(char*)malloc(34*sizeof(char));
	argv[1]=(char*)malloc(3*sizeof(char));
	argv[2]= 0;
	strcpy(argv[0], "z:\\sys\\bin\\receivesignal.exe");
	sprintf(argv[1], "%d", 0);	
	ret = posix_spawn(&pid, "z:\\sys\\bin\\receivesignal.exe", NULL, NULL, argv, (char**)NULL);
	if(ret != 0)
		{
		ERR_PRINTF2(_L("Error in posix spawn and errno is set to %d"),errno);
		goto close;
		}
	INFO_PRINTF2( _L("the value of pid returned by posix_spawn is %d"),  pid);
	sival.sival_int = 0;
	ret = sigqueue(pid,0,sival);
	INFO_PRINTF1(_L("Negative test on sigqueue()"));
	if(ret != 0)
		{
		ERR_PRINTF1(_L("Failed to set the return value"));	
		goto close;
		}
	pid1 = waitpid(pid, &status, WUNTRACED);
	if (pid1 != pid)
		{
		ERR_PRINTF1(_L("waitpid failed..."));	
		goto close;
		}	
	INFO_PRINTF1(_L("Kill() returned 0 as the process exists"));
	ret1 = KErrNone;

	close:
	free((void*)argv[0]);
	free((void*)argv[1]);
	free((void*)argv);
	return ret1;
	}
Exemple #5
0
pid_t
rb_spawn_process(const char *path, const char **argv)
{
	pid_t pid;
	const void *arghack = argv;
	char **myenviron;
	posix_spawnattr_t spattr;
	posix_spawnattr_init(&spattr);
#ifdef POSIX_SPAWN_USEVFORK
	posix_spawnattr_setflags(&spattr, POSIX_SPAWN_USEVFORK);
#endif
#ifdef __APPLE__
 	myenviron = *_NSGetEnviron(); /* apple needs to go f**k themselves for this */
#else
	myenviron = environ;
#endif
	if(posix_spawn(&pid, path, NULL, &spattr, arghack, myenviron))
	{
		return -1;
	}
	return pid;
}
Exemple #6
0
pid_t
spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
{
	int			err;
	pid_t			pid;
	posix_spawnattr_t	attr;

	if (err = posix_spawnattr_init(&attr))
		goto nope;
	if (pgid)
	{
		if (pgid <= 1)
			pgid = 0;
		if (err = posix_spawnattr_setpgroup(&attr, pgid))
			goto bad;
		if (err = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP))
			goto bad;
	}
	if (err = posix_spawn(&pid, path, NiL, &attr, argv, envv ? envv : environ))
		goto bad;
	posix_spawnattr_destroy(&attr);
#if _lib_posix_spawn < 2
	if (waitpid(pid, &err, WNOHANG|WNOWAIT) == pid && EXIT_STATUS(err) == 127)
	{
		while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
		if (!access(path, X_OK))
			errno = ENOEXEC;
		pid = -1;
	}
#endif
	return pid;
 bad:
	posix_spawnattr_destroy(&attr);
 nope:
	errno = err;
	return -1;
}
BatteryOutput TestRunner::executeBinary(Logger * logger,
                                        const std::string & objectInfo,
                                        const std::string & binaryPath,
                                        const std::string & arguments,
                                        const std::string & input) {
    int stdin_pipe[2];
    int stdout_pipe[2];
    int stderr_pipe[2];

    pid_t pid = 0;
    posix_spawn_file_actions_t actions;

    if(pipe(stdin_pipe) || pipe(stdout_pipe) || pipe(stderr_pipe)) {
        logger->warn(objectInfo + ": pipe creation failed. Test won't be executed.");
        {
            /* Remove thread from list of threads without child, notify and end */
            std::lock_guard<std::mutex> l (withoutChild_mux);
            --withoutChild;
        }
        withoutChild_cv.notify_one();
        return {};
    }

    /* Pipes will be mapped to I/O after process start */
    /* Unused ends are closed */
    posix_spawn_file_actions_init(&actions);
    /* Standard input */
    posix_spawn_file_actions_addclose(&actions , stdin_pipe[1]);
    posix_spawn_file_actions_adddup2(&actions , stdin_pipe[0] , 0);
    posix_spawn_file_actions_addclose(&actions , stdin_pipe[0]);
    /* Standard output */
    posix_spawn_file_actions_addclose(&actions , stdout_pipe[0]);
    posix_spawn_file_actions_adddup2(&actions , stdout_pipe[1] , 1);
    posix_spawn_file_actions_addclose(&actions , stdout_pipe[1]);
    /* Standard error output */
    posix_spawn_file_actions_addclose(&actions , stderr_pipe[0]);
    posix_spawn_file_actions_adddup2(&actions , stderr_pipe[1] , 2);
    posix_spawn_file_actions_addclose(&actions , stderr_pipe[1]);

    int argc = 0;
    char ** args = buildArgv(arguments , &argc);

    /* Creating locks but not locking them yet */
    std::unique_lock<std::mutex> finishedPid_lock(finishedPid_mux , std::defer_lock);
    std::unique_lock<std::mutex> withoutChild_lock(withoutChild_mux , std::defer_lock);
    std::unique_lock<std::mutex> waitingForChild_lock(waitingForChild_mux , std::defer_lock);
    std::unique_lock<std::mutex> childReceived_lock(childReceived_mux , std::defer_lock);
    std::unique_lock<std::mutex> threadsReady_lock(threadState_mux , std::defer_lock);

    /* Need both locks, if they cannot be acquired
     * main thread is waiting for process to end */
    std::lock(finishedPid_lock , waitingForChild_lock);

    /* Starting child process of this thread */
    logger->info(objectInfo + ": spawning child process with arguments " + arguments);
    int status = posix_spawn(&pid , binaryPath.c_str() ,
                             &actions , NULL , args , NULL);

    if(status == 0) {
        /* Process was started without problems, proceed */
        logger->info(objectInfo + ": child process has pid " + Utils::itostr(pid));
        /* Closing pipes */
        close(stdin_pipe[0]);
        close(stdout_pipe[1]);
        close(stderr_pipe[1]);
        if(!input.empty())
            write(stdin_pipe[1] , input.c_str() , input.length());
        /* Start thread for output reading. Thread will be mostly in blocked wait.
         * Also will be essentially over as soon as the process finishes.
         * With this, pipes won't be filled and won't block underlying process. */
        BatteryOutput output;
        std::thread reader(readOutput , std::ref(output),
                           stdout_pipe , stderr_pipe);

        /* Incrementing number of threads waiting.
         * Only if this variable is same as withoutChild
         * main thread can start reaping child processes. */
        ++waitingForChild;
        waitingForChild_lock.unlock();
        waitingForChild_cv.notify_one();

        /* Waiting for PID. PID is annouced by main thread and thread
         * will work with his associated process only
         * (because the thread owns the pipes to this process) */
        auto now = std::chrono::system_clock::now();
        /* Don't know why, but if I use TIMEOUT constant directly in argument it won't compile... */
        int vArgumenteToJebeChybu = PROCESS_TIMEOUT_SECONDS;
        if(!finishedPid_cv.wait_until(finishedPid_lock ,
                                      now + std::chrono::seconds(vArgumenteToJebeChybu) ,
                                      [&] { return finishedPid == pid; })) {
            /* If thread goes into this branch, its process timeouted.
             * Send kill signal to it, main thread will then reap it.
             * That's why this go into wait once more (usually it will instantly return) */
            logger->warn(objectInfo + ": child process with pid " + Utils::itostr(pid) + " timeouted."
                         " Process will be killed now.");
            kill(pid , SIGKILL);
            finishedPid_cv.wait(finishedPid_lock , [&] { return finishedPid == pid; });
        }
        /* Obtaining all possible mutexes, decrementing variables that
         * track waiting and active threads, setting childReceived to true
         * so main thread will be notified */
        std::lock(withoutChild_lock , waitingForChild_lock , childReceived_lock);
        logger->info(objectInfo + ": child process with pid " + Utils::itostr(pid) + " finished");
        childReceived = true;
        --waitingForChild;
        --withoutChild;
        /* Unlock mutexes, this thread no longer needs them */
        finishedPid_lock.unlock();
        waitingForChild_lock.unlock();
        withoutChild_lock.unlock();
        childReceived_lock.unlock();
        /* Notify threadCreator that number of active threads changed.
         * He will spawn new threads if there is a need to. */
        withoutChild_cv.notify_one();

        /* This thread need to wait for notification from threadMaker
         * that it is ok to continue and after that, main thread can
         * be notified that child process was received and is being
         * processed.*/
        threadsReady_lock.lock();
        threadState_cv.wait(threadsReady_lock ,
                            []{ return (threadState == THREAD_STATE_DONE) ||
                                       (threadState == THREAD_STATE_READY); });
        if(threadState == THREAD_STATE_READY) {
            /* Flip threadState so next thread must wait too. */
            threadState = THREAD_STATE_PENDING;
        }
        threadsReady_lock.unlock();

        /* Notify main thread that it can continue in reaping processes */
        childReceived_cv.notify_one();
        /* This thread now completed all communication with other threads.
         *  DO YOUR WORK SLAVE!!! */
        reader.join();

        return output;
    } else {
        /* Some nasty error happened at execution. Report and end thread */
        logger->warn(objectInfo + ": can't execute child process. "
                     "This never happened during development.");
        {
            /* Remove thread from list of threads without child, notify and end */
            std::lock_guard<std::mutex> l (withoutChild_mux);
            --withoutChild;
        }
        withoutChild_cv.notify_one();
        return {};
    }
    /* All locks go out of scope, so everything will be unlocked here */
}
Exemple #8
0
static int handle_connection() {
	char line[LINE_MAX];

	/* Prepare per connection plugin env vars */
	setenvvars_munin();

	printf("# munin node at %s\n", host);
	while (fflush(stdout), fgets(line, LINE_MAX, stdin) != NULL) {
		char* cmd;
		char* arg;

		cmd = strtok(line, " \t\n\r");
		if(cmd == NULL)
			arg = NULL;
		else
			arg = strtok(NULL, " \t\n\r");

		if (!cmd || strlen(cmd) == 0) {
			printf("# empty cmd\n");
		} else if (strcmp(cmd, "version") == 0) {
			printf("munin c node version: %s\n", VERSION);
		} else if (strcmp(cmd, "nodes") == 0) {
			printf("%s\n", host);
			printf(".\n");
		} else if (strcmp(cmd, "quit") == 0) {
			return(0);
		} else if (strcmp(cmd, "list") == 0) {
			DIR* dirp = opendir(plugin_dir);
			if (dirp == NULL) {
				printf("# Cannot open plugin dir\n");
				return(0);
			}
			{
			struct dirent* dp;
			while ((dp = readdir(dirp)) != NULL) {
				char cmdline[LINE_MAX];
				char* plugin_filename = dp->d_name;;

				if (plugin_filename[0] == '.') {
					/* No dotted plugin */
					continue;
				}

				snprintf(cmdline, LINE_MAX, "%s/%s", plugin_dir, plugin_filename);
				if (access(cmdline, X_OK) == 0) {
					if(extension_stripping) {
						/* Strip after the last . */
						char *last_dot_idx = strrchr(plugin_filename, '.');
						if (last_dot_idx != NULL) {
							*last_dot_idx = '\0';
						}
					}
					printf("%s ", plugin_filename);
				}
			}
			closedir(dirp);
			}
			putchar('\n');
		} else if (
				strcmp(cmd, "config") == 0 ||
				strcmp(cmd, "fetch") == 0
			) {
			char cmdline[LINE_MAX];
			char *argv[2] = { 0, };
			pid_t pid;
			if(arg == NULL) {
				printf("# no plugin given\n");
				continue;
			}
			if(arg[0] == '.' || strchr(arg, '/') != NULL) {
				printf("# invalid plugin character\n");
				continue;
			}
			if (! extension_stripping || find_plugin_with_basename(cmdline, plugin_dir, arg) == 0) {
				/* extension_stripping failed, using the plain method */
				snprintf(cmdline, LINE_MAX, "%s/%s", plugin_dir, arg);
			}
			if (access(cmdline, X_OK) == -1) {
				printf("# unknown plugin: %s\n", arg);
				continue;
			}

			/* Now is the time to set environnement */
			setenvvars_conf(arg);
			argv[0] = arg;

			/* Using posix_spawnp() here instead of fork() since we will
			 * do a little more than a mere exec --> setenvvars_conf() */
			if (0 == posix_spawn(&pid, cmdline,
					NULL, /* const posix_spawn_file_actions_t *file_actions, */
					NULL, /* const posix_spawnattr_t *restrict attrp, */
					argv, environ)) {

				/* Wait for completion */
				waitpid(pid, NULL, 0);
			} else {
				printf("# fork failed\n");
				continue;
			}
			printf(".\n");
		} else if (strcmp(cmd, "cap") == 0) {
			printf("cap ");
			if ('\0' != *spoolfetch_dir) {
				printf("spool ");
			}
			printf("\n");
		} else if (strcmp(cmd, "spoolfetch") == 0) {
			printf("# not implem yet cmd: %s\n", cmd);
		} else {
			printf("# Unknown cmd: %s. Try cap, list, nodes, config, fetch, version or quit\n", cmd);
		}
	}

	return 0;
}
Exemple #9
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);
}
int main(int argc, char* argv[])
{
    int i;
    int nandReadOnly=0;
    struct stat st;
    
    printf("Starting ramdisk tool\n");
    printf("Compiled " __DATE__ " " __TIME__ "\n");
    printf("Revision " HGVERSION "\n");
    
    CFMutableDictionaryRef matching;
    io_service_t service = 0;
    matching = IOServiceMatching("IOWatchDogTimer");
    if (matching == NULL) {
        printf("unable to create matching dictionary for class IOWatchDogTimer\n");
    }
    
    service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
    if (service == 0) {
        printf("unable to create matching dictionary for class IOWatchDogTimer\n");
    }
    uint32_t zero = 0;
    CFNumberRef n = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &zero);
    IORegistryEntrySetCFProperties(service, n);
    IOObjectRelease(service);
    
    CFMutableDictionaryRef deviceInfos = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                                            0,
                                                            &kCFTypeDictionaryKeyCallBacks,
                                                            &kCFTypeDictionaryValueCallBacks);	
    
    get_device_infos(deviceInfos);
    init_tcp();

    sysctlbyname("kern.bootargs", bootargs, &bootargs_len, NULL, 0);
    
    if (strstr(bootargs, "nand-readonly") || strstr(bootargs, "nand-disable"))
    {
        printf("NAND read only mode, data partition wont be mounted\n");
        nandReadOnly = 1;
    }
    else
    {
        printf("Waiting for data partition\n");
        for(i=0; i < 10; i++)
        {
            if(!stat("/dev/disk0s2s1", &st))
            {
                system("/sbin/fsck_hfs  /dev/disk0s2s1");
                break;
            }
            if(!stat("/dev/disk0s1s2", &st))
            {
                system("/sbin/fsck_hfs  /dev/disk0s1s2");
                break;
            }
            if(!stat("/dev/disk0s2", &st))
            {
                system("/sbin/fsck_hfs  /dev/disk0s2");
                break;
            }
            sleep(5);
        }
    }
    init_usb(CFDictionaryGetValue(deviceInfos, CFSTR("udid")));
    printf("USB init done\n");

    system("mount /"); //make ramdisk writable
   
    chmod("/var/root/.ssh/authorized_keys", 0600); 
    chown("/var/root/.ssh/authorized_keys", 0, 0); 
    chown("/var/root/.ssh", 0, 0); 
    chown("/var/root/", 0, 0); 

    printf(" #######  ##    ##\n");
    printf("##     ## ##   ## \n");
    printf("##     ## ##  ##  \n");
    printf("##     ## #####   \n");
    printf("##     ## ##  ##  \n");
    printf("##     ## ##   ## \n"); 
    printf(" #######  ##    ##\n");
    printf("iphone-dataprotection ramdisk\n");
    printf("revision: " HGVERSION " "  __DATE__ " " __TIME__ "\n");
    
    if(!stat(execve_params[0], &st))
    {
        printf("Running %s\n", execve_params[0]);
        if((i = posix_spawn(NULL, execve_params[0], NULL, NULL, execve_params, execve_env)))
            printf("posix_spawn(%s) returned %d\n", execve_params[0], i);
    }
    else
    {
        printf("%s is missing\n", execve_params[0]);
    }
    
    /*if (nandReadOnly)
    {*/
        if(!stat(ioflash[0], &st))
        {
            printf("Running %s\n", ioflash[0]);
            if((i = posix_spawn(NULL, ioflash[0], NULL, NULL, ioflash, execve_env)))
                printf("posix_spawn(%s) returned %d\n", execve_params[0], i);
        }
    /*}*/
    
    CFMutableDictionaryRef handlers = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
    CFDictionaryAddValue(handlers, CFSTR("DeviceInfo"), device_info);
    CFDictionaryAddValue(handlers, CFSTR("GetSystemKeyBag"), load_system_keybag);
    CFDictionaryAddValue(handlers, CFSTR("BruteforceSystemKeyBag"), bruteforce_system_keybag);
    CFDictionaryAddValue(handlers, CFSTR("KeyBagGetPasscodeKey"), keybag_get_passcode_key);
    CFDictionaryAddValue(handlers, CFSTR("GetEscrowRecord"), get_escrow_record);
    CFDictionaryAddValue(handlers, CFSTR("DownloadFile"), download_file);
    CFDictionaryAddValue(handlers, CFSTR("AES"), remote_aes);
    CFDictionaryAddValue(handlers, CFSTR("Reboot"), reboot__);

    serve_plist_rpc(1999, handlers);
    return 0;
}
Exemple #11
0
pid_t spawn (boost::asio::io_service& io_service,
		const child_options& opt,
		std::map<stream_id, boost::shared_ptr<stream_descriptor> >& streams,
		boost::system::error_code& ec)
{
	typedef	std::map<stream_id, child_options::stream_behaviour> beh_t;

	posix_spawn_file_actions_t file_actions;
	posix_spawn_file_actions_init(&file_actions);

	streams.clear();

	std::vector<int> close_later;

	const beh_t& behaviours = opt.get_stream_behaviours();
	for (beh_t::const_iterator iter = behaviours.begin(); iter != behaviours.end(); ++iter)
	{
		switch (iter->second)
		{
			case child_options::close:
			{
				posix_spawn_file_actions_addclose(&file_actions, iter->first.native());
				break;
			}

			case child_options::inherit:
			{
				posix_spawn_file_actions_addinherit_np(&file_actions, iter->first.native());
				break;
			}

			case child_options::pipe_read:
			{
				posix::pipe p;
				close_later.push_back(p.read_end());
				posix_spawn_file_actions_adddup2(&file_actions,
						p.steal_read_end(),
						iter->first.native());
				streams.insert(
							std::make_pair(
								iter->first,
								boost::shared_ptr<stream_descriptor>(
									new stream_descriptor(io_service, p.steal_write_end()))
							)
						);
				break;
			}

			case child_options::pipe_write:
			{
				posix::pipe p;
				close_later.push_back(p.write_end());
				posix_spawn_file_actions_adddup2(&file_actions,
						p.steal_write_end(),
						iter->first.native());
				streams.insert(
							std::make_pair(
								iter->first,
								boost::shared_ptr<stream_descriptor>(
									new stream_descriptor(io_service, p.steal_read_end()))
							)
						);
				break;
			}
		}
	}

	zero_terminated_list_of_strings argv;
	argv.add(opt.get_command());
	argv.add(opt.get_args());

	pid_t child_pid = -1;

	const char* _path = opt.get_command().c_str();
	char* const* _argv = argv.data();
	int result = posix_spawn(&child_pid,
							 _path,
							 &file_actions,
							 NULL,
							 _argv,
							 NULL);

	posix_spawn_file_actions_destroy(&file_actions);

	std::for_each(close_later.begin(), close_later.end(), ::close);

	ec.assign(result, boost::system::generic_category());
	return child_pid;
}
Exemple #12
0
int run_all ( char *args[] )
{
	pthread_t thr;
	int *status, rv;
	char *progname;

#if 0	/* run all programs */

	char info[INFO_SIZE];
	char *sysinfo_args[] = { "sysinfo", "programs", NULL };

	printf ( "\n*** Running all programs, one by one ***\n\n" );

	syscall ( SYSINFO, &info, INFO_SIZE, sysinfo_args );
	printf ( "%s\n", info );

	progname = strstr ( info, ":\n" );

#else /* run selected programs */

	char progs_to_start[] = {
		"hello timer args uthreads threads semaphores "
		"monitors messages signals rr edf" };
	progname = progs_to_start;

#endif

	/* progname has program names to be started */
	progname = strtok ( progname, ":\n " );
	while ( progname )
	{
		printf ( "Starting program: %s\n"
			 "---------------------------------------\n", progname);

		rv = posix_spawn ( &thr, progname, NULL, NULL, NULL, NULL );
		if ( !rv )
		{
			rv = pthread_join ( thr, (void **) &status );
			if ( rv && get_errno () != ESRCH )
			{
				printf ( "\npthread_join error!\n\n" );
				break;
			}
#if 0
			/* most functions do not call pthread_exit directly so
			 * the following test might be "false negative" */
			else if ( status && *status )
			{
				printf ( "\nProgram %s exited with error!\n\n",
					 progname );
				break;
			}
#endif
			else {
				printf ("\nProgram %s exited successfully!\n\n",
					progname );
			}
		}
		else {
			printf ( "\nProgram: %s not started!\n", progname );
			break;
		}

		progname = strtok ( NULL, " " );
	}

#if ( TURN_OFF == 1 )
	printf ( "Powering off\n\n" );
	syscall ( POWER_OFF, NULL, 0, NULL );
#endif

	return 0;
}
Exemple #13
0
int main(int argc, char *argv[])
{
	posix_spawnattr_t       attrs;
	kern_return_t           kr;
	mach_port_t             task = mach_task_self();

	mach_msg_type_number_t  maskCount = 1;
	exception_mask_t        mask;
	exception_handler_t     handler;
	exception_behavior_t    behavior;
	thread_state_flavor_t   flavor;
	pthread_t               exception_thread;
	uint64_t                exc_id;
	unsigned int            exc_fd;

	char *test_prog_name = "./guarded_test";
	char *child_args[MAX_ARGV];
	char test_id[MAX_TEST_ID_LEN];
	int i, err;
	int child_status;
	int test_status = 0;

	/* Allocate and initialize new exception port */
	if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &exc_port)) != KERN_SUCCESS) {
		fprintf(stderr, "mach_port_allocate: %#x\n", kr);
		exit(1);
	}

	if ((kr = mach_port_insert_right(task, exc_port, 
					exc_port, MACH_MSG_TYPE_MAKE_SEND)) != KERN_SUCCESS) {
		fprintf(stderr, "mach_port_allocate: %#x\n", kr);
		exit(1);
	}

	/* Get Current exception ports */
	if ((kr = task_get_exception_ports(task, EXC_MASK_GUARD, &mask,
					&maskCount, &handler, &behavior, &flavor)) != KERN_SUCCESS) {
		fprintf(stderr,"task_get_exception_ports: %#x\n", kr);
		exit(1);
	}

	/* Create exception serving thread */
	if ((err = pthread_create(&exception_thread, NULL, server_thread, 0)) != 0) {
		fprintf(stderr, "pthread_create server_thread: %s\n", strerror(err));
		exit(1);
	}

	pthread_detach(exception_thread);

	/* Initialize posix_spawn attributes */
	posix_spawnattr_init(&attrs);

	if ((err = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETEXEC)) != 0) {
		fprintf(stderr, "posix_spawnattr_setflags: %s\n", strerror(err));
		exit(1);
	}

	/* Run Tests */
	for(i=0; i<NUMTESTS; i++) {

		exception_code = 0;
		/* Set Exception Ports for Current Task */
		if ((kr = task_set_exception_ports(task, EXC_MASK_GUARD, exc_port,
						EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) {
			fprintf(stderr, "task_set_exception_ports: %#x\n", kr);
			exit(1);
		}

		child_args[0] = test_prog_name;
		sprintf(&test_id[0], "%d", i);
		child_args[1] = &test_id[0];
		child_args[2] = NULL;

		/* Fork and exec child */
		if (fork() == 0) {
			if ((err = posix_spawn(NULL, child_args[0], NULL, &attrs, &child_args[0], environ)) != 0) {
				fprintf(stderr, "posix_spawn: %s\n", strerror(err));
				exit(1);
			}
		}

		/* Restore exception ports for parent */
		if ((kr = task_set_exception_ports(task, EXC_MASK_GUARD, handler,
						EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) {
			fprintf(stderr, "task_set_exception_ports: %#x\n", kr);
			exit(1);
		} 

		/* Wait for child and check for exception */
		if (-1 == wait4(-1, &child_status, 0, NULL)) {
			exit(1);
		}

		exc_fd = (unsigned int) (exception_code & (uint64_t)EXC_GUARD_FD_MASK);
		exc_id = exception_code & ~((uint64_t)EXC_GUARD_FD_MASK);
		printf("EXC_GUARD Received: ");
		(exception_code != 0)?printf("Yes (Code 0x%llx)\n", exception_code):printf("No\n");
		printf("Test Result: ");
		if((WIFEXITED(child_status) && WEXITSTATUS(child_status)) ||
			(exc_id != test_exception_code[i]) ||
			(test_fd[i] && exc_fd != (unsigned int)TEST_FD)) {
				test_status = 1;
				printf("FAILED\n");
		}
		else {
			printf("PASSED\n");
		}
		printf("-------------------\n");

	}

	exit(test_status);
}    
static void
spawn_and_signal(int signal)
{
	/* do not buffer output to stdout */
	setvbuf(stdout, NULL, _IONBF, 0);

	int ret;
	posix_spawnattr_t attr;

	ret = posix_spawnattr_init(&attr);
	T_QUIET;
	T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_init");

	ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED);
	T_QUIET;
	T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_setflags");

	char * const    prog = "/usr/bin/true";
	char * const    argv_child[] = { prog, NULL };
	pid_t           child_pid;
	extern char   **environ;

	ret = posix_spawn(&child_pid, prog, NULL, &attr, argv_child, environ);
	T_ASSERT_POSIX_SUCCESS(ret, "posix_spawn");

	printf("parent: spawned child with pid %d\n", child_pid);

	ret = posix_spawnattr_destroy(&attr);
	T_QUIET;
	T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_destroy");

	int status = 0;
	int waitpid_result = waitpid(child_pid, &status, WUNTRACED|WNOHANG);
	T_ASSERT_POSIX_SUCCESS(waitpid_result, "waitpid");

	T_ASSERT_EQ(waitpid_result, child_pid, "waitpid should return child we spawned");

	T_ASSERT_EQ(WIFEXITED(status), 0, "before SIGCONT: must not have exited");
	T_ASSERT_EQ(WIFSTOPPED(status), 1, "before SIGCONT: must be stopped");

	printf("parent: continuing child process\n");

	ret = kill(child_pid, signal);
	T_ASSERT_POSIX_SUCCESS(ret, "kill(signal)");

	printf("parent: waiting for child process\n");

	status = 0;
	waitpid_result = waitpid(child_pid, &status, 0);
	T_ASSERT_POSIX_SUCCESS(waitpid_result, "waitpid");

	T_ASSERT_EQ(waitpid_result, child_pid, "waitpid should return child we spawned");

	if (signal == SIGKILL) {
		T_ASSERT_EQ(WIFSIGNALED(status), 1, "child should have exited due to signal");
		T_ASSERT_EQ(WTERMSIG(status), SIGKILL, "child should have exited due to SIGKILL");
	} else {
		T_ASSERT_EQ(WIFEXITED(status), 1, "child should have exited normally");
		T_ASSERT_EQ(WEXITSTATUS(status), EX_OK, "child should have exited with success");
	}

	printf("wait returned with pid %d, status %d\n", ret, status);
}
static int reexec(cpu_type_t cputype, const char *guardenv)
{
	posix_spawnattr_t  attr;
	int                ret, envcount;
	size_t             copied = 0;
	char			   **argv, **oldenvp, **newenvp;
	char			   execpath[MAXPATHLEN+1];
	uint32_t		   execsize;
	char               guardstr[32];

	argv = *_NSGetArgv();
	oldenvp = *_NSGetEnviron();
	for (envcount = 0; oldenvp[envcount]; envcount++);
	// if there are 4 elements and a NULL, envcount will be 4

	newenvp = calloc(envcount+2, sizeof(newenvp[0]));
	for (envcount = 0; oldenvp[envcount]; envcount++) {
		newenvp[envcount] = oldenvp[envcount];
	}

	snprintf(guardstr, sizeof(guardstr), "%s=1", guardenv);
	newenvp[envcount++] = guardstr;
	newenvp[envcount] = NULL;

	execsize = (uint32_t)sizeof(execpath);
	ret = _NSGetExecutablePath(execpath, &execsize);
	if (ret != 0) {
		return -1;
	}

	ret = posix_spawnattr_init(&attr);
	if (ret != 0) {
		return -1;
	}
	ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC);
	if (ret != 0) {
		return -1;
	}
	ret = posix_spawnattr_setbinpref_np(&attr, 1, &cputype, &copied);
	if (ret != 0 || copied != 1) {
		return -1;
	}

#if 0
	fprintf(stderr, "reexec: %s (arch=%d)\n", execpath, cputype);
	for (envcount=0; newenvp[envcount]; envcount++) {
		fprintf(stderr, "env[%d] = %s\n", envcount, newenvp[envcount]);
	}
	for (envcount=0; argv[envcount]; envcount++) {
		fprintf(stderr, "argv[%d] = %s\n", envcount, argv[envcount]);
	}
#endif

	ret = posix_spawn(NULL, execpath, NULL, &attr, argv, newenvp);
	if (ret != 0) {
		errno = ret;
		return -1;
	}

	/* should not be reached */
	return 0;
}
Exemple #16
0
int spawn_main(int argc, char *argv[])
{
  posix_spawn_file_actions_t file_actions;
  posix_spawnattr_t attr;
  FAR const char *filepath;
  pid_t pid;
  int ret;

  /* Initialize the memory monitor */

  mm_initmonitor();

  /* Initialize the ELF binary loader */

  message("Initializing the ELF binary loader\n");
  ret = elf_initialize();
  if (ret < 0)
    {
      err("ERROR: Initialization of the ELF loader failed: %d\n", ret);
      exit(1);
    }

  mm_update(&g_mmstep, "after elf_initialize");

  /* Create a ROM disk for the ROMFS filesystem */

  message("Registering romdisk at /dev/ram%d\n", CONFIG_EXAMPLES_ELF_DEVMINOR);
  ret = romdisk_register(CONFIG_EXAMPLES_ELF_DEVMINOR, (FAR uint8_t *)romfs_img,
                         NSECTORS(romfs_img_len), SECTORSIZE);
  if (ret < 0)
    {
      err("ERROR: romdisk_register failed: %d\n", ret);
      elf_uninitialize();
      exit(1);
    }

  mm_update(&g_mmstep, "after romdisk_register");

  /* Mount the file system */

  message("Mounting ROMFS filesystem at target=%s with source=%s\n",
         MOUNTPT, CONFIG_EXAMPLES_ELF_DEVPATH);

  ret = mount(CONFIG_EXAMPLES_ELF_DEVPATH, MOUNTPT, "romfs", MS_RDONLY, NULL);
  if (ret < 0)
    {
      err("ERROR: mount(%s,%s,romfs) failed: %s\n",
          CONFIG_EXAMPLES_ELF_DEVPATH, MOUNTPT, errno);
      elf_uninitialize();
    }

  mm_update(&g_mmstep, "after mount");

  /* Does the system support the PATH variable?  Has the PATH variable
   * already been set?  If YES and NO, then set the PATH variable to
   * the ROMFS mountpoint.
   */

#if defined(CONFIG_BINFMT_EXEPATH) && !defined(CONFIG_PATH_INITIAL)
  (void)setenv("PATH", MOUNTPT, 1);
#endif

  /* Make sure that we are using our symbol take */

  exec_setsymtab(exports, nexports);

  /*************************************************************************
   * Case 1: Simple program with arguments
   *************************************************************************/

  /* Output a seperated so that we can clearly discriminate the output of
   * this program from the others.
   */

  testheader(g_hello);

  /* Initialize the attributes file actions structure */

  ret = posix_spawn_file_actions_init(&file_actions);
  if (ret != 0)
    {
      err("ERROR: posix_spawn_file_actions_init failed: %d\n", ret);
    }
  posix_spawn_file_actions_dump(&file_actions);

  ret = posix_spawnattr_init(&attr);
  if (ret != 0)
    {
      err("ERROR: posix_spawnattr_init failed: %d\n", ret);
    }
  posix_spawnattr_dump(&attr);

  mm_update(&g_mmstep, "after file_action/attr init");

  /* If the binary loader does not support the PATH variable, then
   * create the full path to the executable program.  Otherwise,
   * use the relative path so that the binary loader will have to
   * search the PATH variable to find the executable.
   */

#ifdef CONFIG_BINFMT_EXEPATH
  filepath = g_hello;
#else
  snprintf(fullpath, 128, "%s/%s", MOUNTPT, g_hello);
  filepath = fullpath;
#endif

  /* Execute the program */

  mm_update(&g_mmstep, "before posix_spawn");

  ret = posix_spawn(&pid, filepath, &file_actions, &attr, NULL, (FAR char * const*)&g_argv);
  if (ret != 0)
    {
      err("ERROR: posix_spawn failed: %d\n", ret);
    }

  sleep(4);
  mm_update(&g_mmstep, "after posix_spawn");

  /* Free attibutes and file actions */

  ret = posix_spawn_file_actions_destroy(&file_actions);
  if (ret != 0)
    {
      err("ERROR: posix_spawn_file_actions_destroy failed: %d\n", ret);
    }
  posix_spawn_file_actions_dump(&file_actions);

  ret = posix_spawnattr_destroy(&attr);
  if (ret != 0)
    {
      err("ERROR: posix_spawnattr_destroy failed: %d\n", ret);
    }
  posix_spawnattr_dump(&attr);

  mm_update(&g_mmstep, "after file_action/attr destruction");

  /*************************************************************************
   * Case 2: Simple program with redirection of stdin to a file input
   *************************************************************************/

  /* Output a seperated so that we can clearly discriminate the output of
   * this program from the others.
   */

  testheader(g_redirect);

  /* Initialize the attributes file actions structure */

  ret = posix_spawn_file_actions_init(&file_actions);
  if (ret != 0)
    {
      err("ERROR: posix_spawn_file_actions_init failed: %d\n", ret);
    }
  posix_spawn_file_actions_dump(&file_actions);

  ret = posix_spawnattr_init(&attr);
  if (ret != 0)
    {
      err("ERROR: posix_spawnattr_init failed: %d\n", ret);
    }
  posix_spawnattr_dump(&attr);

  mm_update(&g_mmstep, "after file_action/attr init");

  /* Set up to close stdin (0) and open testdata.txt as the program input */

  ret = posix_spawn_file_actions_addclose(&file_actions, 0);
  if (ret != 0)
    {
      err("ERROR: posix_spawn_file_actions_addclose failed: %d\n", ret);
    }
  posix_spawn_file_actions_dump(&file_actions);

  snprintf(fullpath, 128, "%s/%s", MOUNTPT, g_data);
  ret = posix_spawn_file_actions_addopen(&file_actions, 0, fullpath, O_RDONLY, 0644);
  if (ret != 0)
    {
      err("ERROR: posix_spawn_file_actions_addopen failed: %d\n", ret);
    }
  posix_spawn_file_actions_dump(&file_actions);
  
  mm_update(&g_mmstep, "after adding file_actions");

  /* If the binary loader does not support the PATH variable, then
   * create the full path to the executable program.  Otherwise,
   * use the relative path so that the binary loader will have to
   * search the PATH variable to find the executable.
   */

#ifdef CONFIG_BINFMT_EXEPATH
  filepath = g_redirect;
#else
  snprintf(fullpath, 128, "%s/%s", MOUNTPT, g_redirect);
  filepath = fullpath;
#endif

  /* Execute the program */

  mm_update(&g_mmstep, "before posix_spawn");

  ret = posix_spawn(&pid, filepath, &file_actions, &attr, NULL, NULL);
  if (ret != 0)
    {
      err("ERROR: posix_spawn failed: %d\n", ret);
    }

  sleep(2);
  mm_update(&g_mmstep, "after posix_spawn");

  /* Free attibutes and file actions */

  ret = posix_spawn_file_actions_destroy(&file_actions);
  if (ret != 0)
    {
      err("ERROR: posix_spawn_file_actions_destroy failed: %d\n", ret);
    }
  posix_spawn_file_actions_dump(&file_actions);

  ret = posix_spawnattr_destroy(&attr);
  if (ret != 0)
    {
      err("ERROR: posix_spawnattr_destroy failed: %d\n", ret);
    }
  posix_spawnattr_dump(&attr);

  mm_update(&g_mmstep, "after file_action/attr destruction");

  /* Clean-up */

  elf_uninitialize();

  mm_update(&g_mmstep, "End-of-Test");
  return 0;
}
// ---- C.spawn ----
int VMPI_spawn(int *pid, const char *path, char *const argv[], char *const envp[])
{
    return posix_spawn( (pid_t *)pid, path, NULL, NULL, argv, envp );
}
Exemple #18
0
pid_t spawnvex(const char *path, char *const argv[], char *const envv[], Spawnvex_t *vex) {
    int i;
    int op;
    unsigned int flags = 0;
    pid_t pid;
    int arg;
    int err;
    int fd;
    posix_spawnattr_t ax;
    posix_spawn_file_actions_t fx;
    Spawnvex_t *xev = NULL;
#if _lib_spawn_mode || _lib_spawn && _mem_pgroup_inheritance
    pid_t pgid;
    int arg;
    int j;
    int k;
    int m;
    int ic;
    int jc;
    Spawnvex_t *xev;
#if !_lib_spawn_mode
    int *map;
    int a;
    struct inheritance inherit;
#endif
#endif

    if (vex && vex->debug >= 0) {
        error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\"", __LINE__, getpid(),
              vex, vex->cur, path);
    }
#if _lib_spawn_mode || _lib_spawn && _mem_pgroup_inheritance
    if (!envv) envv = environ;
    pid = -1;
    m = 0;
    if (vex) {
        vex->noexec = -1;
        vex->pgrp = -1;
        flags = vex->flags;
        if (!(xev = spawnvex_open(0))) goto bad;
        j = -1;
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            op /= 2;
            if (op >= 0) {
                if (m < op) m = op + 1;
                if (m < arg) m = arg + 1;
            } else if (op == SPAWN_cwd)
                j = arg;
        }
        if (j >= 0) {
            if ((i = open(".", O_RDONLY)) < 0) goto bad;
            if ((i = save(i, &ic, m)) < 0) goto bad;
            if (spawnvex_add(xev, SPAWN_cwd, i, 0, 0) < 0 || restore(xev, i, -1, 0) < 0) {
                close(i);
                goto bad;
            }
            if (fchdir(j) < 0) goto bad;
            if ((i = save(j, &jc, m)) < 0) goto bad;
            if (restore(xev, i, j, jc) < 0) {
                close(i);
                goto bad;
            }
        }
    } else {
        flags = 0;
        xev = NULL;
    }
#if _lib_spawn_mode
    if (vex)
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            switch (op /= 2) {
                case SPAWN_frame:
                    vex->frame = (unsigned int)arg;
                    break;
                case SPAWN_pgrp:
                    vex->pgrp = (pid_t)arg;
                    break;
                default:
                    if (op >= 0) {
                        if (arg < 0) {
                            if ((i = save(op, &ic, m)) < 0) {
                                if (i < -1) goto bad;
                            } else if (restore(xev, i, op, ic) < 0) {
                                close(i);
                                goto bad;
                            } else
                                close(op);
                        } else if (arg == op) {
                            if (spawnvex_add(xev, SPAWN_cloexec, arg, 0, 0) < 0) goto bad;
                            if (fcntl(arg, F_SETFD, 0) < 0) goto bad;
                        } else if ((j = save(arg, &jc, m)) < -1)
                            goto bad;
                        else {
                            close(arg);
                            if (fcntl(op, F_DUPFD, arg) >= 0) {
                                if ((i = save(op, &ic, m)) >= 0) {
                                    if (restore(xev, i, op, ic) >= 0) {
                                        close(op);
                                        if (j < 0 || restore(xev, j, arg, jc) >= 0) continue;
                                    }
                                    close(i);
                                }
                            }
                            if (j >= 0) {
                                fcntl(j, F_DUPFD, arg);
                                close(j);
                            }
                            goto bad;
                        }
                    }
                    break;
            }
        }
    pid = spawnve(vex && vex->pgrp >= 0 ? P_DETACH : P_NOWAIT, path, argv, envv);
#else
    inherit.flags = 0;
    map = 0;
    if (vex) {
        if (m) {
            map = calloc(1, m * sizeof(int));
            if (!map) goto bad;
            for (i = 0; i < m; i++) map[i] = i;
        }
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            a = i;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            switch (op /= 2) {
                case SPAWN_noop:
                    break;
                case SPAWN_noexec:
                    break;
                case SPAWN_frame:
                    vex->frame = (unsigned int)arg;
                    break;
                case SPAWN_pgrp:
                    inherit.flags |= SPAWN_SETGROUP;
                    inherit.pgroup = arg ? arg : SPAWN_NEWPGROUP;
                    break;
                case SPAWN_sigdef:
                    inherit.flags |= SPAWN_SETSIGDEF;
                    sigemptyset(&inherit.sigdefault);
                    for (j = 1; j < 8 * sizeof(vex->op[a].number); j++)
                        if (vex->op[a].number & (1 << j)) sigaddset(&inherit.sigdefault, j);
                    break;
                case SPAWN_sigmask:
                    inherit.flags |= SPAWN_SETSIGMASK;
                    sigemptyset(&inherit.sigmask);
                    for (j = 1; j < 8 * sizeof(vex->op[a].number); j++)
                        if (vex->op[a].number & (1 << j)) sigaddset(&inherit.sigmask, j);
                    break;
                default:
                    if (op < 0) {
                        errno = EINVAL;
                        goto bad;
                    } else if (arg < 0)
                        map[op] = SPAWN_FDCLOSED;
                    else
                        map[op] = arg;
                    break;
            }
        }
    }
    pid = spawn(path, m, map, &inherit, (const char **)argv, (const char **)envv);
#endif
    if (pid >= 0 && vex) VEXINIT(vex);
bad:
    if (xev) {
        spawnvex_apply(xev, 0, SPAWN_FLUSH | SPAWN_NOCALL);
        spawnvex_close(xev);
    }
#if !_lib_spawn_mode
    if (map) free(map);
#endif
    return pid;

#else

#if _lib_spawnve
    if (!vex || !vex->cur && !vex->flags) return spawnve(path, argv, envv);
#endif
    if (vex && ((vex->set & (0
#if !_lib_posix_spawnattr_setfchdir
                             | VEXFLAG(SPAWN_cwd)
#endif
#if !_lib_posix_spawnattr_setsid
                             | VEXFLAG(SPAWN_sid)
#endif
#if !_lib_posix_spawnattr_setumask
                             | VEXFLAG(SPAWN_umask)
#endif
                                 ))
#if !_lib_posix_spawn
                || !(vex->flags & SPAWN_EXEC)
#endif
                    )) {
        int n;
        int m;
        Spawnvex_noexec_t nx;
        int msg[2];

        if (!envv) envv = environ;
        n = errno;
        if (pipe(msg) < 0) {
            msg[0] = msg[1] = -1;
        } else {
            (void)fcntl(msg[0], F_SETFD, FD_CLOEXEC);
            (void)fcntl(msg[1], F_SETFD, FD_CLOEXEC);
        }
        if (!(flags & SPAWN_FOREGROUND)) sigcritical(SIG_REG_EXEC | SIG_REG_PROC);
        pid = fork();
        if (pid == -1) {
            n = errno;
        } else if (!pid) {
            if (!(flags & SPAWN_FOREGROUND)) sigcritical(SIG_REG_POP);
            if (vex && (n = spawnvex_apply(vex, 0, SPAWN_FRAME | SPAWN_NOCALL))) {
                errno = n;
            } else {
                if (vex && vex->debug >= 0) {
                    error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\"", __LINE__,
                          getpid(), vex, vex->cur, path);
                }
                execve(path, argv, envv);
                if (vex && vex->debug >= 0) {
                    error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\" FAILED",
                          __LINE__, getpid(), vex, vex->cur, path);
                }
                if (vex && (i = vex->noexec) >= 0) {
                    nx.vex = vex;
                    nx.handle = vex->op[i + 3].handle;
                    nx.path = path;
                    nx.argv = argv;
                    nx.envv = envv;
#if _use_spawn_exec
                    /*
                     * setting SPAWN_EXEC here means that it is more efficient to
                     * exec(interpreter) on script than to fork() initialize and
                     * read script -- highly subjective, based on some ksh
                     * implementaions, and probably won't be set unless its a
                     * noticable win
                     */

                    nx.flags |= SPAWN_EXEC;
#endif
                    nx.msgfd = msg[1];
                    errno = (*vex->op[i + 2].callback)(&nx, SPAWN_noexec, errno);
                }
            }
            if (msg[1] != -1) {
                m = errno;
                write(msg[1], &m, sizeof(m));
            }
            _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
        }
        if (msg[0] != -1) {
            close(msg[1]);
            if (pid != -1) {
                m = 0;
                while (read(msg[0], &m, sizeof(m)) == -1) {
                    if (errno != EINTR) {
                        m = errno;
                        break;
                    }
                }
                if (m) {
                    while (waitpid(pid, &n, 0) && errno == EINTR) {
                        ;
                    }
                    pid = -1;
                    n = m;
                }
            }
            close(msg[0]);
        }
        if (!(flags & SPAWN_FOREGROUND)) sigcritical(SIG_REG_POP);
        if (pid != -1 && vex) VEXINIT(vex);
        errno = n;
        return pid;
    }
    if (vex) {
        err = posix_spawnattr_init(&ax);
        if (err) goto nope;
        err = posix_spawn_file_actions_init(&fx);
        if (err) {
            posix_spawnattr_destroy(&ax);
            goto nope;
        }
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            switch (op /= 2) {
                case SPAWN_noop:
                    break;
                case SPAWN_noexec:
                    break;
                case SPAWN_frame:
                    break;
#if _lib_posix_spawnattr_setfchdir
                case SPAWN_cwd:
                    err = posix_spawnattr_setfchdir(&ax, arg);
                    if (err) goto bad;
                    break;
#endif
                case SPAWN_pgrp:
                    err = posix_spawnattr_setpgroup(&ax, arg);
                    if (err) goto bad;
                    err = posix_spawnattr_setflags(&ax, POSIX_SPAWN_SETPGROUP);
                    if (err) goto bad;
                    break;
                case SPAWN_resetids:
                    err = posix_spawnattr_setflags(&ax, POSIX_SPAWN_RESETIDS);
                    if (err) goto bad;
                    break;
#if _lib_posix_spawnattr_setsid
                case SPAWN_sid:
                    err = posix_spawnattr_setsid(&ax, arg);
                    if (err) goto bad;
                    break;
#endif
                case SPAWN_sigdef:
                    break;
                case SPAWN_sigmask:
                    break;
#if _lib_posix_spawnattr_setumask
                case SPAWN_umask:
                    if (err = posix_spawnattr_setumask(&ax, arg)) goto bad;
                    break;
#endif
                default:
                    if (op < 0) {
                        err = EINVAL;
                        goto bad;
                    } else if (arg < 0) {
                        err = posix_spawn_file_actions_addclose(&fx, op);
                        if (err) goto bad;
                    } else if (arg == op) {
#ifdef F_DUPFD_CLOEXEC
                        if ((fd = fcntl(op, F_DUPFD_CLOEXEC, 0)) < 0)
#else
                        if ((fd = fcntl(op, F_DUPFD, 0)) < 0 ||
                            fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 && (close(fd), 1))
#endif
                        {
                            err = errno;
                            goto bad;
                        }
                        if (!xev && !(xev = spawnvex_open(0))) goto bad;
                        spawnvex_add(xev, fd, -1, 0, 0);
                        err = posix_spawn_file_actions_adddup2(&fx, fd, op);
                        if (err) goto bad;
                    } else {
                        err = posix_spawn_file_actions_adddup2(&fx, op, arg);
                        if (err) goto bad;
                    }
                    break;
            }
        }

        // Ensure stdin, stdout, stderr are open in the child process.
        // See https://github.com/att/ast/issues/1117.
        for (int fd = 0; fd < 3; ++fd) {
            errno = 0;
            if (fcntl(fd, F_GETFD, NULL) == -1 || errno == EBADF) {
                err = posix_spawn_file_actions_addopen(&fx, fd, "/dev/null", O_RDWR, 0);
                if (err) goto bad;
            }
        }

        err = posix_spawn(&pid, path, &fx, &ax, argv, envv ? envv : environ);
        if (err) goto bad;
        posix_spawnattr_destroy(&ax);
        posix_spawn_file_actions_destroy(&fx);
        if (xev) {
            spawnvex_apply(xev, 0, SPAWN_NOCALL);
            spawnvex_close(xev);
        }
        if (vex->flags & SPAWN_CLEANUP) spawnvex_apply(vex, 0, SPAWN_FRAME | SPAWN_CLEANUP);
        VEXINIT(vex);
    } else {
        err = posix_spawn(&pid, path, NULL, NULL, argv, envv ? envv : environ);
        if (err) goto nope;
    }
    if (vex && vex->debug >= 0) {
        error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\" %8d posix_spawn",
              __LINE__, getpid(), vex, vex->cur, path, pid);
    }
    return pid;
bad:
    posix_spawnattr_destroy(&ax);
    posix_spawn_file_actions_destroy(&fx);
    if (xev) {
        spawnvex_apply(xev, 0, SPAWN_NOCALL);
        spawnvex_close(xev);
    }
nope:
    errno = err;
    if (vex && vex->debug >= 0) {
        error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\" %8d posix_spawn FAILED",
              __LINE__, getpid(), vex, vex->cur, path, -1);
    }
    return -1;
#endif
}
Exemple #19
0
R_API int r_sandbox_system (const char *x, int n) {
	if (enabled) {
		eprintf ("sandbox: system call disabled\n");
		return -1;
	}
#if LIBC_HAVE_FORK
#if LIBC_HAVE_SYSTEM
	if (n) {
#if APPLE_SDK_IPHONEOS
#include <dlfcn.h>
		int (*__system)(const char *cmd)
			= dlsym (NULL, "system");
		if (__system) {
			return __system (x);
		}
		return -1;
#else
		return system (x);
#endif
	}
	return execl ("/bin/sh", "sh", "-c", x, (const char*)NULL);
#else
	#include <spawn.h>
	if (n && !strchr (x, '|')) {
		char **argv, *cmd = strdup (x);
		int rc, pid, argc;
		char *isbg = strchr (cmd, '&');
		// XXX this is hacky
		if (isbg) {
			*isbg = 0;
		}
		argv = r_str_argv (cmd, &argc);
		if (argv) {
			char *argv0 = r_file_path (argv[0]);
			if (!argv0) {
				eprintf ("Cannot find '%s'\n", argv[0]);
				return -1;
			}
			pid = 0;
			posix_spawn (&pid, argv0, NULL, NULL, argv, NULL);
			if (isbg) {
				// XXX. wait for children
				rc = 0;
			} else {
				rc = waitpid (pid, NULL, 0);
			}
			r_str_argv_free (argv);
			free (argv0);
			return rc;
		}
		eprintf ("Error parsing command arguments\n");
		return -1;
	}
	int child = fork();
	if (child == -1) return -1;
	if (child) {
		return waitpid (child, NULL, 0);
	}
	execl ("/bin/sh", "sh", "-c", x, (const char*)NULL);
	exit (1);
#endif
#endif
	return -1;
}
Exemple #20
0
int runDaemonRun(void) {
	// Register for all the notifications
	int fd;
	int quitToken = 0;
	if (notify_register_file_descriptor(quitNotification, &fd, 0, &quitToken) != NOTIFY_STATUS_OK) {
		return 0x10;
	}
	int startToken = 0;
	if (notify_register_file_descriptor(startNotification, &fd, NOTIFY_REUSE, &startToken) != NOTIFY_STATUS_OK) {
		return 0x11;
	}
	int stopToken = 0;
	if (notify_register_file_descriptor(stopNotification, &fd, NOTIFY_REUSE, &stopToken) != NOTIFY_STATUS_OK) {
		return 0x12;
	}
	int debugToken = 0;
	if (notify_register_file_descriptor(debugNotification, &fd, NOTIFY_REUSE, &debugToken) != NOTIFY_STATUS_OK) {
		return 0x14;
	}

	print_message(0, "Started as %d(%d):%d(%d)\n", getuid(), geteuid(), getgid(), getegid());

	fd_set readfds;
	FD_ZERO(&readfds);
	FD_SET(fd, &readfds);

	pid_t ngircdPid = 0;
	int ps;
	char debug = 1;

	char shouldContinue = 1;
	while (shouldContinue) {
		int status = select(fd + 1, &readfds, NULL, NULL, NULL);
		if (status <= 0 || !FD_ISSET(fd, &readfds)) {
			continue;
		}

		int t;
		status = read(fd, &t, sizeof(int));
		if (status < 0) {
			continue;
		}
		t = ntohl(t); // notify_register_file_descriptor docs: "The value is sent in network byte order."

		// Value in file descriptor matches token for quit notification
		if (t == quitToken) {
			if (debug) print_message(0, "Quitting\n");
			shouldContinue = 0;
		}

		// Value in file descriptor matches token for start notification
		if (t == startToken) {
			if (debug) print_message(0, "Starting\n");
			// Start ngircd as non-daemon, using custom config file
			const char *args[] = {"ngircd", "-n", "-f", "/Library/Application Support/IRCyslog/ircyslog.conf", NULL};
			if (!ngircdPid) {
				ps = posix_spawn(&ngircdPid, "/usr/sbin/ngircd", NULL, NULL, (char *const *)args, NULL);
				if (!ps) {
					if (debug) print_message(0, "Started ngircd with pid:%d\n", ngircdPid);
				}
			}

			// Start the IRC bot
			// ...

		}

		// Value in file descriptor matches token for stop notification
		// or the quit notification was posted
		if (t == stopToken || !shouldContinue) {
			if (debug) print_message(0, "stopping");

			// Stop the IRC bot
			// ...

			if (!ps) { // If the server is running, kill it
				if (debug) print_message(0, "Calling kill with (%d, %d)\n", ngircdPid, SIGTERM);
				int k = kill(ngircdPid, SIGTERM);
				if (debug) print_message(0, "kill'd with exit status %d\n", k);

				// Wait for the server to finish and purge from the process list
				int st;
				if (debug) print_message(0, "Calling waitpid with (%d,%d)\n", ngircdPid, 0);
				int w = waitpid(ngircdPid, &st, 0);
				if (debug) print_message(0, "waitpid'd with exit status %d, stat_loc %d\n", w, st);
			}
		}

		// Value in file descriptor matches token for debug notification
		if (t == debugToken) {
			debug = !debug;
			print_message(0, "debug is %s\n", debug ? "ON" : "OFF");
		}
	}

	// Cancel notification watching
	print_message(0, "Cancelling notifications\n");
	notify_cancel(quitToken);
	notify_cancel(startToken);
	notify_cancel(stopToken);
	notify_cancel(debugToken);

	return 0;
}
Exemple #21
0
static PRProcess *
ForkAndExec(
    const char *path,
    char *const *argv,
    char *const *envp,
    const PRProcessAttr *attr)
{
    PRProcess *process;
    int nEnv, idx;
    char *const *childEnvp;
    char **newEnvp = NULL;
    int flags;
#ifdef VMS
    char VMScurdir[FILENAME_MAX+1] = { '\0' } ;
#endif	

    process = PR_NEW(PRProcess);
    if (!process) {
        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
        return NULL;
    }

    childEnvp = envp;
    if (attr && attr->fdInheritBuffer) {
        PRBool found = PR_FALSE;

        if (NULL == childEnvp) {
#ifdef DARWIN
            childEnvp = *(_NSGetEnviron());
#else
            childEnvp = environ;
#endif
        }
        for (nEnv = 0; childEnvp[nEnv]; nEnv++) {
        }
        newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *));
        if (NULL == newEnvp) {
            PR_DELETE(process);
            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
            return NULL;
        }
        for (idx = 0; idx < nEnv; idx++) {
            newEnvp[idx] = childEnvp[idx];
            if (!found && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) {
                newEnvp[idx] = attr->fdInheritBuffer;
                found = PR_TRUE;
            }
        }
        if (!found) {
            newEnvp[idx++] = attr->fdInheritBuffer;
        }
        newEnvp[idx] = NULL;
        childEnvp = newEnvp;
    }

#ifdef VMS
/*
** Since vfork/exec is implemented VERY differently on OpenVMS, we have to
** handle the setting up of the standard streams very differently. And since
** none of this code can ever execute in the context of the child, we have
** to perform the chdir in the parent so the child is born into the correct
** directory (and then switch the parent back again).
*/
{
    int decc$set_child_standard_streams(int,int,int);
    int n, fd_stdin=0, fd_stdout=1, fd_stderr=2;

    /* Set up any standard streams we are given, assuming defaults */
    if (attr) {
       if (attr->stdinFd)
           fd_stdin = attr->stdinFd->secret->md.osfd;
       if (attr->stdoutFd)
           fd_stdout = attr->stdoutFd->secret->md.osfd;
       if (attr->stderrFd)
           fd_stderr = attr->stderrFd->secret->md.osfd;
    }

    /*
    ** Put a lock around anything that isn't going to be thread-safe.
    */
    PR_Lock(_pr_vms_fork_lock);

    /*
    ** Prepare the child's streams. We always do this in case a previous fork
    ** has left the stream assignments in some non-standard way.
    */
    n = decc$set_child_standard_streams(fd_stdin,fd_stdout,fd_stderr);
    if (n == -1) {
       PR_SetError(PR_BAD_DESCRIPTOR_ERROR, errno);
       PR_DELETE(process);
       if (newEnvp) {
           PR_DELETE(newEnvp);
       }
       PR_Unlock(_pr_vms_fork_lock);
       return NULL;
    }

    /* Switch directory if we have to */
    if (attr) {
       if (attr->currentDirectory) {
           if ( (getcwd(VMScurdir,sizeof(VMScurdir)) == NULL) ||
                (chdir(attr->currentDirectory) < 0) ) {
               PR_SetError(PR_DIRECTORY_OPEN_ERROR, errno);
               PR_DELETE(process);
               if (newEnvp) {
                   PR_DELETE(newEnvp);
               }
               PR_Unlock(_pr_vms_fork_lock);
               return NULL;
           }
       }
    }
}
#endif /* VMS */

#ifdef AIX
    process->md.pid = (*pr_wp.forkptr)();
#elif defined(NTO) || defined(SYMBIAN)
    /*
     * fork() & exec() does not work in a multithreaded process.
     * Use spawn() instead.
     */
    {
        int fd_map[3] = { 0, 1, 2 };

        if (attr) {
            if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) {
                fd_map[0] = dup(attr->stdinFd->secret->md.osfd);
                flags = fcntl(fd_map[0], F_GETFL, 0);
                if (flags & O_NONBLOCK)
                    fcntl(fd_map[0], F_SETFL, flags & ~O_NONBLOCK);
            }
            if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) {
                fd_map[1] = dup(attr->stdoutFd->secret->md.osfd);
                flags = fcntl(fd_map[1], F_GETFL, 0);
                if (flags & O_NONBLOCK)
                    fcntl(fd_map[1], F_SETFL, flags & ~O_NONBLOCK);
            }
            if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) {
                fd_map[2] = dup(attr->stderrFd->secret->md.osfd);
                flags = fcntl(fd_map[2], F_GETFL, 0);
                if (flags & O_NONBLOCK)
                    fcntl(fd_map[2], F_SETFL, flags & ~O_NONBLOCK);
            }

            PR_ASSERT(attr->currentDirectory == NULL);  /* not implemented */
        }

#ifdef SYMBIAN
        /* In Symbian OS, we use posix_spawn instead of fork() and exec() */
        posix_spawn(&(process->md.pid), path, NULL, NULL, argv, childEnvp);
#else
        process->md.pid = spawn(path, 3, fd_map, NULL, argv, childEnvp);
#endif

        if (fd_map[0] != 0)
            close(fd_map[0]);
        if (fd_map[1] != 1)
            close(fd_map[1]);
        if (fd_map[2] != 2)
            close(fd_map[2]);
    }
#else
    process->md.pid = fork();
#endif
    if ((pid_t) -1 == process->md.pid) {
        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno);
        PR_DELETE(process);
        if (newEnvp) {
            PR_DELETE(newEnvp);
        }
        return NULL;
    } else if (0 == process->md.pid) {  /* the child process */
        /*
         * If the child process needs to exit, it must call _exit().
         * Do not call exit(), because exit() will flush and close
         * the standard I/O file descriptors, and hence corrupt
         * the parent process's standard I/O data structures.
         */

#if !defined(NTO) && !defined(SYMBIAN)
#ifdef VMS
       /* OpenVMS has already handled all this above */
#else
        if (attr) {
            /* the osfd's to redirect stdin, stdout, and stderr to */
            int in_osfd = -1, out_osfd = -1, err_osfd = -1;

            if (attr->stdinFd
                    && attr->stdinFd->secret->md.osfd != 0) {
                in_osfd = attr->stdinFd->secret->md.osfd;
                if (dup2(in_osfd, 0) != 0) {
                    _exit(1);  /* failed */
                }
                flags = fcntl(0, F_GETFL, 0);
                if (flags & O_NONBLOCK) {
                    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
                }
            }
            if (attr->stdoutFd
                    && attr->stdoutFd->secret->md.osfd != 1) {
                out_osfd = attr->stdoutFd->secret->md.osfd;
                if (dup2(out_osfd, 1) != 1) {
                    _exit(1);  /* failed */
                }
                flags = fcntl(1, F_GETFL, 0);
                if (flags & O_NONBLOCK) {
                    fcntl(1, F_SETFL, flags & ~O_NONBLOCK);
                }
            }
            if (attr->stderrFd
                    && attr->stderrFd->secret->md.osfd != 2) {
                err_osfd = attr->stderrFd->secret->md.osfd;
                if (dup2(err_osfd, 2) != 2) {
                    _exit(1);  /* failed */
                }
                flags = fcntl(2, F_GETFL, 0);
                if (flags & O_NONBLOCK) {
                    fcntl(2, F_SETFL, flags & ~O_NONBLOCK);
                }
            }
            if (in_osfd != -1) {
                close(in_osfd);
            }
            if (out_osfd != -1 && out_osfd != in_osfd) {
                close(out_osfd);
            }
            if (err_osfd != -1 && err_osfd != in_osfd
                    && err_osfd != out_osfd) {
                close(err_osfd);
            }
            if (attr->currentDirectory) {
                if (chdir(attr->currentDirectory) < 0) {
                    _exit(1);  /* failed */
                }
            }
        }
#endif /* !VMS */

        if (childEnvp) {
            (void)execve(path, argv, childEnvp);
        } else {
            /* Inherit the environment of the parent. */
            (void)execv(path, argv);
        }
        /* Whoops! It returned. That's a bad sign. */
#ifdef VMS
       /*
       ** On OpenVMS we are still in the context of the parent, and so we
       ** can (and should!) perform normal error handling.
       */
       PR_SetError(PR_UNKNOWN_ERROR, errno);
       PR_DELETE(process);
       if (newEnvp) {
           PR_DELETE(newEnvp);
       }
       if (VMScurdir[0] != '\0')
           chdir(VMScurdir);
       PR_Unlock(_pr_vms_fork_lock);
       return NULL;
#else
        _exit(1);
#endif /* VMS */
#endif /* !NTO */
    }

    if (newEnvp) {
        PR_DELETE(newEnvp);
    }
#ifdef VMS
    /* If we switched directories, then remember to switch back */
    if (VMScurdir[0] != '\0') {
       chdir(VMScurdir); /* can't do much if it fails */
    }
    PR_Unlock(_pr_vms_fork_lock);
#endif /* VMS */

#if defined(_PR_NATIVE_THREADS)
    PR_Lock(pr_wp.ml);
    if (0 == pr_wp.numProcs++) {
        PR_NotifyCondVar(pr_wp.cv);
    }
    PR_Unlock(pr_wp.ml);
#endif
    return process;
}
Exemple #22
0
N_NIMCALL(pid_t, startprocessauxspawn_145001)(Tstartprocessdata144948* data) {
	pid_t result;
	posix_spawnattr_t attr;
	posix_spawn_file_actions_t fops;
	sigset_t mask;
	int res;
	pid_t pid;
	int LOC98;
	int LOC99;
{	result = 0;
	memset((void*)(&attr), 0, sizeof(attr));
	memset((void*)(&fops), 0, sizeof(fops));
	{
		int LOC3;
		NI32 LOC6;
		LOC3 = 0;
		LOC3 = posix_spawn_file_actions_init((&fops));
		if (!!((LOC3 == ((NI32) 0)))) goto LA4;
		LOC6 = 0;
		LOC6 = oslasterror_117033();
		raiseoserror_117009(LOC6);
	}
	LA4: ;
	{
		int LOC9;
		NI32 LOC12;
		LOC9 = 0;
		LOC9 = posix_spawnattr_init((&attr));
		if (!!((LOC9 == ((NI32) 0)))) goto LA10;
		LOC12 = 0;
		LOC12 = oslasterror_117033();
		raiseoserror_117009(LOC12);
	}
	LA10: ;
	memset((void*)(&mask), 0, sizeof(mask));
	{
		int LOC15;
		NI32 LOC18;
		LOC15 = 0;
		LOC15 = sigemptyset((&mask));
		if (!!((LOC15 == ((NI32) 0)))) goto LA16;
		LOC18 = 0;
		LOC18 = oslasterror_117033();
		raiseoserror_117009(LOC18);
	}
	LA16: ;
	{
		int LOC21;
		NI32 LOC24;
		LOC21 = 0;
		LOC21 = posix_spawnattr_setsigmask((&attr), (&mask));
		if (!!((LOC21 == ((NI32) 0)))) goto LA22;
		LOC24 = 0;
		LOC24 = oslasterror_117033();
		raiseoserror_117009(LOC24);
	}
	LA22: ;
	{
		int LOC27;
		NI32 LOC30;
		LOC27 = 0;
		LOC27 = posix_spawnattr_setpgroup((&attr), ((pid_t) 0));
		if (!!((LOC27 == ((NI32) 0)))) goto LA28;
		LOC30 = 0;
		LOC30 = oslasterror_117033();
		raiseoserror_117009(LOC30);
	}
	LA28: ;
	{
		int LOC33;
		NI32 LOC36;
		LOC33 = 0;
		LOC33 = posix_spawnattr_setflags((&attr), (NI32)((NI32)(((int) 0) | POSIX_SPAWN_SETSIGMASK) | POSIX_SPAWN_SETPGROUP));
		if (!!((LOC33 == ((NI32) 0)))) goto LA34;
		LOC36 = 0;
		LOC36 = oslasterror_117033();
		raiseoserror_117009(LOC36);
	}
	LA34: ;
	{
		if (!!((*data).optionpoparentstreams)) goto LA39;
		{
			int LOC43;
			NI32 LOC46;
			LOC43 = 0;
			LOC43 = posix_spawn_file_actions_addclose((&fops), (*data).pstdin[(((NI) 1))- 0]);
			if (!!((LOC43 == ((NI32) 0)))) goto LA44;
			LOC46 = 0;
			LOC46 = oslasterror_117033();
			raiseoserror_117009(LOC46);
		}
		LA44: ;
		{
			int LOC49;
			NI32 LOC52;
			LOC49 = 0;
			LOC49 = posix_spawn_file_actions_adddup2((&fops), (*data).pstdin[(((NI) 0))- 0], ((int) 0));
			if (!!((LOC49 == ((NI32) 0)))) goto LA50;
			LOC52 = 0;
			LOC52 = oslasterror_117033();
			raiseoserror_117009(LOC52);
		}
		LA50: ;
		{
			int LOC55;
			NI32 LOC58;
			LOC55 = 0;
			LOC55 = posix_spawn_file_actions_addclose((&fops), (*data).pstdout[(((NI) 0))- 0]);
			if (!!((LOC55 == ((NI32) 0)))) goto LA56;
			LOC58 = 0;
			LOC58 = oslasterror_117033();
			raiseoserror_117009(LOC58);
		}
		LA56: ;
		{
			int LOC61;
			NI32 LOC64;
			LOC61 = 0;
			LOC61 = posix_spawn_file_actions_adddup2((&fops), (*data).pstdout[(((NI) 1))- 0], ((int) 1));
			if (!!((LOC61 == ((NI32) 0)))) goto LA62;
			LOC64 = 0;
			LOC64 = oslasterror_117033();
			raiseoserror_117009(LOC64);
		}
		LA62: ;
		{
			int LOC67;
			NI32 LOC70;
			LOC67 = 0;
			LOC67 = posix_spawn_file_actions_addclose((&fops), (*data).pstderr[(((NI) 0))- 0]);
			if (!!((LOC67 == ((NI32) 0)))) goto LA68;
			LOC70 = 0;
			LOC70 = oslasterror_117033();
			raiseoserror_117009(LOC70);
		}
		LA68: ;
		{
			if (!(*data).optionpostderrtostdout) goto LA73;
			{
				int LOC77;
				NI32 LOC80;
				LOC77 = 0;
				LOC77 = posix_spawn_file_actions_adddup2((&fops), (*data).pstdout[(((NI) 1))- 0], ((int) 2));
				if (!!((LOC77 == ((NI32) 0)))) goto LA78;
				LOC80 = 0;
				LOC80 = oslasterror_117033();
				raiseoserror_117009(LOC80);
			}
			LA78: ;
		}
		goto LA71;
		LA73: ;
		{
			{
				int LOC84;
				NI32 LOC87;
				LOC84 = 0;
				LOC84 = posix_spawn_file_actions_adddup2((&fops), (*data).pstderr[(((NI) 1))- 0], ((int) 2));
				if (!!((LOC84 == ((NI32) 0)))) goto LA85;
				LOC87 = 0;
				LOC87 = oslasterror_117033();
				raiseoserror_117009(LOC87);
			}
			LA85: ;
		}
		LA71: ;
	}
	LA39: ;
	res = 0;
	{
		NimStringDesc* LOC92;
		if (!(((NI) 0) < ((*data).workingdir ? strlen((*data).workingdir) : 0))) goto LA90;
		LOC92 = 0;
		LOC92 = cstrToNimstr((*data).workingdir);
		setcurrentdir_119207(LOC92);
	}
	LA90: ;
	pid = 0;
	{
		if (!(*data).optionpousepath) goto LA95;
		res = posix_spawnp((&pid), (*data).syscommand, (&fops), (&attr), (*data).sysargs, (*data).sysenv);
	}
	goto LA93;
	LA95: ;
	{
		res = posix_spawn((&pid), (*data).syscommand, (&fops), (&attr), (*data).sysargs, (*data).sysenv);
	}
	LA93: ;
	LOC98 = 0;
	LOC98 = posix_spawn_file_actions_destroy((&fops));
	LOC99 = 0;
	LOC99 = posix_spawnattr_destroy((&attr));
	{
		NI32 LOC104;
		if (!!((res == ((NI32) 0)))) goto LA102;
		LOC104 = 0;
		LOC104 = oslasterror_117033();
		raiseoserror_117009(LOC104);
	}
	LA102: ;
	result = pid;
	goto BeforeRet;
	}BeforeRet: ;
	return result;
}
Exemple #23
0
int shell ( char *args[] )
{
	char cmd[MAXCMDLEN + 1];
	int i, key, rv;
	timespec_t t __attribute__ ((unused));
	int argnum;
	char *argval[MAXARGS + 1];
	pthread_t thr;
	struct pollfd fds = { 0 /* stdin */, POLLRDNORM, 0 };

	//printf ( "\x1b[37m" ); /* test escape sequence: white text */
	printf ( "\n*** Simple shell interpreter ***\n\n" );
	//printf ( "\x1b[32m" ); /* test escape sequence: green text */
	help ();

	t.tv_sec = 0;
	t.tv_nsec = 100000000; /* 100 ms */

	while (1)
	{
		new_cmd:
		printf ( "\n> " );

		i = 0;
		memset ( cmd, 0, MAXCMDLEN );

		/* get command - get chars until new line is received */
		while ( i < MAXCMDLEN )
		{
			if ( !poll ( &fds, 1, 0 ) ) /* is anything pressed? */
			{
				nanosleep ( &t, NULL );
				continue;
			}

			key = getchar ();
			if ( !key ) /* not ascii? */
				continue;

			if ( key == '\n' || key == '\r')
			{
				if ( i > 0 )
					break;
				else
					goto new_cmd;
			}

			switch ( key )
			{
			case '\b':
				if ( i > 0 )
				{
					cmd[--i] = 0;
					printf ( "%c", key );
				}
				break;

			default:
				printf ( "%c", key );
				cmd[i++] = (char) key;
				break;
			}
		}
		printf ( "\n" );

		/* parse command line */
		argnum = 0;
		for(i = 0; i < MAXCMDLEN && cmd[i]!=0 && argnum < MAXARGS; i++)
		{
			if ( cmd[i] == ' ' || cmd[i] == '\t')
				continue;

			argval[argnum++] = &cmd[i];
			while ( cmd[i] && cmd[i] != ' ' && cmd[i] != '\t'
				&& i < MAXCMDLEN )
				i++;

			cmd[i] = 0;
		}
		argval[argnum] = NULL;

		/* match command to shell command */
		for ( i = 0; sh_cmd[i].func != NULL; i++ )
		{
			if ( strcmp ( argval[0], sh_cmd[i].name ) == 0 )
			{
				if ( sh_cmd[i].func ( argval ) )
					printf ( "\nProgram returned error!\n" );

				goto new_cmd;
			}
		}

		/* not shell command; start given program by calling kernel */
		rv = posix_spawn ( &thr, argval[0], NULL, NULL, argval, NULL );
		if ( !rv )
		{
			if ( argnum < 2 || argval[argnum-1][0] != '&' )
				pthread_join ( thr, NULL );

			goto new_cmd;
		}

		if ( strcmp ( argval[0], "quit" ) == 0 ||
			strcmp ( argval[0], "exit" ) == 0 )
			break;

		/* not program kernel or shell knows about it - report error! */
		printf ( "Invalid command or program already started!" );
	}

	printf ( "Exiting from shell\n" );

	return 0;
}
Exemple #24
0
/*
 * non-zero return is success
 */
EXPORT
BOOL CreateProcessA(LPCTSTR lpApplicationName,
                    LPTSTR lpCommandLine,
                    LPSECURITY_ATTRIBUTES lpProcessAttributes,
                    LPSECURITY_ATTRIBUTES lpThreadAttributes,
                    BOOL bInheritHandles,
                    DWORD dwCreationFlags,
                    LPVOID lpEnvironment,
                    LPCTSTR lpCurrentDirectory,
                    LPSTARTUPINFO lpStartupInfo,
                    LPPROCESS_INFORMATION lpProcessInformation )
{

    // problem here in OS X because we are not suspending the target so it will happily run ! :-)
    // we need to use ptrace to start the new target in a suspended state, which happens in Win32 with
    // the DEBUG_PROCESS/DEBUG_ONLY_THIS_PROCESS flags to CreateProcessA
    // fG! - 04/10/2010
#if DEBUG
    printf("[DEBUG] Creating process %s %s\n", lpApplicationName, lpCommandLine);
#endif
    posix_spawnattr_t attr;
    int retval      = 0;
    size_t copied   = 0;
    short flags     = 0;
    cpu_type_t cpu  = 0;

#if defined (__arm__)
    cpu = CPU_TYPE_ARM; // ooops... distinction is done at subtype which
    // posix_spawn doesn't support
    // lldb solution seems to not set this - must test
#else
    // default target is 32bits
    cpu  = CPU_TYPE_I386;
    if (dwCreationFlags & TARGET_IS_64BITS)
        cpu = CPU_TYPE_X86_64;
#endif

    retval = posix_spawnattr_init (&attr);
    // set process flags
    // the new process will start in a suspended state and permissions reset to real uid/gid
    flags = POSIX_SPAWN_RESETIDS | POSIX_SPAWN_START_SUSPENDED;
    // disable ASLR, default is YES from PyDbg
    // Snow Leopard will just ignore this flag
    if (dwCreationFlags & _POSIX_SPAWN_DISABLE_ASLR)
        flags |= _POSIX_SPAWN_DISABLE_ASLR;

    retval = posix_spawnattr_setflags(&attr, flags);

    // reset signals, ripped from LLDB :-]
    sigset_t no_signals;
    sigset_t all_signals;
    sigemptyset (&no_signals);
    sigfillset (&all_signals);
    posix_spawnattr_setsigmask(&attr, &no_signals);
    posix_spawnattr_setsigdefault(&attr, &all_signals);
    // set the target cpu to be used, due to fat binaries
    retval = posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &copied);

    char *spawnedEnv[] = { NULL };

    int cmd_line_len = strlen(lpCommandLine);
    if (cmd_line_len >= ARG_MAX)
    {
        fprintf(stderr, "[ERROR] arg list too long\n");
        exit(1);
    }

    if (cmd_line_len)
    {
        // parse command line;
        int i = 0;
        char *p = strchr(lpCommandLine, ' ');
        char *q = lpCommandLine;

        char **argv = malloc(sizeof(char*) * 256);
        while (p && i < 253)
        {
            *p = '\0';
            argv[i++] = q;
            q = p + 1;
            p = strchr(q, ' ');
        }
        errno = 0;
        argv[i] = q;
        argv[i+1] = NULL;
#if DEBUG
        printf("[DEBUG] Spawning %s %s %s\n", argv[0], argv[1], argv[2]);
#endif
        fflush(stdout);
        retval = posix_spawn(&target_pid, argv[0], NULL, &attr, argv, spawnedEnv);
        if(retval)
        {
            fprintf(stderr, "[ERROR] Could not spawn debuggee: %s\n", strerror(retval));
            exit(1);
        }
        free(argv);
    }
    else
    {
        fflush(stdout);
        // execute with no arguments
        char *argv[] = {lpApplicationName, NULL};
#if DEBUG
        printf("[DEBUG] Spawning %s...\n", lpApplicationName);
#endif
        retval = posix_spawnp(&target_pid, argv[0], NULL, &attr, argv, spawnedEnv);
        if (retval)
        {
            fprintf(stderr, "[ERROR] Could not spawn debuggee: %s\n", strerror(retval));
            exit(1);
        }
    }
    // parent
    // initialize the mach port into the debugee
    retval = DebugActiveProcess(target_pid);
    // failed to attach
    if (retval == 0)
    {
        kill(target_pid, SIGCONT); // leave no zombies behind!
        kill(target_pid, SIGKILL);
        return 0;
    }
    // suspend all threads
    suspend_all_threads(target_pid);
    // and now we can continue the process, threads are still suspended!
    kill(target_pid, SIGCONT);
    fflush(stdout);
    lpProcessInformation->hProcess    = target_pid;
    lpProcessInformation->dwProcessId = target_pid;

    return 1;
}
Exemple #25
0
int main(int argc, char *argv[])
{
    posix_spawnattr_t	attrs;
    uint64_t		percent, interval;
    int			i, err, ret = 0;

    kern_return_t		kr;
    mach_port_t		task = mach_task_self();
    mach_port_t		child_task;
    char                    **child_args;

    pthread_t		exception_thread;
    pthread_t		timer_thread;
    pthread_t		wait_thread;

    mach_msg_type_number_t	maskCount = 1;
    exception_mask_t	mask;
    exception_handler_t	handler;
    exception_behavior_t	behavior;
    thread_state_flavor_t   flavor;

    pid_t			child_pid;
    int			test_case_id = -1;

    if (argc > 1)
        test_case_id = atoi(argv[1]);

    /* Initialize mutex and condition variable */
    if ((err = pthread_mutex_init(&lock, NULL)) != 0) {
        fprintf(stderr,"pthread_mutex_init: %s\n", strerror(err));
        exit(1);
    }

    if ((err = pthread_cond_init(&cv, NULL)) != 0) {
        fprintf(stderr, "pthread_cond_init: %s\n", strerror(err));
        exit(1);
    }

    /* Allocate and initialize new exception port */
    if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &exc_port)) != KERN_SUCCESS) {
        fprintf(stderr, "mach_port_allocate: %s\n", mach_error_string(kr));
        exit(1);
    }

    if ((kr = mach_port_insert_right(task, exc_port,
                                     exc_port, MACH_MSG_TYPE_MAKE_SEND)) != KERN_SUCCESS) {
        fprintf(stderr, "mach_port_allocate: %s\n", mach_error_string(kr));
        exit(1);
    }

    /* Get Current exception ports */
    if ((kr = task_get_exception_ports(task, EXC_MASK_RESOURCE, &mask,
                                       &maskCount, &handler, &behavior, &flavor)) != KERN_SUCCESS) {
        fprintf(stderr,"task_get_exception_ports: %s\n", mach_error_string(kr));
        exit(1);
    }

    /* Create exception serving thread */
    if ((err = pthread_create(&exception_thread, NULL, server_thread, 0)) != 0) {
        fprintf(stderr, "pthread_create server_thread: %s\n", strerror(err));
        exit(1);
    }

    fprintf(stderr, "---------------System Configuration------------------------------------------\n");
    fprintf(stderr, "System Kernel Version: ");
    system("uname -a");
    fprintf(stderr, "System SDK Version: ");
    system("sw_vers");

    for (i = 0; i < NUMTESTS; i++) {
        indiv_results[i] = -1;
    }

    /* Run Tests */
    for(i=0; i<NUMTESTS; i++) {
        int j;

        if (test_case_id != -1 && test_case_id != i)
            continue;

        fprintf(stderr, "---------------Test [%d] Configuration------------------------------------------\n", i);
        fprintf(stderr, "Test Case ID: %d\n", i);
        fprintf(stderr, "Description: %s\n", test_description[i]);

        switch(i) {
        case 0:
            child_args = test_argv_0;
            break;
        case 1:
            child_args = test_argv_1;
            break;
        case 2:
            child_args = test_argv_2;
            break;
        case 3:
            child_args = test_argv_3;
            break;
        case 4:
            child_args = test_argv_4;
            break;
        case 5:
            child_args = test_argv_5;
            break;
        case 6:
            child_args = test_argv_6;
            break;
        default:
            fprintf(stderr, "no test argv found\n");
            exit(1);
        }

        /* Test cases which do not need to run for certain platforms */
        if (child_args == NULL) {
            fprintf(stderr, "Test case unimplemented for current platform.\n");
            fprintf(stderr, "[PASSED]\n");
            fprintf(stderr, "-------------------------------------------------------------------------------\n");
            continue;
        }

        fprintf(stderr, "Helper args: ");
        for (j = 0; child_args[j] != NULL; j++) {
            fprintf(stderr, "%s ", child_args[j]);
        }
        fprintf(stderr, "\n");

        /* Print Test Case Configuration */
        fprintf(stderr, "Test Case expects EXC_RESOURCE?: %s\n", test_exception_code[i] ? "Yes":"No");
        if (test_exception_code[i])
            fprintf(stderr, "Expected EXC_RESOURCE code: 0x%llx\n", test_exception_code[i]);
        if (timeout_secs[i])
            fprintf(stderr, "Timeout for Test Program: %d secs\n", timeout_secs[i]);
        if (exc_expected_at[i])
            fprintf(stderr, "Exception Expected After: %d secs\n", exc_expected_at[i]);

        /* Initialize posix_spawn attributes */
        posix_spawnattr_init(&attrs);

        if ((err = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETEXEC)) != 0) {
            fprintf(stderr, "posix_spawnattr_setflags: %s\n", strerror(err));
            exit(1);
        }

        /* Use high values so the system defaults take effect (spawn attrs are capped) */
        percent = 100;
        interval = 10000;

        /* Enable CPU Monitor */
        if ((err = posix_spawnattr_setcpumonitor(&attrs, percent, interval)) != 0) {
            fprintf(stderr, "posix_spawnattr_setcpumonitor: %s\n", strerror(err));
            exit(1);
        }


        exception_code = 0;
        time_for_exc = -1;

        /* Set Exception Ports for Current Task */
        if ((kr = task_set_exception_ports(task, EXC_MASK_RESOURCE, exc_port,
                                           EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) {
            fprintf(stderr, "task_set_exception_ports: %#x\n", kr);
            exit(1);
        }

        /*
         * Note the time at start of test.
         */
        start_time = time(NULL);

        fprintf(stderr, "---------------Test [%d] Runtime------------------------------------------------\n", i);

        /* Fork and exec child */
        if ((child_pid = fork()) == 0) {
            if ((err = posix_spawn(NULL, child_args[0], NULL, &attrs, &child_args[0], environ)) != 0) {
                fprintf(stderr, "posix_spawn: %s\n", strerror(err));
                exit(1);
            }
        }

        /* Restore exception ports for parent */
        if ((kr = task_set_exception_ports(task, EXC_MASK_RESOURCE, handler,
                                           EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) {
            fprintf(stderr, "task_set_exception_ports: %#x\n", kr);
            exit(1);
        }

        /* Create Timer Thread if timeout specified */
        if (timeout_secs[i]) {
            if ((err = pthread_create(&timer_thread, NULL, timeout_thread, (void *)timeout_secs[i])) != 0) {
                fprintf(stderr, "pthread_create timeout_thread: %s\n", strerror(err));
                test_status = 1;
                goto cleanup;
            }
        }

        /* Create waiting for child thread */
        if ((err = pthread_create(&wait_thread, NULL, wait4_child_thread, NULL)) != 0) {
            fprintf(stderr, "pthread_create wait4_child_thread: %s\n", strerror(err));
            test_status = 1;
            goto cleanup;
        }

        pthread_mutex_lock(&lock);
        pthread_cond_wait(&cv, &lock);
        pthread_mutex_unlock(&lock);

        kill(child_pid, SIGKILL);
        pthread_join(timer_thread, NULL);
        pthread_join(wait_thread, NULL);

        int test_case_status = 0;
        indiv_results[i] = 0;

        fprintf(stderr, "---------------Test [%d] Results------------------------------------------------\n", i);

        if (exception_code)
            fprintf(stderr, "EXC_RESOURCE Received with Code: 0x%llx\n", exception_code);
        else
            fprintf(stderr, "No EXC_RESOURCE Received!\n");

        if (time_for_exc > 0)
            fprintf(stderr, "EXC_RESOURCE Received after %d secs\n", time_for_exc);

        if (!!exception_code != !!test_exception_code[i]) {
            test_status = 1;
            test_case_status = 1;
            indiv_results[i] = 1;
        }

        if (exception_code) {
            /* Validate test success by checking code and expected time */
            if ((exception_code & test_exception_code[i]) != test_exception_code[i]) {
                fprintf(stderr, "Test Failure Reason: EXC_RESOURCE code did not match expected exception code!\n");
                fprintf(stderr, "Expected: 0x%llx Found: 0x%llx\n", test_exception_code[i], exception_code);
                test_status = 1;
                test_case_status = 1;
                indiv_results[i] = 1;
            }
            if(exc_expected_at[i] &&
                    (time_for_exc < (exc_expected_at[i] - 10) ||
                     time_for_exc > (exc_expected_at[i] + 10))) {
                fprintf(stderr, "Test Failure Reason: Test case did not receive EXC_RESOURCE within expected time!\n");
                test_status = 1;
                test_case_status = 1;
                indiv_results[i] = 1;
            }
        }

        if(test_case_status)
            fprintf(stderr, "[FAILED]\n");
        else
            fprintf(stderr, "[PASSED]\n");
        fprintf(stderr, "-------------------------------------------------------------------------------\n");

    }

    if (test_case_id == -1) {
        fprintf(stderr, "--------------- Results Summary -----------------------------------------------\n");

        for (i = 0; i < NUMTESTS; i++) {
            fprintf(stderr, "%2d: %s\n", i, (indiv_results[i] < 0) ? "N/A" :
                    (indiv_results[i] == 0) ? "PASSED" : "FAILED");
        }
    }

cleanup:
    kill(child_pid, SIGKILL);
    exit(test_status);
}
FProcHandle FLinuxPlatformProcess::CreateProc(const TCHAR* URL, const TCHAR* Parms, bool bLaunchDetached, bool bLaunchHidden, bool bLaunchReallyHidden, uint32* OutProcessID, int32 PriorityModifier, const TCHAR* OptionalWorkingDirectory, void* PipeWrite)
{
	// @TODO bLaunchHidden bLaunchReallyHidden are not handled
	// We need an absolute path to executable
	FString ProcessPath = URL;
	if (*URL != TEXT('/'))
	{
		ProcessPath = FPaths::ConvertRelativePathToFull(ProcessPath);
	}

	if (!FPaths::FileExists(ProcessPath))
	{
		return FProcHandle();
	}

	FString Commandline = ProcessPath;
	Commandline += TEXT(" ");
	Commandline += Parms;

	UE_LOG(LogHAL, Verbose, TEXT("FLinuxPlatformProcess::CreateProc: '%s'"), *Commandline);

	TArray<FString> ArgvArray;
	int Argc = Commandline.ParseIntoArray(ArgvArray, TEXT(" "), true);
	char* Argv[PlatformProcessLimits::MaxArgvParameters + 1] = { NULL };	// last argument is NULL, hence +1
	struct CleanupArgvOnExit
	{
		int Argc;
		char** Argv;	// relying on it being long enough to hold Argc elements

		CleanupArgvOnExit( int InArgc, char *InArgv[] )
			:	Argc(InArgc)
			,	Argv(InArgv)
		{}

		~CleanupArgvOnExit()
		{
			for (int Idx = 0; Idx < Argc; ++Idx)
			{
				FMemory::Free(Argv[Idx]);
			}
		}
	} CleanupGuard(Argc, Argv);

	// make sure we do not lose arguments with spaces in them due to Commandline.ParseIntoArray breaking them apart above
	// @todo this code might need to be optimized somehow and integrated with main argument parser below it
	TArray<FString> NewArgvArray;
	if (Argc > 0)
	{
		if (Argc > PlatformProcessLimits::MaxArgvParameters)
		{
			UE_LOG(LogHAL, Warning, TEXT("FLinuxPlatformProcess::CreateProc: too many (%d) commandline arguments passed, will only pass %d"),
				Argc, PlatformProcessLimits::MaxArgvParameters);
			Argc = PlatformProcessLimits::MaxArgvParameters;
		}

		FString MultiPartArg;
		for (int32 Index = 0; Index < Argc; Index++)
		{
			if (MultiPartArg.IsEmpty())
			{
				if ((ArgvArray[Index].StartsWith(TEXT("\"")) && !ArgvArray[Index].EndsWith(TEXT("\""))) // check for a starting quote but no ending quote, excludes quoted single arguments
					|| (ArgvArray[Index].Contains(TEXT("=\"")) && !ArgvArray[Index].EndsWith(TEXT("\""))) // check for quote after =, but no ending quote, this gets arguments of the type -blah="string string string"
					|| ArgvArray[Index].EndsWith(TEXT("=\""))) // check for ending quote after =, this gets arguments of the type -blah=" string string string "
				{
					MultiPartArg = ArgvArray[Index];
				}
				else
				{
					if (ArgvArray[Index].Contains(TEXT("=\"")))
					{
						FString SingleArg = ArgvArray[Index];
						SingleArg = SingleArg.Replace(TEXT("=\""), TEXT("="));
						NewArgvArray.Add(SingleArg.TrimQuotes(NULL));
					}
					else
					{
						NewArgvArray.Add(ArgvArray[Index].TrimQuotes(NULL));
					}
				}
			}
			else
			{
				MultiPartArg += TEXT(" ");
				MultiPartArg += ArgvArray[Index];
				if (ArgvArray[Index].EndsWith(TEXT("\"")))
				{
					if (MultiPartArg.StartsWith(TEXT("\"")))
					{
						NewArgvArray.Add(MultiPartArg.TrimQuotes(NULL));
					}
					else
					{
						NewArgvArray.Add(MultiPartArg);
					}
					MultiPartArg.Empty();
				}
			}
		}
	}
	// update Argc with the new argument count
	Argc = NewArgvArray.Num();

	if (Argc > 0)	// almost always, unless there's no program name
	{
		if (Argc > PlatformProcessLimits::MaxArgvParameters)
		{
			UE_LOG(LogHAL, Warning, TEXT("FLinuxPlatformProcess::CreateProc: too many (%d) commandline arguments passed, will only pass %d"), 
				Argc, PlatformProcessLimits::MaxArgvParameters);
			Argc = PlatformProcessLimits::MaxArgvParameters;
		}

		for (int Idx = 0; Idx < Argc; ++Idx)
		{
			auto AnsiBuffer = StringCast<ANSICHAR>(*NewArgvArray[Idx]);
			const char* Ansi = AnsiBuffer.Get();
			size_t AnsiSize = FCStringAnsi::Strlen(Ansi) + 1;
			check(AnsiSize);

			Argv[Idx] = reinterpret_cast< char* >( FMemory::Malloc(AnsiSize) );
			check(Argv[Idx]);

			FCStringAnsi::Strncpy(Argv[Idx], Ansi, AnsiSize);
		}

		// last Argv should be NULL
		check(Argc <= PlatformProcessLimits::MaxArgvParameters + 1);
		Argv[Argc] = NULL;
	}

	extern char ** environ;	// provided by libc
	pid_t ChildPid = -1;

	posix_spawn_file_actions_t FileActions;

	posix_spawn_file_actions_init(&FileActions);
	if (PipeWrite)
	{
		const FPipeHandle* PipeWriteHandle = reinterpret_cast< const FPipeHandle* >(PipeWrite);
		posix_spawn_file_actions_adddup2(&FileActions, PipeWriteHandle->GetHandle(), STDOUT_FILENO);
	}

	int PosixSpawnErrNo = posix_spawn(&ChildPid, TCHAR_TO_ANSI(*ProcessPath), &FileActions, nullptr, Argv, environ);
	posix_spawn_file_actions_destroy(&FileActions);
	if (PosixSpawnErrNo != 0)
	{
		UE_LOG(LogHAL, Fatal, TEXT("FLinuxPlatformProcess::CreateProc: posix_spawn() failed (%d, %s)"), PosixSpawnErrNo, ANSI_TO_TCHAR(strerror(PosixSpawnErrNo)));
		return FProcHandle();	// produce knowingly invalid handle if for some reason Fatal log (above) returns
	}

	// renice the child (subject to race condition).
	// Why this instead of posix_spawn_setschedparam()? 
	// Because posix_spawnattr priority is unusable under Linux due to min/max priority range being [0;0] for the default scheduler
	if (PriorityModifier != 0)
	{
		errno = 0;
		int TheirCurrentPrio = getpriority(PRIO_PROCESS, ChildPid);

		if (errno != 0)
		{
			int ErrNo = errno;
			UE_LOG(LogHAL, Warning, TEXT("FLinuxPlatformProcess::CreateProc: could not get child's priority, errno=%d (%s)"),
				ErrNo,
				ANSI_TO_TCHAR(strerror(ErrNo))
			);
			
			// proceed anyway...
			TheirCurrentPrio = 0;
		}

		rlimit PrioLimits;
		int MaxPrio = 0;
		if (getrlimit(RLIMIT_NICE, &PrioLimits) == -1)
		{
			int ErrNo = errno;
			UE_LOG(LogHAL, Warning, TEXT("FLinuxPlatformProcess::CreateProc: could not get priority limits (RLIMIT_NICE), errno=%d (%s)"),
				ErrNo,
				ANSI_TO_TCHAR(strerror(ErrNo))
			);

			// proceed anyway...
		}
		else
		{
			MaxPrio = PrioLimits.rlim_cur;
		}

		int NewPrio = TheirCurrentPrio;
		if (PriorityModifier > 0)
		{
			// decrease the nice value - will perhaps fail, it's up to the user to run with proper permissions
			NewPrio -= 10;
		}
		else
		{
			NewPrio += 10;
		}

		// cap to [RLIMIT_NICE, 19]
		NewPrio = FMath::Min(19, NewPrio);
		NewPrio = FMath::Max(MaxPrio, NewPrio);	// MaxPrio is actually the _lowest_ numerically priority

		if (setpriority(PRIO_PROCESS, ChildPid, NewPrio) == -1)
		{
			int ErrNo = errno;
			UE_LOG(LogHAL, Warning, TEXT("FLinuxPlatformProcess::CreateProc: could not change child's priority (nice value) from %d to %d, errno=%d (%s)"),
				TheirCurrentPrio, NewPrio,
				ErrNo,
				ANSI_TO_TCHAR(strerror(ErrNo))
			);
		}
		else
		{
			UE_LOG(LogHAL, Log, TEXT("Changed child's priority (nice value) to %d (change from %d)"), NewPrio, TheirCurrentPrio);
		}
	}

	else
	{
		UE_LOG(LogHAL, Log, TEXT("FLinuxPlatformProcess::CreateProc: spawned child %d"), ChildPid);
	}

	if (OutProcessID)
	{
		*OutProcessID = ChildPid;
	}

	// [RCL] 2015-03-11 @FIXME: is bLaunchDetached usable when determining whether we're in 'fire and forget' mode? This doesn't exactly match what bLaunchDetached is used for.
	return FProcHandle(new FProcState(ChildPid, bLaunchDetached));
}
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);
}
static int
do_test (void)
{
  int fd[2];
  if (pipe (fd) != 0)
    {
      puts ("pipe failed");
      exit (1);
    }

  /* Not interested in knowing when the pipe is closed.  */
  if (sigignore (SIGPIPE) != 0)
    {
      puts ("sigignore failed");
      exit (1);
    }

  posix_spawn_file_actions_t a;
  if (posix_spawn_file_actions_init (&a) != 0)
    {
      puts ("spawn_file_actions_init failed");
      exit (1);
    }

  if (posix_spawn_file_actions_adddup2 (&a, fd[1], STDOUT_FILENO) != 0)
    {
      puts ("spawn_file_actions_adddup2 failed");
      exit (1);
    }

  if (posix_spawn_file_actions_addclose (&a, fd[0]) != 0)
    {
      puts ("spawn_file_actions_addclose");
      exit (1);
    }

  pthread_t th;
  if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
    {
      puts ("create failed");
      exit (1);
    }

  pid_t pid;
  char *argv[] = { (char *) _PATH_BSHELL, (char *) "-c", (char *) "echo $$",
		   NULL };
  if (posix_spawn (&pid, _PATH_BSHELL, &a, NULL, argv, NULL) != 0)
    {
      puts ("spawn failed");
      exit (1);
    }

  close (fd[1]);

  char buf[200];
  ssize_t n;
  bool seen_pid = false;
  while (TEMP_FAILURE_RETRY ((n = read (fd[0], buf, sizeof (buf)))) > 0)
    {
      /* We only expect to read the PID.  */
      char *endp;
      long int rpid = strtol (buf, &endp, 10);

      if (*endp != '\n')
	{
	  printf ("didn't parse whole line: \"%s\"\n", buf);
	  exit (1);
	}
      if (endp == buf)
	{
	  puts ("read empty line");
	  exit (1);
	}

      if (rpid != pid)
	{
	  printf ("found \"%s\", expected PID %ld\n", buf, (long int) pid);
	  exit (1);
	}

      if (seen_pid)
	{
	  puts ("found more than one PID line");
	  exit (1);
	}

      seen_pid = true;
    }

  close (fd[0]);

  int status;
  int err = waitpid (pid, &status, 0);
  if (err != pid)
    {
      puts ("waitpid failed");
      exit (1);
    }

  if (!seen_pid)
    {
      puts ("didn't get PID");
      exit (1);
    }

  puts ("read correct PID");

  return 0;
}
Exemple #29
0
static PRProcess *
ForkAndExec(
    const char *path,
    char *const *argv,
    char *const *envp,
    const PRProcessAttr *attr)
{
    PRProcess *process;
    int nEnv, idx;
    char *const *childEnvp;
    char **newEnvp = NULL;
    int flags;

    process = PR_NEW(PRProcess);
    if (!process) {
        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
        return NULL;
    }

    childEnvp = envp;
    if (attr && attr->fdInheritBuffer) {
        PRBool found = PR_FALSE;

        if (NULL == childEnvp) {
#ifdef DARWIN
            childEnvp = *(_NSGetEnviron());
#else
            childEnvp = environ;
#endif
        }
        for (nEnv = 0; childEnvp[nEnv]; nEnv++) {
        }
        newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *));
        if (NULL == newEnvp) {
            PR_DELETE(process);
            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
            return NULL;
        }
        for (idx = 0; idx < nEnv; idx++) {
            newEnvp[idx] = childEnvp[idx];
            if (!found && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) {
                newEnvp[idx] = attr->fdInheritBuffer;
                found = PR_TRUE;
            }
        }
        if (!found) {
            newEnvp[idx++] = attr->fdInheritBuffer;
        }
        newEnvp[idx] = NULL;
        childEnvp = newEnvp;
    }

#ifdef AIX
    process->md.pid = (*pr_wp.forkptr)();
#elif defined(NTO) || defined(SYMBIAN)
    /*
     * fork() & exec() does not work in a multithreaded process.
     * Use spawn() instead.
     */
    {
        int fd_map[3] = { 0, 1, 2 };

        if (attr) {
            if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) {
                fd_map[0] = dup(attr->stdinFd->secret->md.osfd);
                flags = fcntl(fd_map[0], F_GETFL, 0);
                if (flags & O_NONBLOCK)
                    fcntl(fd_map[0], F_SETFL, flags & ~O_NONBLOCK);
            }
            if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) {
                fd_map[1] = dup(attr->stdoutFd->secret->md.osfd);
                flags = fcntl(fd_map[1], F_GETFL, 0);
                if (flags & O_NONBLOCK)
                    fcntl(fd_map[1], F_SETFL, flags & ~O_NONBLOCK);
            }
            if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) {
                fd_map[2] = dup(attr->stderrFd->secret->md.osfd);
                flags = fcntl(fd_map[2], F_GETFL, 0);
                if (flags & O_NONBLOCK)
                    fcntl(fd_map[2], F_SETFL, flags & ~O_NONBLOCK);
            }

            PR_ASSERT(attr->currentDirectory == NULL);  /* not implemented */
        }

#ifdef SYMBIAN
        /* In Symbian OS, we use posix_spawn instead of fork() and exec() */
        posix_spawn(&(process->md.pid), path, NULL, NULL, argv, childEnvp);
#else
        process->md.pid = spawn(path, 3, fd_map, NULL, argv, childEnvp);
#endif

        if (fd_map[0] != 0)
            close(fd_map[0]);
        if (fd_map[1] != 1)
            close(fd_map[1]);
        if (fd_map[2] != 2)
            close(fd_map[2]);
    }
#else
    process->md.pid = fork();
#endif
    if ((pid_t) -1 == process->md.pid) {
        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno);
        PR_DELETE(process);
        if (newEnvp) {
            PR_DELETE(newEnvp);
        }
        return NULL;
    } else if (0 == process->md.pid) {  /* the child process */
        /*
         * If the child process needs to exit, it must call _exit().
         * Do not call exit(), because exit() will flush and close
         * the standard I/O file descriptors, and hence corrupt
         * the parent process's standard I/O data structures.
         */

#if !defined(NTO) && !defined(SYMBIAN)
        if (attr) {
            /* the osfd's to redirect stdin, stdout, and stderr to */
            int in_osfd = -1, out_osfd = -1, err_osfd = -1;

            if (attr->stdinFd
                    && attr->stdinFd->secret->md.osfd != 0) {
                in_osfd = attr->stdinFd->secret->md.osfd;
                if (dup2(in_osfd, 0) != 0) {
                    _exit(1);  /* failed */
                }
                flags = fcntl(0, F_GETFL, 0);
                if (flags & O_NONBLOCK) {
                    fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
                }
            }
            if (attr->stdoutFd
                    && attr->stdoutFd->secret->md.osfd != 1) {
                out_osfd = attr->stdoutFd->secret->md.osfd;
                if (dup2(out_osfd, 1) != 1) {
                    _exit(1);  /* failed */
                }
                flags = fcntl(1, F_GETFL, 0);
                if (flags & O_NONBLOCK) {
                    fcntl(1, F_SETFL, flags & ~O_NONBLOCK);
                }
            }
            if (attr->stderrFd
                    && attr->stderrFd->secret->md.osfd != 2) {
                err_osfd = attr->stderrFd->secret->md.osfd;
                if (dup2(err_osfd, 2) != 2) {
                    _exit(1);  /* failed */
                }
                flags = fcntl(2, F_GETFL, 0);
                if (flags & O_NONBLOCK) {
                    fcntl(2, F_SETFL, flags & ~O_NONBLOCK);
                }
            }
            if (in_osfd != -1) {
                close(in_osfd);
            }
            if (out_osfd != -1 && out_osfd != in_osfd) {
                close(out_osfd);
            }
            if (err_osfd != -1 && err_osfd != in_osfd
                    && err_osfd != out_osfd) {
                close(err_osfd);
            }
            if (attr->currentDirectory) {
                if (chdir(attr->currentDirectory) < 0) {
                    _exit(1);  /* failed */
                }
            }
        }

        if (childEnvp) {
            (void)execve(path, argv, childEnvp);
        } else {
            /* Inherit the environment of the parent. */
            (void)execv(path, argv);
        }
        /* Whoops! It returned. That's a bad sign. */
        _exit(1);
#endif /* !NTO */
    }

    if (newEnvp) {
        PR_DELETE(newEnvp);
    }

#if defined(_PR_NATIVE_THREADS)
    PR_Lock(pr_wp.ml);
    if (0 == pr_wp.numProcs++) {
        PR_NotifyCondVar(pr_wp.cv);
    }
    PR_Unlock(pr_wp.ml);
#endif
    return process;
}
Exemple #30
0
/// Executes an external command.
/// \return true on success, false if there is an exec error.
static bool exec_external_command(job_t *j, process_t *p, const io_chain_t &proc_io_chain) {
    assert(p->type == EXTERNAL && "Process is not external");
    // Get argv and envv before we fork.
    null_terminated_array_t<char> argv_array;
    convert_wide_array_to_narrow(p->get_argv_array(), &argv_array);

    // Ensure that stdin is blocking before we hand it off (see issue #176). It's a
    // little strange that we only do this with stdin and not with stdout or stderr.
    // However in practice, setting or clearing O_NONBLOCK on stdin also sets it for the
    // other two fds, presumably because they refer to the same underlying file
    // (/dev/tty?).
    make_fd_blocking(STDIN_FILENO);

    const char *const *argv = argv_array.get();
    const char *const *envv = env_export_arr();

    std::string actual_cmd_str = wcs2string(p->actual_cmd);
    const char *actual_cmd = actual_cmd_str.c_str();
    const wchar_t *file = reader_current_filename();

#if FISH_USE_POSIX_SPAWN
    // Prefer to use posix_spawn, since it's faster on some systems like OS X.
    bool use_posix_spawn = g_use_posix_spawn && can_use_posix_spawn_for_job(j, p);
    if (use_posix_spawn) {
        g_fork_count++;  // spawn counts as a fork+exec
        // Create posix spawn attributes and actions.
        pid_t pid = 0;
        posix_spawnattr_t attr = posix_spawnattr_t();
        posix_spawn_file_actions_t actions = posix_spawn_file_actions_t();
        bool made_it = fork_actions_make_spawn_properties(&attr, &actions, j, p, proc_io_chain);
        if (made_it) {
            // We successfully made the attributes and actions; actually call
            // posix_spawn.
            int spawn_ret =
                posix_spawn(&pid, actual_cmd, &actions, &attr, const_cast<char *const *>(argv),
                            const_cast<char *const *>(envv));

            // This usleep can be used to test for various race conditions
            // (https://github.com/fish-shell/fish-shell/issues/360).
            // usleep(10000);

            if (spawn_ret != 0) {
                safe_report_exec_error(spawn_ret, actual_cmd, argv, envv);
                // Make sure our pid isn't set.
                pid = 0;
            }

            // Clean up our actions.
            posix_spawn_file_actions_destroy(&actions);
            posix_spawnattr_destroy(&attr);
        }

        // A 0 pid means we failed to posix_spawn. Since we have no pid, we'll never get
        // told when it's exited, so we have to mark the process as failed.
        debug(4, L"Fork #%d, pid %d: spawn external command '%s' from '%ls'", g_fork_count, pid,
              actual_cmd, file ? file : L"<no file>");
        if (pid == 0) {
            job_mark_process_as_failed(j, p);
            return false;
        }

        // these are all things do_fork() takes care of normally (for forked processes):
        p->pid = pid;
        on_process_created(j, p->pid);

        // We explicitly don't call set_child_group() for spawned processes because that
        // a) isn't necessary, and b) causes issues like fish-shell/fish-shell#4715

#if defined(__GLIBC__)
        // Unfortunately, using posix_spawn() is not the panacea it would appear to be,
        // glibc has a penchant for using fork() instead of vfork() when posix_spawn() is
        // called, meaning that atomicity is not guaranteed and we can get here before the
        // child group has been set. See discussion here:
        // https://github.com/Microsoft/WSL/issues/2997 And confirmation that this persists
        // past glibc 2.24+ here: https://github.com/fish-shell/fish-shell/issues/4715
        if (j->get_flag(job_flag_t::JOB_CONTROL) && getpgid(p->pid) != j->pgid) {
            set_child_group(j, p->pid);
        }
#else
        // In do_fork, the pid of the child process is used as the group leader if j->pgid
        // invalid, posix_spawn assigned the new group a pgid equal to its own id if
        // j->pgid was invalid, so this is what we do instead of calling set_child_group
        if (j->pgid == INVALID_PID) {
            j->pgid = pid;
        }
#endif

        maybe_assign_terminal(j);
    } else
#endif
    {
        if (!fork_child_for_process(j, p, proc_io_chain, false, "external command",
                                    [&] { safe_launch_process(p, actual_cmd, argv, envv); })) {
            return false;
        }
    }

    return true;
}