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)); }
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); }
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); }
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)); }
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; }
static int l_posix_spawnattr_setflags(lua_State *L) { int r; posix_spawnattr_t *attr = luaL_checkudata(L, 1, "posix_spawnattr_t"); short int flags = 0; luaL_checktype(L, 2, LUA_TTABLE); lua_getfield(L, 2, "resetids"); if (lua_toboolean(L, -1)) flags |= POSIX_SPAWN_RESETIDS; lua_getfield(L, 2, "setpgroup"); if (lua_toboolean(L, -1)) flags |= POSIX_SPAWN_SETPGROUP; lua_getfield(L, 2, "setsigdef"); if (lua_toboolean(L, -1)) flags |= POSIX_SPAWN_SETSIGDEF; lua_getfield(L, 2, "setsigmask"); if (lua_toboolean(L, -1)) flags |= POSIX_SPAWN_SETSIGMASK; lua_getfield(L, 2, "setschedparam"); if (lua_toboolean(L, -1)) flags |= POSIX_SPAWN_SETSCHEDPARAM; lua_getfield(L, 2, "setscheduler"); if (lua_toboolean(L, -1)) flags |= POSIX_SPAWN_SETSCHEDULER; lua_pop(L, 6); #ifdef POSIX_SPAWN_USEVFORK lua_getfield(L, 2, "usevfork"); if (lua_toboolean(L, -1)) flags |= POSIX_SPAWN_USEVFORK; lua_pop(L, 1); #endif if (0 != (r = posix_spawnattr_setflags(attr, flags))) { lua_pushnil(L); lua_pushstring(L, strerror(r)); lua_pushinteger(L, r); return 3; } lua_pushboolean(L, 1); return 1; }
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; }
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; }
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 */ } }
TEST(spawn, posix_spawnattr_setflags_posix_spawnattr_getflags) { posix_spawnattr_t sa; ASSERT_EQ(0, posix_spawnattr_init(&sa)); ASSERT_EQ(0, posix_spawnattr_setflags(&sa, POSIX_SPAWN_RESETIDS)); short flags; ASSERT_EQ(0, posix_spawnattr_getflags(&sa, &flags)); ASSERT_EQ(POSIX_SPAWN_RESETIDS, flags); constexpr short all_flags = POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER | POSIX_SPAWN_USEVFORK | POSIX_SPAWN_SETSID; ASSERT_EQ(0, posix_spawnattr_setflags(&sa, all_flags)); ASSERT_EQ(0, posix_spawnattr_getflags(&sa, &flags)); ASSERT_EQ(all_flags, flags); ASSERT_EQ(0, posix_spawnattr_destroy(&sa)); }
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"); } }
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; }
int main (void) { pid_t pid ; posix_spawn_file_actions_t actions ; posix_spawnattr_t attr ; char *const argv[2] = { "/bin/true", 0 } ; char *const envp[1] = { 0 } ; posix_spawnattr_setflags(&attr, 0) ; posix_spawn_file_actions_init(&actions) ; return posix_spawn(&pid, argv[0], 0, 0, argv, envp) ; }
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; }
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 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; }
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)); }
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); }
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); });
void ChildProcess::Options::setFlags(short flags) { short currentFlags; auto err = posix_spawnattr_getflags(&inner_->attr, ¤tFlags); if (err) { throw std::system_error( err, std::generic_category(), "posix_spawnattr_getflags"); } err = posix_spawnattr_setflags(&inner_->attr, currentFlags | flags); if (err) { throw std::system_error( err, std::generic_category(), "posix_spawnattr_setflags"); } }
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); });
static int l_posix_spawnattr_setflags(lua_State *L) { int r; size_t i; posix_spawnattr_t *attr = luaL_checkudata(L, 1, "posix_spawnattr_t"); short int flags = 0; luaL_checktype(L, 2, LUA_TTABLE); for (i=0; i<N_SUPPORTED_FLAGS; i++) { lua_getfield(L, 2, supported_flags[i].flagname); if (lua_toboolean(L, -1)) flags |= supported_flags[i].value; lua_pop(L, 1); } if (0 != (r = posix_spawnattr_setflags(attr, flags))) { lua_pushnil(L); lua_pushstring(L, strerror(r)); lua_pushinteger(L, r); return 3; } lua_pushboolean(L, 1); return 1; }
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; }
static void tc_libc_spawn_posix_spawnattr_setgetflags(void) { int ret_chk = ERROR; pid_t pid; posix_spawnattr_t st_attr; short int flags; ret_chk = posix_spawnattr_init(&st_attr); TC_ASSERT_EQ("posix_spawnattr_init", ret_chk, OK); ret_chk = posix_spawnattr_setflags(&st_attr, POSIX_SPAWN_SETSCHEDPARAM); TC_ASSERT_EQ("posix_spawnattr_setflags", ret_chk, OK); ret_chk = task_spawn(&pid, "spawn_flag", function_name_spawn, NULL, &st_attr, (char *const *)NULL, (char *const *)NULL); sleep(SEC_3); TC_ASSERT_EQ("task_spawn", ret_chk, OK); ret_chk = posix_spawnattr_getflags(&st_attr, &flags); TC_ASSERT_EQ("posix_spawnattr_getflags", ret_chk, OK); TC_ASSERT_EQ("posix_spawnattr_getflags", flags, POSIX_SPAWN_SETSCHEDPARAM); TC_SUCCESS_RESULT(); }
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; }
bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_file_actions_t *actions, job_t *j, process_t *p, const io_chain_t &io_chain) { /* Initialize the output */ if (posix_spawnattr_init(attr) != 0) { return false; } if (posix_spawn_file_actions_init(actions) != 0) { posix_spawnattr_destroy(attr); return false; } bool should_set_parent_group_id = false; int desired_parent_group_id = 0; if (job_get_flag(j, JOB_CONTROL)) { should_set_parent_group_id = true; // PCA: I'm quite fuzzy on process groups, // but I believe that the default value of 0 // means that the process becomes its own // group leader, which is what set_child_group did // in this case. So we want this to be 0 if j->pgid is 0. desired_parent_group_id = j->pgid; } /* Set the handling for job control signals back to the default. */ bool reset_signal_handlers = true; /* Remove all signal blocks */ bool reset_sigmask = true; /* Set our flags */ short flags = 0; if (reset_signal_handlers) flags |= POSIX_SPAWN_SETSIGDEF; if (reset_sigmask) flags |= POSIX_SPAWN_SETSIGMASK; if (should_set_parent_group_id) flags |= POSIX_SPAWN_SETPGROUP; int err = 0; if (! err) err = posix_spawnattr_setflags(attr, flags); if (! err && should_set_parent_group_id) err = posix_spawnattr_setpgroup(attr, desired_parent_group_id); /* Everybody gets default handlers */ if (! err && reset_signal_handlers) { sigset_t sigdefault; get_signals_with_handlers(&sigdefault); err = posix_spawnattr_setsigdefault(attr, &sigdefault); } /* No signals blocked */ sigset_t sigmask; sigemptyset(&sigmask); if (! err && reset_sigmask) err = posix_spawnattr_setsigmask(attr, &sigmask); for (size_t idx = 0; idx < io_chain.size(); idx++) { const shared_ptr<const io_data_t> io = io_chain.at(idx); if (io->io_mode == IO_FD) { CAST_INIT(const io_fd_t *, io_fd, io.get()); if (io->fd == io_fd->old_fd) continue; } switch (io->io_mode) { case IO_CLOSE: { if (! err) err = posix_spawn_file_actions_addclose(actions, io->fd); break; } case IO_FILE: { CAST_INIT(const io_file_t *, io_file, io.get()); if (! err) err = posix_spawn_file_actions_addopen(actions, io->fd, io_file->filename_cstr, io_file->flags /* mode */, OPEN_MASK); break; } case IO_FD: { CAST_INIT(const io_fd_t *, io_fd, io.get()); if (! err) err = posix_spawn_file_actions_adddup2(actions, io_fd->old_fd /* from */, io->fd /* to */); break; } case IO_BUFFER: case IO_PIPE: { CAST_INIT(const io_pipe_t *, io_pipe, io.get()); unsigned int write_pipe_idx = (io_pipe->is_input ? 0 : 1); int from_fd = io_pipe->pipe_fd[write_pipe_idx]; int to_fd = io->fd; if (! err) err = posix_spawn_file_actions_adddup2(actions, from_fd, to_fd); if (write_pipe_idx > 0) { if (! err) err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[0]); if (! err) err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[1]); } else { if (! err) err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[0]); } break; } } }