diff --git a/scripts/ci/run-ci-tests.sh b/scripts/ci/run-ci-tests.sh index 5b9f6d9292..dc82432efd 100755 --- a/scripts/ci/run-ci-tests.sh +++ b/scripts/ci/run-ci-tests.sh @@ -259,6 +259,7 @@ if [ -n "$TRAVIS" ] || [ -n "$CIRCLECI" ]; then # GitHub Actions (and Cirrus CI) does not provide a real TTY and CRIU will fail with: # Error (criu/tty.c:1014): tty: Don't have tty to inherit session from, aborting make -C test/others/shell-job/ run + make -C test/others/criu-ns/ run fi make -C test/others/skip-file-rwx-check/ run make -C test/others/rpc/ run diff --git a/scripts/criu-ns b/scripts/criu-ns index d51e7772c0..dd2d749645 100755 --- a/scripts/criu-ns +++ b/scripts/criu-ns @@ -70,7 +70,7 @@ def _wait_for_process_status(criu_pid): try: (pid, status) = os.wait() if pid == criu_pid: - return os.waitstatus_to_exitcode(status) + return os.WEXITSTATUS(status) except OSError: return -251 @@ -80,8 +80,20 @@ def run_criu(args): Spawn CRIU binary """ print(sys.argv) - os.execlp('criu', *['criu'] + args) - raise OSError(errno.ENOENT, "No such command") + + if "--criu-binary" in args: + try: + path = args[args.index("--criu-binary") + 1] + args.remove("--criu-binary") + args.remove(path) + args.insert(0, "criu") + os.execv(path, args) + raise OSError(errno.ENOENT, "No such command") + except (ValueError, IndexError): + raise OSError(errno.ENOENT, "--criu-binary missing argument") + else: + os.execlp("criu", *["criu"] + args) + raise OSError(errno.ENOENT, "No such command") # pidns_holder creates a process that is reparented to the init. diff --git a/test/others/criu-ns/Makefile b/test/others/criu-ns/Makefile new file mode 100644 index 0000000000..d81733ef4d --- /dev/null +++ b/test/others/criu-ns/Makefile @@ -0,0 +1,2 @@ +run: + ../../zdtm_ct run.py diff --git a/test/others/criu-ns/run.py b/test/others/criu-ns/run.py new file mode 100755 index 0000000000..36156245b6 --- /dev/null +++ b/test/others/criu-ns/run.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +import os +import pty +import shutil +import subprocess +import sys +import time + + +CRIU_BIN = "../../../criu/criu" +CRIU_NS = "../../../scripts/criu-ns" + + +def check_dumpdir(): + if os.path.isdir("dumpdir"): + shutil.rmtree("dumpdir") + os.mkdir("dumpdir", 0o755) + + +def create_pty(): + fd_m, fd_s = pty.openpty() + return (os.fdopen(fd_m, "wb"), os.fdopen(fd_s, "wb")) + + +def test_dump_and_restore_with_shell_job(): + check_dumpdir() + + open("running", "w").close() + fd_m, fd_s = create_pty() + pid = os.fork() + if pid == 0: + os.setsid() + while True: + if not os.access("running", os.F_OK): + sys.exit(0) + time.sleep(1) + sys.exit(1) + + cmd = [CRIU_NS, "dump", "-D", "dumpdir", "-v", "--shell-job", + "-t", str(pid), "--criu-binary", CRIU_BIN] + ret = subprocess.Popen(cmd).wait() + if ret != 0: + sys.exit(ret) + + os.unlink("running") + fd_m, fd_s = create_pty() + pid = os.fork() + if pid == 0: + cmd = [CRIU_NS, "restore", "-D", "dumpdir", "-v", + "--shell-job", "--criu-binary", CRIU_BIN] + ret = subprocess.Popen(cmd).wait() + if ret != 0: + sys.exit(ret) + os._exit(0) + + os.waitpid(pid, 0) + + +def test_dump_and_restore_without_shell_job(restore_detached=False): + check_dumpdir() + + open("running", "w").close() + fd_m, fd_s = create_pty() + pid = os.fork() + if pid == 0: + os.setsid() + os.dup2(fd_s.fileno(), 0) + os.dup2(fd_s.fileno(), 1) + os.dup2(fd_s.fileno(), 2) + while True: + if not os.access("running", os.F_OK): + sys.exit(0) + time.sleep(1) + sys.exit(1) + + cmd = [CRIU_NS, "dump", "-D", "dumpdir", "-v", "-t", str(pid), + "--criu-binary", CRIU_BIN] + ret = subprocess.Popen(cmd).wait() + if ret != 0: + sys.exit(ret) + + os.unlink("running") + fd_m, fd_s = create_pty() + pid = os.fork() + if pid == 0: + os.setsid() + + if restore_detached: + cmd = [CRIU_NS, "restore", "-D", "dumpdir", "-v", + "--restore-detached", "--criu-binary", + CRIU_BIN] + else: + cmd = [CRIU_NS, "restore", "-D", "dumpdir", "-v", + "--criu-binary", CRIU_BIN] + + ret = subprocess.Popen(cmd).wait() + if ret != 0: + sys.exit(ret) + os._exit(0) + + os.waitpid(pid, 0) + + +if __name__ == "__main__": + test_dump_and_restore_with_shell_job() + test_dump_and_restore_without_shell_job() + test_dump_and_restore_without_shell_job(restore_detached=True)