mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-23 10:09:57 +00:00
After the commit
02c763939c10 ("test/zdtm: unify common code")
CFLAGS with -D_GNU_SOURCE defined in the top Makefile
are being passed to tests Makefiles.
As _GNU_SOURCE is also defined by tests, that resulted in
zdtm tests build failures:
make[2]: Entering directory `/home/criu/test/zdtm/lib'
CC test.o
test.c:1:0: error: "_GNU_SOURCE" redefined [-Werror]
#define _GNU_SOURCE
^
<command-line>:0:0: note: this is the location of the previous definition
cc1: all warnings being treated as errors
make[2]: *** [test.o] Error 1
However, we didn't catch this in time by Travis-CI, as zdtm.py doesn't
do `make zdtm`, rather it does `make -C test/zdtm/{lib,static,transition}`.
By calling middle makefile this way, it doesn't have _GNU_SOURCE in
CFLAGS from top-Makefile.
I think the right thing to do here - is following CRIU's way:
rely on definition of _GNU_SOURCE by Makefiles.
This patch is almost fully generated with
find test/zdtm/ -name '*.c' -type f \
-exec sed -i '/define _GNU_SOURCE/{n;/^$/d;}' '{}' \; \
-exec sed -i '/define _GNU_SOURCE/d' '{}' \;
With an exception for adding -D_GNU_SOURCE in tests Makefile.inc for
keeping the same behaviour for zdtm.py.
Also changed utsname.c to use utsname::domainname, rather private
utsname::__domainname, as now it's uncovered (from sys/utsname.h):
> struct utsname
> {
...
> # ifdef __USE_GNU
> char domainname[_UTSNAME_DOMAIN_LENGTH];
> # else
> char __domainname[_UTSNAME_DOMAIN_LENGTH];
> # endif
Reported-by: Adrian Reber <areber@redhat.com>
Cc: Kir Kolyshkin <kir@openvz.org>
Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
337 lines
7.1 KiB
C
337 lines
7.1 KiB
C
#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;
|
|
}
|