#include #include #include #include #include #include #include #include #include #include #include #include #define ATF_REQUIRE(a) assert(a) #define CHILD_REQUIRE(a) assert(a) #define FORKEE_ASSERTX(x) \ do { \ int ret = (x); \ if (!ret) \ errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \ __FILE__, __LINE__, __func__, #x); \ } while (0) #define FORKEE_ASSERT(x) \ do { \ int ret = (x); \ if (!ret) \ err(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \ __FILE__, __LINE__, __func__, #x); \ } while (0) #ifndef nitemps #define nitems(x) (sizeof((x)) / sizeof((x)[0])) #endif #if defined(linux) #define WALLSIG __WALL #define sys_signame sys_siglist #endif static void wait_for_zombie(pid_t pid) { printf("KR!!! %s(): %s:%d\n", __func__, __FILE__, __LINE__); /* * Wait for a process to exit. This is kind of gross, but * there is not a better way. */ for (;;) { printf("KR!!! %s(): %s:%d\n", __func__, __FILE__, __LINE__); #if defined(__FreeBSD__) || defined(__NetBSD__) #if defined(__NetBSD__) struct kinfo_proc2 kp; #elif defined(__FreeBSD__) struct kinfo_proc kp; #endif size_t len; int mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = pid; #if defined(__NetBSD__) mib[4] = sizeof(kp); mib[5] = 1; #endif len = sizeof(kp); if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) { /* The KERN_PROC_PID sysctl fails for zombies. */ ATF_REQUIRE(errno == ESRCH); break; } #elif defined(linux) printf("KR!!! %s(): %s:%d\n", __func__, __FILE__, __LINE__); bool iszombie = false; // open the /proc/*/stat file char pbuf[32]; snprintf(pbuf, sizeof(pbuf), "/proc/%d/stat", (int)pid); FILE* fpstat = fopen(pbuf, "r"); if (!fpstat) { break; }; { int rpid =0; char rcmd[32]; char rstatc = 0; fscanf(fpstat, "%d %30s %c", &rpid, rcmd, &rstatc); iszombie = rstatc == 'Z'; } fclose(fpstat); if (iszombie == true) break; #endif usleep(5000); } printf("KR!!! %s(): %s:%d pid=%d zombie!\n", __func__, __FILE__, __LINE__, getpid()); } int main(int argc, char **argv) { pid_t child, debugger, wpid; int cpipe[2], dpipe[2], status; char c = '0'; int tmp; printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); ATF_REQUIRE(pipe(cpipe) == 0); ATF_REQUIRE((child = fork()) != -1); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); if (child == 0) { printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); /* Child process. */ close(cpipe[1]); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); /* Wait for parent to be ready. */ FORKEE_ASSERTX(read(cpipe[0], &c, sizeof(c)) == sizeof(c)); // assert printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); _exit(1); } printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); ATF_REQUIRE(pipe(dpipe) == 0); ATF_REQUIRE((debugger = fork()) != -1); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); if (debugger == 0) { close(cpipe[0]); close(cpipe[1]); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); /* Debugger process. */ FORKEE_ASSERT(ptrace(PT_ATTACH, child, NULL, 0) != -1); // assert printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); wpid = waitpid(child, &status, 0); CHILD_REQUIRE(wpid == child); CHILD_REQUIRE(WIFSTOPPED(status)); CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); FORKEE_ASSERT(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); /* Signal parent that debugger is attached. */ char debug1 = 'd'; printf("KR!!! %s(): %s:%d pid=%d trying to write to pipe character '%c'\n", __func__, __FILE__, __LINE__, getpid(), debug1); FORKEE_ASSERT(write(dpipe[1], &debug1, sizeof(debug1)) == sizeof(debug1)); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); /* Wait for parent's failed wait. */ sleep(1); /* tmp = read(dpipe[0], &c, sizeof(c)); if (tmp != 0) printf("KR!!! %s(): %s:%d pid=%d got a character '%c'\n", __func__, __FILE__, __LINE__, getpid(), c); else printf("KR!!! %s(): %s:%d pid=%d no character!\n", __func__, __FILE__, __LINE__, getpid()); FORKEE_ASSERT(tmp == 0); */ printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); wpid = waitpid(child, &status, 0); CHILD_REQUIRE(wpid == child); CHILD_REQUIRE(WIFEXITED(status)); CHILD_REQUIRE(WEXITSTATUS(status) == 1); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); _exit(0); } printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); // close(dpipe[0]); /* Parent process. */ printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); /* Wait for the debugger to attach to the child. */ ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c)); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); /* Release the child. */ ATF_REQUIRE(write(cpipe[1], &c, sizeof(c)) == sizeof(c)); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); //ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); close(cpipe[0]); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); close(cpipe[1]); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); wait_for_zombie(child); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); /* * This wait should return a pid of 0 to indicate no status to * report. The parent should see the child as non-exited * until the debugger sees the exit. */ wpid = waitpid(child, &status, WNOHANG); ATF_REQUIRE(wpid == 0); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); /* Signal the debugger to wait for the child. */ close(dpipe[0]); close(dpipe[1]); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); /* Wait for the debugger. */ wpid = waitpid(debugger, &status, 0); ATF_REQUIRE(wpid == debugger); ATF_REQUIRE(WIFEXITED(status)); ATF_REQUIRE(WEXITSTATUS(status) == 0); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); /* The child process should now be ready. */ wpid = waitpid(child, &status, WNOHANG); ATF_REQUIRE(wpid == child); ATF_REQUIRE(WIFEXITED(status)); ATF_REQUIRE(WEXITSTATUS(status) == 1); printf("KR!!! %s(): %s:%d pid=%d\n", __func__, __FILE__, __LINE__, getpid()); printf("dziala!!\n"); return 0; }