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)); }
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; }
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 ; }
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)); }
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); }
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); }
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 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 Close (vlc_object_t *obj) { vlc_inhibit_t *ih = (vlc_inhibit_t *)obj; vlc_inhibit_sys_t *p_sys = ih->p_sys; vlc_timer_destroy (p_sys->timer); posix_spawnattr_destroy (&p_sys->attr); free (p_sys); }
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"); } }
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)); }
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; }
static int l_posix_spawnattr_destroy(lua_State *L) { int r; posix_spawnattr_t *attr = luaL_checkudata(L, 1, "posix_spawnattr_t"); if (0 != (r = posix_spawnattr_destroy(attr))) { lua_pushnil(L); lua_pushstring(L, strerror(r)); lua_pushinteger(L, r); return 3; } lua_pushboolean(L, 1); return 1; }
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)); }
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)); }
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 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; }
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; }
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)); }
TEST(spawn, posix_spawnattr_setsigmask_posix_spawnattr_getsigmask) { posix_spawnattr_t sa; ASSERT_EQ(0, posix_spawnattr_init(&sa)); sigset_t sigs; ASSERT_EQ(0, posix_spawnattr_getsigmask(&sa, &sigs)); ASSERT_FALSE(sigismember(&sigs, SIGALRM)); 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_getsigmask(&sa, &sigs)); ASSERT_TRUE(sigismember(&sigs, SIGALRM)); ASSERT_EQ(0, posix_spawnattr_destroy(&sa)); }
TEST(spawn, posix_spawnattr_setsigmask64_posix_spawnattr_getsigmask64) { posix_spawnattr_t sa; ASSERT_EQ(0, posix_spawnattr_init(&sa)); sigset64_t sigs; ASSERT_EQ(0, posix_spawnattr_getsigmask64(&sa, &sigs)); ASSERT_FALSE(sigismember64(&sigs, SIGRTMIN)); sigset64_t just_SIGRTMIN; sigemptyset64(&just_SIGRTMIN); sigaddset64(&just_SIGRTMIN, SIGRTMIN); ASSERT_EQ(0, posix_spawnattr_setsigmask64(&sa, &just_SIGRTMIN)); ASSERT_EQ(0, posix_spawnattr_getsigmask64(&sa, &sigs)); ASSERT_TRUE(sigismember64(&sigs, SIGRTMIN)); 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; }
int spawn_param_execute(struct spawn_params *p) { lua_State *L = p->L; int ret; struct process *proc; if (!p->argv) { p->argv = lua_newuserdata(L, 2 * sizeof *p->argv); p->argv[0] = p->command; p->argv[1] = 0; } if (!p->envp) p->envp = (const char **)environ; proc = lua_newuserdata(L, sizeof *proc); luaL_getmetatable(L, PROCESS_HANDLE); lua_setmetatable(L, -2); proc->status = -1; errno = 0; ret = posix_spawnp(&proc->pid, p->command, &p->redirect, &p->attr, (char *const *)p->argv, (char *const *)p->envp); posix_spawn_file_actions_destroy(&p->redirect); posix_spawnattr_destroy(&p->attr); return ret != 0 || errno != 0 ? push_error(L) : 1; }
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; } } }
static int dropbox_update(void *data) { struct dropbox_section *section = data; char *argv[] = {"dropbox.py", "status", NULL}; posix_spawn_file_actions_t file_actions; posix_spawnattr_t attr; int status = -1; sigset_t mask; int pipefd[2] = {-1, -1}; pid_t pid; int ret; section->running = false; errno = posix_spawn_file_actions_init(&file_actions); if (errno) { perror("posix_spawn_file_actions_init"); return -1; } errno = posix_spawnattr_init(&attr); if (errno) { perror("posix_spawnattr_init"); goto out_file_actions; } ret = pipe(pipefd); if (ret) { perror("pipe2"); goto out_spawnattr; } errno = posix_spawn_file_actions_addclose(&file_actions, pipefd[0]); if (errno) { perror("posix_spawn_file_actions_addclose"); goto out; } errno = posix_spawn_file_actions_adddup2(&file_actions, pipefd[1], STDOUT_FILENO); if (errno) { perror("posix_spawn_file_actions_adddup2"); goto out; } sigemptyset(&mask); errno = posix_spawnattr_setsigmask(&attr, &mask); if (errno) { perror("posix_spawnattr_setsigmask"); goto out; } errno = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK); if (errno) { perror("posix_spawnattr_setflags"); goto out; } errno = posix_spawnp(&pid, "dropbox-cli", &file_actions, &attr, argv, environ); if (errno) { perror("posix_spawnp"); status = 0; goto out; } close(pipefd[1]); ret = read_all_output(section, pid, pipefd[0]); if (ret) { if (errno == ENOMEM) status = -1; else status = 0; goto out; } if (strcmp(section->status.buf, "Dropbox isn't running!\n") != 0) section->running = true; if (strcmp(section->status.buf, "Up to date\n") == 0 || strcmp(section->status.buf, "Idle\n") == 0) section->uptodate = true; else section->uptodate = false; status = 0; out: close(pipefd[0]); close(pipefd[1]); out_spawnattr: posix_spawnattr_destroy(&attr); out_file_actions: posix_spawn_file_actions_destroy(&file_actions); return status; }
int main () { char *argv[3] = { "/bin/sh", CHILD_PROGRAM_FILENAME, NULL }; int ofd[2]; sigset_t blocked_signals; sigset_t fatal_signal_set; posix_spawn_file_actions_t actions; bool actions_allocated; posix_spawnattr_t attrs; bool attrs_allocated; int err; pid_t child; int fd; FILE *fp; int written; int status; int exitstatus; if (pipe (ofd) < 0 || (ofd[1] = fd_safer (ofd[1])) < 0) { perror ("cannot create pipe"); exit (1); } sigprocmask (SIG_SETMASK, NULL, &blocked_signals); sigemptyset (&fatal_signal_set); sigaddset (&fatal_signal_set, SIGINT); sigaddset (&fatal_signal_set, SIGTERM); sigaddset (&fatal_signal_set, SIGHUP); sigaddset (&fatal_signal_set, SIGPIPE); sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL); actions_allocated = false; attrs_allocated = false; if ((err = posix_spawn_file_actions_init (&actions)) != 0 || (actions_allocated = true, (err = posix_spawn_file_actions_adddup2 (&actions, ofd[0], STDIN_FILENO)) != 0 || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0 || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0 || (err = posix_spawnattr_init (&attrs)) != 0 || (attrs_allocated = true, (err = posix_spawnattr_setsigmask (&attrs, &blocked_signals)) != 0 || (err = posix_spawnattr_setflags (&attrs, POSIX_SPAWN_SETSIGMASK)) != 0) || (err = posix_spawnp (&child, "/bin/sh", &actions, &attrs, argv, environ)) != 0)) { if (actions_allocated) posix_spawn_file_actions_destroy (&actions); if (attrs_allocated) posix_spawnattr_destroy (&attrs); sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL); errno = err; perror ("subprocess failed"); exit (1); } posix_spawn_file_actions_destroy (&actions); posix_spawnattr_destroy (&attrs); sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL); close (ofd[0]); fd = ofd[1]; fp = fdopen (fd, "w"); if (fp == NULL) { fprintf (stderr, "fdopen() failed\n"); exit (1); } written = fwrite ("Halle Potta\n", 1, 12, fp); if (written < 12) { fprintf (stderr, "could not write input\n"); exit (1); } fclose (fp); status = 0; while (waitpid (child, &status, 0) != child) ; if (!WIFEXITED (status)) { fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status); exit (1); } exitstatus = WEXITSTATUS (status); if (exitstatus != 0) { fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus); exit (1); } return 0; }