/* make sure we can vfork/exec across setjmp/longjmp's * and make sure signal block masks don't get corrupted * in the process. */ #include #include #include #include #include #include #include #include #include #include int verbose = 0; static int execute_child(const char *prog) { int status; pid_t child; child = vfork(); if (child == 0) { execlp(prog, prog, NULL); perror("Could not execute specified prog"); _exit(1); } else if (child == 1) return 1; wait(&status); return WEXITSTATUS(status); } sigset_t orig_mask; static int check_sig_mask(void) { int status; pid_t child; child = vfork(); if (child == 0) { int ret; sigset_t child_mask; memset(&child_mask, 0x00, sizeof(child_mask)); ret = sigprocmask(SIG_BLOCK, NULL, &child_mask); if (ret != 0) { perror("could not get child sig block mask"); _exit(1); } ret = memcmp(&orig_mask, &child_mask, sizeof(orig_mask)); _exit(ret); } else if (child == 1) return 1; wait(&status); return WEXITSTATUS(status); } int main(int argc, char *argv[]) { const char *prog; jmp_buf env; sigjmp_buf sigenv; int max; /* values modified between setjmp/longjmp cannot be local to this func */ static int cnt, ret; memset(&orig_mask, 0x00, sizeof(orig_mask)); ret = sigprocmask(SIG_BLOCK, NULL, &orig_mask); if (ret != 0) { perror("could not get orig sig block mask"); return 1; } prog = (argc > 1 ? argv[1] : "true"); ret = 0; verbose = 0; max = 10; /* test vfork()/exec() inside of sigsetjmp/siglongjmp */ cnt = 0; sigsetjmp(sigenv, 1); ++cnt; if (verbose) printf("sigsetjmp loop %i\n", cnt); ret |= check_sig_mask(); ret |= execute_child(prog); if (cnt < max) siglongjmp(sigenv, 0); /* test vfork()/sigprocmask() inside of setjmp/longjmp */ cnt = 0; setjmp(env); ++cnt; if (verbose) printf("setjmp loop %i\n", cnt); ret |= check_sig_mask(); ret |= execute_child(prog); if (cnt < max) longjmp(env, 0); return ret; }