TEST(spawn, posix_spawnattr_setsschedparam_posix_spawnattr_getsschedparam) { posix_spawnattr_t sa; ASSERT_EQ(0, posix_spawnattr_init(&sa)); sched_param sp; ASSERT_EQ(0, posix_spawnattr_getschedparam(&sa, &sp)); ASSERT_EQ(0, sp.sched_priority); sched_param sp123 = { .sched_priority = 123 }; ASSERT_EQ(0, posix_spawnattr_setschedparam(&sa, &sp123)); ASSERT_EQ(0, posix_spawnattr_getschedparam(&sa, &sp)); ASSERT_EQ(123, sp.sched_priority); ASSERT_EQ(0, posix_spawnattr_destroy(&sa)); } TEST(spawn, posix_spawnattr_setschedpolicy_posix_spawnattr_getschedpolicy) { posix_spawnattr_t sa; ASSERT_EQ(0, posix_spawnattr_init(&sa)); int p; ASSERT_EQ(0, posix_spawnattr_getschedpolicy(&sa, &p)); ASSERT_EQ(0, p); ASSERT_EQ(0, posix_spawnattr_setschedpolicy(&sa, SCHED_FIFO)); ASSERT_EQ(0, posix_spawnattr_getschedpolicy(&sa, &p)); ASSERT_EQ(SCHED_FIFO, p); ASSERT_EQ(0, posix_spawnattr_destroy(&sa)); }
TEST(spawn, signal_stress) { // Ensure that posix_spawn doesn't restore the caller's signal mask in the // child without first defaulting any caught signals (http://b/68707996). static pid_t parent = getpid(); setpgid(0, 0); signal(SIGRTMIN, SIG_IGN); pid_t pid = fork(); ASSERT_NE(-1, pid); if (pid == 0) { for (size_t i = 0; i < 1024; ++i) { kill(0, SIGRTMIN); usleep(10); } _exit(99); } // We test both with and without attributes, because they used to be // different codepaths. We also test with an empty `sigdefault` set. posix_spawnattr_t attr1; posix_spawnattr_init(&attr1); sigset_t empty_mask = {}; posix_spawnattr_t attr2; posix_spawnattr_init(&attr2); posix_spawnattr_setflags(&attr2, POSIX_SPAWN_SETSIGDEF); posix_spawnattr_setsigdefault(&attr2, &empty_mask); posix_spawnattr_t* attrs[] = { nullptr, &attr1, &attr2 }; // We use a real-time signal because that's a tricky case for LP32 // because our sigset_t was too small. ScopedSignalHandler ssh(SIGRTMIN, [](int) { ASSERT_EQ(getpid(), parent); }); const size_t pid_count = 128; pid_t spawned_pids[pid_count]; ExecTestHelper eth; eth.SetArgs({"true", nullptr}); for (size_t i = 0; i < pid_count; ++i) { pid_t spawned_pid; ASSERT_EQ(0, posix_spawn(&spawned_pid, "true", nullptr, attrs[i % 3], eth.GetArgs(), nullptr)); spawned_pids[i] = spawned_pid; } for (pid_t spawned_pid : spawned_pids) { ASSERT_EQ(spawned_pid, TEMP_FAILURE_RETRY(waitpid(spawned_pid, nullptr, 0))); } AssertChildExited(pid, 99); }
static int Open (vlc_object_t *obj) { vlc_inhibit_t *ih = (vlc_inhibit_t *)obj; vlc_inhibit_sys_t *p_sys = malloc (sizeof (*p_sys)); if (p_sys == NULL) return VLC_ENOMEM; posix_spawnattr_init (&p_sys->attr); /* Reset signal handlers to default and clear mask in the child process */ { sigset_t set; sigemptyset (&set); posix_spawnattr_setsigmask (&p_sys->attr, &set); sigaddset (&set, SIGPIPE); posix_spawnattr_setsigdefault (&p_sys->attr, &set); posix_spawnattr_setflags (&p_sys->attr, POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); } ih->p_sys = p_sys; if (vlc_timer_create (&p_sys->timer, Timer, ih)) { posix_spawnattr_destroy (&p_sys->attr); free (p_sys); return VLC_ENOMEM; } ih->inhibit = Inhibit; return VLC_SUCCESS; }
TEST(spawn, posix_spawn_POSIX_SPAWN_SETSIGMASK) { // Block SIGBUS in the parent... sigset_t just_SIGBUS; sigemptyset(&just_SIGBUS); sigaddset(&just_SIGBUS, SIGBUS); ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGBUS, nullptr)); posix_spawnattr_t sa; ASSERT_EQ(0, posix_spawnattr_init(&sa)); // Ask for only SIGALRM to be blocked in the child... sigset_t just_SIGALRM; sigemptyset(&just_SIGALRM); sigaddset(&just_SIGALRM, SIGALRM); ASSERT_EQ(0, posix_spawnattr_setsigmask(&sa, &just_SIGALRM)); ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETSIGMASK)); // Check that's what happens... ProcStatus ps = {}; GetChildStatus(&sa, &ps); // TIMER_SIGNAL should also be blocked. uint64_t expected_blocked = 0; SignalSetAdd(&expected_blocked, SIGALRM); SignalSetAdd(&expected_blocked, __SIGRTMIN + 0); EXPECT_EQ(expected_blocked, ps.sigblk); EXPECT_EQ(static_cast<uint64_t>(0), ps.sigign); ASSERT_EQ(0, posix_spawnattr_destroy(&sa)); }
TEST(spawn, posix_spawn_POSIX_SPAWN_SETSIGDEF) { // Ignore SIGALRM and SIGCONT in the parent... ASSERT_NE(SIG_ERR, signal(SIGALRM, SIG_IGN)); ASSERT_NE(SIG_ERR, signal(SIGCONT, SIG_IGN)); posix_spawnattr_t sa; ASSERT_EQ(0, posix_spawnattr_init(&sa)); // Ask for SIGALRM to be defaulted in the child... sigset_t just_SIGALRM; sigemptyset(&just_SIGALRM); sigaddset(&just_SIGALRM, SIGALRM); ASSERT_EQ(0, posix_spawnattr_setsigdefault(&sa, &just_SIGALRM)); ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETSIGDEF)); // Check that's what happens... ProcStatus ps = {}; GetChildStatus(&sa, &ps); // TIMER_SIGNAL should be blocked. uint64_t expected_blocked = 0; SignalSetAdd(&expected_blocked, __SIGRTMIN + 0); EXPECT_EQ(expected_blocked, ps.sigblk); uint64_t expected_ignored = 0; SignalSetAdd(&expected_ignored, SIGCONT); EXPECT_EQ(expected_ignored, ps.sigign); ASSERT_EQ(0, posix_spawnattr_destroy(&sa)); }
/** * @fn : tc_libc_spawn_posix_spawnattr_SetGetschedparam * @brief : sets and gets the value of the scheduling parameters attribute * @scenario : The scheduling parameters attribute governs the parameter assigned to a new process image in a spawn operation * @API's covered : posix_spawnattr_init, posix_spawnattr_setschedparam, posix_spawnattr_getschedparam * @Preconditions : posix_spawnattr_init * @Postconditions : none * @Return : void */ static void tc_libc_spawn_posix_spawnattr_setgetschedparam(void) { int ret_chk = ERROR; pid_t pid; struct sched_param setParam; struct sched_param getParam; posix_spawnattr_t st_attr; ret_chk = posix_spawnattr_init(&st_attr); TC_ASSERT_EQ("posix_spawnattr_init", ret_chk, OK); setParam.sched_priority = HIGH_PRIORITY; ret_chk = posix_spawnattr_setschedparam(&st_attr, &setParam); TC_ASSERT_EQ("posix_spawnattr_setschedparam", ret_chk, OK); ret_chk = task_spawn(&pid, "spawn", function_name_spawn, NULL, &st_attr, (char *const *)NULL, (char *const *)NULL); sleep(SEC_4); TC_ASSERT_EQ("task_spawn", ret_chk, OK); ret_chk = posix_spawnattr_getschedparam(&st_attr, &getParam); TC_ASSERT_EQ("posix_spawnattr_getschedparam", ret_chk, OK); TC_ASSERT_EQ("posix_spawnattr_getschedparam", setParam.sched_priority, getParam.sched_priority); TC_SUCCESS_RESULT(); }
static void spawn_win32(void) { char module_name[WATCHMAN_NAME_MAX]; GetModuleFileName(NULL, module_name, sizeof(module_name)); char *argv[MAX_DAEMON_ARGS] = { module_name, "--foreground", NULL }; posix_spawn_file_actions_t actions; posix_spawnattr_t attr; pid_t pid; int i; for (i = 0; daemon_argv[i]; i++) { append_argv(argv, daemon_argv[i]); } posix_spawnattr_init(&attr); posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP); posix_spawn_file_actions_init(&actions); posix_spawn_file_actions_addopen(&actions, STDIN_FILENO, "/dev/null", O_RDONLY, 0); posix_spawn_file_actions_addopen(&actions, STDOUT_FILENO, log_name, O_WRONLY|O_CREAT|O_APPEND, 0600); posix_spawn_file_actions_adddup2(&actions, STDOUT_FILENO, STDERR_FILENO); posix_spawnp(&pid, argv[0], &actions, &attr, argv, environ); posix_spawnattr_destroy(&attr); posix_spawn_file_actions_destroy(&actions); }
static void spawn_via_gimli(void) { char *argv[MAX_DAEMON_ARGS] = { GIMLI_MONITOR_PATH, #ifdef WATCHMAN_STATE_DIR "--trace-dir=" WATCHMAN_STATE_DIR "/traces", #endif "--pidfile", pid_file, "watchman", "--foreground", NULL }; posix_spawn_file_actions_t actions; posix_spawnattr_t attr; pid_t pid; int i; for (i = 0; daemon_argv[i]; i++) { append_argv(argv, daemon_argv[i]); } close_random_fds(); posix_spawnattr_init(&attr); posix_spawn_file_actions_init(&actions); posix_spawn_file_actions_addopen(&actions, STDOUT_FILENO, log_name, O_WRONLY|O_CREAT|O_APPEND, 0600); posix_spawn_file_actions_adddup2(&actions, STDOUT_FILENO, STDERR_FILENO); posix_spawnp(&pid, argv[0], &actions, &attr, argv, environ); posix_spawnattr_destroy(&attr); posix_spawn_file_actions_destroy(&actions); }
void target_proc(struct execute_context *ctx) { int ret; char **args = ctx->passing_args; short ps_flags = 0; pid_t pid; posix_spawn_file_actions_t actions; posix_spawnattr_t attrs; if (args == NULL) { return; } RESET_ERROR; posix_spawn_file_actions_init(&actions); posix_spawnattr_init(&attrs); #ifndef _POSIX_SPAWN_DISABLE_ASLR # define _POSIX_SPAWN_DISABLE_ASLR 0x0100 #endif ps_flags |= POSIX_SPAWN_SETEXEC; ps_flags |= _POSIX_SPAWN_DISABLE_ASLR; ret = posix_spawnattr_setflags(&attrs, ps_flags); if (ret != 0) { fprintf(stderr, "cannot set posix_spawn flags\n"); return; } /* attached */ ret = ptrace(PT_TRACE_ME, 0, 0, 0); posix_spawn(&pid, args[0], &actions, &attrs, args, NULL); fprintf(stderr, "Failed\n"); exit(1); }
pid_t rb_spawn_process(const char *path, const char **argv) { pid_t pid; const void *arghack = argv; char **myenviron; int error; 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 error = posix_spawn(&pid, path, NULL, &spattr, arghack, myenviron); posix_spawnattr_destroy(&spattr); if (error != 0) { errno = error; pid = -1; } return pid; }
int main(int argc, char **argv) { extern char **environ; pid_t pid; posix_spawnattr_t attr; int res, status = 1; char *default_argv[] = {"/bin/sh", NULL}; if (argc >= 2) ++ argv; else argv = default_argv; res = posix_spawnattr_init(&attr); if (res != 0) return res; res = posix_spawnattr_setflags(&attr, _POSIX_SPAWN_DISABLE_ASLR); if (res != 0) return res; res = posix_spawn(&pid, argv[0], NULL, &attr, argv, environ); if (res != 0) return res; if (waitpid(pid, &status, 0) == -1) return 1; if (!WIFEXITED(status)) return 1; return WEXITSTATUS(status); }
/* * Static function implementations */ pid_t Launch_posixSpawnSuspended(cpu_type_t cpuType, const char *path, char** argv) { pid_t retVal = -1; if (path == NULL || argv == NULL) { Log_invalidArgument("path: %p, argv: %p", path, argv); } else { posix_spawnattr_t attr = 0; int ret = posix_spawnattr_init(&attr); if (ret != 0) { Log_errorPosix(ret, "posix_spawnattr_init"); } else { sigset_t no_signals = 0; sigset_t all_signals = 0; sigemptyset(&no_signals); sigfillset(&all_signals); posix_spawnattr_setsigmask(&attr, &no_signals); posix_spawnattr_setsigdefault(&attr, &all_signals); if (cpuType != CPU_TYPE_ANY) { size_t ocount = 0; // if specified choose the arch from the fat binary to run ret = posix_spawnattr_setbinpref_np(&attr, 1, &cpuType, &ocount); if (ret != 0) { Log_errorPosix(ret, "posix_spawnattr_setbinpref_np"); } } if (ret == 0) { ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED | _POSIX_SPAWN_DISABLE_ASLR | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); if (ret != 0) { Log_errorPosix(ret, "posix_spawnattr_setflags"); } else { pid_t pid = -1; ret = posix_spawnp(&pid, path, NULL, &attr, (char * const*)argv, (char * const*)NULL); if (ret != 0) { Log_errorPosix(ret, "posix_spawnp"); } else { retVal = pid; } } } posix_spawnattr_destroy(&attr); } } return retVal; }
/* * Helper function for posix_spawn test * arch: target architecture to spawn for */ int do_spawn_test(int arch, int shouldfail) { int my_err, my_pid, my_status; size_t my_size; posix_spawnattr_t attr; char * args[] = {"helpers/arch", NULL}; my_err = posix_spawnattr_init(&attr); if (my_err != 0) { printf("posix_spawnattr_init failed\n"); goto done; } /* set spawn to only succeed for arch 'arch' */ my_err = posix_spawnattr_setbinpref_np(&attr, 1, &arch, &my_size); if (my_err != 0 || my_size != 1) { printf("posix_spawnattr_setbinpref_np failed\n"); goto done; } /* spawn off child process */ my_err = posix_spawn(&my_pid, args[0], NULL, &attr, args, NULL); if (shouldfail) { if( my_err == 0) { printf("posix_spawn should have failed on arch %d\n", arch); goto done; } my_err = 0; } else { /* * child should exit with return code == arch; note that the * posix_spawn error numers are *returned*, NOT set in errno!!! */ if (my_err != 0) { printf("posix_spawn failed with errno %d - %s\n", my_err, strerror(my_err)); goto done; } my_err = wait4(my_pid, &my_status, 0, NULL); if (my_err == -1) { printf("wait4 failed with errno %d - %s\n", errno, strerror(errno)); goto done; } my_err = 0; if (WEXITSTATUS(my_status) != (arch & 0xff)) { printf("child exited with status %d (expected %d)\n", (WEXITSTATUS(my_status)), (arch & 0xff)); my_err = -1; goto done; } } done: return my_err; }
static void setup_spawnattr(posix_spawnattr_t* spawnattr) { size_t ocount; size_t count; cpu_type_t cpu_types[1]; short flags = 0; #ifdef __LP64__ int ch; #endif if ((errno = posix_spawnattr_init(spawnattr)) != 0) { err(2, "posix_spawnattr_int"); /* NOTREACHTED */ } count = 1; /* Run the real python executable using the same architecture as this * executable, this allows users to control the architecture using * "arch -ppc python" */ #if defined(__ppc64__) cpu_types[0] = CPU_TYPE_POWERPC64; #elif defined(__x86_64__) cpu_types[0] = CPU_TYPE_X86_64; #elif defined(__ppc__) cpu_types[0] = CPU_TYPE_POWERPC; #elif defined(__i386__) cpu_types[0] = CPU_TYPE_X86; #else # error "Unknown CPU" #endif if (posix_spawnattr_setbinpref_np(spawnattr, count, cpu_types, &ocount) == -1) { err(1, "posix_spawnattr_setbinpref"); /* NOTREACHTED */ } if (count != ocount) { fprintf(stderr, "posix_spawnattr_setbinpref failed to copy\n"); exit(1); /* NOTREACHTED */ } /* * Set flag that causes posix_spawn to behave like execv */ flags |= POSIX_SPAWN_SETEXEC; if ((errno = posix_spawnattr_setflags(spawnattr, flags)) != 0) { err(1, "posix_spawnattr_setflags"); /* NOTREACHTED */ } }
static void do_test_setsid (bool test_setsid) { pid_t sid, child_sid; int res; /* Current session ID. */ sid = getsid(0); if (sid == (pid_t) -1) FAIL_EXIT1 ("getsid (0): %m"); posix_spawnattr_t attrp; /* posix_spawnattr_init should not fail (it basically memset the attribute). */ posix_spawnattr_init (&attrp); if (test_setsid) { res = posix_spawnattr_setflags (&attrp, POSIX_SPAWN_SETSID); if (res != 0) { errno = res; FAIL_EXIT1 ("posix_spawnattr_setflags: %m"); } } /* Program to run. */ char *args[2] = { (char *) "true", NULL }; pid_t child; res = posix_spawnp (&child, "true", NULL, &attrp, args, environ); /* posix_spawnattr_destroy is noop. */ posix_spawnattr_destroy (&attrp); if (res != 0) { errno = res; FAIL_EXIT1 ("posix_spawnp: %m"); } /* Child should have a different session ID than parent. */ child_sid = getsid (child); if (child_sid == (pid_t) -1) FAIL_EXIT1 ("getsid (%i): %m", child); if (test_setsid) { if (child_sid == sid) FAIL_EXIT1 ("child session ID matched parent one"); } else { if (child_sid != sid) FAIL_EXIT1 ("child session ID did not match parent one"); } }
static pid_t start_program(char **command, sigset_t *mask) { char **arg, *s; pid_t pid; #ifdef HAVE_POSIX_SPAWN posix_spawnattr_t attr; if (posix_spawnattr_init(&attr)) { pr_err("failed to init spawn attributes: %m"); return 0; } if (posix_spawnattr_setsigmask(&attr, mask) || posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) || posix_spawnp(&pid, command[0], NULL, &attr, command, environ)) { pr_err("failed to spawn %s: %m", command[0]); posix_spawnattr_destroy(&attr); return 0; } posix_spawnattr_destroy(&attr); #else pid = fork(); if (pid < 0) { pr_err("fork() failed: %m"); return 0; } if (!pid) { /* restore the signal mask */ if (sigprocmask(SIG_SETMASK, mask, NULL) < 0) { pr_err("sigprocmask() failed: %m"); exit(100); } execvp(command[0], (char **)command); pr_err("failed to execute %s: %m", command[0]); exit(101); } #endif for (s = xstrdup(""), arg = command; *arg; arg++) string_appendf(&s, "%s ", *arg); pr_info("process %d started: %s", pid, s); free(s); return pid; }
struct spawn_params *spawn_param_init(lua_State *L) { struct spawn_params *p = lua_newuserdata(L, sizeof *p); p->L = L; p->command = 0; p->argv = p->envp = 0; posix_spawn_file_actions_init(&p->redirect); posix_spawnattr_init(&p->attr); posix_spawnattr_setflags(&p->attr, POSIX_SPAWN_USEVFORK); return p; }
TEST(spawn, posix_spawnattr_setpgroup_posix_spawnattr_getpgroup) { posix_spawnattr_t sa; ASSERT_EQ(0, posix_spawnattr_init(&sa)); ASSERT_EQ(0, posix_spawnattr_setpgroup(&sa, 123)); pid_t g; ASSERT_EQ(0, posix_spawnattr_getpgroup(&sa, &g)); ASSERT_EQ(123, g); ASSERT_EQ(0, posix_spawnattr_destroy(&sa)); }
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; }
TEST(spawn, posix_spawn_POSIX_SPAWN_SETSID_set) { pid_t parent_sid = getsid(0); posix_spawnattr_t sa; ASSERT_EQ(0, posix_spawnattr_init(&sa)); ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETSID)); ProcStat ps = {}; GetChildStat(&sa, &ps); ASSERT_NE(parent_sid, ps.sid); ASSERT_EQ(0, posix_spawnattr_destroy(&sa)); }
/** * @fn :tc_libc_spawn_posix_spawnattr_init * @brief :Initializes the given spawn attributes object. * @scenario :Initializes the given spawn attributes object with the default value for all the attributes * @API's covered :posix_spawnattr_init * @Preconditions :none * @Postconditions :none * @Return :void */ static void tc_libc_spawn_posix_spawnattr_init(void) { int ret_chk = ERROR; posix_spawnattr_t st_attr; ret_chk = posix_spawnattr_init(&st_attr); TC_ASSERT_EQ("posix_spawnattr_init", ret_chk, OK); TC_ASSERT_EQ("posix_spawnattr_init", st_attr.flags, 0); TC_ASSERT_EQ("posix_spawnattr_init", st_attr.stacksize, CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE); TC_SUCCESS_RESULT(); }
TEST(spawn, posix_spawn_POSIX_SPAWN_SETPGROUP_clear) { pid_t parent_pgrp = getpgrp(); posix_spawnattr_t sa; ASSERT_EQ(0, posix_spawnattr_init(&sa)); ASSERT_EQ(0, posix_spawnattr_setflags(&sa, 0)); ProcStat ps = {}; GetChildStat(&sa, &ps); ASSERT_EQ(parent_pgrp, ps.pgrp); ASSERT_EQ(0, posix_spawnattr_destroy(&sa)); }
static int l_posix_spawnattr_init(lua_State *L) { int r; posix_spawnattr_t *attr = lua_newuserdata(L, sizeof(posix_spawnattr_t)); luaL_setmetatable(L, "posix_spawnattr_t"); if (0 != (r = posix_spawnattr_init(attr))) { lua_pushnil(L); lua_pushstring(L, strerror(r)); lua_pushinteger(L, r); return 3; } return 1; }
static struct task_and_pid launchTest(const char* testProgPath, bool launchOtherArch, bool launchSuspended) { posix_spawnattr_t attr = 0; if ( posix_spawnattr_init(&attr) != 0 ) { printf("[FAIL] dyld_process_info posix_spawnattr_init()\n"); exit(0); } if ( launchSuspended ) { if ( posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED) != 0 ) { printf("[FAIL] dyld_process_info POSIX_SPAWN_START_SUSPENDED\n"); exit(0); } } if ( launchOtherArch ) { size_t copied; if ( posix_spawnattr_setbinpref_np(&attr, 1, otherArch, &copied) != 0 ) { printf("[FAIL] dyld_process_info posix_spawnattr_setbinpref_np()\n"); exit(0); } } struct task_and_pid child = {0, 0}; const char* argv[] = { testProgPath, NULL }; int psResult = posix_spawn(&child.pid, testProgPath, NULL, &attr, (char**)argv, environ); if ( psResult != 0 ) { printf("[FAIL] dyld_process_info posix_spawn(%s) failed, err=%d\n", testProgPath, psResult); exit(0); } if (posix_spawnattr_destroy(&attr) != 0) { printf("[FAIL] dyld_process_info posix_spawnattr_destroy()\n"); exit(0); } if ( task_for_pid(mach_task_self(), child.pid, &child.task) != KERN_SUCCESS ) { printf("[FAIL] dyld_process_info task_for_pid()\n"); kill(child.pid, SIGKILL); exit(0); } #if __x86_64__ //printf("child pid=%d task=%d (%s, %s)\n", child.pid, child.task, launchOtherArch ? "i386" : "x86_64", launchSuspended ? "suspended" : "active"); #endif // wait until process is up and has suspended itself struct task_basic_info info; do { unsigned count = TASK_BASIC_INFO_COUNT; kern_return_t kr = task_info(child.task, TASK_BASIC_INFO, (task_info_t)&info, &count); sleep(1); } while ( info.suspend_count == 0 ); return child; }
void test_proc(pid_t bad_pid) { dispatch_source_t proc_s[PID_CNT], proc; int res; pid_t pid, monitor_pid; event_cnt = 0; // Creates a process and register multiple observers. Send a signal, // exit the process, etc., and verify all observers were notified. posix_spawnattr_t attr; res = posix_spawnattr_init(&attr); assert(res == 0); #if HAVE_DECL_POSIX_SPAWN_START_SUSPENDED res = posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED); assert(res == 0); #endif char* args[] = { "/bin/sleep", "2", NULL }; res = posix_spawnp(&pid, args[0], NULL, &attr, args, NULL); if (res < 0) { perror(args[0]); exit(127); } res = posix_spawnattr_destroy(&attr); assert(res == 0); dispatch_group_t group = dispatch_group_create(); assert(pid > 0); monitor_pid = bad_pid ? bad_pid : pid; // rdar://problem/8090801 int i; for (i = 0; i < PID_CNT; ++i) { dispatch_group_enter(group); proc = proc_s[i] = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, monitor_pid, DISPATCH_PROC_EXIT, dispatch_get_global_queue(0, 0)); test_ptr_notnull("dispatch_source_proc_create", proc); dispatch_source_set_event_handler(proc, ^{ long flags = dispatch_source_get_data(proc); test_long("DISPATCH_PROC_EXIT", flags, DISPATCH_PROC_EXIT); event_cnt++; dispatch_source_cancel(proc); }); dispatch_source_set_cancel_handler(proc, ^{ dispatch_group_leave(group); });
// Spawn watchman via a site-specific spawn helper program. // We'll pass along any daemon-appropriate arguments that // we noticed during argument parsing. static void spawn_site_specific(const char *spawner) { char *argv[MAX_DAEMON_ARGS] = { (char*)spawner, NULL }; posix_spawn_file_actions_t actions; posix_spawnattr_t attr; pid_t pid; int i; int res, err; for (i = 0; daemon_argv[i]; i++) { append_argv(argv, daemon_argv[i]); } close_random_fds(); posix_spawnattr_init(&attr); posix_spawn_file_actions_init(&actions); posix_spawn_file_actions_addopen(&actions, STDOUT_FILENO, log_name, O_WRONLY|O_CREAT|O_APPEND, 0600); posix_spawn_file_actions_adddup2(&actions, STDOUT_FILENO, STDERR_FILENO); res = posix_spawnp(&pid, argv[0], &actions, &attr, argv, environ); err = errno; posix_spawnattr_destroy(&attr); posix_spawn_file_actions_destroy(&actions); if (res) { w_log(W_LOG_FATAL, "Failed to spawn watchman via `%s': %s\n", spawner, strerror(err)); } if (waitpid(pid, &res, 0) == -1) { w_log(W_LOG_FATAL, "Failed waiting for %s: %s\n", spawner, strerror(errno)); } if (WIFEXITED(res) && WEXITSTATUS(res) == 0) { return; } if (WIFEXITED(res)) { w_log(W_LOG_FATAL, "%s: exited with status %d\n", spawner, WEXITSTATUS(res)); } else if (WIFSIGNALED(res)) { w_log(W_LOG_FATAL, "%s: signaled with %d\n", spawner, WTERMSIG(res)); } w_log(W_LOG_ERR, "%s: failed to start, exit status %d\n", spawner, res); }
pid_t child_spawn1_internal (char const *prog, char const *const *argv, char const *const *envp, int *p, int to) { posix_spawn_file_actions_t actions ; posix_spawnattr_t attr ; int e ; pid_t pid ; int haspath = !!env_get("PATH") ; if (coe(p[!(to & 1)]) < 0) { e = errno ; goto err ; } e = posix_spawnattr_init(&attr) ; if (e) goto err ; { sigset_t set ; sigemptyset(&set) ; e = posix_spawnattr_setsigmask(&attr, &set) ; if (e) goto errattr ; e = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK) ; if (e) goto errattr ; } e = posix_spawn_file_actions_init(&actions) ; if (e) goto errattr ; e = posix_spawn_file_actions_adddup2(&actions, p[to & 1], to & 1) ; if (e) goto erractions ; e = posix_spawn_file_actions_addclose(&actions, p[to & 1]) ; if (e) goto erractions ; if (to & 2) { e = posix_spawn_file_actions_adddup2(&actions, to & 1, !(to & 1)) ; if (e) goto erractions ; } if (!haspath && (setenv("PATH", SKALIBS_DEFAULTPATH, 0) < 0)) { e = errno ; goto erractions ; } e = posix_spawnp(&pid, prog, &actions, &attr, (char *const *)argv, (char *const *)envp) ; if (!haspath) unsetenv("PATH") ; posix_spawn_file_actions_destroy(&actions) ; posix_spawnattr_destroy(&attr) ; fd_close(p[to & 1]) ; if (e) goto errp ; return pid ; erractions: posix_spawn_file_actions_destroy(&actions) ; errattr: posix_spawnattr_destroy(&attr) ; err: fd_close(p[to & 1]) ; errp: fd_close(p[!(to & 1)]) ; errno = e ; return 0 ; }
TEST(spawn, posix_spawn_POSIX_SPAWN_SETPGROUP_set) { pid_t parent_pgrp = getpgrp(); posix_spawnattr_t sa; ASSERT_EQ(0, posix_spawnattr_init(&sa)); ASSERT_EQ(0, posix_spawnattr_setpgroup(&sa, 0)); ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_SETPGROUP)); ProcStat ps = {}; GetChildStat(&sa, &ps); ASSERT_NE(parent_pgrp, ps.pgrp); // Setting pgid 0 means "the same as the caller's pid". ASSERT_EQ(ps.pid, ps.pgrp); ASSERT_EQ(0, posix_spawnattr_destroy(&sa)); }
int main() { int ret_err = 0; pid_t pid_child; char buf_err[64]; char *argv_child[] = { "forkexec_child", NULL }; printf("Parent[%d]: Start\n", getpid()); posix_spawnattr_t posix_attr; if ((ret_err = posix_spawnattr_init(&posix_attr)) != 0) { strerror_r(ret_err, buf_err, sizeof(buf_err)); fprintf(stderr, "Fail: attr_init: %s\n", buf_err); exit(EXIT_FAILURE); } short posix_flags = POSIX_SPAWN_SETPGROUP; if ((ret_err = posix_spawnattr_setflags(&posix_attr, posix_flags)) != 0) { strerror_r(ret_err, buf_err, sizeof(buf_err)); fprintf(stderr, "Fail: attr_setflags: %s\n", buf_err); exit(EXIT_FAILURE); } // set pgid pid_t pid_pgid = 0; /* child process shall become process group reader */ if ((ret_err = posix_spawnattr_setpgroup(&posix_attr, pid_pgid)) != 0) { strerror_r(ret_err, buf_err, sizeof(buf_err)); fprintf(stderr, "Fail: attr_setpgroup: %s\n", buf_err); exit(EXIT_FAILURE); } ret_err = posix_spawn( &pid_child, argv_child[0], NULL, &posix_attr, /* attribute */ argv_child, NULL); if ((ret_err = posix_spawnattr_destroy(&posix_attr)) != 0) { strerror_r(ret_err, buf_err, sizeof(buf_err)); fprintf(stderr, "Fail: attr_destroy: %s\n", buf_err); exit(EXIT_FAILURE); } printf("Parent[%d]: Wait for child(%d)\n", getpid(), (int)pid_child); (void)wait(NULL); /* wait for child */ printf("Parent[%d]: Exit\n", getpid()); return 0; }
int main(int argc, char *argv[]) { dispatch_source_t tmp_ds; int res; pid_t pid; if (argc < 2) { fprintf(stderr, "usage: harness [...]\n"); exit(1); } posix_spawnattr_t attr; res = posix_spawnattr_init(&attr); assert(res == 0); res = posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED); assert(res == 0); int i; char** newargv = calloc(argc, sizeof(void*)); for (i = 1; i < argc; ++i) { newargv[i-1] = argv[i]; } newargv[i-1] = NULL; res = posix_spawnp(&pid, newargv[0], NULL, &attr, newargv, environ); if (res) { errno = res; perror(newargv[0]); exit(EXIT_FAILURE); } //fprintf(stderr, "pid = %d\n", pid); assert(pid > 0); dispatch_queue_t main_q = dispatch_get_main_queue(); tmp_ds = dispatch_source_proc_create(pid, DISPATCH_PROC_EXIT, NULL, main_q, ^(dispatch_event_t ev __attribute__((unused))) { int status; int res2 = waitpid(pid, &status, 0); assert(res2 != -1); //int passed = (WIFEXITED(status) && WEXITSTATUS(status) == 0); test_long("Process exited", WEXITSTATUS(status) | WTERMSIG(status), 0); exit(0); });