Commit 63dcf183 authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

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: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 23501ffe
...@@ -51,6 +51,7 @@ TST_NOFILE = \ ...@@ -51,6 +51,7 @@ TST_NOFILE = \
pty00 \ pty00 \
tty00 \ tty00 \
mountpoints \ mountpoints \
session01 \
# jobctl00 \ # jobctl00 \
TST_FILE = \ TST_FILE = \
......
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include "zdtmtst.h"
#include "lock.h"
const char *test_doc = "Test that sid, pgid are restored";
const char *test_author = "Andrey Vagin <avagin@openvz.org>";
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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment