static int parasite_init_daemon(struct parasite_ctl *ctl) { struct parasite_init_args *args; pid_t pid = ctl->rpid; user_regs_struct_t regs; struct ctl_msg m = { }; *ctl->addr_cmd = PARASITE_CMD_INIT_DAEMON; args = compel_parasite_args(ctl, struct parasite_init_args); args->sigframe = (uintptr_t)ctl->rsigframe; args->log_level = compel_log_get_loglevel(); futex_set(&args->daemon_connected, 0); if (prepare_tsock(ctl, pid, args)) goto err; /* after this we can catch parasite errors in chld handler */ if (setup_child_handler(ctl)) goto err; regs = ctl->orig.regs; if (parasite_run(pid, PTRACE_CONT, ctl->parasite_ip, ctl->rstack, ®s, &ctl->orig)) goto err; futex_wait_while_eq(&args->daemon_connected, 0); if (futex_get(&args->daemon_connected) != 1) { errno = -(int)futex_get(&args->daemon_connected); pr_perror("Unable to connect a transport socket"); goto err; } if (accept_tsock(ctl) < 0) goto err; if (compel_util_send_fd(ctl, ctl->ictx.log_fd)) goto err; pr_info("Wait for parasite being daemonized...\n"); if (parasite_wait_ack(ctl->tsock, PARASITE_CMD_INIT_DAEMON, &m)) { pr_err("Can't switch parasite %d to daemon mode %d\n", pid, m.err); goto err; } ctl->sigreturn_addr = (void*)(uintptr_t)args->sigreturn_addr; ctl->daemonized = true; pr_info("Parasite %d has been switched to daemon mode\n", pid); return 0; err: return -1; }
static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) { char *r; if (futex_get(&task_entries->start) == CR_STATE_RESTORE_SIGCHLD) { pr_debug("%ld: Collect a zombie with (pid %d, %d)\n", sys_getpid(), siginfo->si_pid, siginfo->si_pid); futex_dec_and_wake(&task_entries->nr_in_progress); futex_dec_and_wake(&zombies_inprogress); task_entries->nr_threads--; task_entries->nr_tasks--; mutex_unlock(&task_entries->zombie_lock); return; } if (siginfo->si_code & CLD_EXITED) r = " exited, status="; else if (siginfo->si_code & CLD_KILLED) r = " killed by signal "; else r = "disappeared with "; pr_info("Task %d %s %d\n", siginfo->si_pid, r, siginfo->si_status); futex_abort_and_wake(&task_entries->nr_in_progress); /* sa_restorer may be unmaped, so we can't go back to userspace*/ sys_kill(sys_getpid(), SIGSTOP); sys_exit_group(1); }
inline bool Lock(uint64 timeout = 0) { if(0 == timeout) { futex_get(&m_lock); return true; } else { struct timespec next; int2timespec(timeout, MILLIS, & next); return 0 == futex_get_timeout(&m_lock, &next); } }
static void ns_sig_hand(int signo) { int status, len = 0; pid_t pid; char buf[128] = ""; if (signo == SIGTERM) { futex_set_and_wake(&sig_received, signo); len = snprintf(buf, sizeof(buf), "Time to stop and check\n"); goto write_out; } while (1) { pid = waitpid(-1, &status, WNOHANG); if (pid == 0) return; if (pid == -1) { if (errno == ECHILD) { if (futex_get(&sig_received)) return; futex_set_and_wake(&sig_received, signo); len = snprintf(buf, sizeof(buf), "All test processes exited\n"); } else { len = snprintf(buf, sizeof(buf), "wait() failed: %m\n"); } goto write_out; } if (status) fprintf(stderr, "%d return %d\n", pid, status); } return; write_out: /* fprintf can't be used in a sighandler due to glibc locks */ write(STDERR_FILENO, buf, MIN(len, sizeof(buf))); }
void test_init(int argc, char **argv) { pid_t pid; static FILE *pidf; char *val; struct sigaction sa = { .sa_handler = sig_hand, .sa_flags = SA_RESTART, }; sigemptyset(&sa.sa_mask); parseargs(argc, argv); val = getenv("ZDTM_NEWNS"); if (val) { unsetenv("ZDTM_NEWNS"); ns_create(argc, argv); exit(1); } val = getenv("ZDTM_EXE"); if (val) { test_log_init(outfile, "ns"); redir_stdfds(); unsetenv("ZDTM_EXE"); ns_init(argc, argv); exit(1); } val = getenv("ZDTM_GID"); if (val && (setgid(atoi(val)) == -1)) { fprintf(stderr, "Can't set gid: %m"); exit(1); } val = getenv("ZDTM_UID"); if (val && (setuid(atoi(val)) == -1)) { fprintf(stderr, "Can't set gid: %m"); exit(1); } if (sigaction(SIGTERM, &sa, NULL)) { fprintf(stderr, "Can't set SIGTERM handler: %m\n"); exit(1); } if (sigaction(SIGCHLD, &sa, NULL)) { fprintf(stderr, "Can't set SIGCHLD handler: %m\n"); exit(1); } setup_outfile(); redir_stdfds(); pidf = fopen(pidfile, "wx"); if (!pidf) { err("Can't create pid file %s: %m\n", pidfile); exit(1); } pid = fork(); if (pid < 0) { err("Daemonizing failed: %m\n"); exit(1); } if (pid) { /* parent will exit when the child is ready */ test_waitsig(); if (futex_get(&sig_received) == SIGCHLD) { int ret; waitpid(pid, &ret, 0); if (WIFEXITED(ret)) { err("Test exited with unexpectedly with code %d\n", WEXITSTATUS(ret)); exit(0); } if (WIFSIGNALED(ret)) { err("Test exited on unexpected signal %d\n", WTERMSIG(ret)); exit(0); } } fprintf(pidf, "%d\n", pid); fclose(pidf); _exit(0); } /* record the test pid to remember the ownership of the pidfile */ master_pid = getpid(); fclose(pidf); sa.sa_handler = SIG_DFL; if (sigaction(SIGCHLD, &sa, NULL)) { err("Can't reset SIGCHLD handler: %m\n"); exit(1); } if (setsid() < 0) { err("Can't become session group leader: %m\n"); exit(1); } srand48(time(NULL)); /* just in case we need it */ }
int test_go(void) { return !futex_get(&sig_received); }
void test_init(int argc, char **argv) { pid_t pid; char *val; struct sigaction sa = { .sa_handler = sig_hand, .sa_flags = SA_RESTART, }; sigemptyset(&sa.sa_mask); parseargs(argc, argv); val = getenv("ZDTM_NEWNS"); if (val) { if (!strcmp(val, "1")) { ns_create(argc, argv); exit(1); } if (!strcmp(val, "2")) { test_log_init(outfile, "ns"); redir_stdfds(); ns_init(argc, argv); } } val = getenv("ZDTM_GROUPS"); if (val) { char *tok = NULL; unsigned int size = 0, groups[NGROUPS_MAX]; tok = strtok(val, " "); while (tok) { size++; groups[size - 1] = atoi(tok); tok = strtok(NULL, " "); } if (setgroups(size, groups)) { fprintf(stderr, "Can't set groups: %m"); exit(1); } } val = getenv("ZDTM_GID"); if (val && (setgid(atoi(val)) == -1)) { fprintf(stderr, "Can't set gid: %m"); exit(1); } val = getenv("ZDTM_UID"); if (val && (setuid(atoi(val)) == -1)) { fprintf(stderr, "Can't set gid: %m"); exit(1); } if (prctl(PR_SET_DUMPABLE, 1)) { fprintf(stderr, "Can't set the dumpable flag"); exit(1); } if (sigaction(SIGTERM, &sa, NULL)) { fprintf(stderr, "Can't set SIGTERM handler: %m\n"); exit(1); } if (sigaction(SIGCHLD, &sa, NULL)) { fprintf(stderr, "Can't set SIGCHLD handler: %m\n"); exit(1); } setup_outfile(); redir_stdfds(); pid = fork(); if (pid < 0) { pr_perror("Daemonizing failed"); exit(1); } if (pid) { /* parent will exit when the child is ready */ test_waitsig(); if (futex_get(&sig_received) == SIGCHLD) { int ret; if (waitpid(pid, &ret, 0) != pid) { pr_perror("Unable to wait %d, pid"); exit(1); } if (WIFEXITED(ret)) { pr_err("Test exited unexpectedly with code %d\n", WEXITSTATUS(ret)); exit(1); } if (WIFSIGNALED(ret)) { pr_err("Test exited on unexpected signal %d\n", WTERMSIG(ret)); exit(1); } } if (write_pidfile(pid)) exit(1); _exit(0); } if (setsid() < 0) { pr_perror("Can't become session group leader"); exit(1); } /* record the test pid to remember the ownership of the pidfile */ master_pid = getpid(); sa.sa_handler = SIG_DFL; if (sigaction(SIGCHLD, &sa, NULL)) { pr_perror("Can't reset SIGCHLD handler"); exit(1); } srand48(time(NULL)); /* just in case we need it */ }