From 63dcf183f299b2c9df99dc7db8e934e7111cd61e Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Mon, 2 Jul 2012 15:25:00 +0400 Subject: [PATCH] zdtm: add a test case for checking sid and pgid A process tree is described in the array. New cases are easy for adding. Signed-off-by: Andrey Vagin Signed-off-by: Pavel Emelyanov --- test/zdtm/live/static/Makefile | 1 + test/zdtm/live/static/session01.c | 337 ++++++++++++++++++++++++++++++ 2 files changed, 338 insertions(+) create mode 100644 test/zdtm/live/static/session01.c diff --git a/test/zdtm/live/static/Makefile b/test/zdtm/live/static/Makefile index 0a7301691..f6af812d8 100644 --- a/test/zdtm/live/static/Makefile +++ b/test/zdtm/live/static/Makefile @@ -51,6 +51,7 @@ TST_NOFILE = \ pty00 \ tty00 \ mountpoints \ + session01 \ # jobctl00 \ TST_FILE = \ diff --git a/test/zdtm/live/static/session01.c b/test/zdtm/live/static/session01.c new file mode 100644 index 000000000..f300630bf --- /dev/null +++ b/test/zdtm/live/static/session01.c @@ -0,0 +1,337 @@ +#include +#include +#include +#include +#include + +#include "zdtmtst.h" +#include "lock.h" + +const char *test_doc = "Test that sid, pgid are restored"; +const char *test_author = "Andrey Vagin "; + +struct master { + pid_t pid; + pid_t ppid; + pid_t sid; + pid_t pgid; +}; + +struct testcase { + pid_t pid; + pid_t ppid; + pid_t sid; + pid_t born_sid; + pid_t pgid; + int alive; + struct master master; + futex_t futex; +}; + +enum { + TEST_FORK, + TEST_PGID, + TEST_WAIT, + TEST_MASTER, + TEST_CHECK, + TEST_EXIT, +}; + +static struct testcase *testcases; +static futex_t *fstate; +static struct testcase __testcases[] = { + { 2, 1, 2, 1, 2, 1 }, /* session00 */ + { 4, 2, 4, 2, 4, 1 }, /* |\_session00 */ + {15, 4, 4, 4, 15, 1 }, /* | |\_session00 */ + {16, 4, 4, 4, 15, 1 }, /* | \_session00 */ + {17, 4, 4, 4, 17, 0 }, /* | |\_session00 */ + {18, 4, 4, 4, 17, 1 }, /* | \_session00 */ + { 5, 2, 2, 2, 2, 1 }, /* |\_session00 */ + { 8, 2, 8, 2, 8, 1 }, /* |\_session00 */ + { 9, 8, 2, 2, 2, 1 }, /* | \_session00 */ + {10, 2, 10, 2, 10, 1 }, /* |\_session00 */ + {11, 10, 11, 2, 11, 1 }, /* | \_session00 */ + {12, 11, 2, 2, 2, 1 }, /* | \_session00 */ + {13, 2, 2, 2, 2, 0 }, /* \_session00 */ + { 3, 13, 2, 2, 2, 1 }, /* session00 */ + { 6, 2, 6, 2, 6, 0 }, /* \_session00 */ + {14, 6, 6, 6, 6, 1 }, /* session00 */ +}; + +#define TESTS (sizeof(__testcases) / sizeof(struct testcase)) + +#define check(n, a, b) do { if ((a) != (b)) { err("%s mismatch %d != %d", n, a, b); goto err; } } while (0) + +static int child(const int c); +static int fork_children(struct testcase *t, int leader) +{ + int i; + pid_t cid; + + for (i = 0; i < TESTS; i++) { + if (t->pid != testcases[i].ppid) + continue; + + if (leader ^ (t->pid == testcases[i].born_sid)) + continue; + + cid = test_fork_id(i); + if (cid < 0) + goto err; + if (cid == 0) { + test_msg("I'm %d with pid %d\n", i, getpid()); + child(i); + exit(0); + } + + testcases[i].master.pid = cid; + } + return 0; +err: + return -1; +} + +static int child(const int c) +{ + int i; + struct testcase *t = &testcases[c]; + + t->master.pid = getpid(); + + if (fork_children(t, 0)) + goto err; + + if (t->pid == t->sid) { + if (getpid() != getsid(getpid())) + if (setsid() < 0) + goto err; + if (fork_children(t, 1)) + goto err; + } + if (t->pid == t->pgid) { + if (getpid() != getpgid(getpid())) + if (setpgid(getpid(), getpid()) < 0) { + err("setpgid() failed"); + goto err; + } + t->master.pgid = t->master.pid; + } + + futex_set_and_wake(&t->futex, c); + + if (c == 0) + goto out; + + futex_wait_until(fstate, TEST_PGID); + + for (i = 0; i < TESTS; i++) { + if (c == 0) + break; + if (t->pgid != testcases[i].pid) + continue; + if (getpgid(getpid()) != testcases[i].master.pid) + if (setpgid(getpid(), testcases[i].master.pid) < 0) { + err("setpgid() failed (%d) (%d)\n", c, i); + goto err; + } + + t->master.pgid = testcases[i].master.pid; + break; + } + + futex_set_and_wake(&t->futex, c); + + futex_wait_until(fstate, TEST_WAIT); + + for (i = 0; i < TESTS; i++) { + if (t->pid != testcases[i].ppid) + continue; + if (testcases[i].alive) + continue; + test_msg("Wait porcess %d (pid %d)\n", i, testcases[i].master.pid); + waitpid(testcases[i].master.pid, NULL, 0); + } + + if (!t->alive) + goto out; + + futex_set_and_wake(&t->futex, c); + + futex_wait_until(fstate, TEST_MASTER); + + /* Save the master copy */ + t->master.ppid = getppid(); + t->master.sid = getsid(getpid()); + + futex_set_and_wake(&t->futex, c); + + futex_wait_until(fstate, TEST_CHECK); + + check("pid", t->master.pid, getpid()); + check("ppid", t->master.ppid, getppid()); + check("sid", t->master.sid, getsid(getpid())); + check("pgid", t->master.pgid, getpgid(getpid())); + + futex_set_and_wake(&t->futex, c); + + /* Wait while all test cases check results */ + futex_wait_until(fstate, TEST_EXIT); +out: + return 0; +err: + futex_set_and_wake(&t->futex, -1); + return 1; +} + +int main(int argc, char ** argv) +{ + int i, err, ret; + void *ptr; + + BUG_ON(sizeof(*fstate) + sizeof(__testcases) > 4096); + + ptr = mmap(NULL, 4096, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (ptr == MAP_FAILED) + return 1; + + fstate = ptr; + futex_set(fstate, TEST_FORK); + testcases = ptr + sizeof(*fstate); + + memcpy(testcases, &__testcases, sizeof(__testcases)); + + test_init(argc, argv); + + testcases[0].master.pid = getpid();; + if (child(0)) + goto err; + + for (i = 1; i < TESTS; i++) { + ret = futex_wait_while(&testcases[i].futex, 0); + if (ret < 0) + return 1; + futex_set(&testcases[i].futex, 0); + } + + test_msg("TEST_PGID\n"); + futex_set_and_wake(fstate, TEST_PGID); + for (i = 1; i < TESTS; i++) { + ret = futex_wait_while(&testcases[i].futex, 0); + if (ret < 0) + goto err; + futex_set(&testcases[i].futex, 0); + } + + test_msg("TEST_WAIT\n"); + futex_set_and_wake(fstate, TEST_WAIT); + for (i = 1; i < TESTS; i++) { + if (!testcases[i].alive) + continue; + ret = futex_wait_while(&testcases[i].futex, 0); + if (ret < 0) + goto err; + futex_set(&testcases[i].futex, 0); + } + + for (i = 0; i < TESTS; i++) { + if (testcases[0].pid != testcases[i].ppid) + continue; + if (testcases[i].alive) + continue; + test_msg("Wait porcess %d (pid %d)\n", + i, testcases[i].master.pid); + waitpid(testcases[i].master.pid, NULL, 0); + } + + test_msg("TEST_MASTER\n"); + futex_set_and_wake(fstate, TEST_MASTER); + for (i = 1; i < TESTS; i++) { + if (!testcases[i].alive) + continue; + ret = futex_wait_while(&testcases[i].futex, 0); + if (ret < 0) + goto err; + futex_set(&testcases[i].futex, 0); + test_msg("The process %d initilized\n", ret); + } + + test_daemon(); + + test_waitsig(); + + err = 0; + for (i = 1; i < TESTS; i++) { + int j; + struct testcase *t = testcases + i; + pid_t sid, pgid; + + if (!t->alive) + continue; + + for (j = 0; j < TESTS; j++) { + struct testcase *p = testcases + j; + /* sanity check */ + if (p->pid == t->sid && t->master.sid != p->master.pid) { + err("session mismatch (%d) %d != (%d) %d", + i, t->master.sid, j, p->master.pid); + err++; + } + if (p->pid == t->pgid && t->master.pgid != p->master.pid) { + err("pgid mismatch (%d) %d != (%d) %d", + i, t->master.pgid, j, p->master.pid); + err++; + } + } + + sid = getsid(t->master.pid); + if (t->master.sid != sid) { + err("%d: session mismatch %d (expected %d)", + i, sid, t->master.sid); + err++; + } + + pgid = getpgid(t->master.pid); + if (t->master.pgid != pgid) { + err("%d: pgid mismatch %d (expected %d)", + i, t->master.pgid, pgid); + err++; + } + } + + test_msg("TEST_CHECK\n"); + futex_set_and_wake(fstate, TEST_CHECK); + + for (i = 1; i < TESTS; i++) { + if (!testcases[i].alive) + continue; + + ret = futex_wait_while(&testcases[i].futex, 0); + if (ret < 0) + goto err; + futex_set(&testcases[i].futex, 0); + + if (ret < 0) { + fail("Someone failed"); + err++; + continue; + } + test_msg("The process %u is restored correctly\n", (unsigned)ret); + } + + test_msg("TEST_EXIT\n"); + futex_set_and_wake(fstate, TEST_EXIT); + + if (!err) + pass(); + + return 0; +err: + for (i = 1; i < TESTS; i++) { + pid_t pid = testcases[i].master.pid; + if (pid > 0) { + ret = kill(pid, SIGKILL); + test_msg("kill %d %s\n", pid, strerror(ret == -1 ? errno : 0)); + } + } + return 1; +}