mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-19 01:26:22 +00:00
Move static and transition into zdtm top. We can't move all the micro tests themselves, as we need to distinguish static from non static (zdtm.py makes additional checks on static ones). Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
338 lines
7.2 KiB
C
338 lines
7.2 KiB
C
#define _GNU_SOURCE
|
|
#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)) { pr_perror("%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) {
|
|
pr_perror("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) {
|
|
pr_perror("setpgid() failed (%d) (%d)", 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) {
|
|
pr_perror("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) {
|
|
pr_perror("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) {
|
|
pr_perror("%d: session mismatch %d (expected %d)",
|
|
i, sid, t->master.sid);
|
|
err++;
|
|
}
|
|
|
|
pgid = getpgid(t->master.pid);
|
|
if (t->master.pgid != pgid) {
|
|
pr_perror("%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;
|
|
}
|