mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-28 20:42:49 +00:00
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 <avagin@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
23501ffe32
commit
63dcf183f2
2 changed files with 338 additions and 0 deletions
|
|
@ -51,6 +51,7 @@ TST_NOFILE = \
|
|||
pty00 \
|
||||
tty00 \
|
||||
mountpoints \
|
||||
session01 \
|
||||
# jobctl00 \
|
||||
|
||||
TST_FILE = \
|
||||
|
|
|
|||
337
test/zdtm/live/static/session01.c
Normal file
337
test/zdtm/live/static/session01.c
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
#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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue