[CRIU] [PATCH 1/2] tests: move non-zdtm tests to tests/others/
Andrey Vagin
avagin at openvz.org
Fri Feb 19 13:11:39 PST 2016
From: Andrew Vagin <avagin at virtuozzo.com>
Signed-off-by: Andrew Vagin <avagin at virtuozzo.com>
---
scripts/build/extract-deb-pkg | 4 +-
test/bers/Makefile | 47 --
test/bers/bers.c | 420 -------------
test/bers/bers.txt | 74 ---
test/ext-links/Makefile | 4 -
test/ext-links/addmv.sh | 8 -
test/ext-links/addmv_raw.sh | 6 -
test/ext-links/mvlink.c | 28 -
test/ext-links/run.sh | 58 --
test/ext-links/run_ns.sh | 10 -
test/ext-links/run_wait.sh | 15 -
test/ext-tty/run.py | 36 --
test/fault-injection/Makefile | 2 -
test/fault-injection/parasite.stp | 44 --
test/libcriu/.gitignore | 6 -
test/libcriu/Makefile | 26 -
test/libcriu/lib.c | 47 --
test/libcriu/lib.h | 2 -
test/libcriu/run.sh | 44 --
test/libcriu/test_errno.c | 154 -----
test/libcriu/test_iters.c | 143 -----
test/libcriu/test_notify.c | 97 ---
test/libcriu/test_self.c | 96 ---
test/libcriu/test_sub.c | 107 ----
test/mem-snap/Makefile | 2 -
test/mem-snap/run-predump-2.sh | 66 ---
test/mem-snap/run-predump.sh | 77 ---
test/mem-snap/run-snap-auto-dedup.sh | 93 ---
test/mem-snap/run-snap-dedup-on-restore.sh | 87 ---
test/mem-snap/run-snap-dedup.sh | 99 ----
test/mem-snap/run-snap-maps04.sh | 68 ---
test/mem-snap/run-snap.sh | 74 ---
test/mem-snap/run.sh | 13 -
test/mounts/ext/Makefile | 13 -
test/mounts/ext/ext-mount.c | 101 ----
test/mounts/ext/ns_init.c | 143 -----
test/mounts/ext/run.sh | 125 ----
test/mounts/mounts.py | 31 -
test/mounts/mounts.sh | 27 -
test/mounts/run.sh | 24 -
test/others/bers/Makefile | 47 ++
test/others/bers/bers.c | 420 +++++++++++++
test/others/bers/bers.txt | 74 +++
test/others/ext-links/Makefile | 4 +
test/others/ext-links/addmv.sh | 8 +
test/others/ext-links/addmv_raw.sh | 6 +
test/others/ext-links/mvlink.c | 28 +
test/others/ext-links/run.sh | 58 ++
test/others/ext-links/run_ns.sh | 10 +
test/others/ext-links/run_wait.sh | 15 +
test/others/ext-tty/run.py | 36 ++
test/others/fault-injection/Makefile | 2 +
test/others/fault-injection/parasite.stp | 44 ++
test/others/libcriu/.gitignore | 6 +
test/others/libcriu/Makefile | 26 +
test/others/libcriu/lib.c | 47 ++
test/others/libcriu/lib.h | 2 +
test/others/libcriu/run.sh | 45 ++
test/others/libcriu/test_errno.c | 154 +++++
test/others/libcriu/test_iters.c | 143 +++++
test/others/libcriu/test_notify.c | 97 +++
test/others/libcriu/test_self.c | 96 +++
test/others/libcriu/test_sub.c | 107 ++++
test/others/mem-snap/Makefile | 2 +
test/others/mem-snap/run-predump-2.sh | 66 +++
test/others/mem-snap/run-predump.sh | 77 +++
test/others/mem-snap/run-snap-auto-dedup.sh | 93 +++
test/others/mem-snap/run-snap-dedup-on-restore.sh | 87 +++
test/others/mem-snap/run-snap-dedup.sh | 99 ++++
test/others/mem-snap/run-snap-maps04.sh | 68 +++
test/others/mem-snap/run-snap.sh | 74 +++
test/others/mem-snap/run.sh | 13 +
test/others/mounts/ext/Makefile | 13 +
test/others/mounts/ext/ext-mount.c | 101 ++++
test/others/mounts/ext/ns_init.c | 143 +++++
test/others/mounts/ext/run.sh | 125 ++++
test/others/mounts/mounts.py | 31 +
test/others/mounts/mounts.sh | 27 +
test/others/mounts/run.sh | 24 +
test/others/overlayfs/Makefile | 6 +
test/others/overlayfs/run.sh | 58 ++
test/others/pipes/Makefile | 14 +
test/others/pipes/pipe.c | 693 ++++++++++++++++++++++
test/others/rpc/.gitignore | 3 +
test/others/rpc/Makefile | 28 +
test/others/rpc/errno.py | 135 +++++
test/others/rpc/loop.sh | 4 +
test/others/rpc/ps_test.py | 73 +++
test/others/rpc/restore-loop.py | 40 ++
test/others/rpc/rpc.proto | 1 +
test/others/rpc/run.sh | 91 +++
test/others/rpc/test-c.c | 170 ++++++
test/others/rpc/test.py | 44 ++
test/others/security/Makefile | 34 ++
test/others/security/loop.sh | 13 +
test/others/security/run.sh | 89 +++
test/others/socketpairs/Makefile | 9 +
test/others/socketpairs/socketpair.c | 600 +++++++++++++++++++
test/others/tcp/Makefile | 11 +
test/others/tcp/cln.c | 122 ++++
test/others/tcp/run.sh | 67 +++
test/others/tcp/srv.c | 112 ++++
test/others/unix-callback/Makefile | 22 +
test/others/unix-callback/lib/syslog-lib.so | 1 +
test/others/unix-callback/lib/unix-lib.so | 1 +
test/others/unix-callback/run.sh | 48 ++
test/others/unix-callback/syslog-lib.c | 66 +++
test/others/unix-callback/unix-client.c | 121 ++++
test/others/unix-callback/unix-lib.c | 187 ++++++
test/others/unix-callback/unix-server.c | 104 ++++
test/others/unix-callback/unix.proto | 4 +
test/overlayfs/Makefile | 6 -
test/overlayfs/run.sh | 58 --
test/pipes/Makefile | 14 -
test/pipes/pipe.c | 693 ----------------------
test/rpc/.gitignore | 3 -
test/rpc/Makefile | 28 -
test/rpc/errno.py | 135 -----
test/rpc/loop.sh | 4 -
test/rpc/ps_test.py | 73 ---
test/rpc/restore-loop.py | 40 --
test/rpc/rpc.proto | 1 -
test/rpc/run.sh | 91 ---
test/rpc/test-c.c | 170 ------
test/rpc/test.py | 44 --
test/security/Makefile | 34 --
test/security/loop.sh | 13 -
test/security/run.sh | 89 ---
test/socketpairs/Makefile | 9 -
test/socketpairs/socketpair.c | 600 -------------------
test/tcp/Makefile | 11 -
test/tcp/cln.c | 122 ----
test/tcp/run.sh | 67 ---
test/tcp/srv.c | 112 ----
test/unix-callback/Makefile | 22 -
test/unix-callback/lib/syslog-lib.so | 1 -
test/unix-callback/lib/unix-lib.so | 1 -
test/unix-callback/run.sh | 48 --
test/unix-callback/syslog-lib.c | 66 ---
test/unix-callback/unix-client.c | 121 ----
test/unix-callback/unix-lib.c | 187 ------
test/unix-callback/unix-server.c | 104 ----
test/unix-callback/unix.proto | 4 -
143 files changed, 5491 insertions(+), 5490 deletions(-)
delete mode 100644 test/bers/Makefile
delete mode 100644 test/bers/bers.c
delete mode 100644 test/bers/bers.txt
delete mode 100644 test/ext-links/Makefile
delete mode 100755 test/ext-links/addmv.sh
delete mode 100755 test/ext-links/addmv_raw.sh
delete mode 100644 test/ext-links/mvlink.c
delete mode 100755 test/ext-links/run.sh
delete mode 100755 test/ext-links/run_ns.sh
delete mode 100755 test/ext-links/run_wait.sh
delete mode 100755 test/ext-tty/run.py
delete mode 100644 test/fault-injection/Makefile
delete mode 100644 test/fault-injection/parasite.stp
delete mode 100644 test/libcriu/.gitignore
delete mode 100644 test/libcriu/Makefile
delete mode 100644 test/libcriu/lib.c
delete mode 100644 test/libcriu/lib.h
delete mode 100755 test/libcriu/run.sh
delete mode 100644 test/libcriu/test_errno.c
delete mode 100644 test/libcriu/test_iters.c
delete mode 100644 test/libcriu/test_notify.c
delete mode 100644 test/libcriu/test_self.c
delete mode 100644 test/libcriu/test_sub.c
delete mode 100644 test/mem-snap/Makefile
delete mode 100755 test/mem-snap/run-predump-2.sh
delete mode 100755 test/mem-snap/run-predump.sh
delete mode 100755 test/mem-snap/run-snap-auto-dedup.sh
delete mode 100755 test/mem-snap/run-snap-dedup-on-restore.sh
delete mode 100755 test/mem-snap/run-snap-dedup.sh
delete mode 100755 test/mem-snap/run-snap-maps04.sh
delete mode 100755 test/mem-snap/run-snap.sh
delete mode 100755 test/mem-snap/run.sh
delete mode 100644 test/mounts/ext/Makefile
delete mode 100644 test/mounts/ext/ext-mount.c
delete mode 100644 test/mounts/ext/ns_init.c
delete mode 100755 test/mounts/ext/run.sh
delete mode 100755 test/mounts/mounts.py
delete mode 100755 test/mounts/mounts.sh
delete mode 100755 test/mounts/run.sh
create mode 100644 test/others/bers/Makefile
create mode 100644 test/others/bers/bers.c
create mode 100644 test/others/bers/bers.txt
create mode 100644 test/others/ext-links/Makefile
create mode 100755 test/others/ext-links/addmv.sh
create mode 100755 test/others/ext-links/addmv_raw.sh
create mode 100644 test/others/ext-links/mvlink.c
create mode 100755 test/others/ext-links/run.sh
create mode 100755 test/others/ext-links/run_ns.sh
create mode 100755 test/others/ext-links/run_wait.sh
create mode 100755 test/others/ext-tty/run.py
create mode 100644 test/others/fault-injection/Makefile
create mode 100644 test/others/fault-injection/parasite.stp
create mode 100644 test/others/libcriu/.gitignore
create mode 100644 test/others/libcriu/Makefile
create mode 100644 test/others/libcriu/lib.c
create mode 100644 test/others/libcriu/lib.h
create mode 100755 test/others/libcriu/run.sh
create mode 100644 test/others/libcriu/test_errno.c
create mode 100644 test/others/libcriu/test_iters.c
create mode 100644 test/others/libcriu/test_notify.c
create mode 100644 test/others/libcriu/test_self.c
create mode 100644 test/others/libcriu/test_sub.c
create mode 100644 test/others/mem-snap/Makefile
create mode 100755 test/others/mem-snap/run-predump-2.sh
create mode 100755 test/others/mem-snap/run-predump.sh
create mode 100755 test/others/mem-snap/run-snap-auto-dedup.sh
create mode 100755 test/others/mem-snap/run-snap-dedup-on-restore.sh
create mode 100755 test/others/mem-snap/run-snap-dedup.sh
create mode 100755 test/others/mem-snap/run-snap-maps04.sh
create mode 100755 test/others/mem-snap/run-snap.sh
create mode 100755 test/others/mem-snap/run.sh
create mode 100644 test/others/mounts/ext/Makefile
create mode 100644 test/others/mounts/ext/ext-mount.c
create mode 100644 test/others/mounts/ext/ns_init.c
create mode 100755 test/others/mounts/ext/run.sh
create mode 100755 test/others/mounts/mounts.py
create mode 100755 test/others/mounts/mounts.sh
create mode 100755 test/others/mounts/run.sh
create mode 100644 test/others/overlayfs/Makefile
create mode 100755 test/others/overlayfs/run.sh
create mode 100644 test/others/pipes/Makefile
create mode 100644 test/others/pipes/pipe.c
create mode 100644 test/others/rpc/.gitignore
create mode 100644 test/others/rpc/Makefile
create mode 100755 test/others/rpc/errno.py
create mode 100755 test/others/rpc/loop.sh
create mode 100755 test/others/rpc/ps_test.py
create mode 100755 test/others/rpc/restore-loop.py
create mode 120000 test/others/rpc/rpc.proto
create mode 100755 test/others/rpc/run.sh
create mode 100644 test/others/rpc/test-c.c
create mode 100755 test/others/rpc/test.py
create mode 100644 test/others/security/Makefile
create mode 100755 test/others/security/loop.sh
create mode 100755 test/others/security/run.sh
create mode 100644 test/others/socketpairs/Makefile
create mode 100644 test/others/socketpairs/socketpair.c
create mode 100644 test/others/tcp/Makefile
create mode 100644 test/others/tcp/cln.c
create mode 100755 test/others/tcp/run.sh
create mode 100644 test/others/tcp/srv.c
create mode 100644 test/others/unix-callback/Makefile
create mode 120000 test/others/unix-callback/lib/syslog-lib.so
create mode 120000 test/others/unix-callback/lib/unix-lib.so
create mode 100755 test/others/unix-callback/run.sh
create mode 100644 test/others/unix-callback/syslog-lib.c
create mode 100644 test/others/unix-callback/unix-client.c
create mode 100644 test/others/unix-callback/unix-lib.c
create mode 100644 test/others/unix-callback/unix-server.c
create mode 100644 test/others/unix-callback/unix.proto
delete mode 100644 test/overlayfs/Makefile
delete mode 100755 test/overlayfs/run.sh
delete mode 100644 test/pipes/Makefile
delete mode 100644 test/pipes/pipe.c
delete mode 100644 test/rpc/.gitignore
delete mode 100644 test/rpc/Makefile
delete mode 100755 test/rpc/errno.py
delete mode 100755 test/rpc/loop.sh
delete mode 100755 test/rpc/ps_test.py
delete mode 100755 test/rpc/restore-loop.py
delete mode 120000 test/rpc/rpc.proto
delete mode 100755 test/rpc/run.sh
delete mode 100644 test/rpc/test-c.c
delete mode 100755 test/rpc/test.py
delete mode 100644 test/security/Makefile
delete mode 100755 test/security/loop.sh
delete mode 100755 test/security/run.sh
delete mode 100644 test/socketpairs/Makefile
delete mode 100644 test/socketpairs/socketpair.c
delete mode 100644 test/tcp/Makefile
delete mode 100644 test/tcp/cln.c
delete mode 100755 test/tcp/run.sh
delete mode 100644 test/tcp/srv.c
delete mode 100644 test/unix-callback/Makefile
delete mode 120000 test/unix-callback/lib/syslog-lib.so
delete mode 120000 test/unix-callback/lib/unix-lib.so
delete mode 100755 test/unix-callback/run.sh
delete mode 100644 test/unix-callback/syslog-lib.c
delete mode 100644 test/unix-callback/unix-client.c
delete mode 100644 test/unix-callback/unix-lib.c
delete mode 100644 test/unix-callback/unix-server.c
delete mode 100644 test/unix-callback/unix.proto
diff --git a/scripts/build/extract-deb-pkg b/scripts/build/extract-deb-pkg
index 8ccec37..ac63319 100755
--- a/scripts/build/extract-deb-pkg
+++ b/scripts/build/extract-deb-pkg
@@ -3,8 +3,8 @@ set -e
test -d $1 && exit
mkdir $1
cd $1
-pkg=`curl http://mirror.yandex.ru/debian/dists/jessie/main/binary-amd64/Packages.gz | zcat | grep "Filename.*$1" | awk '{ print $2 }'`
-wget "http://mirror.yandex.ru/debian/$pkg"
+pkg=`curl http://mirror.yandex.ru/ubuntu/ubuntu/dists/wily/universe/binary-amd64/Packages.gz | zcat | grep "Filename.*$1" | awk '{ print $2 }'`
+wget "http://mirror.yandex.ru/ubuntu/$pkg"
pkg=`basename $pkg`
ar vx $pkg
tar -xJvf data.tar.xz
diff --git a/test/bers/Makefile b/test/bers/Makefile
deleted file mode 100644
index 74b6142..0000000
--- a/test/bers/Makefile
+++ /dev/null
@@ -1,47 +0,0 @@
-ifeq ($(strip $(V)),)
- E = @echo
- Q = @
-else
- E = @\#
- Q =
-endif
-
-export E Q
-
-ASCIIDOC := asciidoc
-A2X := a2x
-XMLTO := xmlto
-
-SRC += bers.txt
-XMLS := $(patsubst %.txt,%.xml,$(SRC))
-MANS := $(patsubst %.txt,%.8,$(SRC))
-
-%.8: %.txt
- $(E) " GEN " $@
- $(Q) $(ASCIIDOC) -b docbook -d manpage -o $(patsubst %.8,%.xml,$@) $<
- $(Q) $(XMLTO) man --skip-validation $(patsubst %.8,%.xml,$@) 2>/dev/null
-
-docs: $(MANS)
- @true
-
-CFLAGS := -O0 -ggdb3
-LIBS := -lpthread
-
-%.o: %.c
- $(E) " CC " $@
- $(Q) $(CC) -c -o $@ $(CFLAGS) $^
-
-bers: bers.o
- $(E) " LINK " $@
- $(Q) $(CC) -o $@ $(CFLAGS) $(LIBS) $^
-
-all: bers
- @true
-
-clean:
- $(E) " CLEAN "
- $(Q) rm -f $(XMLS) $(MANS)
- $(Q) rm -f bers.o
- $(Q) rm -f bers
-
-.PHONY: all docs clean
diff --git a/test/bers/bers.c b/test/bers/bers.c
deleted file mode 100644
index 208325c..0000000
--- a/test/bers/bers.c
+++ /dev/null
@@ -1,420 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <string.h>
-#include <limits.h>
-#include <stdbool.h>
-
-#include <pthread.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <syscall.h>
-
-#define min(x, y) ({ \
- typeof(x) _min1 = (x); \
- typeof(y) _min2 = (y); \
- (void) (&_min1 == &_min2); \
- _min1 < _min2 ? _min1 : _min2; })
-
-#define max(x, y) ({ \
- typeof(x) _max1 = (x); \
- typeof(y) _max2 = (y); \
- (void) (&_max1 == &_max2); \
- _max1 > _max2 ? _max1 : _max2; })
-
-#define MAX_CHUNK 4096
-#define PAGE_SIZE 4096
-
-#define pr_info(fmt, ...) \
- printf("%8d: " fmt, sys_gettid(), ##__VA_ARGS__)
-
-#define pr_err(fmt, ...) \
- printf("%8d: Error (%s:%d): " fmt, sys_gettid(),\
- __FILE__, __LINE__, ##__VA_ARGS__)
-
-#define pr_perror(fmt, ...) \
- pr_err(fmt ": %m\n", ##__VA_ARGS__)
-
-#define pr_msg(fmt, ...) \
- printf(fmt, ##__VA_ARGS__)
-
-
-#define pr_trace(fmt, ...) \
- printf("%8d: %s: " fmt, sys_gettid(), __func__, \
- ##__VA_ARGS__)
-
-enum {
- MEM_FILL_MODE_NONE = 0,
- MEM_FILL_MODE_ALL = 1,
- MEM_FILL_MODE_LIGHT = 2,
- MEM_FILL_MODE_DIRTIFY = 3,
-};
-
-typedef struct {
- pthread_mutex_t mutex;
- pthread_mutexattr_t mutex_attr;
-
- size_t opt_tasks;
-
- size_t opt_files;
- size_t opt_file_size;
- int prev_fd[MAX_CHUNK];
-
- size_t opt_mem;
- size_t opt_mem_chunks;
- size_t opt_mem_chunk_size;
- int opt_mem_fill_mode;
- int opt_mem_cycle_mode;
- unsigned int opt_refresh_time;
-
- char *opt_work_dir;
- int work_dir_fd;
- DIR *work_dir;
-
- pid_t err_pid;
- int err_no;
-
- unsigned long prev_map[MAX_CHUNK];
-} shared_data_t;
-
-static shared_data_t *shared;
-
-static int sys_gettid(void)
-{
- return syscall(__NR_gettid);
-}
-
-static void dirtify_memory(unsigned long *chunks, size_t nr_chunks,
- size_t chunk_size, int mode, const size_t nr_pages)
-{
- void *page;
- size_t i;
-
- pr_trace("filling memory\n");
- switch (mode) {
- case MEM_FILL_MODE_LIGHT:
- *((unsigned long *)chunks[0]) = -1ul;
- break;
- case MEM_FILL_MODE_ALL:
- for (i = 0; i < nr_chunks; i++)
- memset((void *)chunks[i], (char)i, chunk_size);
- break;
- case MEM_FILL_MODE_DIRTIFY:
- for (i = 0; i < nr_chunks; i++)
- *((unsigned long *)chunks[i]) = -1ul;
- break;
- }
-}
-
-static void dirtify_files(int *fd, size_t nr_files, size_t size)
-{
- size_t buf[8192];
- size_t i, j, c;
-
- /*
- * Note we don't write any _sane_ data here, the only
- * important thing is I/O activity by self.
- */
-
- for (i = 0; i < nr_files; i++) {
- size_t c = min(size, sizeof(buf));
- size_t left = size;
-
- while (left > 0) {
- write(fd[i], buf, c);
- left -= c;
- c = min(left, sizeof(buf));
- }
- }
-}
-
-static int create_files(shared_data_t *shared, int *fd, size_t nr_files)
-{
- char path[PATH_MAX];
- size_t i;
-
- memset(fd, 0xff, sizeof(fd));
-
- pr_info("\tCreating %lu files\n", shared->opt_files);
-
- for (i = 0; i < shared->opt_files; i++) {
- if (shared->prev_fd[i] != -1) {
- close(shared->prev_fd[i]);
- shared->prev_fd[i] = -1;
- }
- snprintf(path, sizeof(path), "%08d-%04d-temp", sys_gettid(), i);
- fd[i] = openat(shared->work_dir_fd, path, O_RDWR | O_CREAT | O_TRUNC, 0666);
- if (fd[i] < 0) {
- pr_perror("Can't open %s/%s", shared->opt_work_dir, path);
- shared->err_pid = sys_gettid();
- shared->err_no = -errno;
- return -1;
- }
- shared->prev_fd[i] = fd[i];
- }
-
- return 0;
-}
-
-static void work_on_fork(shared_data_t *shared)
-{
- const size_t nr_pages = shared->opt_mem_chunk_size / PAGE_SIZE;
- unsigned long chunks[MAX_CHUNK] = { };
- int fd[MAX_CHUNK];
- size_t i;
- void *mem;
-
- pr_trace("locking\n");
- pthread_mutex_lock(&shared->mutex);
- pr_trace("init\n");
-
- pr_info("\tCreating %lu mmaps each %lu K\n",
- shared->opt_mem_chunks, shared->opt_mem_chunk_size >> 10);
-
- for (i = 0; i < shared->opt_mem_chunks; i++) {
- if (shared->prev_map[i]) {
- munmap((void *)shared->prev_map[i], shared->opt_mem_chunk_size);
- shared->prev_map[i] = 0;
- }
-
- /* If we won't change proto here, the kernel might merge close areas */
- mem = mmap(NULL, shared->opt_mem_chunk_size,
- PROT_READ | PROT_WRITE | ((i % 2) ? PROT_EXEC : 0),
- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
-
- if (mem != (void *)MAP_FAILED) {
- shared->prev_map[i] = (unsigned long)mem;
- chunks[i] = (unsigned long)mem;
-
- pr_info("\t\tMap at %lx\n",(unsigned long)mem);
- } else {
- pr_info("\t\tCan't map\n");
-
- shared->err_pid = sys_gettid();
- shared->err_no = -errno;
- exit(1);
- }
- }
-
- if (shared->opt_mem_fill_mode)
- dirtify_memory(chunks, shared->opt_mem_chunks,
- shared->opt_mem_chunk_size,
- shared->opt_mem_fill_mode,
- nr_pages);
-
- if (create_files(shared, fd, shared->opt_files))
- exit(1);
-
- if (shared->opt_file_size)
- dirtify_files(fd, shared->opt_files, shared->opt_file_size);
-
- pr_trace("releasing\n");
- pthread_mutex_unlock(&shared->mutex);
-
- while (1) {
- sleep(shared->opt_refresh_time);
- if (shared->opt_mem_cycle_mode)
- dirtify_memory(chunks, shared->opt_mem_chunks,
- shared->opt_mem_chunk_size,
- shared->opt_mem_cycle_mode,
- nr_pages);
- if (shared->opt_file_size)
- dirtify_files(fd, shared->opt_files, shared->opt_file_size);
- }
-}
-
-static int parse_mem_mode(int *mode, char *opt)
-{
- if (!strcmp(opt, "all")) {
- *mode = MEM_FILL_MODE_ALL;
- } else if (!strcmp(opt, "light")) {
- *mode = MEM_FILL_MODE_LIGHT;
- } else if (!strcmp(opt, "dirtify")) {
- *mode = MEM_FILL_MODE_DIRTIFY;
- } else {
- pr_err("Unrecognized option %s\n", opt);
- return -1;
- }
- return 0;
-}
-
-int main(int argc, char *argv[])
-{
- /* a - 97, z - 122, A - 65, 90 */
- static const char short_opts[] = "t:d:f:m:c:h";
- static struct option long_opts[] = {
- {"tasks", required_argument, 0, 't'},
- {"dir", required_argument, 0, 'd'},
- {"files", required_argument, 0, 'f'},
- {"memory", required_argument, 0, 'm'},
- {"mem-chunks", required_argument, 0, 'c'},
- {"help", no_argument, 0, 'h'},
- {"mem-fill", required_argument, 0, 10},
- {"mem-cycle", required_argument, 0, 11},
- {"refresh", required_argument, 0, 12},
- {"file-size", required_argument, 0, 13},
- { },
- };
-
- char workdir[PATH_MAX];
- int opt, idx, pidfd;
- char pidbuf[32];
- int status;
- pid_t pid;
- size_t i;
-
- shared = (void *)mmap(NULL, sizeof(*shared), PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_SHARED, -1, 0);
- if ((void *)shared == MAP_FAILED) {
- pr_err("Failed to setup shared data\n");
- exit(1);
- }
-
- pthread_mutexattr_init(&shared->mutex_attr);
- pthread_mutexattr_setpshared(&shared->mutex_attr, PTHREAD_PROCESS_SHARED);
- pthread_mutex_init(&shared->mutex, &shared->mutex_attr);
-
- /*
- * Default options.
- */
- shared->opt_mem_chunks = 1;
- shared->opt_refresh_time = 1;
- shared->opt_tasks = 1;
- shared->opt_mem = 1 << 20ul;
- memset(shared->prev_fd, 0xff, sizeof(shared->prev_fd));
-
- while (1) {
- idx = -1;
- opt = getopt_long(argc, argv, short_opts, long_opts, &idx);
- if (opt == -1)
- break;
-
- switch(opt) {
- case 't':
- shared->opt_tasks = (size_t)atol(optarg);
- break;
- case 'f':
- shared->opt_files = (size_t)atol(optarg);
- break;
- case 'm':
- /* In megabytes */
- shared->opt_mem = (size_t)atol(optarg) << 20ul;
- break;
- case 'c':
- shared->opt_mem_chunks = (size_t)atol(optarg);
- break;
- case 'd':
- shared->opt_work_dir = optarg;
- break;
- case 'h':
- goto usage;
- break;
- case 10:
- if (parse_mem_mode(&shared->opt_mem_fill_mode, optarg))
- goto usage;
- case 11:
- if (parse_mem_mode(&shared->opt_mem_cycle_mode, optarg))
- goto usage;
- break;
- case 12:
- shared->opt_refresh_time = (unsigned int)atoi(optarg);
- break;
- case 13:
- shared->opt_file_size = (size_t)atol(optarg);
- }
- }
-
- if (!shared->opt_work_dir) {
- shared->opt_work_dir = getcwd(workdir, sizeof(workdir));
- if (!shared->opt_work_dir) {
- pr_perror("Can't fetch current working dir");
- exit(1);
- }
- shared->opt_work_dir = workdir;
- }
-
- if (shared->opt_mem_chunks > MAX_CHUNK)
- shared->opt_mem_chunks = MAX_CHUNK;
-
- if (shared->opt_files > MAX_CHUNK)
- shared->opt_files = MAX_CHUNK;
-
- shared->work_dir = opendir(shared->opt_work_dir);
- if (!shared->work_dir) {
- pr_perror("Can't open working dir `%s'",
- shared->opt_work_dir);
- exit(1);
- }
- shared->work_dir_fd = dirfd(shared->work_dir);
-
- shared->opt_mem_chunk_size = shared->opt_mem / shared->opt_mem_chunks;
-
- if (shared->opt_mem_chunk_size &&
- shared->opt_mem_chunk_size < PAGE_SIZE) {
- pr_err("Memory chunk size is too small, provide at least %lu M of memory\n",
- (shared->opt_mem_chunks * PAGE_SIZE) >> 20ul);
- exit(1);
- }
-
- for (i = 0; i < shared->opt_tasks; i++) {
- if (shared->err_no)
- goto err_child;
-
- pid = fork();
- if (pid < 0) {
- printf("Can't create fork: %m\n");
- exit(1);
- } else if (pid == 0) {
- work_on_fork(shared);
- }
- }
-
- /*
- * Once everything is done and we're in cycle,
- * create pidfile and go to sleep...
- */
- pid = sys_gettid();
- pidfd = openat(shared->work_dir_fd, "bers.pid", O_RDWR | O_CREAT | O_TRUNC, 0666);
- if (pidfd < 0) {
- pr_perror("Can't open pidfile");
- exit(1);
- }
- snprintf(pidbuf, sizeof(pidbuf), "%d", sys_gettid());
- write(pidfd, pidbuf, strlen(pidbuf));
- close(pidfd);
- pidfd = -1;
-
- /*
- * Endless!
- */
- while (!shared->err_no)
- sleep(1);
-
-err_child:
- pr_err("Child %d exited with %d\n",
- shared->err_pid, shared->err_no);
- return shared->err_no;
-
-usage:
- pr_msg("bers [options]\n");
- pr_msg(" -t|--tasks <num> create <num> of tasks\n");
- pr_msg(" -d|--dir <dir> use directory <dir> for temporary files\n");
- pr_msg(" -f|--files <num> create <num> files for each task\n");
- pr_msg(" -m|--memory <num> allocate <num> megabytes for each task\n");
- pr_msg(" --memory-chunks <num> split memory to <num> equal parts\n");
- pr_msg(" --mem-fill <mode> fill memory with data dependin on <mode>:\n");
- pr_msg(" all fill every byte of memory\n");
- pr_msg(" light fill first bytes of every page\n");
- pr_msg(" dirtify fill every page\n");
- pr_msg(" --mem-cycle <mode> same as --mem-fill but for cycling\n");
- pr_msg(" --refresh <second> refresh loading of every task each <second>\n");
- pr_msg(" --file-size <bytes> write <bytes> of data into each file on every refresh cycle\n");
-
- return 1;
-}
diff --git a/test/bers/bers.txt b/test/bers/bers.txt
deleted file mode 100644
index 17c0c08..0000000
--- a/test/bers/bers.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-bers(8)
-=======
-:doctype: manpage
-:man source: bers
-:man version: 0.0.1
-:man manual: bers manual
-
-NAME
-----
-bers - go berserk and eat computer resources
-
-SYNOPSIS
---------
-*bers* ['options']
-
-DESCRIPTION
------------
-*bers* is a command line utility aimed to eat resources of the computer it runs on.
-Idea behind is to create a number of tasks which would trash computer resources
-eating cpu and i/o time.
-
-OPTIONS
--------
-*-t*, *--tasks* 'num'::
- Create 'num' number of forks.
-
-*-d*, *--dir* 'dir'::
- Path to 'dir' directory where temporary files will be created to load
- I/O subsystem.
-
-*-f*, *--files* 'num'::
- Create 'num' files in each task.
-
-*-m*, *--memory* 'num'::
- Allocate 'num' megabytes of memory for every task.
-
-*--mem-chunks* 'num'::
- Allocate memory for each task not as one slab but split
- it into 'num' equal parts.
-
-*--mem-fill* 'mode'::
- Touch (write) into allocated memory once task is created. The
- 'mode' might be one of the following: 'all' -- write every
- single byte of the memory, 'light' -- write into first bytes
- of first page of the allocated memory chunk, 'dirtify' -- write
- into every page of every allocated chunk.
-
-*--mem-cycle* 'mode'::
- Same as *--mem-fill*, but 'mode' taken into account while
- task is cycling. By default each cycle initiated per one second.
-
-*--refresh* 'second'::
- Refresh load state of every task each 'second'. By refsresh
- here means to dirtify memory and file contents.
-
-*--file-size* 'bytes'::
- Write 'bytes' of data into each file on every refresh cycle.
-
-EXAMPLE
--------
-
-bers -d test/bers/dump -t 256 -m 54 -c 4 -f 200 --mem-fill dirtify --mem-cycle dirtify
-
-We generate 256 tasks wit each allocating 54 megabytes of memory splitted
-equally into 4 memory areas. Each task opens 200 files. On creation and
-cycling we touch every page of every memory area.
-
-AUTHOR
-------
-OpenVZ team.
-
-COPYRIGHT
----------
-Copyright \(C) 2014, Parallels Inc.
diff --git a/test/ext-links/Makefile b/test/ext-links/Makefile
deleted file mode 100644
index 6b32c25..0000000
--- a/test/ext-links/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-all: mvlink.so
-
-mvlink.so: mvlink.c
- gcc -g -Werror -Wall -shared -nostartfiles mvlink.c -o mvlink.so -iquote ../../include -fPIC
diff --git a/test/ext-links/addmv.sh b/test/ext-links/addmv.sh
deleted file mode 100755
index 0ccc971..0000000
--- a/test/ext-links/addmv.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-# $1 -- link name
-# $2 -- file with namespace pid
-if [ "$CRTOOLS_SCRIPT_ACTION" == "setup-namespaces" ]; then
- $(dirname $0)/addmv_raw.sh $1 $(cat $2)
-else
- exit 0
-fi
diff --git a/test/ext-links/addmv_raw.sh b/test/ext-links/addmv_raw.sh
deleted file mode 100755
index 224f243..0000000
--- a/test/ext-links/addmv_raw.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-# $1 -- link name
-# $2 -- pid of task in namespace
-set -x
-$ip link add link eth0 name $1 type macvlan || exit 1
-$ip link set $1 netns $2
diff --git a/test/ext-links/mvlink.c b/test/ext-links/mvlink.c
deleted file mode 100644
index a1c764d..0000000
--- a/test/ext-links/mvlink.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "criu-plugin.h"
-#include "criu-log.h"
-
-extern cr_plugin_init_t cr_plugin_init;
-extern cr_plugin_dump_ext_link_t cr_plugin_dump_ext_link;
-
-int cr_plugin_init(void)
-{
- pr_info("Initialized macvlan dumper\n");
- return 0;
-}
-
-int cr_plugin_dump_ext_link(int index, int type, char *kind)
-{
- if (strcmp(kind, "macvlan"))
- return -ENOTSUP;
- else {
- pr_info("Dump %d macvlan\n", index);
- return 0;
- }
-}
diff --git a/test/ext-links/run.sh b/test/ext-links/run.sh
deleted file mode 100755
index a48b73a..0000000
--- a/test/ext-links/run.sh
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/bin/bash
-
-ip=${CR_IP_TOOL:-ip}
-mvln="mv0"
-finf="finish"
-outf="ns_output"
-pidf="ns_pid"
-criu="../../criu/criu"
-
-export ip
-export mvln
-export finf
-export outf
-export pidf
-
-function fail {
- $ip link del $mvln
- touch $finf
- echo $@
- exit 1
-}
-
-# Build the mvlink plugin
-make
-
-set -x
-
-rm -f "$finf" "$outf" "$pidf"
-rm -rf "dump"
-
-# Unshare netns. The run_ns will exit once ns is spawned.
-unshare --net ./run_ns.sh
-nspid=$(cat $pidf)
-ps $nspid
-
-# Create and push macvlan device into it. CRIU doesn't support
-# macvlans treating them as external devices.
-./addmv_raw.sh $mvln $nspid || fail "Can't setup namespace"
-
-# Dump
-sleep 1
-mkdir dump
-$criu dump -t $nspid -D dump/ -o dump.log -v4 --lib $(pwd) || fail "Can't dump namespace"
-
-# Restore
-# Ask for the pid (shouldn't change, so just as an example), ask to call
-# script that will put macvlan device back into namespace
-sleep 1
-rm -f $pidf
-$criu restore -D dump/ -o restore.log -v4 --pidfile $(pwd)/$pidf --action-script "$(pwd)/addmv.sh $mvln $(pwd)/$pidf" -d || fail "Can't restore namespaces"
-
-# Finish and check results
-touch $finf
-set +x
-while ! egrep 'PASS|FAIL' $outf; do
- echo "Waiting"
- sleep 1
-done
diff --git a/test/ext-links/run_ns.sh b/test/ext-links/run_ns.sh
deleted file mode 100755
index 878f038..0000000
--- a/test/ext-links/run_ns.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-set -x
-echo "NS: $$" >> $outf
-echo "Links before:" >> $outf
-$ip link list >> $outf 2>&1
-# Detach from session, terminal and parent
-setsid ./run_wait.sh < /dev/null >> $outf 2>&1 &
-# Keep pid for future reference :)
-echo "$!" > $pidf
-exit 0
diff --git a/test/ext-links/run_wait.sh b/test/ext-links/run_wait.sh
deleted file mode 100755
index d600e37..0000000
--- a/test/ext-links/run_wait.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-echo "Wait: $$"
-while [ ! -e "$finf" ]; do
- echo "WAIT ($$)"
- sleep 1;
-done
-
-echo "Links after:"
-$ip link list
-
-# The mvln device (exported from run.sh) should exits in
-# namespace after we get restored
-echo "Check for $mvln:"
-$ip link list $mvln && echo "PASS" || echo "FAIL"
diff --git a/test/ext-tty/run.py b/test/ext-tty/run.py
deleted file mode 100755
index 16fe0f6..0000000
--- a/test/ext-tty/run.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import subprocess
-import pty
-import os, sys, time
-
-master, slave = pty.openpty()
-
-p = subprocess.Popen(["setsid", "--ctty", "sleep", "10000"],
- stdin = slave, stdout = slave, stderr = slave, close_fds = True)
-st = os.stat("/proc/self/fd/%d" % slave)
-ttyid = "tty[%x:%x]" % (st.st_rdev, st.st_dev)
-os.close(slave)
-time.sleep(1)
-
-ret = subprocess.Popen(["../../criu/criu", "dump", "-t", str(p.pid), "-v4", "--external", ttyid]).wait()
-if ret:
- sys.exit(ret)
-p.wait()
-
-new_master, slave = pty.openpty() # get another pty pair
-os.close(master)
-
-ttyid = "fd[%d]:tty[%x:%x]" % (slave, st.st_rdev, st.st_dev)
-
-ret = subprocess.Popen(["../../criu/criu", "restore", "-v4", "--inherit-fd", ttyid, "--restore-sibling", "--restore-detach"]).wait()
-if ret:
- sys.exit(ret)
-os.close(slave)
-os.waitpid(-1, os.WNOHANG) # is the process alive
-
-os.close(new_master)
-_, status = os.wait()
-if not os.WIFSIGNALED(status) or not os.WTERMSIG(status):
- print status
- sys.exit(1)
-
-print "PASS"
diff --git a/test/fault-injection/Makefile b/test/fault-injection/Makefile
deleted file mode 100644
index 1b31e8a..0000000
--- a/test/fault-injection/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-all:
- stap -g -d ../../criu/criu parasite.stp $$RANDOM -c 'bash -x ../zdtm.sh -d -x socket-tcp'
diff --git a/test/fault-injection/parasite.stp b/test/fault-injection/parasite.stp
deleted file mode 100644
index c1b0818..0000000
--- a/test/fault-injection/parasite.stp
+++ /dev/null
@@ -1,44 +0,0 @@
-global i, n, fini_cmd = -1, last_cmd
-
-probe process("../../criu/criu").begin
-{
- i = 0;
- /* randint() returns numbers multiple of 5 */
- n = randint(20 * 5) / 5
- printf("The %d command will be replaced on -1\n", n);
-}
-
-probe process("../../criu/criu").function("__parasite_execute_daemon")
-{
- printf("%s\n", $$parms);
- last_cmd = $cmd;
- if (++i > n) {
- printf("Send invalid command to parasite\n");
- $cmd = -1;
- }
-}
-
-probe process("../../criu/criu").function("__parasite_execute_daemon").return
-{
- printf("%d\n", $return);
-}
-
-probe process("../../criu/criu").function("main").return
-{
- printf("CRIU exits with code %d\n", $return);
- if ( i > n) {
- if ($return)
- $return = 0;
- else {
- printf("CRIU exited with zero code\n");
- if (fini_cmd < 0 || fini_cmd == last_cmd) {
- printf("%d looks like FINI command\n", n);
- fini_cmd = last_cmd
- } else {
- printf("This is the second FINI command %d (%d)",
- n, fini_cmd);
- $return = 1;
- }
- }
- }
-}
diff --git a/test/libcriu/.gitignore b/test/libcriu/.gitignore
deleted file mode 100644
index 6424681..0000000
--- a/test/libcriu/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-test_errno
-test_iters
-test_notify
-test_self
-test_sub
-wdir
diff --git a/test/libcriu/Makefile b/test/libcriu/Makefile
deleted file mode 100644
index 459ae61..0000000
--- a/test/libcriu/Makefile
+++ /dev/null
@@ -1,26 +0,0 @@
-TESTS += test_sub
-TESTS += test_self
-TESTS += test_notify
-TESTS += test_iters
-TESTS += test_errno
-
-all: $(TESTS)
-
-run: all
- ./run.sh
-
-define genb
-$(1): $(1).o lib.o
- gcc $$^ -L ../../lib -L ../../protobuf -lcriu -o $$@
-endef
-
-$(foreach t, $(TESTS), $(eval $(call genb, $(t))))
-
-%.o: %.c
- gcc -c $^ -I../../lib/ -I../../protobuf -o $@ -Werror
-
-clean:
- rm -rf $(TESTS) $(TESTS:%=%.o) lib.o
-
-.PHONY: clean
-.PHONY: all
diff --git a/test/libcriu/lib.c b/test/libcriu/lib.c
deleted file mode 100644
index 33aa409..0000000
--- a/test/libcriu/lib.c
+++ /dev/null
@@ -1,47 +0,0 @@
-#include <stdio.h>
-#include <errno.h>
-#include <sys/wait.h>
-
-void what_err_ret_mean(int ret)
-{
- /* NOTE: errno is set by libcriu */
- switch (ret) {
- case -EBADE:
- perror("RPC has returned fail");
- break;
- case -ECONNREFUSED:
- perror("Unable to connect to CRIU");
- break;
- case -ECOMM:
- perror("Unable to send/recv msg to/from CRIU");
- break;
- case -EINVAL:
- perror("CRIU doesn't support this type of request."
- "You should probably update CRIU");
- break;
- case -EBADMSG:
- perror("Unexpected response from CRIU."
- "You should probably update CRIU");
- break;
- default:
- perror("Unknown error type code."
- "You should probably update CRIU");
- }
-}
-
-int chk_exit(int status, int want)
-{
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) == want)
- return 0;
-
- printf(" `- FAIL (exit %d)\n", WEXITSTATUS(status));
- } else if (WIFSIGNALED(status))
- printf(" `- FAIL (die %d)\n", WTERMSIG(status));
- else
- printf(" `- FAIL (%#x)\n", status);
-
- return 1;
-}
-
-
diff --git a/test/libcriu/lib.h b/test/libcriu/lib.h
deleted file mode 100644
index 67b784b..0000000
--- a/test/libcriu/lib.h
+++ /dev/null
@@ -1,2 +0,0 @@
-void what_err_ret_mean(int ret);
-int chk_exit(int status, int want);
diff --git a/test/libcriu/run.sh b/test/libcriu/run.sh
deleted file mode 100755
index 51ed141..0000000
--- a/test/libcriu/run.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/bash
-
-source ../env.sh || exit 1
-
-echo "== Clean"
-make clean
-rm -rf wdir
-rm -f ./libcriu.so.1
-
-echo "== Prepare"
-mkdir -p wdir/i/
-
-echo "== Run tests"
-ln -s ../../lib/libcriu.so libcriu.so.1
-export LD_LIBRARY_PATH=.
-export PATH="`dirname ${BASH_SOURCE[0]}`/../../:$PATH"
-
-RESULT=0
-
-function run_test {
- echo "== Build $1"
- if ! make $1; then
- echo "FAIL build $1"
- RESULT=1;
- else
- echo "== Test $1"
- mkdir wdir/i/$1/
- if ! setsid ./$1 ${CRIU} wdir/i/$1/ < /dev/null &>> wdir/i/$1/test.log; then
- echo "$1: FAIL"
- RESULT=1
- fi
- fi
-}
-
-run_test test_sub
-run_test test_self
-run_test test_notify
-run_test test_iters
-run_test test_errno
-
-echo "== Tests done"
-unlink libcriu.so.1
-[ $RESULT -eq 0 ] && echo "Success" || echo "FAIL"
-exit $RESULT
diff --git a/test/libcriu/test_errno.c b/test/libcriu/test_errno.c
deleted file mode 100644
index e091443..0000000
--- a/test/libcriu/test_errno.c
+++ /dev/null
@@ -1,154 +0,0 @@
-#include "criu.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-
-#define PID_MAX "/proc/sys/kernel/pid_max"
-
-static int dir_fd;
-static char *service;
-
-static int init(char *argv[])
-{
- service = argv[1];
-
- dir_fd = open(argv[2], O_DIRECTORY);
- if (dir_fd < 0) {
- perror("Can't open images dir");
- return -1;
- }
-
- return 0;
-}
-
-static void get_base_req(void)
-{
- criu_init_opts();
- criu_set_service_binary(service);
- criu_set_images_dir_fd(dir_fd);
- criu_set_log_level(4);
-}
-
-static int check_resp(int ret, int expected_ret, int err, int expected_err)
-{
- if (ret != expected_ret) {
- fprintf(stderr, "Unexpected ret %d (%d expected)\n", ret, expected_ret);
- return -1;
- }
-
- if (err != expected_err) {
- fprintf(stderr, "Unexpected errno %d (%d expected)\n", err, expected_err);
- return -1;
- }
-
- return 0;
-}
-
-static int no_process(void)
-{
- FILE *f = NULL;
- size_t len;
- ssize_t count;
- char *buf = NULL;
- int pid, fd, ret;
-
- printf("--- Try to dump unexisting process\n");
-
- f = fopen(PID_MAX, "r");
- if (!f) {
- perror("Can't open " PID_MAX);
- goto err;
- }
-
- count = getline(&buf, &len, f);
- if (count == -1) {
- perror("Can't read " PID_MAX);
- goto err;
- }
- pid = atoi(buf);
-
- if (!kill(pid, 0)) {
- fprintf(stderr, "max pid is taken\n");
- goto err;
- }
-
- get_base_req();
- criu_set_pid(pid);
- ret = criu_dump();
- if (check_resp(ret, -EBADE, errno, ESRCH))
- goto err;
-
- printf(" `- Success\n");
- return 0;
-err:
- if (f)
- fclose(f);
- return -1;
-
-}
-
-static int process_exists(void)
-{
- int ret;
-
- printf("--- Try to restore process which pid is already taken by other process\n");
-
- get_base_req();
- criu_set_leave_running(true);
- if (criu_dump()) {
- fprintf(stderr, "Self-dump failed");
- goto err;
- }
-
- get_base_req();
- ret = criu_restore();
- if (check_resp(ret, -EBADE, errno, EEXIST))
- goto err;
-
- printf(" `- Success\n");
- return 0;
-err:
- return -1;
-}
-
-static int bad_options(void)
-{
- int ret;
-
- printf("--- Try to send criu invalid opts\n");
-
- get_base_req();
- criu_set_log_file("../file.log");
- ret = criu_dump();
- if (check_resp(ret, -EBADE, errno, EBADRQC))
- goto err;
-
- printf(" `- Success\n");
- return 0;
-err:
- return -1;
-}
-
-int main(int argc, char *argv[])
-{
- int ret = 1;
-
- if (init(argv))
- goto out;
-
- if (no_process() || process_exists() || bad_options())
- goto out;
-
- ret = 0;
-out:
- if (dir_fd)
- close(dir_fd);
-
- return ret;
-}
diff --git a/test/libcriu/test_iters.c b/test/libcriu/test_iters.c
deleted file mode 100644
index 660da92..0000000
--- a/test/libcriu/test_iters.c
+++ /dev/null
@@ -1,143 +0,0 @@
-#include "criu.h"
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include "lib.h"
-
-static int wdir_fd, cur_iter = 1, cur_imgdir = -1;
-
-static int stop = 0;
-static void sh(int sig)
-{
- stop = 1;
-}
-
-static int open_imgdir(void)
-{
- char p[10];
-
- sprintf(p, "%d", cur_iter);
- mkdirat(wdir_fd, p, 0700);
- cur_imgdir = openat(wdir_fd, p, O_DIRECTORY);
- criu_set_images_dir_fd(cur_imgdir);
-}
-
-#define MAX_ITERS 2
-
-static int next_iter(criu_predump_info pi)
-{
- char p[10];
-
- printf(" `- %d iter over\n", cur_iter);
-
- close(cur_imgdir);
- sprintf(p, "../%d", cur_iter);
- criu_set_parent_images(p);
-
- cur_iter++;
- open_imgdir();
-
- return cur_iter < MAX_ITERS;
-}
-
-#define SUCC_ECODE 42
-
-int main(int argc, char **argv)
-{
- int pid, ret, p[2];
-
- wdir_fd = open(argv[2], O_DIRECTORY);
- if (wdir_fd < 0) {
- perror("Can't open wdir");
- return 1;
- }
-
- printf("--- Start loop ---\n");
- pipe(p);
- pid = fork();
- if (pid < 0) {
- perror("Can't");
- return -1;
- }
-
- if (!pid) {
- printf(" `- loop: initializing\n");
- if (setsid() < 0)
- exit(1);
- if (signal(SIGUSR1, sh) == SIG_ERR)
- exit(1);
-
- close(0);
- close(1);
- close(2);
- close(p[0]);
-
- ret = SUCC_ECODE;
- write(p[1], &ret, sizeof(ret));
- close(p[1]);
-
- while (!stop)
- sleep(1);
- exit(SUCC_ECODE);
- }
-
- close(p[1]);
-
- /* Wait for kid to start */
- ret = -1;
- read(p[0], &ret, sizeof(ret));
- if (ret != SUCC_ECODE) {
- printf("Error starting loop\n");
- goto err;
- }
-
- /* Wait for pipe to get closed, then dump */
- read(p[0], &ret, 1);
- close(p[0]);
-
- printf("--- Dump loop ---\n");
- criu_init_opts();
- criu_set_service_binary(argv[1]);
- criu_set_pid(pid);
- criu_set_log_file("dump.log");
- criu_set_log_level(4);
-
- open_imgdir();
- ret = criu_dump_iters(next_iter);
- if (ret < 0) {
- what_err_ret_mean(ret);
- kill(pid, SIGKILL);
- goto err;
- }
-
- printf(" `- Dump succeeded\n");
- waitpid(pid, NULL, 0);
-
- printf("--- Restore loop ---\n");
- criu_init_opts();
- criu_set_log_level(4);
- criu_set_log_file("restore.log");
- criu_set_images_dir_fd(cur_imgdir);
-
- pid = criu_restore_child();
- if (pid <= 0) {
- what_err_ret_mean(pid);
- return -1;
- }
-
- printf(" `- Restore returned pid %d\n", pid);
- kill(pid, SIGUSR1);
-err:
- if (waitpid(pid, &ret, 0) < 0) {
- perror(" Can't wait kid");
- return -1;
- }
-
- return chk_exit(ret, SUCC_ECODE);
-}
diff --git a/test/libcriu/test_notify.c b/test/libcriu/test_notify.c
deleted file mode 100644
index 54fb255..0000000
--- a/test/libcriu/test_notify.c
+++ /dev/null
@@ -1,97 +0,0 @@
-#include "criu.h"
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "lib.h"
-
-#define SUCC_ECODE 42
-
-static int actions_called = 0;
-static int notify(char *action, criu_notify_arg_t na)
-{
- printf("ACTION: %s\n", action);
- actions_called++;
- return 0;
-}
-
-int main(int argc, char **argv)
-{
- int pid, ret, fd, p[2];
-
- printf("--- Start loop ---\n");
- pipe(p);
- pid = fork();
- if (pid < 0) {
- perror("Can't");
- return -1;
- }
-
- if (!pid) {
- printf(" `- loop: initializing\n");
- if (setsid() < 0)
- exit(1);
-
- close(0);
- close(1);
- close(2);
- close(p[0]);
-
- ret = SUCC_ECODE;
- write(p[1], &ret, sizeof(ret));
- close(p[1]);
-
- while (1)
- sleep(1);
-
- exit(SUCC_ECODE);
- }
-
- close(p[1]);
-
- /* Wait for kid to start */
- ret = -1;
- read(p[0], &ret, sizeof(ret));
- if (ret != SUCC_ECODE) {
- printf("Error starting loop\n");
- goto err;
- }
-
- /* Wait for pipe to get closed, then dump */
- read(p[0], &ret, 1);
- close(p[0]);
-
- printf("--- Dump loop ---\n");
- criu_init_opts();
- criu_set_service_binary(argv[1]);
- criu_set_pid(pid);
- criu_set_log_file("dump.log");
- criu_set_log_level(4);
- criu_set_notify_cb(notify);
- fd = open(argv[2], O_DIRECTORY);
- criu_set_images_dir_fd(fd);
-
- ret = criu_dump();
- if (ret < 0) {
- what_err_ret_mean(ret);
- kill(pid, SIGKILL);
- goto err;
- }
-
- printf(" `- Dump succeeded\n");
- ret = 0;
-err:
- waitpid(pid, NULL, 0);
- if (ret || !actions_called) {
- printf("FAIL (%d/%d)\n", ret, actions_called);
- return 1;
- }
-
- printf(" `- Success (%d actions)\n", actions_called);
- return 0;
-}
diff --git a/test/libcriu/test_self.c b/test/libcriu/test_self.c
deleted file mode 100644
index c9d2a2e..0000000
--- a/test/libcriu/test_self.c
+++ /dev/null
@@ -1,96 +0,0 @@
-#include "criu.h"
-#include <unistd.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include "lib.h"
-
-#define SUCC_DUMP_ECODE 41
-#define SUCC_RSTR_ECODE 43
-
-int main(int argc, char *argv[])
-{
- int ret, fd, pid;
-
- fd = open(argv[2], O_DIRECTORY);
- if (fd < 0) {
- perror("Can't open images dir");
- return 1;
- }
-
- criu_init_opts();
- criu_set_service_binary(argv[1]);
- criu_set_images_dir_fd(fd);
- criu_set_log_level(4);
-
- printf("--- Start child ---\n");
- pid = fork();
- if (pid < 0) {
- perror("Can't");
- return 1;
- }
-
- if (!pid) {
- /*
- * Child process -- dump itself, then
- * parent would restore us.
- */
-
- close(0);
- close(1);
- close(2);
- if (setsid() < 0)
- exit(1);
-
- criu_set_log_file("dump.log");
- criu_set_leave_running(true);
- ret = criu_dump();
- if (ret < 0) {
- what_err_ret_mean(ret);
- exit(1);
- }
-
- if (ret == 0)
- ret = SUCC_DUMP_ECODE; /* dumped OK */
- else if (ret == 1)
- ret = SUCC_RSTR_ECODE; /* restored OK */
- else
- ret = 1;
-
- exit(ret);
- }
-
- printf("--- Wait for self-dump ---\n");
- if (waitpid(pid, &ret, 0) < 0) {
- perror("Can't wait child");
- goto errk;
- }
-
- if (chk_exit(ret, SUCC_DUMP_ECODE))
- goto errk;
-
- printf("--- Restore ---\n");
- criu_set_log_file("restore.log");
-
- pid = criu_restore_child();
- if (pid <= 0) {
- what_err_ret_mean(pid);
- goto err;
- }
-
- if (waitpid(pid, &ret, 0) < 0) {
- perror("Can't wait rchild");
- goto errk;
- }
-
- return chk_exit(ret, SUCC_RSTR_ECODE);
-
-errk:
- kill(pid, SIGKILL);
-err:
- return 1;
-
-}
diff --git a/test/libcriu/test_sub.c b/test/libcriu/test_sub.c
deleted file mode 100644
index b435f67..0000000
--- a/test/libcriu/test_sub.c
+++ /dev/null
@@ -1,107 +0,0 @@
-#include "criu.h"
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include "lib.h"
-
-static int stop = 0;
-static void sh(int sig)
-{
- stop = 1;
-}
-
-#define SUCC_ECODE 42
-
-int main(int argc, char **argv)
-{
- int pid, ret, fd, p[2];
-
- printf("--- Start loop ---\n");
- pipe(p);
- pid = fork();
- if (pid < 0) {
- perror("Can't");
- return -1;
- }
-
- if (!pid) {
- printf(" `- loop: initializing\n");
- if (setsid() < 0)
- exit(1);
- if (signal(SIGUSR1, sh) == SIG_ERR)
- exit(1);
-
- close(0);
- close(1);
- close(2);
- close(p[0]);
-
- ret = SUCC_ECODE;
- write(p[1], &ret, sizeof(ret));
- close(p[1]);
-
- while (!stop)
- sleep(1);
- exit(SUCC_ECODE);
- }
-
- close(p[1]);
-
- /* Wait for kid to start */
- ret = -1;
- read(p[0], &ret, sizeof(ret));
- if (ret != SUCC_ECODE) {
- printf("Error starting loop\n");
- goto err;
- }
-
- /* Wait for pipe to get closed, then dump */
- read(p[0], &ret, 1);
- close(p[0]);
-
- printf("--- Dump loop ---\n");
- criu_init_opts();
- criu_set_service_binary(argv[1]);
- criu_set_pid(pid);
- criu_set_log_file("dump.log");
- criu_set_log_level(4);
- fd = open(argv[2], O_DIRECTORY);
- criu_set_images_dir_fd(fd);
-
- ret = criu_dump();
- if (ret < 0) {
- what_err_ret_mean(ret);
- kill(pid, SIGKILL);
- goto err;
- }
-
- printf(" `- Dump succeeded\n");
- waitpid(pid, NULL, 0);
-
- printf("--- Restore loop ---\n");
- criu_init_opts();
- criu_set_log_level(4);
- criu_set_log_file("restore.log");
- criu_set_images_dir_fd(fd);
-
- pid = criu_restore_child();
- if (pid <= 0) {
- what_err_ret_mean(pid);
- return -1;
- }
-
- printf(" `- Restore returned pid %d\n", pid);
- kill(pid, SIGUSR1);
-err:
- if (waitpid(pid, &ret, 0) < 0) {
- perror(" Can't wait kid");
- return -1;
- }
-
- return chk_exit(ret, SUCC_ECODE);
-}
diff --git a/test/mem-snap/Makefile b/test/mem-snap/Makefile
deleted file mode 100644
index 7779a99..0000000
--- a/test/mem-snap/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-run:
- ./run.sh
diff --git a/test/mem-snap/run-predump-2.sh b/test/mem-snap/run-predump-2.sh
deleted file mode 100755
index 2717cde..0000000
--- a/test/mem-snap/run-predump-2.sh
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/bash
-
-source ../env.sh || exit 1
-
-function fail {
- echo "$@"
- exit 1
-}
-set -x
-
-IMGDIR="dump/"
-
-rm -rf "$IMGDIR"
-mkdir "$IMGDIR"
-
-function launch_test {
- echo "Launching test"
- cd ../zdtm/live/static/
- make cleanout
- make maps04
- make maps04.pid || fail "Can't start test"
- PID=$(cat maps04.pid)
- kill -0 $PID || fail "Test didn't start"
- cd -
-}
-
-function stop_test {
- wtime=1
- cd ../zdtm/live/static/
- make maps04.stop
- cat maps04.out | fgrep PASS || fail "Test failed"
- echo "OK"
-}
-
-launch_test
-
-echo "Taking plain dump"
-
-mkdir "$IMGDIR/dump-1/"
-${CRIU} dump -D "$IMGDIR/dump-1/" -o dump.log -t ${PID} -v4 || fail "Fail to dump"
-
-sleep 1
-echo "Restore to check it works"
-${CRIU} restore -D "${IMGDIR}/dump-1/" -o restore.log -d -v4 || fail "Fail to restore server"
-
-stop_test
-
-
-launch_test
-
-echo "Taking pre and plain dumps"
-
-echo "Pre-dump"
-mkdir "$IMGDIR/dump-2/"
-mkdir "$IMGDIR/dump-2/pre/"
-${CRIU} pre-dump -D "$IMGDIR/dump-2/pre/" -o dump.log -t ${PID} -v4 || fail "Fail to pre-dump"
-
-echo "Plain dump"
-mkdir "$IMGDIR/dump-2/plain/"
-${CRIU} dump -D "$IMGDIR/dump-2/plain/" -o dump.log -t ${PID} -v4 --prev-images-dir=../pre/ --track-mem || fail "Fail to dump"
-
-sleep 1
-echo "Restore"
-${CRIU} restore -D "${IMGDIR}/dump-2/plain/" -o restore.log -d -v4 || fail "Fail to restore server"
-
-stop_test
diff --git a/test/mem-snap/run-predump.sh b/test/mem-snap/run-predump.sh
deleted file mode 100755
index e25ccfd..0000000
--- a/test/mem-snap/run-predump.sh
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/bin/bash
-
-source ../env.sh || exit 1
-
-USEPS=0
-
-if [ "$1" = "-s" ]; then
- echo "Will test via page-server"
- USEPS=1
- shift
-fi
-
-NRSNAP=${1:-3}
-SPAUSE=${2:-4}
-PORT=12345
-
-function fail {
- echo "$@"
- exit 1
-}
-set -x
-
-IMGDIR="dump/"
-
-rm -rf "$IMGDIR"
-mkdir "$IMGDIR"
-
-echo "Launching test"
-cd ../zdtm/live/static/
-make cleanout
-make mem-touch
-make mem-touch.pid || fail "Can't start test"
-PID=$(cat mem-touch.pid)
-kill -0 $PID || fail "Test didn't start"
-cd -
-
-echo "Making $NRSNAP pre-dumps"
-
-for SNAP in $(seq 1 $NRSNAP); do
- sleep $SPAUSE
- mkdir "$IMGDIR/$SNAP/"
- if [ $SNAP -eq 1 ] ; then
- # First pre-dump
- cmd="pre-dump"
- args="--track-mem -R"
- elif [ $SNAP -eq $NRSNAP ]; then
- # Last dump
- cmd="dump"
- args="--prev-images-dir=../$((SNAP - 1))/ --track-mem"
- else
- # Other pre-dumps
- cmd="pre-dump"
- args="--prev-images-dir=../$((SNAP - 1))/ --track-mem -R"
- fi
-
- if [ $USEPS -eq 1 ]; then
- ${CRIU} page-server -D "${IMGDIR}/$SNAP/" -o ps.log --port ${PORT} -v4 &
- PS_PID=$!
- ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
- else
- ps_args=""
- fi
-
- ${CRIU} $cmd -D "${IMGDIR}/$SNAP/" -o dump.log -t ${PID} -v4 $args $ps_args || fail "Fail to dump"
- if [ $USEPS -eq 1 ]; then
- wait $PS_PID
- fi
-done
-
-echo "Restoring"
-${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log -d -v4 || fail "Fail to restore server"
-
-cd ../zdtm/live/static/
-make mem-touch.stop
-cat mem-touch.out | fgrep PASS || fail "Test failed"
-
-echo "Test PASSED"
diff --git a/test/mem-snap/run-snap-auto-dedup.sh b/test/mem-snap/run-snap-auto-dedup.sh
deleted file mode 100755
index f4eb119..0000000
--- a/test/mem-snap/run-snap-auto-dedup.sh
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/bin/bash
-
-source ../env.sh || exit 1
-
-USEPS=0
-
-if [ "$1" = "-s" ]; then
- echo "Will test via page-server"
- USEPS=1
- shift
-fi
-
-NRSNAP=${1:-3}
-SPAUSE=${2:-4}
-PORT=12345
-
-function fail {
- echo "$@"
- exit 1
-}
-set -x
-
-IMGDIR="dump/"
-
-rm -rf "$IMGDIR"
-mkdir "$IMGDIR"
-
-echo "Launching test"
-cd ../zdtm/live/static/
-make cleanout
-make mem-touch
-make mem-touch.pid || fail "Can't start test"
-PID=$(cat mem-touch.pid)
-kill -0 $PID || fail "Test didn't start"
-cd -
-
-echo "Making $NRSNAP snapshots"
-
-for SNAP in $(seq 1 $NRSNAP); do
- sleep $SPAUSE
- mkdir "$IMGDIR/$SNAP/"
- if [ $SNAP -eq 1 ] ; then
- # First snapshot -- no parent, keep running
- args="--track-mem -R"
- elif [ $SNAP -eq $NRSNAP ]; then
- # Last snapshot -- has parent, kill afterwards
- size_first_2=$(du -sh -BK dump/2/pages-*.img | grep -Eo '[0-9]+' | head -1)
- size_first_1=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
- args="--prev-images-dir=../$((SNAP - 1))/ --track-mem --auto-dedup"
- else
- # Other snapshots -- have parent, keep running
- args="--prev-images-dir=../$((SNAP - 1))/ --track-mem -R"
- fi
-
- if [ $USEPS -eq 1 ]; then
- ${CRIU} page-server -D "${IMGDIR}/$SNAP/" -o ps.log --auto-dedup --port ${PORT} -v4 &
- PS_PID=$!
- ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
- else
- ps_args=""
- fi
-
- ${CRIU} dump -D "${IMGDIR}/$SNAP/" -o dump.log -t ${PID} -v4 $args $ps_args || fail "Fail to dump"
- if [ $USEPS -eq 1 ]; then
- wait $PS_PID
- fi
-done
-
-size_last_2=$(du -sh -BK dump/2/pages-*.img | grep -Eo '[0-9]+' | head -1)
-size_last_1=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
-
-dedup_ok_2=1
-if [ $size_first_2 -gt $size_last_2 ]; then
- dedup_ok_2=0
-fi
-
-dedup_ok_1=1
-if [ $size_first_1 -gt $size_last_1 ]; then
- dedup_ok_1=0
-fi
-
-echo "Restoring"
-${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log -d -v4 || fail "Fail to restore server"
-
-cd ../zdtm/live/static/
-make mem-touch.stop
-cat mem-touch.out | fgrep PASS || fail "Test failed"
-
-if [[ $dedup_ok_2 -ne 0 || $dedup_ok_1 -ne 0 ]]; then
- fail "Dedup test failed"
-fi
-
-echo "Test PASSED"
diff --git a/test/mem-snap/run-snap-dedup-on-restore.sh b/test/mem-snap/run-snap-dedup-on-restore.sh
deleted file mode 100755
index 7bfdf0e..0000000
--- a/test/mem-snap/run-snap-dedup-on-restore.sh
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/bin/bash
-
-source ../env.sh || exit 1
-
-USEPS=0
-
-if [ "$1" = "-s" ]; then
- echo "Will test via page-server"
- USEPS=1
- shift
-fi
-
-NRSNAP=${1:-3}
-SPAUSE=${2:-4}
-PORT=12345
-
-function fail {
- echo "$@"
- exit 1
-}
-set -x
-
-IMGDIR="dump/"
-
-rm -rf "$IMGDIR"
-mkdir "$IMGDIR"
-
-echo "Launching test"
-cd ../zdtm/live/static/
-make cleanout
-make mem-touch
-make mem-touch.pid || fail "Can't start test"
-PID=$(cat mem-touch.pid)
-kill -0 $PID || fail "Test didn't start"
-cd -
-
-echo "Making $NRSNAP snapshots"
-
-for SNAP in $(seq 1 $NRSNAP); do
- sleep $SPAUSE
- mkdir "$IMGDIR/$SNAP/"
- if [ $SNAP -eq 1 ] ; then
- # First snapshot -- no parent, keep running
- args="--track-mem -R"
- elif [ $SNAP -eq $NRSNAP ]; then
- # Last snapshot -- has parent, kill afterwards
- args="--prev-images-dir=../$((SNAP - 1))/ --track-mem --auto-dedup"
- else
- # Other snapshots -- have parent, keep running
- args="--prev-images-dir=../$((SNAP - 1))/ --track-mem -R --auto-dedup"
- fi
-
- if [ $USEPS -eq 1 ]; then
- ${CRIU} page-server -D "${IMGDIR}/$SNAP/" -o ps.log --auto-dedup --port ${PORT} -v4 &
- PS_PID=$!
- ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
- else
- ps_args=""
- fi
-
- ${CRIU} dump -D "${IMGDIR}/$SNAP/" -o dump.log -t ${PID} -v4 $args $ps_args || fail "Fail to dump"
- if [ $USEPS -eq 1 ]; then
- wait $PS_PID
- fi
-done
-
-echo "Restoring"
-${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log --auto-dedup -d -v4 || fail "Fail to restore server"
-
-size_last3=$(du -sh -BK dump/3/pages-*.img | grep -Eo '[0-9]+' | head -1)
-size_last2=$(du -sh -BK dump/2/pages-*.img | grep -Eo '[0-9]+' | head -1)
-size_last1=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
-
-restore_dedup_ok=0
-if [[ $size_last1 -ne 0 || $size_last2 -ne 0 || $size_last3 -ne 0 ]]; then
- restore_dedup_ok=1
-fi
-
-cd ../zdtm/live/static/
-make mem-touch.stop
-cat mem-touch.out | fgrep PASS || fail "Test failed"
-
-if [ $restore_dedup_ok -ne 0 ]; then
- fail "Dedup test failed"
-fi
-
-echo "Test PASSED"
diff --git a/test/mem-snap/run-snap-dedup.sh b/test/mem-snap/run-snap-dedup.sh
deleted file mode 100755
index 762e202..0000000
--- a/test/mem-snap/run-snap-dedup.sh
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/bin/bash
-
-source ../env.sh || exit 1
-
-USEPS=0
-
-if [ "$1" = "-s" ]; then
- echo "Will test via page-server"
- USEPS=1
- shift
-fi
-
-NRSNAP=${1:-3}
-SPAUSE=${2:-4}
-PORT=12345
-
-function fail {
- echo "$@"
- exit 1
-}
-set -x
-
-IMGDIR="dump/"
-
-rm -rf "$IMGDIR"
-mkdir "$IMGDIR"
-
-echo "Launching test"
-cd ../zdtm/live/static/
-make cleanout
-make mem-touch
-make mem-touch.pid || fail "Can't start test"
-PID=$(cat mem-touch.pid)
-kill -0 $PID || fail "Test didn't start"
-cd -
-
-echo "Making $NRSNAP snapshots"
-
-for SNAP in $(seq 1 $NRSNAP); do
- sleep $SPAUSE
- mkdir "$IMGDIR/$SNAP/"
- if [ $SNAP -eq 1 ] ; then
- # First snapshot -- no parent, keep running
- args="--track-mem -R"
- elif [ $SNAP -eq $NRSNAP ]; then
- # Last snapshot -- has parent, kill afterwards
- args="--prev-images-dir=../$((SNAP - 1))/ --track-mem"
- else
- # Other snapshots -- have parent, keep running
- args="--prev-images-dir=../$((SNAP - 1))/ --track-mem -R"
- fi
-
- if [ $USEPS -eq 1 ]; then
- ${CRIU} page-server -D "${IMGDIR}/$SNAP/" -o ps.log --port ${PORT} -v4 &
- PS_PID=$!
- ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
- else
- ps_args=""
- fi
-
- ${CRIU} dump -D "${IMGDIR}/$SNAP/" -o dump.log -t ${PID} -v4 $args $ps_args || fail "Fail to dump"
- if [ $USEPS -eq 1 ]; then
- wait $PS_PID
- fi
-done
-
-echo "Dedup test"
-
-size_first_2=$(du -sh -BK dump/2/pages-*.img | grep -Eo '[0-9]+' | head -1)
-size_first_1=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
-
-${CRIU} dedup -D "${IMGDIR}/$NRSNAP/"
-
-size_last_2=$(du -sh -BK dump/2/pages-*.img | grep -Eo '[0-9]+' | head -1)
-size_last_1=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
-
-dedup_ok_2=1
-dedup_ok_1=1
-
-if [ $size_first_2 -gt $size_last_2 ]; then
- dedup_ok_2=0
-fi
-
-if [ $size_first_1 -gt $size_last_1 ]; then
- dedup_ok_1=0
-fi
-
-echo "Restoring"
-${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log -d -v4 || fail "Fail to restore server"
-
-cd ../zdtm/live/static/
-make mem-touch.stop
-cat mem-touch.out | fgrep PASS || fail "Test failed"
-
-if [[ $dedup_ok_2 -ne 0 || $dedup_ok_1 -ne 0 ]]; then
- fail "Dedup test failed"
-fi
-
-echo "Test PASSED"
diff --git a/test/mem-snap/run-snap-maps04.sh b/test/mem-snap/run-snap-maps04.sh
deleted file mode 100755
index 5bd75f3..0000000
--- a/test/mem-snap/run-snap-maps04.sh
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/bash
-
-source ../env.sh || exit 1
-
-USEPS=0
-
-if [ "$1" = "-s" ]; then
- echo "Will test via page-server"
- USEPS=1
- shift
-fi
-
-NRSNAP=1
-SPAUSE=${2:-4}
-PORT=12345
-
-function fail {
- echo "$@"
- exit 1
-}
-set -x
-
-IMGDIR="dump"
-CURDIR=${pwd}
-if ! mount | fgrep "$CURDIR/$IMGDIR" ; then
- rm -rf "$IMGDIR"
- mkdir "$IMGDIR"
-
- mount -t tmpfs -o size=1500M,nr_inodes=10k,mode=700 tmpfs $IMGDIR
-fi
-rm -rf "$IMGDIR/*"
-
-echo "Launching test"
-make -C ../zdtm/live/static/ cleanout
-make -C ../zdtm/live/static/ maps04
-make -C ../zdtm/live/static/ maps04.pid || fail "Can't start test"
-PID=$(cat ../zdtm/live/static/maps04.pid)
-kill -0 $PID || fail "Test haven't started"
-
-mkdir "$IMGDIR/$NRSNAP/"
-
-if [ $USEPS -eq 1 ] ; then
- ${CRIU} page-server -D "${IMGDIR}/$NRSNAP/" -o ps.log --port ${PORT} -d -v4 #&
- PS_PID=$!
- ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
-else
- ps_args=""
-fi
-
-${CRIU} dump -D "${IMGDIR}/$NRSNAP/" -o dump.log -t ${PID} -v4 $ps_args || fail "Fail to dump"
-if [ $USEPS -eq 1 ] ; then
- wait $PS_PID
-fi
-
-echo "Restoring"
-${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log --auto-dedup -d -v4 || fail "Fail to restore"
-
-make -C ../zdtm/live/static/ maps04.stop
-sleep 1
-
-cat "../zdtm/live/static/maps04.out" | fgrep PASS || fail "Test failed"
-
-size=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
-if [ $size -ne 0 ] ; then
- fail "Size not null"
-fi
-
-echo "Test PASSED"
diff --git a/test/mem-snap/run-snap.sh b/test/mem-snap/run-snap.sh
deleted file mode 100755
index 38496a2..0000000
--- a/test/mem-snap/run-snap.sh
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/bin/bash
-
-source ../env.sh || exit 1
-
-USEPS=0
-
-if [ "$1" = "-s" ]; then
- echo "Will test via page-server"
- USEPS=1
- shift
-fi
-
-NRSNAP=${1:-3}
-SPAUSE=${2:-4}
-PORT=12345
-
-function fail {
- echo "$@"
- exit 1
-}
-set -x
-
-IMGDIR="dump/"
-
-rm -rf "$IMGDIR"
-mkdir "$IMGDIR"
-
-echo "Launching test"
-cd ../zdtm/live/static/
-make cleanout
-make mem-touch
-make mem-touch.pid || fail "Can't start test"
-PID=$(cat mem-touch.pid)
-kill -0 $PID || fail "Test didn't start"
-cd -
-
-echo "Making $NRSNAP snapshots"
-
-for SNAP in $(seq 1 $NRSNAP); do
- sleep $SPAUSE
- mkdir "$IMGDIR/$SNAP/"
- if [ $SNAP -eq 1 ] ; then
- # First snapshot -- no parent, keep running
- args="--track-mem -R"
- elif [ $SNAP -eq $NRSNAP ]; then
- # Last snapshot -- has parent, kill afterwards
- args="--prev-images-dir=../$((SNAP - 1))/ --track-mem"
- else
- # Other snapshots -- have parent, keep running
- args="--prev-images-dir=../$((SNAP - 1))/ --track-mem -R"
- fi
-
- if [ $USEPS -eq 1 ]; then
- ${CRIU} page-server -D "${IMGDIR}/$SNAP/" -o ps.log --port ${PORT} -v4 &
- PS_PID=$!
- ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
- else
- ps_args=""
- fi
-
- ${CRIU} dump -D "${IMGDIR}/$SNAP/" -o dump.log -t ${PID} -v4 $args $ps_args || fail "Fail to dump"
- if [ $USEPS -eq 1 ]; then
- wait $PS_PID
- fi
-done
-
-echo "Restoring"
-${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log -d -v4 || fail "Fail to restore server"
-
-cd ../zdtm/live/static/
-make mem-touch.stop
-cat mem-touch.out | fgrep PASS || fail "Test failed"
-
-echo "Test PASSED"
diff --git a/test/mem-snap/run.sh b/test/mem-snap/run.sh
deleted file mode 100755
index b3995ec..0000000
--- a/test/mem-snap/run.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-# Don't execute tests, which use maps04, they are executed by zdtm
-
-set -e
-
-#./run-predump-2.sh
-./run-predump.sh
-./run-snap-auto-dedup.sh
-./run-snap-dedup-on-restore.sh
-./run-snap-dedup.sh
-#./run-snap-maps04.sh
-./run-snap.sh
diff --git a/test/mounts/ext/Makefile b/test/mounts/ext/Makefile
deleted file mode 100644
index 282fba0..0000000
--- a/test/mounts/ext/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-all: ext-mount.so ns_init
-
-ext-mount.so: ext-mount.c
- gcc -g -Werror -Wall -shared -nostartfiles ext-mount.c -o ext-mount.so -iquote ../../../include -fPIC
-
-ns_init: ns_init.o
- gcc -static $< -o $@
-
-ns_init.o: ns_init.c
- gcc -c $< -o $@
-
-run: all
- ./run.sh
diff --git a/test/mounts/ext/ext-mount.c b/test/mounts/ext/ext-mount.c
deleted file mode 100644
index e5e974b..0000000
--- a/test/mounts/ext/ext-mount.c
+++ /dev/null
@@ -1,101 +0,0 @@
-#include <sys/mount.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "criu-plugin.h"
-#include "criu-log.h"
-
-#define IMG_NAME "ext-mount-test-%d.img"
-
-extern cr_plugin_init_t cr_plugin_init;
-extern cr_plugin_dump_ext_mount_t cr_plugin_dump_ext_mount;
-extern cr_plugin_restore_ext_mount_t cr_plugin_restore_ext_mount;
-
-int cr_plugin_init(void)
-{
- pr_info("Initialized ext mount c/r\n");
- return 0;
-}
-
-int cr_plugin_dump_ext_mount(char *mountpoint, int id)
-{
- char *aux, *dst;
- int fd;
- char img[64];
-
- pr_info("Check for ext mount %s being mine\n", mountpoint);
- aux = strrchr(mountpoint, '/');
- if (!aux) {
- pr_err("Bad path provided\n");
- return -ENOTSUP;
- }
-
- dst = getenv("EMP_MOUNTPOINT");
- if (!dst) {
- pr_err("No EMP_MOUNTPOINT env\n");
- return -1;
- }
-
- if (strcmp(aux + 1, dst)) {
- pr_info("Not mine\n");
- return -ENOTSUP;
- }
-
- pr_info("Dumping my mount %d\n", id);
- sprintf(img, IMG_NAME, id);
- fd = openat(criu_get_image_dir(), img,
- O_RDWR | O_CREAT | O_TRUNC, 0600);
- if (fd < 0) {
- pr_perror("Can't open image");
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-int cr_plugin_restore_ext_mount(int id, char *mountpoint, char *old_root, int *is_file)
-{
- int fd;
- char img[64], src[256], *src_file;
-
- pr_info("Restoring my mount %d?\n", id);
- sprintf(img, IMG_NAME, id);
- fd = openat(criu_get_image_dir(), img, O_RDONLY);
- if (fd < 0) {
- if (errno == ENOENT)
- return -ENOTSUP;
- pr_perror("Can't open my image");
- return -1;
- }
- close(fd);
-
- src_file = getenv("EMP_ROOT_P");
- if (!src_file) {
- pr_err("Can't get EMP_ROOT_P env\n");
- return -1;
- }
-
- if (creat(mountpoint, 0600) < 0) {
- if (errno != EEXIST) {
- pr_perror("Can't make mountpoint");
- return -1;
- }
- }
-
- if (is_file)
- *is_file = 1;
-
- sprintf(src, "/%s/%s", old_root, src_file);
- pr_info("Mount %s -> %s\n", src, mountpoint);
- if (mount(src, mountpoint, NULL, MS_BIND, NULL) < 0) {
- pr_perror("Can't bind mount");
- return -1;
- }
-
- return 0;
-}
diff --git a/test/mounts/ext/ns_init.c b/test/mounts/ext/ns_init.c
deleted file mode 100644
index e85bf9d..0000000
--- a/test/mounts/ext/ns_init.c
+++ /dev/null
@@ -1,143 +0,0 @@
-#define _GNU_SOURCE
-#include <sched.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/mount.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <string.h>
-
-static void sigh(int sig)
-{
-}
-
-int main(int argc, char **argv)
-{
- int start[2];
- char res;
- pid_t pid;
-
- /*
- * Usage:
- * run <pidfile> <root> <log-file-name> <file-to-check> <contents-to-check>
- */
-
- if (getpid() == 1) {
- int fd;
- struct sigaction sa = {};
- sigset_t mask;
-
- if (setsid() == -1) {
- fprintf(stderr, "setsid: %m\n");
- return 1;
- }
-
- sa.sa_handler = sigh;
- sigaction(SIGTERM, &sa, NULL);
-
- if (chdir(argv[2]))
- return 1;
-
- fd = open(argv[3], O_WRONLY|O_CREAT|O_TRUNC|O_APPEND, 0600);
- if (fd < 0)
- return 1;
-
- dup2(fd, 1);
- dup2(fd, 2);
- close(fd);
- close(0);
-
- if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) {
- fprintf(stderr, "mount(/, S_REC | MS_PRIVATE)): %m");
- return 1;
- }
-
- mkdir("oldm");
- if (pivot_root(".", "./oldm") < 0)
- return 1;
-
- umount2("/oldm", MNT_DETACH);
-
- mkdir("/proc");
- if (mount("zdtm_proc", "/proc", "proc", 0, NULL)) {
- fprintf(stderr, "mount(/proc): %m");
- return 1;
- }
-
- sigemptyset(&mask);
- sigaddset(&mask, SIGTERM);
- sigprocmask(SIG_BLOCK, &mask, NULL);
-
- fd = atoi(argv[1]);
- write(fd, "!", 1);
- close(fd);
-
- sigemptyset(&mask);
- sigsuspend(&mask);
-
- printf("Woken UP\n");
- printf("Reading %s for [%s]\n", argv[4], argv[5]);
- {
- FILE *f;
- char buf[128];
-
- f = fopen(argv[4], "r");
- if (!f)
- perror("No file with message");
- else {
- memset(buf, 0, sizeof(buf));
- fgets(buf, sizeof(buf), f);
- fclose(f);
- printf("Got [%s]\n", buf);
-
- if (!strcmp(buf, argv[5]))
- printf("PASS\n");
- }
- }
-
- exit(0);
- }
-
- if (unshare(CLONE_NEWNS | CLONE_NEWPID))
- return 1;
-
- pipe(start);
- pid = fork();
- if (pid == 0) {
- char *nargv[7], aux[10];
-
- close(start[0]);
- sprintf(aux, "%d", start[1]);
- nargv[0] = argv[0];
- nargv[1] = aux;
- nargv[2] = argv[2];
- nargv[3] = argv[3];
- nargv[4] = argv[4];
- nargv[5] = argv[5];
- nargv[6] = NULL;
-
- execv(argv[0], nargv);
- exit(0);
- }
-
- close(start[1]);
- res = 'F';
- read(start[0], &res, 1);
- if (res != '!') {
- printf("Failed to start\n");
- return 1;
- }
-
- printf("Container w/ tests started\n");
- {
- FILE *pidf;
- pidf = fopen(argv[1], "w");
- fprintf(pidf, "%d", pid);
- fclose(pidf);
- }
-
- return 0;
-}
diff --git a/test/mounts/ext/run.sh b/test/mounts/ext/run.sh
deleted file mode 100755
index ff2a2d8..0000000
--- a/test/mounts/ext/run.sh
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/bin/bash
-
-set -x
-
-function fail {
- echo $@
- exit 1
-}
-
-make || fail "Can't compile library or ns init"
-
-criu="../../../criu/criu"
-
-# New root for namespace
-NSROOT="nsroot"
-# External file with contents (exported for plugin.restore)
-EMP_ROOT="external_file"
-export EMP_ROOT_P="$(pwd)/$EMP_ROOT"
-# Internal file as seen from namespace (exported for plugin.dump)
-export EMP_MOUNTPOINT="file"
-# Message in a file to check visibility
-FMESSAGE="tram-pam-pam"
-# Binary of namespace's init
-NS_INIT="ns_init"
-# File with namespace init pid
-PIDF="pidf"
-
-start_ns()
-{
- #
- # Prepare the namespace's FS layout
- #
- mkdir $NSROOT
- echo -n "$FMESSAGE" > "$EMP_ROOT"
- mount --bind "$NSROOT" "$NSROOT"
- mount --make-private "$NSROOT"
- touch "$NSROOT/$EMP_MOUNTPOINT"
- mount --bind "$EMP_ROOT" "$NSROOT/$EMP_MOUNTPOINT" || fail "Can't prepare fs for ns"
-
- #
- # Start the namespace's init
- #
- cp $NS_INIT "$NSROOT/"
- "./$NSROOT/$NS_INIT" "$PIDF" "$NSROOT" "log" "$EMP_MOUNTPOINT" "$FMESSAGE" || fail "Can't start namespace"
- umount "$NSROOT/$EMP_MOUNTPOINT"
-
- echo "Namespace started, pid $(cat $PIDF)"
-}
-
-stop_ns()
-{
- #
- # Kill the init
- #
-
- kill -TERM $(cat $PIDF)
- sleep 2 # Shitty, but...
- umount $NSROOT
-
- if [ -z "$1" ]; then
- rm -f "$NSROOT/log"
- else
- mv "$NSROOT/log" "$1"
- fi
-
- rm -f "$PIDF" "$EMP_ROOT" "$NSROOT/$NS_INIT" "$NSROOT/log" "$NSROOT/$EMP_MOUNTPOINT"
- rmdir "$NSROOT/oldm"
- rmdir "$NSROOT/proc"
- rmdir "$NSROOT"
-}
-
-DDIR="dump"
-rm -rf $DDIR
-mkdir $DDIR
-
-chk_pass()
-{
- tail -n1 $1 | fgrep -q "PASS"
-}
-
-#
-# Test 1: handle external mount with plugin
-#
-
-test_plugin()
-{
- echo "=== Testing how plugin works"
- mkdir "$DDIR/plugin/"
- start_ns
-
- $criu dump -D "$DDIR/plugin/" -v4 -o "dump.log" --lib=$(pwd) \
- -t $(cat pidf) || { stop_ns; return 1; }
-
- $criu restore -D "$DDIR/plugin/" -v4 -o "rstr.log" --lib=$(pwd) \
- -d --root="$(pwd)/$NSROOT" --pidfile=$PIDF || { stop_ns; return 1; }
-
- echo "Restored, checking results"
- mv "$DDIR/plugin/$PIDF" .
- stop_ns "$DDIR/plugin/ns.log"
- chk_pass "$DDIR/plugin/ns.log"
-}
-
-test_ext_mount_map()
-{
- echo "=== Testing how --ext-mount-map works"
- mkdir "$DDIR/ext_mount_map/"
- start_ns
-
- $criu dump -D "$DDIR/ext_mount_map/" -v4 -o "dump.log" \
- -t $(cat pidf) --ext-mount-map "/$EMP_MOUNTPOINT:TM" || { stop_ns; return 1; }
-
- $criu restore -D "$DDIR/ext_mount_map/" -v4 -o "rstr.log" \
- -d --root="$(pwd)/$NSROOT" --pidfile=$PIDF --ext-mount-map "TM:$EMP_ROOT_P" || { stop_ns; return 1; }
-
- echo "Restored, checking results"
- mv "$DDIR/ext_mount_map/$PIDF" .
- stop_ns "$DDIR/ext_mount_map/ns.log"
- chk_pass "$DDIR/ext_mount_map/ns.log"
-}
-
-test_plugin || exit 1
-test_ext_mount_map || exit 1
-
-echo "All tests passed"
-exit 0
diff --git a/test/mounts/mounts.py b/test/mounts/mounts.py
deleted file mode 100755
index 7f11d7d..0000000
--- a/test/mounts/mounts.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import os
-import tempfile, random
-
-def mount(src, dst, shared, private, slave):
- cmd = "mount"
- if shared:
- cmd += " --make-shared"
- if private:
- cmd += " --make-private"
- if slave:
- cmd += " --make-slave"
- if src:
- cmd += " --bind '%s' '%s'" % (src, dst)
- else:
- cmd += " -t tmpfs none '%s'" % (dst)
-
- print cmd
- ret = os.system(cmd)
- if ret:
- print "failed"
-
-root = tempfile.mkdtemp(prefix = "root.mount", dir = "/tmp")
-mount(None, root, 1, 0, 0)
-mounts = [root]
-
-for i in xrange(10):
- dstdir = random.choice(mounts)
- dst = tempfile.mkdtemp(prefix = "mount", dir = dstdir)
- src = random.choice(mounts + [None])
- mount(src, dst, random.randint(0,100) > 50, random.randint(0,100) > 90, random.randint(0,100) > 50)
- mounts.append(dst)
diff --git a/test/mounts/mounts.sh b/test/mounts/mounts.sh
deleted file mode 100755
index 19116d0..0000000
--- a/test/mounts/mounts.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-[ -z "$INMNTNS" ] && {
- export INMNTNS=`pwd`
- export INMNTNS_PID=$$
- unshare -m -- setsid bash -x "$0" "$@" < /dev/null &> mounts.log &
- echo $! > mounts.pid
- while :; do
- sleep 1
- done
-}
-
-cd $INMNTNS
-
-mount --make-rprivate /
-
-for i in `cat /proc/self/mounts | awk '{ print $2 }'`; do
- [ '/' = "$i" ] && continue
- [ '/proc' = "$i" ] && continue
- [ '/dev' = "$i" ] && continue
- echo $i
- umount -l $i
-done
-
-python mounts.py
-kill $INMNTNS_PID
-while :; do
- sleep 10
-done
diff --git a/test/mounts/run.sh b/test/mounts/run.sh
deleted file mode 100755
index 23d05e5..0000000
--- a/test/mounts/run.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-
-CRIU=../../criu
-set -x
-
-mkdir -p dump
-
-./mounts.sh
-pid=`cat mounts.pid`
-kill -0 $pid || exit
-
-cat /proc/$pid/mountinfo | sort -k 4
-echo "Suspend server"
-${CRIU} dump -D dump -o dump.log -t $pid -v4 || {
- cat dump/dump.log | grep Error
- exit 1
-}
-echo "Resume server"
-${CRIU} restore -d -D dump -o restore.log -v4 || {
- cat dump/dump.log | grep Error
- exit 1
-}
-cat /proc/$pid/mountinfo | sort -k 4
-kill $pid
diff --git a/test/others/bers/Makefile b/test/others/bers/Makefile
new file mode 100644
index 0000000..74b6142
--- /dev/null
+++ b/test/others/bers/Makefile
@@ -0,0 +1,47 @@
+ifeq ($(strip $(V)),)
+ E = @echo
+ Q = @
+else
+ E = @\#
+ Q =
+endif
+
+export E Q
+
+ASCIIDOC := asciidoc
+A2X := a2x
+XMLTO := xmlto
+
+SRC += bers.txt
+XMLS := $(patsubst %.txt,%.xml,$(SRC))
+MANS := $(patsubst %.txt,%.8,$(SRC))
+
+%.8: %.txt
+ $(E) " GEN " $@
+ $(Q) $(ASCIIDOC) -b docbook -d manpage -o $(patsubst %.8,%.xml,$@) $<
+ $(Q) $(XMLTO) man --skip-validation $(patsubst %.8,%.xml,$@) 2>/dev/null
+
+docs: $(MANS)
+ @true
+
+CFLAGS := -O0 -ggdb3
+LIBS := -lpthread
+
+%.o: %.c
+ $(E) " CC " $@
+ $(Q) $(CC) -c -o $@ $(CFLAGS) $^
+
+bers: bers.o
+ $(E) " LINK " $@
+ $(Q) $(CC) -o $@ $(CFLAGS) $(LIBS) $^
+
+all: bers
+ @true
+
+clean:
+ $(E) " CLEAN "
+ $(Q) rm -f $(XMLS) $(MANS)
+ $(Q) rm -f bers.o
+ $(Q) rm -f bers
+
+.PHONY: all docs clean
diff --git a/test/others/bers/bers.c b/test/others/bers/bers.c
new file mode 100644
index 0000000..208325c
--- /dev/null
+++ b/test/others/bers/bers.c
@@ -0,0 +1,420 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <limits.h>
+#include <stdbool.h>
+
+#include <pthread.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <syscall.h>
+
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({ \
+ typeof(x) _max1 = (x); \
+ typeof(y) _max2 = (y); \
+ (void) (&_max1 == &_max2); \
+ _max1 > _max2 ? _max1 : _max2; })
+
+#define MAX_CHUNK 4096
+#define PAGE_SIZE 4096
+
+#define pr_info(fmt, ...) \
+ printf("%8d: " fmt, sys_gettid(), ##__VA_ARGS__)
+
+#define pr_err(fmt, ...) \
+ printf("%8d: Error (%s:%d): " fmt, sys_gettid(),\
+ __FILE__, __LINE__, ##__VA_ARGS__)
+
+#define pr_perror(fmt, ...) \
+ pr_err(fmt ": %m\n", ##__VA_ARGS__)
+
+#define pr_msg(fmt, ...) \
+ printf(fmt, ##__VA_ARGS__)
+
+
+#define pr_trace(fmt, ...) \
+ printf("%8d: %s: " fmt, sys_gettid(), __func__, \
+ ##__VA_ARGS__)
+
+enum {
+ MEM_FILL_MODE_NONE = 0,
+ MEM_FILL_MODE_ALL = 1,
+ MEM_FILL_MODE_LIGHT = 2,
+ MEM_FILL_MODE_DIRTIFY = 3,
+};
+
+typedef struct {
+ pthread_mutex_t mutex;
+ pthread_mutexattr_t mutex_attr;
+
+ size_t opt_tasks;
+
+ size_t opt_files;
+ size_t opt_file_size;
+ int prev_fd[MAX_CHUNK];
+
+ size_t opt_mem;
+ size_t opt_mem_chunks;
+ size_t opt_mem_chunk_size;
+ int opt_mem_fill_mode;
+ int opt_mem_cycle_mode;
+ unsigned int opt_refresh_time;
+
+ char *opt_work_dir;
+ int work_dir_fd;
+ DIR *work_dir;
+
+ pid_t err_pid;
+ int err_no;
+
+ unsigned long prev_map[MAX_CHUNK];
+} shared_data_t;
+
+static shared_data_t *shared;
+
+static int sys_gettid(void)
+{
+ return syscall(__NR_gettid);
+}
+
+static void dirtify_memory(unsigned long *chunks, size_t nr_chunks,
+ size_t chunk_size, int mode, const size_t nr_pages)
+{
+ void *page;
+ size_t i;
+
+ pr_trace("filling memory\n");
+ switch (mode) {
+ case MEM_FILL_MODE_LIGHT:
+ *((unsigned long *)chunks[0]) = -1ul;
+ break;
+ case MEM_FILL_MODE_ALL:
+ for (i = 0; i < nr_chunks; i++)
+ memset((void *)chunks[i], (char)i, chunk_size);
+ break;
+ case MEM_FILL_MODE_DIRTIFY:
+ for (i = 0; i < nr_chunks; i++)
+ *((unsigned long *)chunks[i]) = -1ul;
+ break;
+ }
+}
+
+static void dirtify_files(int *fd, size_t nr_files, size_t size)
+{
+ size_t buf[8192];
+ size_t i, j, c;
+
+ /*
+ * Note we don't write any _sane_ data here, the only
+ * important thing is I/O activity by self.
+ */
+
+ for (i = 0; i < nr_files; i++) {
+ size_t c = min(size, sizeof(buf));
+ size_t left = size;
+
+ while (left > 0) {
+ write(fd[i], buf, c);
+ left -= c;
+ c = min(left, sizeof(buf));
+ }
+ }
+}
+
+static int create_files(shared_data_t *shared, int *fd, size_t nr_files)
+{
+ char path[PATH_MAX];
+ size_t i;
+
+ memset(fd, 0xff, sizeof(fd));
+
+ pr_info("\tCreating %lu files\n", shared->opt_files);
+
+ for (i = 0; i < shared->opt_files; i++) {
+ if (shared->prev_fd[i] != -1) {
+ close(shared->prev_fd[i]);
+ shared->prev_fd[i] = -1;
+ }
+ snprintf(path, sizeof(path), "%08d-%04d-temp", sys_gettid(), i);
+ fd[i] = openat(shared->work_dir_fd, path, O_RDWR | O_CREAT | O_TRUNC, 0666);
+ if (fd[i] < 0) {
+ pr_perror("Can't open %s/%s", shared->opt_work_dir, path);
+ shared->err_pid = sys_gettid();
+ shared->err_no = -errno;
+ return -1;
+ }
+ shared->prev_fd[i] = fd[i];
+ }
+
+ return 0;
+}
+
+static void work_on_fork(shared_data_t *shared)
+{
+ const size_t nr_pages = shared->opt_mem_chunk_size / PAGE_SIZE;
+ unsigned long chunks[MAX_CHUNK] = { };
+ int fd[MAX_CHUNK];
+ size_t i;
+ void *mem;
+
+ pr_trace("locking\n");
+ pthread_mutex_lock(&shared->mutex);
+ pr_trace("init\n");
+
+ pr_info("\tCreating %lu mmaps each %lu K\n",
+ shared->opt_mem_chunks, shared->opt_mem_chunk_size >> 10);
+
+ for (i = 0; i < shared->opt_mem_chunks; i++) {
+ if (shared->prev_map[i]) {
+ munmap((void *)shared->prev_map[i], shared->opt_mem_chunk_size);
+ shared->prev_map[i] = 0;
+ }
+
+ /* If we won't change proto here, the kernel might merge close areas */
+ mem = mmap(NULL, shared->opt_mem_chunk_size,
+ PROT_READ | PROT_WRITE | ((i % 2) ? PROT_EXEC : 0),
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+
+ if (mem != (void *)MAP_FAILED) {
+ shared->prev_map[i] = (unsigned long)mem;
+ chunks[i] = (unsigned long)mem;
+
+ pr_info("\t\tMap at %lx\n",(unsigned long)mem);
+ } else {
+ pr_info("\t\tCan't map\n");
+
+ shared->err_pid = sys_gettid();
+ shared->err_no = -errno;
+ exit(1);
+ }
+ }
+
+ if (shared->opt_mem_fill_mode)
+ dirtify_memory(chunks, shared->opt_mem_chunks,
+ shared->opt_mem_chunk_size,
+ shared->opt_mem_fill_mode,
+ nr_pages);
+
+ if (create_files(shared, fd, shared->opt_files))
+ exit(1);
+
+ if (shared->opt_file_size)
+ dirtify_files(fd, shared->opt_files, shared->opt_file_size);
+
+ pr_trace("releasing\n");
+ pthread_mutex_unlock(&shared->mutex);
+
+ while (1) {
+ sleep(shared->opt_refresh_time);
+ if (shared->opt_mem_cycle_mode)
+ dirtify_memory(chunks, shared->opt_mem_chunks,
+ shared->opt_mem_chunk_size,
+ shared->opt_mem_cycle_mode,
+ nr_pages);
+ if (shared->opt_file_size)
+ dirtify_files(fd, shared->opt_files, shared->opt_file_size);
+ }
+}
+
+static int parse_mem_mode(int *mode, char *opt)
+{
+ if (!strcmp(opt, "all")) {
+ *mode = MEM_FILL_MODE_ALL;
+ } else if (!strcmp(opt, "light")) {
+ *mode = MEM_FILL_MODE_LIGHT;
+ } else if (!strcmp(opt, "dirtify")) {
+ *mode = MEM_FILL_MODE_DIRTIFY;
+ } else {
+ pr_err("Unrecognized option %s\n", opt);
+ return -1;
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ /* a - 97, z - 122, A - 65, 90 */
+ static const char short_opts[] = "t:d:f:m:c:h";
+ static struct option long_opts[] = {
+ {"tasks", required_argument, 0, 't'},
+ {"dir", required_argument, 0, 'd'},
+ {"files", required_argument, 0, 'f'},
+ {"memory", required_argument, 0, 'm'},
+ {"mem-chunks", required_argument, 0, 'c'},
+ {"help", no_argument, 0, 'h'},
+ {"mem-fill", required_argument, 0, 10},
+ {"mem-cycle", required_argument, 0, 11},
+ {"refresh", required_argument, 0, 12},
+ {"file-size", required_argument, 0, 13},
+ { },
+ };
+
+ char workdir[PATH_MAX];
+ int opt, idx, pidfd;
+ char pidbuf[32];
+ int status;
+ pid_t pid;
+ size_t i;
+
+ shared = (void *)mmap(NULL, sizeof(*shared), PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+ if ((void *)shared == MAP_FAILED) {
+ pr_err("Failed to setup shared data\n");
+ exit(1);
+ }
+
+ pthread_mutexattr_init(&shared->mutex_attr);
+ pthread_mutexattr_setpshared(&shared->mutex_attr, PTHREAD_PROCESS_SHARED);
+ pthread_mutex_init(&shared->mutex, &shared->mutex_attr);
+
+ /*
+ * Default options.
+ */
+ shared->opt_mem_chunks = 1;
+ shared->opt_refresh_time = 1;
+ shared->opt_tasks = 1;
+ shared->opt_mem = 1 << 20ul;
+ memset(shared->prev_fd, 0xff, sizeof(shared->prev_fd));
+
+ while (1) {
+ idx = -1;
+ opt = getopt_long(argc, argv, short_opts, long_opts, &idx);
+ if (opt == -1)
+ break;
+
+ switch(opt) {
+ case 't':
+ shared->opt_tasks = (size_t)atol(optarg);
+ break;
+ case 'f':
+ shared->opt_files = (size_t)atol(optarg);
+ break;
+ case 'm':
+ /* In megabytes */
+ shared->opt_mem = (size_t)atol(optarg) << 20ul;
+ break;
+ case 'c':
+ shared->opt_mem_chunks = (size_t)atol(optarg);
+ break;
+ case 'd':
+ shared->opt_work_dir = optarg;
+ break;
+ case 'h':
+ goto usage;
+ break;
+ case 10:
+ if (parse_mem_mode(&shared->opt_mem_fill_mode, optarg))
+ goto usage;
+ case 11:
+ if (parse_mem_mode(&shared->opt_mem_cycle_mode, optarg))
+ goto usage;
+ break;
+ case 12:
+ shared->opt_refresh_time = (unsigned int)atoi(optarg);
+ break;
+ case 13:
+ shared->opt_file_size = (size_t)atol(optarg);
+ }
+ }
+
+ if (!shared->opt_work_dir) {
+ shared->opt_work_dir = getcwd(workdir, sizeof(workdir));
+ if (!shared->opt_work_dir) {
+ pr_perror("Can't fetch current working dir");
+ exit(1);
+ }
+ shared->opt_work_dir = workdir;
+ }
+
+ if (shared->opt_mem_chunks > MAX_CHUNK)
+ shared->opt_mem_chunks = MAX_CHUNK;
+
+ if (shared->opt_files > MAX_CHUNK)
+ shared->opt_files = MAX_CHUNK;
+
+ shared->work_dir = opendir(shared->opt_work_dir);
+ if (!shared->work_dir) {
+ pr_perror("Can't open working dir `%s'",
+ shared->opt_work_dir);
+ exit(1);
+ }
+ shared->work_dir_fd = dirfd(shared->work_dir);
+
+ shared->opt_mem_chunk_size = shared->opt_mem / shared->opt_mem_chunks;
+
+ if (shared->opt_mem_chunk_size &&
+ shared->opt_mem_chunk_size < PAGE_SIZE) {
+ pr_err("Memory chunk size is too small, provide at least %lu M of memory\n",
+ (shared->opt_mem_chunks * PAGE_SIZE) >> 20ul);
+ exit(1);
+ }
+
+ for (i = 0; i < shared->opt_tasks; i++) {
+ if (shared->err_no)
+ goto err_child;
+
+ pid = fork();
+ if (pid < 0) {
+ printf("Can't create fork: %m\n");
+ exit(1);
+ } else if (pid == 0) {
+ work_on_fork(shared);
+ }
+ }
+
+ /*
+ * Once everything is done and we're in cycle,
+ * create pidfile and go to sleep...
+ */
+ pid = sys_gettid();
+ pidfd = openat(shared->work_dir_fd, "bers.pid", O_RDWR | O_CREAT | O_TRUNC, 0666);
+ if (pidfd < 0) {
+ pr_perror("Can't open pidfile");
+ exit(1);
+ }
+ snprintf(pidbuf, sizeof(pidbuf), "%d", sys_gettid());
+ write(pidfd, pidbuf, strlen(pidbuf));
+ close(pidfd);
+ pidfd = -1;
+
+ /*
+ * Endless!
+ */
+ while (!shared->err_no)
+ sleep(1);
+
+err_child:
+ pr_err("Child %d exited with %d\n",
+ shared->err_pid, shared->err_no);
+ return shared->err_no;
+
+usage:
+ pr_msg("bers [options]\n");
+ pr_msg(" -t|--tasks <num> create <num> of tasks\n");
+ pr_msg(" -d|--dir <dir> use directory <dir> for temporary files\n");
+ pr_msg(" -f|--files <num> create <num> files for each task\n");
+ pr_msg(" -m|--memory <num> allocate <num> megabytes for each task\n");
+ pr_msg(" --memory-chunks <num> split memory to <num> equal parts\n");
+ pr_msg(" --mem-fill <mode> fill memory with data dependin on <mode>:\n");
+ pr_msg(" all fill every byte of memory\n");
+ pr_msg(" light fill first bytes of every page\n");
+ pr_msg(" dirtify fill every page\n");
+ pr_msg(" --mem-cycle <mode> same as --mem-fill but for cycling\n");
+ pr_msg(" --refresh <second> refresh loading of every task each <second>\n");
+ pr_msg(" --file-size <bytes> write <bytes> of data into each file on every refresh cycle\n");
+
+ return 1;
+}
diff --git a/test/others/bers/bers.txt b/test/others/bers/bers.txt
new file mode 100644
index 0000000..17c0c08
--- /dev/null
+++ b/test/others/bers/bers.txt
@@ -0,0 +1,74 @@
+bers(8)
+=======
+:doctype: manpage
+:man source: bers
+:man version: 0.0.1
+:man manual: bers manual
+
+NAME
+----
+bers - go berserk and eat computer resources
+
+SYNOPSIS
+--------
+*bers* ['options']
+
+DESCRIPTION
+-----------
+*bers* is a command line utility aimed to eat resources of the computer it runs on.
+Idea behind is to create a number of tasks which would trash computer resources
+eating cpu and i/o time.
+
+OPTIONS
+-------
+*-t*, *--tasks* 'num'::
+ Create 'num' number of forks.
+
+*-d*, *--dir* 'dir'::
+ Path to 'dir' directory where temporary files will be created to load
+ I/O subsystem.
+
+*-f*, *--files* 'num'::
+ Create 'num' files in each task.
+
+*-m*, *--memory* 'num'::
+ Allocate 'num' megabytes of memory for every task.
+
+*--mem-chunks* 'num'::
+ Allocate memory for each task not as one slab but split
+ it into 'num' equal parts.
+
+*--mem-fill* 'mode'::
+ Touch (write) into allocated memory once task is created. The
+ 'mode' might be one of the following: 'all' -- write every
+ single byte of the memory, 'light' -- write into first bytes
+ of first page of the allocated memory chunk, 'dirtify' -- write
+ into every page of every allocated chunk.
+
+*--mem-cycle* 'mode'::
+ Same as *--mem-fill*, but 'mode' taken into account while
+ task is cycling. By default each cycle initiated per one second.
+
+*--refresh* 'second'::
+ Refresh load state of every task each 'second'. By refsresh
+ here means to dirtify memory and file contents.
+
+*--file-size* 'bytes'::
+ Write 'bytes' of data into each file on every refresh cycle.
+
+EXAMPLE
+-------
+
+bers -d test/bers/dump -t 256 -m 54 -c 4 -f 200 --mem-fill dirtify --mem-cycle dirtify
+
+We generate 256 tasks wit each allocating 54 megabytes of memory splitted
+equally into 4 memory areas. Each task opens 200 files. On creation and
+cycling we touch every page of every memory area.
+
+AUTHOR
+------
+OpenVZ team.
+
+COPYRIGHT
+---------
+Copyright \(C) 2014, Parallels Inc.
diff --git a/test/others/ext-links/Makefile b/test/others/ext-links/Makefile
new file mode 100644
index 0000000..236a97d
--- /dev/null
+++ b/test/others/ext-links/Makefile
@@ -0,0 +1,4 @@
+all: mvlink.so
+
+mvlink.so: mvlink.c
+ gcc -g -Werror -Wall -shared -nostartfiles mvlink.c -o mvlink.so -iquote ../../../criu/include -fPIC
diff --git a/test/others/ext-links/addmv.sh b/test/others/ext-links/addmv.sh
new file mode 100755
index 0000000..0ccc971
--- /dev/null
+++ b/test/others/ext-links/addmv.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+# $1 -- link name
+# $2 -- file with namespace pid
+if [ "$CRTOOLS_SCRIPT_ACTION" == "setup-namespaces" ]; then
+ $(dirname $0)/addmv_raw.sh $1 $(cat $2)
+else
+ exit 0
+fi
diff --git a/test/others/ext-links/addmv_raw.sh b/test/others/ext-links/addmv_raw.sh
new file mode 100755
index 0000000..224f243
--- /dev/null
+++ b/test/others/ext-links/addmv_raw.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+# $1 -- link name
+# $2 -- pid of task in namespace
+set -x
+$ip link add link eth0 name $1 type macvlan || exit 1
+$ip link set $1 netns $2
diff --git a/test/others/ext-links/mvlink.c b/test/others/ext-links/mvlink.c
new file mode 100644
index 0000000..a1c764d
--- /dev/null
+++ b/test/others/ext-links/mvlink.c
@@ -0,0 +1,28 @@
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "criu-plugin.h"
+#include "criu-log.h"
+
+extern cr_plugin_init_t cr_plugin_init;
+extern cr_plugin_dump_ext_link_t cr_plugin_dump_ext_link;
+
+int cr_plugin_init(void)
+{
+ pr_info("Initialized macvlan dumper\n");
+ return 0;
+}
+
+int cr_plugin_dump_ext_link(int index, int type, char *kind)
+{
+ if (strcmp(kind, "macvlan"))
+ return -ENOTSUP;
+ else {
+ pr_info("Dump %d macvlan\n", index);
+ return 0;
+ }
+}
diff --git a/test/others/ext-links/run.sh b/test/others/ext-links/run.sh
new file mode 100755
index 0000000..82fa393
--- /dev/null
+++ b/test/others/ext-links/run.sh
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+ip=${CR_IP_TOOL:-ip}
+mvln="mv0"
+finf="finish"
+outf="ns_output"
+pidf="ns_pid"
+criu="../../../criu/criu"
+
+export ip
+export mvln
+export finf
+export outf
+export pidf
+
+function fail {
+ $ip link del $mvln
+ touch $finf
+ echo $@
+ exit 1
+}
+
+# Build the mvlink plugin
+make
+
+set -x
+
+rm -f "$finf" "$outf" "$pidf"
+rm -rf "dump"
+
+# Unshare netns. The run_ns will exit once ns is spawned.
+unshare --net ./run_ns.sh
+nspid=$(cat $pidf)
+ps $nspid
+
+# Create and push macvlan device into it. CRIU doesn't support
+# macvlans treating them as external devices.
+./addmv_raw.sh $mvln $nspid || fail "Can't setup namespace"
+
+# Dump
+sleep 1
+mkdir dump
+$criu dump -t $nspid -D dump/ -o dump.log -v4 --lib $(pwd) || fail "Can't dump namespace"
+
+# Restore
+# Ask for the pid (shouldn't change, so just as an example), ask to call
+# script that will put macvlan device back into namespace
+sleep 1
+rm -f $pidf
+$criu restore -D dump/ -o restore.log -v4 --pidfile $(pwd)/$pidf --action-script "$(pwd)/addmv.sh $mvln $(pwd)/$pidf" -d || fail "Can't restore namespaces"
+
+# Finish and check results
+touch $finf
+set +x
+while ! egrep 'PASS|FAIL' $outf; do
+ echo "Waiting"
+ sleep 1
+done
diff --git a/test/others/ext-links/run_ns.sh b/test/others/ext-links/run_ns.sh
new file mode 100755
index 0000000..878f038
--- /dev/null
+++ b/test/others/ext-links/run_ns.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -x
+echo "NS: $$" >> $outf
+echo "Links before:" >> $outf
+$ip link list >> $outf 2>&1
+# Detach from session, terminal and parent
+setsid ./run_wait.sh < /dev/null >> $outf 2>&1 &
+# Keep pid for future reference :)
+echo "$!" > $pidf
+exit 0
diff --git a/test/others/ext-links/run_wait.sh b/test/others/ext-links/run_wait.sh
new file mode 100755
index 0000000..d600e37
--- /dev/null
+++ b/test/others/ext-links/run_wait.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+echo "Wait: $$"
+while [ ! -e "$finf" ]; do
+ echo "WAIT ($$)"
+ sleep 1;
+done
+
+echo "Links after:"
+$ip link list
+
+# The mvln device (exported from run.sh) should exits in
+# namespace after we get restored
+echo "Check for $mvln:"
+$ip link list $mvln && echo "PASS" || echo "FAIL"
diff --git a/test/others/ext-tty/run.py b/test/others/ext-tty/run.py
new file mode 100755
index 0000000..22288e3
--- /dev/null
+++ b/test/others/ext-tty/run.py
@@ -0,0 +1,36 @@
+import subprocess
+import pty
+import os, sys, time
+
+master, slave = pty.openpty()
+
+p = subprocess.Popen(["setsid", "--ctty", "sleep", "10000"],
+ stdin = slave, stdout = slave, stderr = slave, close_fds = True)
+st = os.stat("/proc/self/fd/%d" % slave)
+ttyid = "tty[%x:%x]" % (st.st_rdev, st.st_dev)
+os.close(slave)
+time.sleep(1)
+
+ret = subprocess.Popen(["../../../criu/criu", "dump", "-t", str(p.pid), "-v4", "--external", ttyid]).wait()
+if ret:
+ sys.exit(ret)
+p.wait()
+
+new_master, slave = pty.openpty() # get another pty pair
+os.close(master)
+
+ttyid = "fd[%d]:tty[%x:%x]" % (slave, st.st_rdev, st.st_dev)
+
+ret = subprocess.Popen(["../../../criu/criu", "restore", "-v4", "--inherit-fd", ttyid, "--restore-sibling", "--restore-detach"]).wait()
+if ret:
+ sys.exit(ret)
+os.close(slave)
+os.waitpid(-1, os.WNOHANG) # is the process alive
+
+os.close(new_master)
+_, status = os.wait()
+if not os.WIFSIGNALED(status) or not os.WTERMSIG(status):
+ print status
+ sys.exit(1)
+
+print "PASS"
diff --git a/test/others/fault-injection/Makefile b/test/others/fault-injection/Makefile
new file mode 100644
index 0000000..23257eb
--- /dev/null
+++ b/test/others/fault-injection/Makefile
@@ -0,0 +1,2 @@
+all:
+ stap -g -d ../../../criu/criu parasite.stp $$RANDOM -c 'bash -x ../zdtm.sh -d -x socket-tcp'
diff --git a/test/others/fault-injection/parasite.stp b/test/others/fault-injection/parasite.stp
new file mode 100644
index 0000000..c1b0818
--- /dev/null
+++ b/test/others/fault-injection/parasite.stp
@@ -0,0 +1,44 @@
+global i, n, fini_cmd = -1, last_cmd
+
+probe process("../../criu/criu").begin
+{
+ i = 0;
+ /* randint() returns numbers multiple of 5 */
+ n = randint(20 * 5) / 5
+ printf("The %d command will be replaced on -1\n", n);
+}
+
+probe process("../../criu/criu").function("__parasite_execute_daemon")
+{
+ printf("%s\n", $$parms);
+ last_cmd = $cmd;
+ if (++i > n) {
+ printf("Send invalid command to parasite\n");
+ $cmd = -1;
+ }
+}
+
+probe process("../../criu/criu").function("__parasite_execute_daemon").return
+{
+ printf("%d\n", $return);
+}
+
+probe process("../../criu/criu").function("main").return
+{
+ printf("CRIU exits with code %d\n", $return);
+ if ( i > n) {
+ if ($return)
+ $return = 0;
+ else {
+ printf("CRIU exited with zero code\n");
+ if (fini_cmd < 0 || fini_cmd == last_cmd) {
+ printf("%d looks like FINI command\n", n);
+ fini_cmd = last_cmd
+ } else {
+ printf("This is the second FINI command %d (%d)",
+ n, fini_cmd);
+ $return = 1;
+ }
+ }
+ }
+}
diff --git a/test/others/libcriu/.gitignore b/test/others/libcriu/.gitignore
new file mode 100644
index 0000000..6424681
--- /dev/null
+++ b/test/others/libcriu/.gitignore
@@ -0,0 +1,6 @@
+test_errno
+test_iters
+test_notify
+test_self
+test_sub
+wdir
diff --git a/test/others/libcriu/Makefile b/test/others/libcriu/Makefile
new file mode 100644
index 0000000..d828f7e
--- /dev/null
+++ b/test/others/libcriu/Makefile
@@ -0,0 +1,26 @@
+TESTS += test_sub
+TESTS += test_self
+TESTS += test_notify
+TESTS += test_iters
+TESTS += test_errno
+
+all: $(TESTS)
+
+run: all
+ ./run.sh
+
+define genb
+$(1): $(1).o lib.o
+ gcc $$^ -L ../../../../criu/lib/c/ -L ../../../../criu/images/ -lcriu -o $$@
+endef
+
+$(foreach t, $(TESTS), $(eval $(call genb, $(t))))
+
+%.o: %.c
+ gcc -c $^ -I../../../../criu/lib/c/ -I../../../../criu/images/ -o $@ -Werror
+
+clean:
+ rm -rf $(TESTS) $(TESTS:%=%.o) lib.o
+
+.PHONY: clean
+.PHONY: all
diff --git a/test/others/libcriu/lib.c b/test/others/libcriu/lib.c
new file mode 100644
index 0000000..33aa409
--- /dev/null
+++ b/test/others/libcriu/lib.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+void what_err_ret_mean(int ret)
+{
+ /* NOTE: errno is set by libcriu */
+ switch (ret) {
+ case -EBADE:
+ perror("RPC has returned fail");
+ break;
+ case -ECONNREFUSED:
+ perror("Unable to connect to CRIU");
+ break;
+ case -ECOMM:
+ perror("Unable to send/recv msg to/from CRIU");
+ break;
+ case -EINVAL:
+ perror("CRIU doesn't support this type of request."
+ "You should probably update CRIU");
+ break;
+ case -EBADMSG:
+ perror("Unexpected response from CRIU."
+ "You should probably update CRIU");
+ break;
+ default:
+ perror("Unknown error type code."
+ "You should probably update CRIU");
+ }
+}
+
+int chk_exit(int status, int want)
+{
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == want)
+ return 0;
+
+ printf(" `- FAIL (exit %d)\n", WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status))
+ printf(" `- FAIL (die %d)\n", WTERMSIG(status));
+ else
+ printf(" `- FAIL (%#x)\n", status);
+
+ return 1;
+}
+
+
diff --git a/test/others/libcriu/lib.h b/test/others/libcriu/lib.h
new file mode 100644
index 0000000..67b784b
--- /dev/null
+++ b/test/others/libcriu/lib.h
@@ -0,0 +1,2 @@
+void what_err_ret_mean(int ret);
+int chk_exit(int status, int want);
diff --git a/test/others/libcriu/run.sh b/test/others/libcriu/run.sh
new file mode 100755
index 0000000..f7b3b68
--- /dev/null
+++ b/test/others/libcriu/run.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+set -x
+source ../../env.sh || exit 1
+
+echo "== Clean"
+make clean
+rm -rf wdir
+rm -f ./libcriu.so.1
+
+echo "== Prepare"
+mkdir -p wdir/i/
+
+echo "== Run tests"
+ln -s ../../../../criu/lib/c/libcriu.so libcriu.so.1
+export LD_LIBRARY_PATH=.
+export PATH="`dirname ${BASH_SOURCE[0]}`/../../:$PATH"
+
+RESULT=0
+
+function run_test {
+ echo "== Build $1"
+ if ! make $1; then
+ echo "FAIL build $1"
+ RESULT=1;
+ else
+ echo "== Test $1"
+ mkdir wdir/i/$1/
+ if ! setsid ./$1 ${CRIU} wdir/i/$1/ < /dev/null &>> wdir/i/$1/test.log; then
+ echo "$1: FAIL"
+ RESULT=1
+ fi
+ fi
+}
+
+run_test test_sub
+run_test test_self
+run_test test_notify
+run_test test_iters
+run_test test_errno
+
+echo "== Tests done"
+unlink libcriu.so.1
+[ $RESULT -eq 0 ] && echo "Success" || echo "FAIL"
+exit $RESULT
diff --git a/test/others/libcriu/test_errno.c b/test/others/libcriu/test_errno.c
new file mode 100644
index 0000000..e091443
--- /dev/null
+++ b/test/others/libcriu/test_errno.c
@@ -0,0 +1,154 @@
+#include "criu.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#define PID_MAX "/proc/sys/kernel/pid_max"
+
+static int dir_fd;
+static char *service;
+
+static int init(char *argv[])
+{
+ service = argv[1];
+
+ dir_fd = open(argv[2], O_DIRECTORY);
+ if (dir_fd < 0) {
+ perror("Can't open images dir");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void get_base_req(void)
+{
+ criu_init_opts();
+ criu_set_service_binary(service);
+ criu_set_images_dir_fd(dir_fd);
+ criu_set_log_level(4);
+}
+
+static int check_resp(int ret, int expected_ret, int err, int expected_err)
+{
+ if (ret != expected_ret) {
+ fprintf(stderr, "Unexpected ret %d (%d expected)\n", ret, expected_ret);
+ return -1;
+ }
+
+ if (err != expected_err) {
+ fprintf(stderr, "Unexpected errno %d (%d expected)\n", err, expected_err);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int no_process(void)
+{
+ FILE *f = NULL;
+ size_t len;
+ ssize_t count;
+ char *buf = NULL;
+ int pid, fd, ret;
+
+ printf("--- Try to dump unexisting process\n");
+
+ f = fopen(PID_MAX, "r");
+ if (!f) {
+ perror("Can't open " PID_MAX);
+ goto err;
+ }
+
+ count = getline(&buf, &len, f);
+ if (count == -1) {
+ perror("Can't read " PID_MAX);
+ goto err;
+ }
+ pid = atoi(buf);
+
+ if (!kill(pid, 0)) {
+ fprintf(stderr, "max pid is taken\n");
+ goto err;
+ }
+
+ get_base_req();
+ criu_set_pid(pid);
+ ret = criu_dump();
+ if (check_resp(ret, -EBADE, errno, ESRCH))
+ goto err;
+
+ printf(" `- Success\n");
+ return 0;
+err:
+ if (f)
+ fclose(f);
+ return -1;
+
+}
+
+static int process_exists(void)
+{
+ int ret;
+
+ printf("--- Try to restore process which pid is already taken by other process\n");
+
+ get_base_req();
+ criu_set_leave_running(true);
+ if (criu_dump()) {
+ fprintf(stderr, "Self-dump failed");
+ goto err;
+ }
+
+ get_base_req();
+ ret = criu_restore();
+ if (check_resp(ret, -EBADE, errno, EEXIST))
+ goto err;
+
+ printf(" `- Success\n");
+ return 0;
+err:
+ return -1;
+}
+
+static int bad_options(void)
+{
+ int ret;
+
+ printf("--- Try to send criu invalid opts\n");
+
+ get_base_req();
+ criu_set_log_file("../file.log");
+ ret = criu_dump();
+ if (check_resp(ret, -EBADE, errno, EBADRQC))
+ goto err;
+
+ printf(" `- Success\n");
+ return 0;
+err:
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = 1;
+
+ if (init(argv))
+ goto out;
+
+ if (no_process() || process_exists() || bad_options())
+ goto out;
+
+ ret = 0;
+out:
+ if (dir_fd)
+ close(dir_fd);
+
+ return ret;
+}
diff --git a/test/others/libcriu/test_iters.c b/test/others/libcriu/test_iters.c
new file mode 100644
index 0000000..660da92
--- /dev/null
+++ b/test/others/libcriu/test_iters.c
@@ -0,0 +1,143 @@
+#include "criu.h"
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "lib.h"
+
+static int wdir_fd, cur_iter = 1, cur_imgdir = -1;
+
+static int stop = 0;
+static void sh(int sig)
+{
+ stop = 1;
+}
+
+static int open_imgdir(void)
+{
+ char p[10];
+
+ sprintf(p, "%d", cur_iter);
+ mkdirat(wdir_fd, p, 0700);
+ cur_imgdir = openat(wdir_fd, p, O_DIRECTORY);
+ criu_set_images_dir_fd(cur_imgdir);
+}
+
+#define MAX_ITERS 2
+
+static int next_iter(criu_predump_info pi)
+{
+ char p[10];
+
+ printf(" `- %d iter over\n", cur_iter);
+
+ close(cur_imgdir);
+ sprintf(p, "../%d", cur_iter);
+ criu_set_parent_images(p);
+
+ cur_iter++;
+ open_imgdir();
+
+ return cur_iter < MAX_ITERS;
+}
+
+#define SUCC_ECODE 42
+
+int main(int argc, char **argv)
+{
+ int pid, ret, p[2];
+
+ wdir_fd = open(argv[2], O_DIRECTORY);
+ if (wdir_fd < 0) {
+ perror("Can't open wdir");
+ return 1;
+ }
+
+ printf("--- Start loop ---\n");
+ pipe(p);
+ pid = fork();
+ if (pid < 0) {
+ perror("Can't");
+ return -1;
+ }
+
+ if (!pid) {
+ printf(" `- loop: initializing\n");
+ if (setsid() < 0)
+ exit(1);
+ if (signal(SIGUSR1, sh) == SIG_ERR)
+ exit(1);
+
+ close(0);
+ close(1);
+ close(2);
+ close(p[0]);
+
+ ret = SUCC_ECODE;
+ write(p[1], &ret, sizeof(ret));
+ close(p[1]);
+
+ while (!stop)
+ sleep(1);
+ exit(SUCC_ECODE);
+ }
+
+ close(p[1]);
+
+ /* Wait for kid to start */
+ ret = -1;
+ read(p[0], &ret, sizeof(ret));
+ if (ret != SUCC_ECODE) {
+ printf("Error starting loop\n");
+ goto err;
+ }
+
+ /* Wait for pipe to get closed, then dump */
+ read(p[0], &ret, 1);
+ close(p[0]);
+
+ printf("--- Dump loop ---\n");
+ criu_init_opts();
+ criu_set_service_binary(argv[1]);
+ criu_set_pid(pid);
+ criu_set_log_file("dump.log");
+ criu_set_log_level(4);
+
+ open_imgdir();
+ ret = criu_dump_iters(next_iter);
+ if (ret < 0) {
+ what_err_ret_mean(ret);
+ kill(pid, SIGKILL);
+ goto err;
+ }
+
+ printf(" `- Dump succeeded\n");
+ waitpid(pid, NULL, 0);
+
+ printf("--- Restore loop ---\n");
+ criu_init_opts();
+ criu_set_log_level(4);
+ criu_set_log_file("restore.log");
+ criu_set_images_dir_fd(cur_imgdir);
+
+ pid = criu_restore_child();
+ if (pid <= 0) {
+ what_err_ret_mean(pid);
+ return -1;
+ }
+
+ printf(" `- Restore returned pid %d\n", pid);
+ kill(pid, SIGUSR1);
+err:
+ if (waitpid(pid, &ret, 0) < 0) {
+ perror(" Can't wait kid");
+ return -1;
+ }
+
+ return chk_exit(ret, SUCC_ECODE);
+}
diff --git a/test/others/libcriu/test_notify.c b/test/others/libcriu/test_notify.c
new file mode 100644
index 0000000..54fb255
--- /dev/null
+++ b/test/others/libcriu/test_notify.c
@@ -0,0 +1,97 @@
+#include "criu.h"
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "lib.h"
+
+#define SUCC_ECODE 42
+
+static int actions_called = 0;
+static int notify(char *action, criu_notify_arg_t na)
+{
+ printf("ACTION: %s\n", action);
+ actions_called++;
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int pid, ret, fd, p[2];
+
+ printf("--- Start loop ---\n");
+ pipe(p);
+ pid = fork();
+ if (pid < 0) {
+ perror("Can't");
+ return -1;
+ }
+
+ if (!pid) {
+ printf(" `- loop: initializing\n");
+ if (setsid() < 0)
+ exit(1);
+
+ close(0);
+ close(1);
+ close(2);
+ close(p[0]);
+
+ ret = SUCC_ECODE;
+ write(p[1], &ret, sizeof(ret));
+ close(p[1]);
+
+ while (1)
+ sleep(1);
+
+ exit(SUCC_ECODE);
+ }
+
+ close(p[1]);
+
+ /* Wait for kid to start */
+ ret = -1;
+ read(p[0], &ret, sizeof(ret));
+ if (ret != SUCC_ECODE) {
+ printf("Error starting loop\n");
+ goto err;
+ }
+
+ /* Wait for pipe to get closed, then dump */
+ read(p[0], &ret, 1);
+ close(p[0]);
+
+ printf("--- Dump loop ---\n");
+ criu_init_opts();
+ criu_set_service_binary(argv[1]);
+ criu_set_pid(pid);
+ criu_set_log_file("dump.log");
+ criu_set_log_level(4);
+ criu_set_notify_cb(notify);
+ fd = open(argv[2], O_DIRECTORY);
+ criu_set_images_dir_fd(fd);
+
+ ret = criu_dump();
+ if (ret < 0) {
+ what_err_ret_mean(ret);
+ kill(pid, SIGKILL);
+ goto err;
+ }
+
+ printf(" `- Dump succeeded\n");
+ ret = 0;
+err:
+ waitpid(pid, NULL, 0);
+ if (ret || !actions_called) {
+ printf("FAIL (%d/%d)\n", ret, actions_called);
+ return 1;
+ }
+
+ printf(" `- Success (%d actions)\n", actions_called);
+ return 0;
+}
diff --git a/test/others/libcriu/test_self.c b/test/others/libcriu/test_self.c
new file mode 100644
index 0000000..c9d2a2e
--- /dev/null
+++ b/test/others/libcriu/test_self.c
@@ -0,0 +1,96 @@
+#include "criu.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include "lib.h"
+
+#define SUCC_DUMP_ECODE 41
+#define SUCC_RSTR_ECODE 43
+
+int main(int argc, char *argv[])
+{
+ int ret, fd, pid;
+
+ fd = open(argv[2], O_DIRECTORY);
+ if (fd < 0) {
+ perror("Can't open images dir");
+ return 1;
+ }
+
+ criu_init_opts();
+ criu_set_service_binary(argv[1]);
+ criu_set_images_dir_fd(fd);
+ criu_set_log_level(4);
+
+ printf("--- Start child ---\n");
+ pid = fork();
+ if (pid < 0) {
+ perror("Can't");
+ return 1;
+ }
+
+ if (!pid) {
+ /*
+ * Child process -- dump itself, then
+ * parent would restore us.
+ */
+
+ close(0);
+ close(1);
+ close(2);
+ if (setsid() < 0)
+ exit(1);
+
+ criu_set_log_file("dump.log");
+ criu_set_leave_running(true);
+ ret = criu_dump();
+ if (ret < 0) {
+ what_err_ret_mean(ret);
+ exit(1);
+ }
+
+ if (ret == 0)
+ ret = SUCC_DUMP_ECODE; /* dumped OK */
+ else if (ret == 1)
+ ret = SUCC_RSTR_ECODE; /* restored OK */
+ else
+ ret = 1;
+
+ exit(ret);
+ }
+
+ printf("--- Wait for self-dump ---\n");
+ if (waitpid(pid, &ret, 0) < 0) {
+ perror("Can't wait child");
+ goto errk;
+ }
+
+ if (chk_exit(ret, SUCC_DUMP_ECODE))
+ goto errk;
+
+ printf("--- Restore ---\n");
+ criu_set_log_file("restore.log");
+
+ pid = criu_restore_child();
+ if (pid <= 0) {
+ what_err_ret_mean(pid);
+ goto err;
+ }
+
+ if (waitpid(pid, &ret, 0) < 0) {
+ perror("Can't wait rchild");
+ goto errk;
+ }
+
+ return chk_exit(ret, SUCC_RSTR_ECODE);
+
+errk:
+ kill(pid, SIGKILL);
+err:
+ return 1;
+
+}
diff --git a/test/others/libcriu/test_sub.c b/test/others/libcriu/test_sub.c
new file mode 100644
index 0000000..b435f67
--- /dev/null
+++ b/test/others/libcriu/test_sub.c
@@ -0,0 +1,107 @@
+#include "criu.h"
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "lib.h"
+
+static int stop = 0;
+static void sh(int sig)
+{
+ stop = 1;
+}
+
+#define SUCC_ECODE 42
+
+int main(int argc, char **argv)
+{
+ int pid, ret, fd, p[2];
+
+ printf("--- Start loop ---\n");
+ pipe(p);
+ pid = fork();
+ if (pid < 0) {
+ perror("Can't");
+ return -1;
+ }
+
+ if (!pid) {
+ printf(" `- loop: initializing\n");
+ if (setsid() < 0)
+ exit(1);
+ if (signal(SIGUSR1, sh) == SIG_ERR)
+ exit(1);
+
+ close(0);
+ close(1);
+ close(2);
+ close(p[0]);
+
+ ret = SUCC_ECODE;
+ write(p[1], &ret, sizeof(ret));
+ close(p[1]);
+
+ while (!stop)
+ sleep(1);
+ exit(SUCC_ECODE);
+ }
+
+ close(p[1]);
+
+ /* Wait for kid to start */
+ ret = -1;
+ read(p[0], &ret, sizeof(ret));
+ if (ret != SUCC_ECODE) {
+ printf("Error starting loop\n");
+ goto err;
+ }
+
+ /* Wait for pipe to get closed, then dump */
+ read(p[0], &ret, 1);
+ close(p[0]);
+
+ printf("--- Dump loop ---\n");
+ criu_init_opts();
+ criu_set_service_binary(argv[1]);
+ criu_set_pid(pid);
+ criu_set_log_file("dump.log");
+ criu_set_log_level(4);
+ fd = open(argv[2], O_DIRECTORY);
+ criu_set_images_dir_fd(fd);
+
+ ret = criu_dump();
+ if (ret < 0) {
+ what_err_ret_mean(ret);
+ kill(pid, SIGKILL);
+ goto err;
+ }
+
+ printf(" `- Dump succeeded\n");
+ waitpid(pid, NULL, 0);
+
+ printf("--- Restore loop ---\n");
+ criu_init_opts();
+ criu_set_log_level(4);
+ criu_set_log_file("restore.log");
+ criu_set_images_dir_fd(fd);
+
+ pid = criu_restore_child();
+ if (pid <= 0) {
+ what_err_ret_mean(pid);
+ return -1;
+ }
+
+ printf(" `- Restore returned pid %d\n", pid);
+ kill(pid, SIGUSR1);
+err:
+ if (waitpid(pid, &ret, 0) < 0) {
+ perror(" Can't wait kid");
+ return -1;
+ }
+
+ return chk_exit(ret, SUCC_ECODE);
+}
diff --git a/test/others/mem-snap/Makefile b/test/others/mem-snap/Makefile
new file mode 100644
index 0000000..7779a99
--- /dev/null
+++ b/test/others/mem-snap/Makefile
@@ -0,0 +1,2 @@
+run:
+ ./run.sh
diff --git a/test/others/mem-snap/run-predump-2.sh b/test/others/mem-snap/run-predump-2.sh
new file mode 100755
index 0000000..809612e
--- /dev/null
+++ b/test/others/mem-snap/run-predump-2.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+source ../../env.sh || exit 1
+
+function fail {
+ echo "$@"
+ exit 1
+}
+set -x
+
+IMGDIR="dump/"
+
+rm -rf "$IMGDIR"
+mkdir "$IMGDIR"
+
+function launch_test {
+ echo "Launching test"
+ cd ../../zdtm/live/static/
+ make cleanout
+ make maps04
+ make maps04.pid || fail "Can't start test"
+ PID=$(cat maps04.pid)
+ kill -0 $PID || fail "Test didn't start"
+ cd -
+}
+
+function stop_test {
+ wtime=1
+ cd ../../zdtm/live/static/
+ make maps04.stop
+ cat maps04.out | fgrep PASS || fail "Test failed"
+ echo "OK"
+}
+
+launch_test
+
+echo "Taking plain dump"
+
+mkdir "$IMGDIR/dump-1/"
+${CRIU} dump -D "$IMGDIR/dump-1/" -o dump.log -t ${PID} -v4 || fail "Fail to dump"
+
+sleep 1
+echo "Restore to check it works"
+${CRIU} restore -D "${IMGDIR}/dump-1/" -o restore.log -d -v4 || fail "Fail to restore server"
+
+stop_test
+
+
+launch_test
+
+echo "Taking pre and plain dumps"
+
+echo "Pre-dump"
+mkdir "$IMGDIR/dump-2/"
+mkdir "$IMGDIR/dump-2/pre/"
+${CRIU} pre-dump -D "$IMGDIR/dump-2/pre/" -o dump.log -t ${PID} -v4 || fail "Fail to pre-dump"
+
+echo "Plain dump"
+mkdir "$IMGDIR/dump-2/plain/"
+${CRIU} dump -D "$IMGDIR/dump-2/plain/" -o dump.log -t ${PID} -v4 --prev-images-dir=../pre/ --track-mem || fail "Fail to dump"
+
+sleep 1
+echo "Restore"
+${CRIU} restore -D "${IMGDIR}/dump-2/plain/" -o restore.log -d -v4 || fail "Fail to restore server"
+
+stop_test
diff --git a/test/others/mem-snap/run-predump.sh b/test/others/mem-snap/run-predump.sh
new file mode 100755
index 0000000..073784a
--- /dev/null
+++ b/test/others/mem-snap/run-predump.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+
+source ../../env.sh || exit 1
+
+USEPS=0
+
+if [ "$1" = "-s" ]; then
+ echo "Will test via page-server"
+ USEPS=1
+ shift
+fi
+
+NRSNAP=${1:-3}
+SPAUSE=${2:-4}
+PORT=12345
+
+function fail {
+ echo "$@"
+ exit 1
+}
+set -x
+
+IMGDIR="dump/"
+
+rm -rf "$IMGDIR"
+mkdir "$IMGDIR"
+
+echo "Launching test"
+cd ../../zdtm//live/static/
+make cleanout
+make mem-touch
+make mem-touch.pid || fail "Can't start test"
+PID=$(cat mem-touch.pid)
+kill -0 $PID || fail "Test didn't start"
+cd -
+
+echo "Making $NRSNAP pre-dumps"
+
+for SNAP in $(seq 1 $NRSNAP); do
+ sleep $SPAUSE
+ mkdir "$IMGDIR/$SNAP/"
+ if [ $SNAP -eq 1 ] ; then
+ # First pre-dump
+ cmd="pre-dump"
+ args="--track-mem -R"
+ elif [ $SNAP -eq $NRSNAP ]; then
+ # Last dump
+ cmd="dump"
+ args="--prev-images-dir=../$((SNAP - 1))/ --track-mem"
+ else
+ # Other pre-dumps
+ cmd="pre-dump"
+ args="--prev-images-dir=../$((SNAP - 1))/ --track-mem -R"
+ fi
+
+ if [ $USEPS -eq 1 ]; then
+ ${CRIU} page-server -D "${IMGDIR}/$SNAP/" -o ps.log --port ${PORT} -v4 &
+ PS_PID=$!
+ ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
+ else
+ ps_args=""
+ fi
+
+ ${CRIU} $cmd -D "${IMGDIR}/$SNAP/" -o dump.log -t ${PID} -v4 $args $ps_args || fail "Fail to dump"
+ if [ $USEPS -eq 1 ]; then
+ wait $PS_PID
+ fi
+done
+
+echo "Restoring"
+${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log -d -v4 || fail "Fail to restore server"
+
+cd ../../zdtm//live/static/
+make mem-touch.stop
+cat mem-touch.out | fgrep PASS || fail "Test failed"
+
+echo "Test PASSED"
diff --git a/test/others/mem-snap/run-snap-auto-dedup.sh b/test/others/mem-snap/run-snap-auto-dedup.sh
new file mode 100755
index 0000000..c0d8779
--- /dev/null
+++ b/test/others/mem-snap/run-snap-auto-dedup.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+source ../../env.sh || exit 1
+
+USEPS=0
+
+if [ "$1" = "-s" ]; then
+ echo "Will test via page-server"
+ USEPS=1
+ shift
+fi
+
+NRSNAP=${1:-3}
+SPAUSE=${2:-4}
+PORT=12345
+
+function fail {
+ echo "$@"
+ exit 1
+}
+set -x
+
+IMGDIR="dump/"
+
+rm -rf "$IMGDIR"
+mkdir "$IMGDIR"
+
+echo "Launching test"
+cd ../../zdtm//live/static/
+make cleanout
+make mem-touch
+make mem-touch.pid || fail "Can't start test"
+PID=$(cat mem-touch.pid)
+kill -0 $PID || fail "Test didn't start"
+cd -
+
+echo "Making $NRSNAP snapshots"
+
+for SNAP in $(seq 1 $NRSNAP); do
+ sleep $SPAUSE
+ mkdir "$IMGDIR/$SNAP/"
+ if [ $SNAP -eq 1 ] ; then
+ # First snapshot -- no parent, keep running
+ args="--track-mem -R"
+ elif [ $SNAP -eq $NRSNAP ]; then
+ # Last snapshot -- has parent, kill afterwards
+ size_first_2=$(du -sh -BK dump/2/pages-*.img | grep -Eo '[0-9]+' | head -1)
+ size_first_1=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
+ args="--prev-images-dir=../$((SNAP - 1))/ --track-mem --auto-dedup"
+ else
+ # Other snapshots -- have parent, keep running
+ args="--prev-images-dir=../$((SNAP - 1))/ --track-mem -R"
+ fi
+
+ if [ $USEPS -eq 1 ]; then
+ ${CRIU} page-server -D "${IMGDIR}/$SNAP/" -o ps.log --auto-dedup --port ${PORT} -v4 &
+ PS_PID=$!
+ ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
+ else
+ ps_args=""
+ fi
+
+ ${CRIU} dump -D "${IMGDIR}/$SNAP/" -o dump.log -t ${PID} -v4 $args $ps_args || fail "Fail to dump"
+ if [ $USEPS -eq 1 ]; then
+ wait $PS_PID
+ fi
+done
+
+size_last_2=$(du -sh -BK dump/2/pages-*.img | grep -Eo '[0-9]+' | head -1)
+size_last_1=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
+
+dedup_ok_2=1
+if [ $size_first_2 -gt $size_last_2 ]; then
+ dedup_ok_2=0
+fi
+
+dedup_ok_1=1
+if [ $size_first_1 -gt $size_last_1 ]; then
+ dedup_ok_1=0
+fi
+
+echo "Restoring"
+${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log -d -v4 || fail "Fail to restore server"
+
+cd ../../zdtm//live/static/
+make mem-touch.stop
+cat mem-touch.out | fgrep PASS || fail "Test failed"
+
+if [[ $dedup_ok_2 -ne 0 || $dedup_ok_1 -ne 0 ]]; then
+ fail "Dedup test failed"
+fi
+
+echo "Test PASSED"
diff --git a/test/others/mem-snap/run-snap-dedup-on-restore.sh b/test/others/mem-snap/run-snap-dedup-on-restore.sh
new file mode 100755
index 0000000..5821d8a
--- /dev/null
+++ b/test/others/mem-snap/run-snap-dedup-on-restore.sh
@@ -0,0 +1,87 @@
+#!/bin/bash
+
+source ../../env.sh || exit 1
+
+USEPS=0
+
+if [ "$1" = "-s" ]; then
+ echo "Will test via page-server"
+ USEPS=1
+ shift
+fi
+
+NRSNAP=${1:-3}
+SPAUSE=${2:-4}
+PORT=12345
+
+function fail {
+ echo "$@"
+ exit 1
+}
+set -x
+
+IMGDIR="dump/"
+
+rm -rf "$IMGDIR"
+mkdir "$IMGDIR"
+
+echo "Launching test"
+cd ../../zdtm//live/static/
+make cleanout
+make mem-touch
+make mem-touch.pid || fail "Can't start test"
+PID=$(cat mem-touch.pid)
+kill -0 $PID || fail "Test didn't start"
+cd -
+
+echo "Making $NRSNAP snapshots"
+
+for SNAP in $(seq 1 $NRSNAP); do
+ sleep $SPAUSE
+ mkdir "$IMGDIR/$SNAP/"
+ if [ $SNAP -eq 1 ] ; then
+ # First snapshot -- no parent, keep running
+ args="--track-mem -R"
+ elif [ $SNAP -eq $NRSNAP ]; then
+ # Last snapshot -- has parent, kill afterwards
+ args="--prev-images-dir=../$((SNAP - 1))/ --track-mem --auto-dedup"
+ else
+ # Other snapshots -- have parent, keep running
+ args="--prev-images-dir=../$((SNAP - 1))/ --track-mem -R --auto-dedup"
+ fi
+
+ if [ $USEPS -eq 1 ]; then
+ ${CRIU} page-server -D "${IMGDIR}/$SNAP/" -o ps.log --auto-dedup --port ${PORT} -v4 &
+ PS_PID=$!
+ ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
+ else
+ ps_args=""
+ fi
+
+ ${CRIU} dump -D "${IMGDIR}/$SNAP/" -o dump.log -t ${PID} -v4 $args $ps_args || fail "Fail to dump"
+ if [ $USEPS -eq 1 ]; then
+ wait $PS_PID
+ fi
+done
+
+echo "Restoring"
+${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log --auto-dedup -d -v4 || fail "Fail to restore server"
+
+size_last3=$(du -sh -BK dump/3/pages-*.img | grep -Eo '[0-9]+' | head -1)
+size_last2=$(du -sh -BK dump/2/pages-*.img | grep -Eo '[0-9]+' | head -1)
+size_last1=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
+
+restore_dedup_ok=0
+if [[ $size_last1 -ne 0 || $size_last2 -ne 0 || $size_last3 -ne 0 ]]; then
+ restore_dedup_ok=1
+fi
+
+cd ../../zdtm//live/static/
+make mem-touch.stop
+cat mem-touch.out | fgrep PASS || fail "Test failed"
+
+if [ $restore_dedup_ok -ne 0 ]; then
+ fail "Dedup test failed"
+fi
+
+echo "Test PASSED"
diff --git a/test/others/mem-snap/run-snap-dedup.sh b/test/others/mem-snap/run-snap-dedup.sh
new file mode 100755
index 0000000..f59342e
--- /dev/null
+++ b/test/others/mem-snap/run-snap-dedup.sh
@@ -0,0 +1,99 @@
+#!/bin/bash
+
+source ../../env.sh || exit 1
+
+USEPS=0
+
+if [ "$1" = "-s" ]; then
+ echo "Will test via page-server"
+ USEPS=1
+ shift
+fi
+
+NRSNAP=${1:-3}
+SPAUSE=${2:-4}
+PORT=12345
+
+function fail {
+ echo "$@"
+ exit 1
+}
+set -x
+
+IMGDIR="dump/"
+
+rm -rf "$IMGDIR"
+mkdir "$IMGDIR"
+
+echo "Launching test"
+cd ../../zdtm/live/static/
+make cleanout
+make mem-touch
+make mem-touch.pid || fail "Can't start test"
+PID=$(cat mem-touch.pid)
+kill -0 $PID || fail "Test didn't start"
+cd -
+
+echo "Making $NRSNAP snapshots"
+
+for SNAP in $(seq 1 $NRSNAP); do
+ sleep $SPAUSE
+ mkdir "$IMGDIR/$SNAP/"
+ if [ $SNAP -eq 1 ] ; then
+ # First snapshot -- no parent, keep running
+ args="--track-mem -R"
+ elif [ $SNAP -eq $NRSNAP ]; then
+ # Last snapshot -- has parent, kill afterwards
+ args="--prev-images-dir=../$((SNAP - 1))/ --track-mem"
+ else
+ # Other snapshots -- have parent, keep running
+ args="--prev-images-dir=../$((SNAP - 1))/ --track-mem -R"
+ fi
+
+ if [ $USEPS -eq 1 ]; then
+ ${CRIU} page-server -D "${IMGDIR}/$SNAP/" -o ps.log --port ${PORT} -v4 &
+ PS_PID=$!
+ ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
+ else
+ ps_args=""
+ fi
+
+ ${CRIU} dump -D "${IMGDIR}/$SNAP/" -o dump.log -t ${PID} -v4 $args $ps_args || fail "Fail to dump"
+ if [ $USEPS -eq 1 ]; then
+ wait $PS_PID
+ fi
+done
+
+echo "Dedup test"
+
+size_first_2=$(du -sh -BK dump/2/pages-*.img | grep -Eo '[0-9]+' | head -1)
+size_first_1=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
+
+${CRIU} dedup -D "${IMGDIR}/$NRSNAP/"
+
+size_last_2=$(du -sh -BK dump/2/pages-*.img | grep -Eo '[0-9]+' | head -1)
+size_last_1=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
+
+dedup_ok_2=1
+dedup_ok_1=1
+
+if [ $size_first_2 -gt $size_last_2 ]; then
+ dedup_ok_2=0
+fi
+
+if [ $size_first_1 -gt $size_last_1 ]; then
+ dedup_ok_1=0
+fi
+
+echo "Restoring"
+${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log -d -v4 || fail "Fail to restore server"
+
+cd ../../zdtm/live/static/
+make mem-touch.stop
+cat mem-touch.out | fgrep PASS || fail "Test failed"
+
+if [[ $dedup_ok_2 -ne 0 || $dedup_ok_1 -ne 0 ]]; then
+ fail "Dedup test failed"
+fi
+
+echo "Test PASSED"
diff --git a/test/others/mem-snap/run-snap-maps04.sh b/test/others/mem-snap/run-snap-maps04.sh
new file mode 100755
index 0000000..97c4939
--- /dev/null
+++ b/test/others/mem-snap/run-snap-maps04.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+source ../../env.sh || exit 1
+
+USEPS=0
+
+if [ "$1" = "-s" ]; then
+ echo "Will test via page-server"
+ USEPS=1
+ shift
+fi
+
+NRSNAP=1
+SPAUSE=${2:-4}
+PORT=12345
+
+function fail {
+ echo "$@"
+ exit 1
+}
+set -x
+
+IMGDIR="dump"
+CURDIR=${pwd}
+if ! mount | fgrep "$CURDIR/$IMGDIR" ; then
+ rm -rf "$IMGDIR"
+ mkdir "$IMGDIR"
+
+ mount -t tmpfs -o size=1500M,nr_inodes=10k,mode=700 tmpfs $IMGDIR
+fi
+rm -rf "$IMGDIR/*"
+
+echo "Launching test"
+make -C ../../zdtm//live/static/ cleanout
+make -C ../../zdtm//live/static/ maps04
+make -C ../../zdtm//live/static/ maps04.pid || fail "Can't start test"
+PID=$(cat ../../zdtm//live/static/maps04.pid)
+kill -0 $PID || fail "Test haven't started"
+
+mkdir "$IMGDIR/$NRSNAP/"
+
+if [ $USEPS -eq 1 ] ; then
+ ${CRIU} page-server -D "${IMGDIR}/$NRSNAP/" -o ps.log --port ${PORT} -d -v4 #&
+ PS_PID=$!
+ ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
+else
+ ps_args=""
+fi
+
+${CRIU} dump -D "${IMGDIR}/$NRSNAP/" -o dump.log -t ${PID} -v4 $ps_args || fail "Fail to dump"
+if [ $USEPS -eq 1 ] ; then
+ wait $PS_PID
+fi
+
+echo "Restoring"
+${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log --auto-dedup -d -v4 || fail "Fail to restore"
+
+make -C ../../zdtm//live/static/ maps04.stop
+sleep 1
+
+cat "../zdtm/live/static/maps04.out" | fgrep PASS || fail "Test failed"
+
+size=$(du -sh -BK dump/1/pages-*.img | grep -Eo '[0-9]+' | head -1)
+if [ $size -ne 0 ] ; then
+ fail "Size not null"
+fi
+
+echo "Test PASSED"
diff --git a/test/others/mem-snap/run-snap.sh b/test/others/mem-snap/run-snap.sh
new file mode 100755
index 0000000..6aca4d9
--- /dev/null
+++ b/test/others/mem-snap/run-snap.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+source ../../env.sh || exit 1
+
+USEPS=0
+
+if [ "$1" = "-s" ]; then
+ echo "Will test via page-server"
+ USEPS=1
+ shift
+fi
+
+NRSNAP=${1:-3}
+SPAUSE=${2:-4}
+PORT=12345
+
+function fail {
+ echo "$@"
+ exit 1
+}
+set -x
+
+IMGDIR="dump/"
+
+rm -rf "$IMGDIR"
+mkdir "$IMGDIR"
+
+echo "Launching test"
+cd ../../zdtm/live/static/
+make cleanout
+make mem-touch
+make mem-touch.pid || fail "Can't start test"
+PID=$(cat mem-touch.pid)
+kill -0 $PID || fail "Test didn't start"
+cd -
+
+echo "Making $NRSNAP snapshots"
+
+for SNAP in $(seq 1 $NRSNAP); do
+ sleep $SPAUSE
+ mkdir "$IMGDIR/$SNAP/"
+ if [ $SNAP -eq 1 ] ; then
+ # First snapshot -- no parent, keep running
+ args="--track-mem -R"
+ elif [ $SNAP -eq $NRSNAP ]; then
+ # Last snapshot -- has parent, kill afterwards
+ args="--prev-images-dir=../$((SNAP - 1))/ --track-mem"
+ else
+ # Other snapshots -- have parent, keep running
+ args="--prev-images-dir=../$((SNAP - 1))/ --track-mem -R"
+ fi
+
+ if [ $USEPS -eq 1 ]; then
+ ${CRIU} page-server -D "${IMGDIR}/$SNAP/" -o ps.log --port ${PORT} -v4 &
+ PS_PID=$!
+ ps_args="--page-server --address 127.0.0.1 --port=${PORT}"
+ else
+ ps_args=""
+ fi
+
+ ${CRIU} dump -D "${IMGDIR}/$SNAP/" -o dump.log -t ${PID} -v4 $args $ps_args || fail "Fail to dump"
+ if [ $USEPS -eq 1 ]; then
+ wait $PS_PID
+ fi
+done
+
+echo "Restoring"
+${CRIU} restore -D "${IMGDIR}/$NRSNAP/" -o restore.log -d -v4 || fail "Fail to restore server"
+
+cd ../../zdtm/live/static/
+make mem-touch.stop
+cat mem-touch.out | fgrep PASS || fail "Test failed"
+
+echo "Test PASSED"
diff --git a/test/others/mem-snap/run.sh b/test/others/mem-snap/run.sh
new file mode 100755
index 0000000..b3995ec
--- /dev/null
+++ b/test/others/mem-snap/run.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Don't execute tests, which use maps04, they are executed by zdtm
+
+set -e
+
+#./run-predump-2.sh
+./run-predump.sh
+./run-snap-auto-dedup.sh
+./run-snap-dedup-on-restore.sh
+./run-snap-dedup.sh
+#./run-snap-maps04.sh
+./run-snap.sh
diff --git a/test/others/mounts/ext/Makefile b/test/others/mounts/ext/Makefile
new file mode 100644
index 0000000..282fba0
--- /dev/null
+++ b/test/others/mounts/ext/Makefile
@@ -0,0 +1,13 @@
+all: ext-mount.so ns_init
+
+ext-mount.so: ext-mount.c
+ gcc -g -Werror -Wall -shared -nostartfiles ext-mount.c -o ext-mount.so -iquote ../../../include -fPIC
+
+ns_init: ns_init.o
+ gcc -static $< -o $@
+
+ns_init.o: ns_init.c
+ gcc -c $< -o $@
+
+run: all
+ ./run.sh
diff --git a/test/others/mounts/ext/ext-mount.c b/test/others/mounts/ext/ext-mount.c
new file mode 100644
index 0000000..e5e974b
--- /dev/null
+++ b/test/others/mounts/ext/ext-mount.c
@@ -0,0 +1,101 @@
+#include <sys/mount.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "criu-plugin.h"
+#include "criu-log.h"
+
+#define IMG_NAME "ext-mount-test-%d.img"
+
+extern cr_plugin_init_t cr_plugin_init;
+extern cr_plugin_dump_ext_mount_t cr_plugin_dump_ext_mount;
+extern cr_plugin_restore_ext_mount_t cr_plugin_restore_ext_mount;
+
+int cr_plugin_init(void)
+{
+ pr_info("Initialized ext mount c/r\n");
+ return 0;
+}
+
+int cr_plugin_dump_ext_mount(char *mountpoint, int id)
+{
+ char *aux, *dst;
+ int fd;
+ char img[64];
+
+ pr_info("Check for ext mount %s being mine\n", mountpoint);
+ aux = strrchr(mountpoint, '/');
+ if (!aux) {
+ pr_err("Bad path provided\n");
+ return -ENOTSUP;
+ }
+
+ dst = getenv("EMP_MOUNTPOINT");
+ if (!dst) {
+ pr_err("No EMP_MOUNTPOINT env\n");
+ return -1;
+ }
+
+ if (strcmp(aux + 1, dst)) {
+ pr_info("Not mine\n");
+ return -ENOTSUP;
+ }
+
+ pr_info("Dumping my mount %d\n", id);
+ sprintf(img, IMG_NAME, id);
+ fd = openat(criu_get_image_dir(), img,
+ O_RDWR | O_CREAT | O_TRUNC, 0600);
+ if (fd < 0) {
+ pr_perror("Can't open image");
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+int cr_plugin_restore_ext_mount(int id, char *mountpoint, char *old_root, int *is_file)
+{
+ int fd;
+ char img[64], src[256], *src_file;
+
+ pr_info("Restoring my mount %d?\n", id);
+ sprintf(img, IMG_NAME, id);
+ fd = openat(criu_get_image_dir(), img, O_RDONLY);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ return -ENOTSUP;
+ pr_perror("Can't open my image");
+ return -1;
+ }
+ close(fd);
+
+ src_file = getenv("EMP_ROOT_P");
+ if (!src_file) {
+ pr_err("Can't get EMP_ROOT_P env\n");
+ return -1;
+ }
+
+ if (creat(mountpoint, 0600) < 0) {
+ if (errno != EEXIST) {
+ pr_perror("Can't make mountpoint");
+ return -1;
+ }
+ }
+
+ if (is_file)
+ *is_file = 1;
+
+ sprintf(src, "/%s/%s", old_root, src_file);
+ pr_info("Mount %s -> %s\n", src, mountpoint);
+ if (mount(src, mountpoint, NULL, MS_BIND, NULL) < 0) {
+ pr_perror("Can't bind mount");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/test/others/mounts/ext/ns_init.c b/test/others/mounts/ext/ns_init.c
new file mode 100644
index 0000000..e85bf9d
--- /dev/null
+++ b/test/others/mounts/ext/ns_init.c
@@ -0,0 +1,143 @@
+#define _GNU_SOURCE
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+
+static void sigh(int sig)
+{
+}
+
+int main(int argc, char **argv)
+{
+ int start[2];
+ char res;
+ pid_t pid;
+
+ /*
+ * Usage:
+ * run <pidfile> <root> <log-file-name> <file-to-check> <contents-to-check>
+ */
+
+ if (getpid() == 1) {
+ int fd;
+ struct sigaction sa = {};
+ sigset_t mask;
+
+ if (setsid() == -1) {
+ fprintf(stderr, "setsid: %m\n");
+ return 1;
+ }
+
+ sa.sa_handler = sigh;
+ sigaction(SIGTERM, &sa, NULL);
+
+ if (chdir(argv[2]))
+ return 1;
+
+ fd = open(argv[3], O_WRONLY|O_CREAT|O_TRUNC|O_APPEND, 0600);
+ if (fd < 0)
+ return 1;
+
+ dup2(fd, 1);
+ dup2(fd, 2);
+ close(fd);
+ close(0);
+
+ if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) {
+ fprintf(stderr, "mount(/, S_REC | MS_PRIVATE)): %m");
+ return 1;
+ }
+
+ mkdir("oldm");
+ if (pivot_root(".", "./oldm") < 0)
+ return 1;
+
+ umount2("/oldm", MNT_DETACH);
+
+ mkdir("/proc");
+ if (mount("zdtm_proc", "/proc", "proc", 0, NULL)) {
+ fprintf(stderr, "mount(/proc): %m");
+ return 1;
+ }
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGTERM);
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ fd = atoi(argv[1]);
+ write(fd, "!", 1);
+ close(fd);
+
+ sigemptyset(&mask);
+ sigsuspend(&mask);
+
+ printf("Woken UP\n");
+ printf("Reading %s for [%s]\n", argv[4], argv[5]);
+ {
+ FILE *f;
+ char buf[128];
+
+ f = fopen(argv[4], "r");
+ if (!f)
+ perror("No file with message");
+ else {
+ memset(buf, 0, sizeof(buf));
+ fgets(buf, sizeof(buf), f);
+ fclose(f);
+ printf("Got [%s]\n", buf);
+
+ if (!strcmp(buf, argv[5]))
+ printf("PASS\n");
+ }
+ }
+
+ exit(0);
+ }
+
+ if (unshare(CLONE_NEWNS | CLONE_NEWPID))
+ return 1;
+
+ pipe(start);
+ pid = fork();
+ if (pid == 0) {
+ char *nargv[7], aux[10];
+
+ close(start[0]);
+ sprintf(aux, "%d", start[1]);
+ nargv[0] = argv[0];
+ nargv[1] = aux;
+ nargv[2] = argv[2];
+ nargv[3] = argv[3];
+ nargv[4] = argv[4];
+ nargv[5] = argv[5];
+ nargv[6] = NULL;
+
+ execv(argv[0], nargv);
+ exit(0);
+ }
+
+ close(start[1]);
+ res = 'F';
+ read(start[0], &res, 1);
+ if (res != '!') {
+ printf("Failed to start\n");
+ return 1;
+ }
+
+ printf("Container w/ tests started\n");
+ {
+ FILE *pidf;
+ pidf = fopen(argv[1], "w");
+ fprintf(pidf, "%d", pid);
+ fclose(pidf);
+ }
+
+ return 0;
+}
diff --git a/test/others/mounts/ext/run.sh b/test/others/mounts/ext/run.sh
new file mode 100755
index 0000000..ff2a2d8
--- /dev/null
+++ b/test/others/mounts/ext/run.sh
@@ -0,0 +1,125 @@
+#!/bin/bash
+
+set -x
+
+function fail {
+ echo $@
+ exit 1
+}
+
+make || fail "Can't compile library or ns init"
+
+criu="../../../criu/criu"
+
+# New root for namespace
+NSROOT="nsroot"
+# External file with contents (exported for plugin.restore)
+EMP_ROOT="external_file"
+export EMP_ROOT_P="$(pwd)/$EMP_ROOT"
+# Internal file as seen from namespace (exported for plugin.dump)
+export EMP_MOUNTPOINT="file"
+# Message in a file to check visibility
+FMESSAGE="tram-pam-pam"
+# Binary of namespace's init
+NS_INIT="ns_init"
+# File with namespace init pid
+PIDF="pidf"
+
+start_ns()
+{
+ #
+ # Prepare the namespace's FS layout
+ #
+ mkdir $NSROOT
+ echo -n "$FMESSAGE" > "$EMP_ROOT"
+ mount --bind "$NSROOT" "$NSROOT"
+ mount --make-private "$NSROOT"
+ touch "$NSROOT/$EMP_MOUNTPOINT"
+ mount --bind "$EMP_ROOT" "$NSROOT/$EMP_MOUNTPOINT" || fail "Can't prepare fs for ns"
+
+ #
+ # Start the namespace's init
+ #
+ cp $NS_INIT "$NSROOT/"
+ "./$NSROOT/$NS_INIT" "$PIDF" "$NSROOT" "log" "$EMP_MOUNTPOINT" "$FMESSAGE" || fail "Can't start namespace"
+ umount "$NSROOT/$EMP_MOUNTPOINT"
+
+ echo "Namespace started, pid $(cat $PIDF)"
+}
+
+stop_ns()
+{
+ #
+ # Kill the init
+ #
+
+ kill -TERM $(cat $PIDF)
+ sleep 2 # Shitty, but...
+ umount $NSROOT
+
+ if [ -z "$1" ]; then
+ rm -f "$NSROOT/log"
+ else
+ mv "$NSROOT/log" "$1"
+ fi
+
+ rm -f "$PIDF" "$EMP_ROOT" "$NSROOT/$NS_INIT" "$NSROOT/log" "$NSROOT/$EMP_MOUNTPOINT"
+ rmdir "$NSROOT/oldm"
+ rmdir "$NSROOT/proc"
+ rmdir "$NSROOT"
+}
+
+DDIR="dump"
+rm -rf $DDIR
+mkdir $DDIR
+
+chk_pass()
+{
+ tail -n1 $1 | fgrep -q "PASS"
+}
+
+#
+# Test 1: handle external mount with plugin
+#
+
+test_plugin()
+{
+ echo "=== Testing how plugin works"
+ mkdir "$DDIR/plugin/"
+ start_ns
+
+ $criu dump -D "$DDIR/plugin/" -v4 -o "dump.log" --lib=$(pwd) \
+ -t $(cat pidf) || { stop_ns; return 1; }
+
+ $criu restore -D "$DDIR/plugin/" -v4 -o "rstr.log" --lib=$(pwd) \
+ -d --root="$(pwd)/$NSROOT" --pidfile=$PIDF || { stop_ns; return 1; }
+
+ echo "Restored, checking results"
+ mv "$DDIR/plugin/$PIDF" .
+ stop_ns "$DDIR/plugin/ns.log"
+ chk_pass "$DDIR/plugin/ns.log"
+}
+
+test_ext_mount_map()
+{
+ echo "=== Testing how --ext-mount-map works"
+ mkdir "$DDIR/ext_mount_map/"
+ start_ns
+
+ $criu dump -D "$DDIR/ext_mount_map/" -v4 -o "dump.log" \
+ -t $(cat pidf) --ext-mount-map "/$EMP_MOUNTPOINT:TM" || { stop_ns; return 1; }
+
+ $criu restore -D "$DDIR/ext_mount_map/" -v4 -o "rstr.log" \
+ -d --root="$(pwd)/$NSROOT" --pidfile=$PIDF --ext-mount-map "TM:$EMP_ROOT_P" || { stop_ns; return 1; }
+
+ echo "Restored, checking results"
+ mv "$DDIR/ext_mount_map/$PIDF" .
+ stop_ns "$DDIR/ext_mount_map/ns.log"
+ chk_pass "$DDIR/ext_mount_map/ns.log"
+}
+
+test_plugin || exit 1
+test_ext_mount_map || exit 1
+
+echo "All tests passed"
+exit 0
diff --git a/test/others/mounts/mounts.py b/test/others/mounts/mounts.py
new file mode 100755
index 0000000..7f11d7d
--- /dev/null
+++ b/test/others/mounts/mounts.py
@@ -0,0 +1,31 @@
+import os
+import tempfile, random
+
+def mount(src, dst, shared, private, slave):
+ cmd = "mount"
+ if shared:
+ cmd += " --make-shared"
+ if private:
+ cmd += " --make-private"
+ if slave:
+ cmd += " --make-slave"
+ if src:
+ cmd += " --bind '%s' '%s'" % (src, dst)
+ else:
+ cmd += " -t tmpfs none '%s'" % (dst)
+
+ print cmd
+ ret = os.system(cmd)
+ if ret:
+ print "failed"
+
+root = tempfile.mkdtemp(prefix = "root.mount", dir = "/tmp")
+mount(None, root, 1, 0, 0)
+mounts = [root]
+
+for i in xrange(10):
+ dstdir = random.choice(mounts)
+ dst = tempfile.mkdtemp(prefix = "mount", dir = dstdir)
+ src = random.choice(mounts + [None])
+ mount(src, dst, random.randint(0,100) > 50, random.randint(0,100) > 90, random.randint(0,100) > 50)
+ mounts.append(dst)
diff --git a/test/others/mounts/mounts.sh b/test/others/mounts/mounts.sh
new file mode 100755
index 0000000..19116d0
--- /dev/null
+++ b/test/others/mounts/mounts.sh
@@ -0,0 +1,27 @@
+[ -z "$INMNTNS" ] && {
+ export INMNTNS=`pwd`
+ export INMNTNS_PID=$$
+ unshare -m -- setsid bash -x "$0" "$@" < /dev/null &> mounts.log &
+ echo $! > mounts.pid
+ while :; do
+ sleep 1
+ done
+}
+
+cd $INMNTNS
+
+mount --make-rprivate /
+
+for i in `cat /proc/self/mounts | awk '{ print $2 }'`; do
+ [ '/' = "$i" ] && continue
+ [ '/proc' = "$i" ] && continue
+ [ '/dev' = "$i" ] && continue
+ echo $i
+ umount -l $i
+done
+
+python mounts.py
+kill $INMNTNS_PID
+while :; do
+ sleep 10
+done
diff --git a/test/others/mounts/run.sh b/test/others/mounts/run.sh
new file mode 100755
index 0000000..6428239
--- /dev/null
+++ b/test/others/mounts/run.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+CRIU=../../../criu
+set -x
+
+mkdir -p dump
+
+./mounts.sh
+pid=`cat mounts.pid`
+kill -0 $pid || exit
+
+cat /proc/$pid/mountinfo | sort -k 4
+echo "Suspend server"
+${CRIU} dump -D dump -o dump.log -t $pid -v4 || {
+ cat dump/dump.log | grep Error
+ exit 1
+}
+echo "Resume server"
+${CRIU} restore -d -D dump -o restore.log -v4 || {
+ cat dump/dump.log | grep Error
+ exit 1
+}
+cat /proc/$pid/mountinfo | sort -k 4
+kill $pid
diff --git a/test/others/overlayfs/Makefile b/test/others/overlayfs/Makefile
new file mode 100644
index 0000000..78c246b
--- /dev/null
+++ b/test/others/overlayfs/Makefile
@@ -0,0 +1,6 @@
+run:
+ ./run.sh
+
+clean:
+ umount -f overlay_test/z
+ rm -rf overlay_test output checkpoint
diff --git a/test/others/overlayfs/run.sh b/test/others/overlayfs/run.sh
new file mode 100755
index 0000000..26e6ec2
--- /dev/null
+++ b/test/others/overlayfs/run.sh
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+set -eu
+
+CRIU=../../../criu/criu
+
+setup() {
+ setup_mount
+ setsid sleep 10 3>z/file < /dev/null &> output &
+ PROC_PID=$!
+ echo "PROC_PID=$PROC_PID"
+ sleep 1
+}
+
+setup_mount() {
+ mkdir -p overlay_test
+ cd overlay_test
+ mkdir -p a b c z checkpoint
+ mount -t overlay -o lowerdir=a,upperdir=b,workdir=c overlayfs z
+}
+
+check_criu() {
+ echo "Dumping $PROC_PID..."
+ if ! $CRIU dump -D checkpoint -t "${PROC_PID}"; then
+ echo "ERROR! dump failed"
+ return 1
+ fi
+
+ echo "Restoring..."
+ if ! $CRIU restore -d -D checkpoint; then
+ echo "ERROR! restore failed"
+ return 1
+ fi
+ return 0
+}
+
+cleanup() {
+ kill -INT "${PROC_PID}" > /dev/null 2>&1
+ umount z
+ cd "${ORIG_WD}"
+ rm -rf overlay_test
+}
+
+main() {
+ ORIG_WD=$(pwd)
+ setup
+
+ check_criu || {
+ cleanup
+ exit 1
+ }
+
+ cleanup
+ echo "OverlayFS C/R successful."
+ exit 0
+}
+
+main
diff --git a/test/others/pipes/Makefile b/test/others/pipes/Makefile
new file mode 100644
index 0000000..71b16be
--- /dev/null
+++ b/test/others/pipes/Makefile
@@ -0,0 +1,14 @@
+CFLAGS += -Wall
+pipe: pipe.c
+clean:
+ rm -f pipe
+run: pipe
+ ./pipe - && \
+ ./pipe -c && \
+ ./pipe -cl && \
+ ./pipe -d && \
+ ./pipe -o && \
+ ./pipe -r && \
+ ./pipe -dc && \
+ ./pipe -dcl && \
+ true
diff --git a/test/others/pipes/pipe.c b/test/others/pipes/pipe.c
new file mode 100644
index 0000000..33ec60e
--- /dev/null
+++ b/test/others/pipes/pipe.c
@@ -0,0 +1,693 @@
+/*
+ * A simple demo/test program using criu's --inherit-fd command line
+ * option to restore a process with (1) an external pipe and (2) a
+ * new log file.
+ *
+ * Note that it's possible to restore the process without --inherit-fd,
+ * but when it reads from or writes to the pipe, it will get a broken
+ * pipe signal.
+ *
+ * Also note that changing the log file during restore has nothing to do
+ * with the pipe. It's just a nice feature for cases where it's desirable
+ * to have a restored process use a different file then the original one.
+ *
+ * The parent process spawns a child that will write messages to its
+ * parent through a pipe. After a couple of messages, parent invokes
+ * criu to checkpoint the child. Since the child exits after checkpoint,
+ * its pipe will be broken. Parent sets up a new pipe and invokes criu
+ * to restore the child using the new pipe (instead of the old one).
+ * The restored child exits after writing a couple more messages.
+ *
+ * To make sure that fd clashes are correctly handled during restore,
+ * child can optionally open a regular file and move it to a clashing fd.
+ *
+ * Make sure CRIU_BINARY defined below points to the right criu.
+ *
+ * $ cc -Wall -o pipe pipe.c
+ * $ sudo ./pipe -v
+ *
+ * The following should all succeed:
+ *
+ * $ sudo ./pipe -q && echo OK
+ * $ sudo ./pipe -qc && echo OK
+ * $ sudo ./pipe -qcl && echo OK
+ * $ sudo ./pipe -qd && echo OK
+ * $ sudo ./pipe -qdc && echo OK
+ * $ sudo ./pipe -qdcl && echo OK
+ *
+ * The following should all fail:
+ *
+ * $ sudo ./pipe -qn || echo $?
+ * $ sudo ./pipe -qo || echo $?
+ * $ sudo ./pipe -qr || echo $?
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+
+typedef void (*sighandler_t)(int);
+typedef unsigned long ulong;
+
+/* colors */
+#define CS_PARENT "\033[00;32m"
+#define CS_CHILD "\033[00;33m"
+#define CS_DUMP "\033[00;34m"
+#define CS_RESTORE "\033[00;35m"
+#define CE "\033[0m"
+
+#define die(fmt, ...) do { \
+ if (!qflag) \
+ fprintf(stderr, fmt ": %m\n", __VA_ARGS__); \
+ if (getpid() == parent_pid) { \
+ (void)kill(0, 9); \
+ exit(1); \
+ } \
+ _exit(1); \
+} while (0)
+
+#define READ_FD 0 /* pipe read fd */
+#define WRITE_FD 1 /* pipe write fd */
+#define CLASH_FD 3 /* force inherit fd clash */
+
+#define MAX_FORKS 3 /* child, checkpoint, restore */
+
+#define CRIU_BINARY "../../../criu/criu"
+#define IMG_DIR "images"
+#define DUMP_LOG_FILE "dump.log"
+#define RESTORE_LOG_FILE "restore.log"
+#define RESTORE_PID_FILE "restore.pid"
+#define INHERIT_FD_OPTION "--inherit-fd"
+#define OLD_LOG_FILE "/tmp/oldlog"
+#define NEW_LOG_FILE "/tmp/newlog"
+
+/*
+ * Command line options (see usage()).
+ */
+char *cli_flags = "cdhlnoqrv";
+
+int cflag;
+int dflag;
+int lflag;
+int nflag;
+int oflag;
+int qflag;
+int rflag;
+int vflag;
+
+char pid_number[8];
+char inh_pipe_opt[16];
+char inh_pipe_arg[64];
+char inh_file_opt[16];
+char inh_file_arg[64];
+
+char *dump_argv[] = {
+ "criu", "dump",
+ "-D", IMG_DIR, "-o", DUMP_LOG_FILE,
+ "-v4",
+ "-t", pid_number,
+ NULL
+};
+
+char *restore_argv[] = {
+ "criu", "restore", "-d",
+ "-D", IMG_DIR, "-o", RESTORE_LOG_FILE,
+ "--pidfile", RESTORE_PID_FILE,
+ "-v4",
+ inh_pipe_opt, inh_pipe_arg,
+ inh_file_opt, inh_file_arg,
+ NULL
+};
+
+int max_msgs;
+int max_forks;
+int parent_pid;
+int child_pid;
+int criu_dump_pid;
+int criu_restore_pid;
+
+/* prototypes */
+void chld_handler(int signum);
+int parent(int *pipefd);
+int child(int *pipefd, int dupfd, int newfd);
+void checkpoint_child(int child_pid, int *pipefd);
+void restore_child(int *new_pipefd, char *old_pipe_name);
+void write_to_fd(int fd, char *name, int i, int newline);
+void ls_proc_fd(int fd);
+char *pipe_name(int fd);
+char *who(pid_t pid);
+void pipe_safe(int pipefd[2]);
+pid_t fork_safe(void);
+void signal_safe(int signum, sighandler_t handler);
+int open_safe(char *pathname, int flags);
+void close_safe(int fd);
+void write_safe(int fd, char *buf, int count);
+int read_safe(int fd, char *buf, int count);
+int dup_safe(int oldfd);
+void move_fd(int oldfd, int newfd);
+void mkdir_safe(char *dirname, int mode);
+void unlink_safe(char *pathname);
+void execv_safe(char *path, char *argv[], int ls);
+pid_t waitpid_safe(pid_t pid, int *status, int options, int id);
+void prctl_safe(int option, ulong arg2, ulong arg3, ulong arg4, ulong arg5);
+int dup2_safe(int oldfd, int newfd);
+
+void usage(char *cmd)
+{
+ printf("Usage: %s [%s]\n", cmd, cli_flags);
+ printf("-c\tcause a clash during restore by opening %s as fd %d\n",
+ OLD_LOG_FILE, CLASH_FD);
+ printf("-d\tdup the pipe and write to it\n");
+ printf("-l\tchange log file from %s to %s during restore\n",
+ OLD_LOG_FILE, NEW_LOG_FILE);
+
+ printf("\n");
+ printf("The following flags should cause restore failure\n");
+ printf("-n\tdo not use the %s option\n", INHERIT_FD_OPTION);
+ printf("-o\topen the pipe via /proc/<pid>/fd and write to it\n");
+ printf("-r\tspecify read end of pipe during restore\n");
+
+ printf("\n");
+ printf("Miscellaneous flags\n");
+ printf("-h\tprint this help and exit\n");
+ printf("-q\tquiet mode, don't print anything\n");
+ printf("-v\tverbose mode (list contents of /proc/<pid>/fd)\n");
+
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ int opt;
+ int pipefd[2];
+
+ max_msgs = 4;
+ while ((opt = getopt(argc, argv, cli_flags)) != -1) {
+ switch (opt) {
+ case 'c': cflag++; break;
+ case 'd': dflag++; max_msgs += 4; break;
+ case 'h': usage(argv[0]); return 0;
+ case 'l': lflag++; break;
+ case 'n': nflag++; break;
+ case 'o': oflag++; max_msgs += 4; break;
+ case 'q': qflag++; vflag = 0;break;
+ case 'r': rflag++; break;
+ case 'v': vflag++; qflag = 0; break;
+ default: usage(argv[0]); return 1;
+ }
+ }
+
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+ mkdir_safe(IMG_DIR, 0700);
+
+ pipe_safe(pipefd);
+ child_pid = fork_safe();
+ if (child_pid > 0) {
+ parent_pid = getpid();
+
+ signal_safe(SIGCHLD, chld_handler);
+ prctl_safe(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
+
+ close_safe(pipefd[WRITE_FD]);
+
+ ret = parent(pipefd);
+ } else {
+ /* child */
+ int dupfd = -1;
+ int openfd = -1;
+ int logfd, flags;
+
+ child_pid = getpid();
+
+ close_safe(pipefd[READ_FD]);
+ setsid();
+ logfd = open_safe(OLD_LOG_FILE, O_WRONLY | O_APPEND | O_CREAT);
+ dup2_safe(logfd, 1);
+ dup2_safe(logfd, 2);
+ close(logfd);
+ close(0);
+
+ /* open a regular file and move it to CLASH_FD */
+ if (cflag)
+ move_fd(open_safe(OLD_LOG_FILE, O_WRONLY | O_APPEND | O_CREAT), CLASH_FD);
+
+ fcntl(pipefd[WRITE_FD], F_SETFL, O_NONBLOCK | O_WRONLY);
+ /* open additional descriptors on the pipe and use them all */
+ if (dflag)
+ dupfd = dup_safe(pipefd[WRITE_FD]);
+ if (oflag) {
+ char buf[128];
+ snprintf(buf, sizeof buf, "/proc/self/fd/%d", pipefd[WRITE_FD]);
+ openfd = open_safe(buf, O_WRONLY);
+ }
+
+ ret = child(pipefd, dupfd, openfd);
+
+ flags = fcntl(pipefd[WRITE_FD], F_GETFL, 0);
+ if ((flags & O_NONBLOCK) == 0) {
+ printf("Unexpected flags %x\n", flags);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Parent reads message from its pipe with the child.
+ * After a couple of messages, it checkpoints the child
+ * which causes the child to exit. Parent then creates
+ * a new pipe and restores the child.
+ */
+int parent(int *pipefd)
+{
+ char buf[32];
+ char old_pipe[32];
+ int nread;
+
+ nread = 0;
+ while (max_forks <= MAX_FORKS) {
+ if (read_safe(pipefd[READ_FD], buf, sizeof buf) == 0)
+ continue;
+ nread++;
+ if (vflag && nread == 1)
+ ls_proc_fd(-1);
+
+ if (!qflag) {
+ printf("%s read %s from %s\n", who(0), buf,
+ pipe_name(pipefd[READ_FD]));
+ }
+
+ if (nread == (max_msgs / 2)) {
+ checkpoint_child(child_pid, pipefd);
+
+ if (!nflag) {
+ /* save the old pipe's name before closing it */
+ snprintf(old_pipe, sizeof old_pipe, "%s",
+ pipe_name(pipefd[READ_FD]));
+ close_safe(pipefd[READ_FD]);
+
+ /* create a new one */
+ if (!qflag)
+ printf("%s creating a new pipe\n", who(0));
+ pipe_safe(pipefd);
+ }
+ restore_child(pipefd, old_pipe);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Child sends a total of max_messages messages to its
+ * parent, half before checkpoint and half after restore.
+ */
+int child(int *pipefd, int dupfd, int openfd)
+{
+ int i;
+ int fd;
+ int num_wfds;
+ struct timespec req = { 1, 0 };
+
+ /*
+ * Count the number of pipe descriptors we'll be
+ * writing to. At least 1 (for pipefd[WRITE_FD])
+ * and at most 3.
+ */
+ num_wfds = 1;
+ if (dupfd >= 0)
+ num_wfds++;
+ if (openfd >= 0)
+ num_wfds++;
+
+ for (i = 0; i < max_msgs; i++) {
+ /* print first time and after checkpoint */
+ if (vflag && (i == 0 || i == (max_msgs / 2)))
+ ls_proc_fd(-1);
+
+ switch (i % num_wfds) {
+ case 0: fd = pipefd[WRITE_FD]; break;
+ case 1: fd = dflag ? dupfd : openfd; break;
+ case 2: fd = openfd; break;
+ }
+
+ write_to_fd(fd, pipe_name(pipefd[WRITE_FD]), i+1, 0);
+ if (cflag)
+ write_to_fd(CLASH_FD, "log file", i+1, 1);
+
+ /*
+ * Since sleep will be interrupted by C/R, make sure
+ * to sleep an entire second to minimize the chance of
+ * writing before criu restore has exited. If criu is
+ * still around and we write to a broken pipe, we'll be
+ * killed but SIGCHLD will be delivered to criu instead
+ * of parent.
+ */
+ while (nanosleep(&req, NULL))
+ ;
+ if (!qflag)
+ printf("\n");
+ }
+
+ return 0;
+}
+
+void chld_handler(int signum)
+{
+ int status;
+ pid_t pid;
+
+ pid = waitpid_safe(-1, &status, WNOHANG, 1);
+ if (WIFEXITED(status))
+ status = WEXITSTATUS(status);
+ if (pid == child_pid) {
+ if (!qflag) {
+ printf("%s %s exited with status %d\n", who(0),
+ who(pid), status);
+ }
+ /* if child exited successfully, we're done */
+ if (status == 0)
+ exit(0);
+ /* checkpoint kills the child */
+ if (status != 9)
+ exit(status);
+ }
+}
+
+void checkpoint_child(int child_pid, int *pipefd)
+{
+ /* prepare -t <pid> */
+ snprintf(pid_number, sizeof pid_number, "%d", child_pid);
+
+ criu_dump_pid = fork_safe();
+ if (criu_dump_pid > 0) {
+ int status;
+ pid_t pid;
+
+ pid = waitpid_safe(criu_dump_pid, &status, 0, 2);
+ if (WIFEXITED(status))
+ status = WEXITSTATUS(status);
+ if (!qflag) {
+ printf("%s %s exited with status %d\n", who(0),
+ who(pid), status);
+ }
+ if (status)
+ exit(status);
+ } else {
+ close(pipefd[READ_FD]);
+ criu_dump_pid = getpid();
+ execv_safe(CRIU_BINARY, dump_argv, 0);
+ }
+}
+
+void restore_child(int *new_pipefd, char *old_pipe_name)
+{
+ char buf[64];
+
+ criu_restore_pid = fork_safe();
+ if (criu_restore_pid > 0) {
+ int status;
+ pid_t pid;
+
+ if (!nflag)
+ close_safe(new_pipefd[WRITE_FD]);
+
+ pid = waitpid_safe(criu_restore_pid, &status, 0, 3);
+ if (WIFEXITED(status))
+ status = WEXITSTATUS(status);
+ if (!qflag) {
+ printf("%s %s exited with status %d\n", who(0),
+ who(pid), status);
+ }
+ if (status)
+ exit(status);
+ } else {
+ criu_restore_pid = getpid();
+
+ if (!nflag) {
+ /*
+ * We should close the read descriptor of the new pipe
+ * and use its write descriptor to call criu restore.
+ * But if rflag was set (for testing purposes), use the
+ * read descriptor which should cause the application to
+ * fail.
+ *
+ * Regardless of read or write descriptor, move it to a
+ * clashing fd to test inherit fd clash resolve code.
+ */
+ if (rflag)
+ move_fd(new_pipefd[READ_FD], CLASH_FD);
+ else {
+ close_safe(new_pipefd[READ_FD]);
+ move_fd(new_pipefd[WRITE_FD], CLASH_FD);
+ }
+
+ /* --inherit-fd fd[CLASH_FD]:pipe[xxxxxx] */
+ snprintf(inh_pipe_opt, sizeof inh_pipe_opt,
+ "%s", INHERIT_FD_OPTION);
+ snprintf(inh_pipe_arg, sizeof inh_pipe_arg, "fd[%d]:%s",
+ CLASH_FD, old_pipe_name);
+
+ if (lflag) {
+ /* create a new log file to replace the old one */
+ int filefd = open_safe(NEW_LOG_FILE, O_WRONLY | O_APPEND | O_CREAT);
+
+ /* --inherit-fd fd[x]:tmp/oldlog */
+ snprintf(inh_file_opt, sizeof inh_file_opt,
+ "%s", INHERIT_FD_OPTION);
+ snprintf(inh_file_arg, sizeof inh_file_arg,
+ "fd[%d]:%s", filefd, OLD_LOG_FILE + 1);
+
+ restore_argv[12] = inh_file_opt;
+ } else
+ restore_argv[12] = NULL;
+ restore_argv[10] = inh_pipe_opt;
+ } else
+ restore_argv[10] = NULL;
+
+ snprintf(buf, sizeof buf, "%s/%s", IMG_DIR, RESTORE_PID_FILE);
+ unlink_safe(buf);
+ execv_safe(CRIU_BINARY, restore_argv, 1);
+ }
+}
+
+void write_to_fd(int fd, char *name, int i, int newline)
+{
+ int n;
+ char buf[16]; /* fit "hello d\n" for small d */
+
+ n = snprintf(buf, sizeof buf, "hello %d", i);
+ if (!qflag)
+ printf("%s writing %s to %s via fd %d\n", who(0), buf, name, fd);
+
+ if (newline) {
+ buf[n++] = '\n';
+ buf[n] = '\0';
+ }
+ write_safe(fd, buf, strlen(buf));
+}
+
+void ls_proc_fd(int fd)
+{
+ char cmd[128];
+
+ if (qflag)
+ return;
+
+ if (fd == -1)
+ snprintf(cmd, sizeof cmd, "ls -l /proc/%d/fd", getpid());
+ else
+ snprintf(cmd, sizeof cmd, "ls -l /proc/%d/fd/%d", getpid(), fd);
+ printf("%s %s\n", who(0), cmd);
+ system(cmd);
+}
+
+char *pipe_name(int fd)
+{
+ static char pipe_name[64];
+ char path[64];
+
+ snprintf(path, sizeof path, "/proc/self/fd/%d", fd);
+ if (readlink(path, pipe_name, sizeof pipe_name) == -1)
+ die("readlink: path=%s", path);
+ return pipe_name;
+}
+
+/*
+ * Use two buffers to support two calls to
+ * this function in a printf argument list.
+ */
+char *who(pid_t pid)
+{
+ static char pidstr1[64];
+ static char pidstr2[64];
+ static char *cp;
+ char *np;
+ char *ep;
+ int p;
+
+ p = pid ? pid : getpid();
+ if (p == parent_pid) {
+ np = "parent";
+ ep = CS_PARENT;
+ } else if (p == child_pid) {
+ np = "child";
+ ep = CS_CHILD;
+ } else if (p == criu_dump_pid) {
+ np = "dump";
+ ep = CS_DUMP;
+ } else if (p == criu_restore_pid) {
+ np = "restore";
+ ep = CS_RESTORE;
+ } else
+ np = "???";
+
+ cp = (cp == pidstr1) ? pidstr2 : pidstr1;
+ snprintf(cp, sizeof pidstr1, "%s[%s %d]", pid ? "" : ep, np, p);
+ return cp;
+}
+
+void pipe_safe(int pipefd[2])
+{
+ if (pipe(pipefd) == -1)
+ die("pipe: %p", pipefd);
+}
+
+pid_t fork_safe(void)
+{
+ pid_t pid;
+
+ if ((pid = fork()) == -1)
+ die("fork: pid=%d", pid);
+ max_forks++;
+ return pid;
+}
+
+void signal_safe(int signum, sighandler_t handler)
+{
+ if (signal(signum, handler) == SIG_ERR)
+ die("signal: signum=%d", signum);
+}
+
+int open_safe(char *pathname, int flags)
+{
+ int fd;
+
+ if ((fd = open(pathname, flags, 0777)) == -1)
+ die("open: pathname=%s", pathname);
+ return fd;
+}
+
+void close_safe(int fd)
+{
+ if (close(fd) == -1)
+ die("close: fd=%d", fd);
+}
+
+void write_safe(int fd, char *buf, int count)
+{
+ if (write(fd, buf, count) != count) {
+ die("write: fd=%d buf=\"%s\" count=%d errno=%d",
+ fd, buf, count, errno);
+ }
+}
+
+int read_safe(int fd, char *buf, int count)
+{
+ int n;
+
+ if ((n = read(fd, buf, count)) < 0)
+ die("read: fd=%d count=%d", fd, count);
+ buf[n] = '\0';
+ return n;
+}
+
+int dup_safe(int oldfd)
+{
+ int newfd;
+
+ if ((newfd = dup(oldfd)) == -1)
+ die("dup: oldfd=%d", oldfd);
+ return newfd;
+}
+
+int dup2_safe(int oldfd, int newfd)
+{
+ if (dup2(oldfd, newfd) != newfd)
+ die("dup2: oldfd=%d newfd=%d", oldfd, newfd);
+ return newfd;
+}
+
+void move_fd(int oldfd, int newfd)
+{
+ if (oldfd != newfd) {
+ dup2_safe(oldfd, newfd);
+ close_safe(oldfd);
+ }
+}
+
+void mkdir_safe(char *dirname, int mode)
+{
+ if (mkdir(dirname, mode) == -1 && errno != EEXIST)
+ die("mkdir dirname=%s mode=0x%x\n", dirname, mode);
+}
+
+void unlink_safe(char *pathname)
+{
+ if (unlink(pathname) == -1 && errno != ENOENT) {
+ die("unlink: pathname=%s\n", pathname);
+ }
+}
+
+void execv_safe(char *path, char *argv[], int ls)
+{
+ int i;
+ struct timespec req = { 0, 1000000 };
+
+ if (!qflag) {
+ printf("\n%s ", who(0));
+ for (i = 0; argv[i] != NULL; i++)
+ printf("%s ", argv[i]);
+ printf("\n");
+ }
+
+ /* give parent a chance to wait for us */
+ while (nanosleep(&req, NULL))
+ ;
+
+ if (vflag && ls)
+ ls_proc_fd(-1);
+
+ execv(path, argv);
+ die("execv: path=%s", path);
+}
+
+pid_t waitpid_safe(pid_t pid, int *status, int options, int id)
+{
+ pid_t p;
+
+ p = waitpid(pid, status, options);
+ if (p == -1)
+ fprintf(stderr, "waitpid pid=%d id=%d %m\n", pid, id);
+ return p;
+}
+
+void prctl_safe(int option, ulong arg2, ulong arg3, ulong arg4, ulong arg5)
+{
+ if (prctl(option, arg2, arg3, arg4, arg5) == -1)
+ die("prctl: option=0x%x", option);
+}
diff --git a/test/others/rpc/.gitignore b/test/others/rpc/.gitignore
new file mode 100644
index 0000000..75fca39
--- /dev/null
+++ b/test/others/rpc/.gitignore
@@ -0,0 +1,3 @@
+rpc.pb-c.*
+*_pb2.py
+test-c
diff --git a/test/others/rpc/Makefile b/test/others/rpc/Makefile
new file mode 100644
index 0000000..8bd663e
--- /dev/null
+++ b/test/others/rpc/Makefile
@@ -0,0 +1,28 @@
+all: test-c rpc_pb2.py criu
+.PHONY: all
+
+CFLAGS += -g -Werror -Wall -I.
+LDFLAGS += -lprotobuf-c
+
+run: all
+ mkdir -p build
+ chmod a+rwx build
+ sudo -g '#1000' -u '#1000' ./run.sh
+
+criu: ../../../criu/criu
+ cp ../../../criu/criu $@
+ chmod u+s $@
+
+test-c: rpc.pb-c.o test-c.o
+
+test-c.o: test-c.c rpc.pb-c.c
+
+rpc_pb2.py: rpc.proto
+ protoc --proto_path=. --python_out=. rpc.proto
+
+rpc.pb-c.c: rpc.proto
+ protoc-c --proto_path=. --c_out=. rpc.proto
+
+clean:
+ rm -rf build rpc.pb-c.o test-c.o test-c rpc.pb-c.c rpc.pb-c.h rpc_pb2.py rpc_pb2.pyc criu
+.PHONY: clean
diff --git a/test/others/rpc/errno.py b/test/others/rpc/errno.py
new file mode 100755
index 0000000..666dfff
--- /dev/null
+++ b/test/others/rpc/errno.py
@@ -0,0 +1,135 @@
+#!/usr/bin/python
+# Test criu errno
+
+import socket, os, imp, sys, errno
+import rpc_pb2 as rpc
+import argparse
+
+parser = argparse.ArgumentParser(description="Test errno reported by CRIU RPC")
+parser.add_argument('socket', type = str, help = "CRIU service socket")
+parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed")
+
+args = vars(parser.parse_args())
+
+# Prepare dir for images
+class test:
+ def __init__(self):
+ self.imgs_fd = os.open(args['dir'], os.O_DIRECTORY)
+ self.s = -1
+ self._MAX_MSG_SIZE = 1024
+
+ def connect(self):
+ self.s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+ self.s.connect(args['socket'])
+
+ def get_base_req(self):
+ req = rpc.criu_req()
+ req.opts.log_level = 4
+ req.opts.images_dir_fd = self.imgs_fd
+ return req
+
+ def send_req(self, req):
+ self.connect()
+ self.s.send(req.SerializeToString())
+
+ def recv_resp(self):
+ resp = rpc.criu_resp()
+ resp.ParseFromString(self.s.recv(self._MAX_MSG_SIZE))
+ return resp
+
+ def check_resp(self, resp, typ, err):
+ if resp.type != typ:
+ raise Exception('Unexpected responce type ' + str(resp.type))
+
+ if resp.success:
+ raise Exception('Unexpected success = True')
+
+ if err and resp.cr_errno != err:
+ raise Exception('Unexpected cr_errno ' + str(resp.cr_errno))
+
+ def no_process(self):
+ print 'Try to dump unexisting process'
+ # Get pid of non-existing process.
+ # Suppose max_pid is not taken by any process.
+ with open("/proc/sys/kernel/pid_max", "r") as f:
+ pid = int(f.readline())
+ try:
+ os.kill(pid, 0)
+ except OSError:
+ pass
+ else:
+ raise Exception('max pid is taken')
+
+ # Ask criu to dump non-existing process.
+ req = self.get_base_req()
+ req.type = rpc.DUMP
+ req.opts.pid = pid
+
+ self.send_req(req)
+ resp = self.recv_resp()
+
+ self.check_resp(resp, rpc.DUMP, errno.ESRCH)
+
+ print 'Success'
+
+ def process_exists(self):
+ print 'Try to restore process which pid is already taken by other process'
+
+ # Perform self-dump
+ req = self.get_base_req()
+ req.type = rpc.DUMP
+ req.opts.leave_running = True
+
+ self.send_req(req)
+ resp = self.recv_resp()
+
+ if resp.success != True:
+ raise Exception('Self-dump failed')
+
+ # Ask to restore process from images of ourselves
+ req = self.get_base_req()
+ req.type = rpc.RESTORE
+
+ self.send_req(req)
+ resp = self.recv_resp()
+
+ self.check_resp(resp, rpc.RESTORE, errno.EEXIST)
+
+ print 'Success'
+
+ def bad_options(self):
+ print 'Try to send criu invalid opts'
+
+ # Subdirs are not allowed in log_file
+ req = self.get_base_req()
+ req.type = rpc.DUMP
+ req.opts.log_file = "../file.log"
+
+ self.send_req(req)
+ resp = self.recv_resp()
+
+ self.check_resp(resp, rpc.DUMP, errno.EBADRQC)
+
+ print 'Success'
+
+ def bad_request(self):
+ print 'Try to send criu invalid request type'
+
+ req = self.get_base_req()
+ req.type = rpc.NOTIFY
+
+ self.send_req(req)
+ resp = self.recv_resp()
+
+ self.check_resp(resp, rpc.EMPTY, None)
+
+ print 'Success'
+
+ def run(self):
+ self.no_process()
+ self.process_exists()
+ self.bad_options()
+ self.bad_request()
+
+t = test()
+t.run()
diff --git a/test/others/rpc/loop.sh b/test/others/rpc/loop.sh
new file mode 100755
index 0000000..0ab34ce
--- /dev/null
+++ b/test/others/rpc/loop.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+while :; do
+ sleep 1
+done
diff --git a/test/others/rpc/ps_test.py b/test/others/rpc/ps_test.py
new file mode 100755
index 0000000..82e5a50
--- /dev/null
+++ b/test/others/rpc/ps_test.py
@@ -0,0 +1,73 @@
+#!/usr/bin/python
+
+import socket, os, imp, sys, errno
+import rpc_pb2 as rpc
+import argparse
+
+parser = argparse.ArgumentParser(description="Test page-server using CRIU RPC")
+parser.add_argument('socket', type = str, help = "CRIU service socket")
+parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed")
+
+args = vars(parser.parse_args())
+
+# Connect to service socket
+s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+s.connect(args['socket'])
+
+# Start page-server
+print 'Starting page-server'
+req = rpc.criu_req()
+req.type = rpc.PAGE_SERVER
+req.opts.log_file = 'page-server.log'
+req.opts.log_level = 4
+req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY)
+
+s.send(req.SerializeToString())
+
+resp = rpc.criu_resp()
+MAX_MSG_SIZE = 1024
+resp.ParseFromString(s.recv(MAX_MSG_SIZE))
+
+if resp.type != rpc.PAGE_SERVER:
+ print 'Unexpected msg type'
+ sys.exit(1)
+else:
+ if resp.success:
+ # check if pid even exists
+ try:
+ os.kill(resp.ps.pid, 0)
+ except OSError as err:
+ if err.errno == errno.ESRCH:
+ print 'No process with page-server pid %d' %(resp.ps.pid)
+ else:
+ print 'Can\'t check that process %d exists' %(resp.ps.pid)
+ sys.exit(1)
+ print 'Success, page-server pid %d started on port %u' %(resp.ps.pid, resp.ps.port)
+ else:
+ print 'Failed to start page-server'
+ sys.exit(1)
+
+
+# Perform self-dump
+print 'Dumping myself using page-server'
+req.type = rpc.DUMP
+req.opts.ps.port = resp.ps.port
+req.opts.log_file = 'dump.log'
+req.opts.leave_running = True
+
+s.close()
+s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+s.connect(args['socket'])
+s.send(req.SerializeToString())
+
+resp.ParseFromString(s.recv(MAX_MSG_SIZE))
+
+if resp.type != rpc.DUMP:
+ print 'Unexpected msg type'
+ sys.exit(1)
+else:
+ if resp.success:
+ print 'Success'
+ else:
+ print 'Fail'
+ sys.exit(1)
diff --git a/test/others/rpc/restore-loop.py b/test/others/rpc/restore-loop.py
new file mode 100755
index 0000000..70cb64e
--- /dev/null
+++ b/test/others/rpc/restore-loop.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+
+import socket, os, imp, sys
+import rpc_pb2 as rpc
+import argparse
+
+parser = argparse.ArgumentParser(description="Test ability to restore a process from images using CRIU RPC")
+parser.add_argument('socket', type = str, help = "CRIU service socket")
+parser.add_argument('dir', type = str, help = "Directory where CRIU images could be found")
+
+args = vars(parser.parse_args())
+
+# Connect to service socket
+s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+s.connect(args['socket'])
+
+# Create criu msg, set it's type to dump request
+# and set dump options. Checkout more options in protobuf/rpc.proto
+req = rpc.criu_req()
+req.type = rpc.RESTORE
+req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY)
+
+# Send request
+s.send(req.SerializeToString())
+
+# Recv response
+resp = rpc.criu_resp()
+MAX_MSG_SIZE = 1024
+resp.ParseFromString(s.recv(MAX_MSG_SIZE))
+
+if resp.type != rpc.RESTORE:
+ print 'Unexpected msg type'
+ sys.exit(-1)
+else:
+ if resp.success:
+ print 'Restore success'
+ else:
+ print 'Restore fail'
+ sys.exit(-1)
+ print "PID of the restored program is %d\n" %(resp.restore.pid)
diff --git a/test/others/rpc/rpc.proto b/test/others/rpc/rpc.proto
new file mode 120000
index 0000000..f65c529
--- /dev/null
+++ b/test/others/rpc/rpc.proto
@@ -0,0 +1 @@
+../../../images/rpc.proto
\ No newline at end of file
diff --git a/test/others/rpc/run.sh b/test/others/rpc/run.sh
new file mode 100755
index 0000000..ed99add
--- /dev/null
+++ b/test/others/rpc/run.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+
+set -e
+
+CRIU=./criu
+
+export PROTODIR=`readlink -f "${PWD}/../../protobuf"`
+
+echo $PROTODIR
+
+function title_print {
+ echo -e "\n**************************************************"
+ echo -e "\t\t"$1
+ echo -e "**************************************************\n"
+
+}
+
+function start_server {
+ title_print "Start service server"
+ ${CRIU} service -v4 -W build -o service.log --address criu_service.socket -d --pidfile pidfile
+}
+
+function stop_server {
+ title_print "Shutdown service server"
+ kill -SIGTERM $(cat build/pidfile)
+ unlink build/pidfile
+}
+
+function test_c {
+ mkdir -p build/imgs_c
+
+ title_print "Run test-c"
+ setsid ./test-c build/criu_service.socket build/imgs_c < /dev/null &>> build/output_c
+
+ title_print "Restore test-c"
+ ${CRIU} restore -v4 -o restore-c.log -D build/imgs_c
+}
+
+function test_py {
+ mkdir -p build/imgs_py
+
+ title_print "Run test-py"
+ setsid ./test.py build/criu_service.socket build/imgs_py < /dev/null &>> build/output_py
+
+ title_print "Restore test-py"
+ ${CRIU} restore -v4 -o restore-py.log -D build/imgs_py
+}
+
+function test_restore_loop {
+ mkdir -p build/imgs_loop
+
+ title_print "Run loop.sh"
+ setsid ./loop.sh < /dev/null &> build/loop.log &
+ P=${!}
+ echo "pid ${P}"
+
+ title_print "Dump loop.sh"
+ ${CRIU} dump -v4 -o dump-loop.log -D build/imgs_loop -t ${P}
+
+ title_print "Run restore-loop"
+ ./restore-loop.py build/criu_service.socket build/imgs_loop
+ kill -SIGTERM ${P}
+}
+
+function test_ps {
+ mkdir -p build/imgs_ps
+
+ title_print "Run ps_test"
+ setsid ./ps_test.py build/criu_service.socket build/imgs_ps < /dev/null &>> build/output_ps
+}
+
+function test_errno {
+ mkdir -p build/imgs_errno
+
+ title_print "Run cr_errno test"
+ setsid ./errno.py build/criu_service.socket build/imgs_errno < /dev/null &>> build/output_errno
+}
+
+trap 'echo "FAIL"; stop_server' EXIT
+
+start_server
+
+test_c
+test_py
+test_restore_loop
+test_ps
+test_errno
+
+stop_server
+
+trap 'echo "Success"' EXIT
diff --git a/test/others/rpc/test-c.c b/test/others/rpc/test-c.c
new file mode 100644
index 0000000..490a07a
--- /dev/null
+++ b/test/others/rpc/test-c.c
@@ -0,0 +1,170 @@
+#include "rpc.pb-c.h"
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/fcntl.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#define MAX_MSG_SIZE 1024
+
+static CriuResp *recv_resp(int socket_fd)
+{
+ unsigned char buf[MAX_MSG_SIZE];
+ int len;
+ CriuResp *msg = 0;
+
+ len = read(socket_fd, buf, MAX_MSG_SIZE);
+ if (len == -1) {
+ perror("Can't read response");
+ return NULL;
+ }
+
+ msg = criu_resp__unpack(NULL, len, buf);
+ if (!msg) {
+ perror("Failed unpacking response");
+ return NULL;
+ }
+
+ return msg;
+}
+
+static int send_req(int socket_fd, CriuReq *req)
+{
+ unsigned char buf[MAX_MSG_SIZE];
+ int len;
+
+ len = criu_req__get_packed_size(req);
+
+ if (criu_req__pack(req, buf) != len) {
+ perror("Failed packing request");
+ return -1;
+ }
+
+ if (write(socket_fd, buf, len) == -1) {
+ perror("Can't send request");
+ return -1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ CriuReq req = CRIU_REQ__INIT;
+ CriuResp *resp = NULL;
+ int fd, dir_fd;
+ int ret = 0;
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: test-c criu-service.socket imgs_dir");
+ return -1;
+ }
+
+ /*
+ * Open a directory, in which criu will
+ * put images
+ */
+
+ puts(argv[2]);
+ dir_fd = open(argv[2], O_DIRECTORY);
+ if (dir_fd == -1) {
+ perror("Can't open imgs dir");
+ return -1;
+ }
+
+ /*
+ * Set "DUMP" type of request.
+ * Allocate CriuDumpReq.
+ */
+ req.type = CRIU_REQ_TYPE__DUMP;
+ req.opts = malloc(sizeof(CriuOpts));
+ if (!req.opts) {
+ perror("Can't allocate memory for dump request");
+ return -1;
+ }
+
+ criu_opts__init(req.opts);
+
+ /*
+ * Set dump options.
+ * Checkout more in protobuf/rpc.proto.
+ */
+ req.opts->has_leave_running = true;
+ req.opts->leave_running = true;
+ req.opts->images_dir_fd = dir_fd;
+ req.opts->has_log_level = true;
+ req.opts->log_level = 4;
+
+ /*
+ * Connect to service socket
+ */
+ fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
+ if (fd == -1) {
+ perror("Can't create socket");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_LOCAL;
+
+ strcpy(addr.sun_path, argv[1]);
+
+ addr_len = strlen(addr.sun_path) + sizeof(addr.sun_family);
+
+ ret = connect(fd, (struct sockaddr *) &addr, addr_len);
+ if (ret == -1) {
+ perror("Cant connect to socket");
+ goto exit;
+ }
+
+ /*
+ * Send request
+ */
+ ret = send_req(fd, &req);
+ if (ret == -1) {
+ perror("Can't send request");
+ goto exit;
+ }
+
+ /*
+ * Recv response
+ */
+ resp = recv_resp(fd);
+ if (!resp) {
+ perror("Can't recv response");
+ ret = -1;
+ goto exit;
+ }
+
+ if (resp->type != CRIU_REQ_TYPE__DUMP) {
+ perror("Unexpected response type");
+ ret = -1;
+ goto exit;
+ }
+
+ /*
+ * Check response.
+ */
+ if (resp->success)
+ puts("Success");
+ else {
+ puts("Fail");
+ ret = -1;
+ goto exit;
+ }
+
+ if (resp->dump->has_restored && resp->dump->restored)
+ puts("Restored");
+
+exit:
+ close(fd);
+ close(dir_fd);
+ if (resp)
+ criu_resp__free_unpacked(resp, NULL);
+ return ret;
+}
diff --git a/test/others/rpc/test.py b/test/others/rpc/test.py
new file mode 100755
index 0000000..7154c00
--- /dev/null
+++ b/test/others/rpc/test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/python
+
+import socket, os, imp, sys
+import rpc_pb2 as rpc
+import argparse
+
+parser = argparse.ArgumentParser(description="Test dump/restore using CRIU RPC")
+parser.add_argument('socket', type = str, help = "CRIU service socket")
+parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed")
+
+args = vars(parser.parse_args())
+
+# Connect to service socket
+s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+s.connect(args['socket'])
+
+# Create criu msg, set it's type to dump request
+# and set dump options. Checkout more options in protobuf/rpc.proto
+req = rpc.criu_req()
+req.type = rpc.DUMP
+req.opts.leave_running = True
+req.opts.log_level = 4
+req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY)
+
+# Send request
+s.send(req.SerializeToString())
+
+# Recv response
+resp = rpc.criu_resp()
+MAX_MSG_SIZE = 1024
+resp.ParseFromString(s.recv(MAX_MSG_SIZE))
+
+if resp.type != rpc.DUMP:
+ print 'Unexpected msg type'
+ sys.exit(-1)
+else:
+ if resp.success:
+ print 'Success'
+ else:
+ print 'Fail'
+ sys.exit(-1)
+
+ if resp.dump.restored:
+ print 'Restored'
diff --git a/test/others/security/Makefile b/test/others/security/Makefile
new file mode 100644
index 0000000..1b9120d
--- /dev/null
+++ b/test/others/security/Makefile
@@ -0,0 +1,34 @@
+DIR := $(shell pwd)/data
+LOOP := $(DIR)/loop.sh
+PIDFILE := $(DIR)/loop.pid
+IMGS := $(DIR)/imgs
+CRIU := $(DIR)/criu
+
+ROOT :=root
+USR1 :=criu-test-user1
+USR2 :=criu-test-user2
+
+export DIR LOOP PIDFILE IMGS CRIU ROOT USR1 USR2
+
+run: testdir users
+ ./run.sh
+
+testdir: ../../../criu/criu
+ mkdir -p $(DIR)
+ mkdir -p $(IMGS)
+ cp ../../../criu/criu $(CRIU)
+ chmod u+s $(CRIU)
+ cp loop.sh $(LOOP)
+ chmod 777 $(DIR)
+
+users:
+ -userdel -f $(USR1)
+ -userdel -f $(USR2)
+ useradd -M -U $(USR1)
+ useradd -M -U $(USR2)
+ usermod -a -G $(USR2) $(USR1)
+
+clean:
+ rm -rf $(DIR)
+ -userdel -f $(USR1)
+ -userdel -f $(USR2)
diff --git a/test/others/security/loop.sh b/test/others/security/loop.sh
new file mode 100755
index 0000000..0a01053
--- /dev/null
+++ b/test/others/security/loop.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+echo $$ > $1.int
+mv $1.int $1
+
+if [ "$2" == "--chgrp" ]; then
+ grps=( $(groups) )
+ newgrp ${grps[2]}
+fi
+
+while :; do
+ sleep 1
+done
diff --git a/test/others/security/run.sh b/test/others/security/run.sh
new file mode 100755
index 0000000..e75ab44
--- /dev/null
+++ b/test/others/security/run.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+
+set -x
+
+PID=
+
+function run_as {
+ echo "== Run ${LOOP} as $1"
+ echo ${PIDFILE}
+ rm -f ${PIDFILE}
+ su $1 -c "setsid ${LOOP} ${PIDFILE} $2 < /dev/null &> /dev/null &"
+ for i in `seq 100`; do
+ test -f ${PIDFILE} && break
+ sleep 1
+ done
+ PID=`cat ${PIDFILE}`
+ echo ${PID}
+}
+
+function dump_as {
+ test -d ${IMGS} && rm -rf ${IMGS}
+ mkdir -p ${IMGS}
+ echo "== Dump ${PID} as $@"
+ su $@ -c "${CRIU} dump --tree ${PID} --images-dir ${IMGS}"
+ return $?
+}
+
+function rstr_as {
+ echo "== Restore ${IMGS} as $@"
+ su $@ -c "${CRIU} restore --images-dir ${IMGS} --restore-detached"
+ return $?
+}
+
+function result {
+ local BGRED='\033[41m'
+ local BGGREEN='\033[42m'
+ local NORMAL=$(tput sgr0)
+
+ if [ $1 -ne 0 ]; then
+ echo -e "${BGRED}FAIL${NORMAL}"
+ exit 1
+ else
+ echo -e "${BGGREEN}PASS${NORMAL}"
+ fi
+}
+
+function test_root {
+ echo "==== Check that non-root can't dump/restore process owned by root"
+
+ run_as ${ROOT}
+
+ dump_as ${USR1} ; result $((!$?))
+ dump_as ${ROOT} ; result $(($?))
+
+ rstr_as ${USR1} ; result $((!$?))
+ rstr_as ${ROOT} ; result $(($?))
+
+ kill -SIGKILL ${PID}
+}
+
+function test_other {
+ echo "==== Check that user2 can't dump/restore process owned by user1"
+
+ run_as ${USR1}
+
+ dump_as ${USR2} ; result $((!$?))
+ dump_as ${USR1} ; result $(($?))
+
+ rstr_as ${USR2} ; result $((!$?))
+ rstr_as ${USR1} ; result $(($?))
+
+ kill -SIGKILL ${PID}
+}
+
+function test_own {
+ echo "==== Check that user1 can dump/restore his own process that changes it's gid to one from groups"
+
+ run_as ${USR1} "--chgrp"
+
+ dump_as ${USR1} ; result $(($?))
+
+ rstr_as ${USR1} ; result $(($?))
+
+ kill -SIGKILL ${PID}
+}
+
+test_root
+test_other
+test_own
diff --git a/test/others/socketpairs/Makefile b/test/others/socketpairs/Makefile
new file mode 100644
index 0000000..dbb152c
--- /dev/null
+++ b/test/others/socketpairs/Makefile
@@ -0,0 +1,9 @@
+CFLAGS += -Wall
+socketpair: socketpair.c
+clean:
+ rm -f socketpair
+run: socketpair
+ ./socketpair && \
+ ./socketpair -v && \
+ ./socketpair -m4 && \
+ true
diff --git a/test/others/socketpairs/socketpair.c b/test/others/socketpairs/socketpair.c
new file mode 100644
index 0000000..900c3d6
--- /dev/null
+++ b/test/others/socketpairs/socketpair.c
@@ -0,0 +1,600 @@
+/*
+ * A simple demo/test program using criu's --inherit-fd command line
+ * option to restore a process with an external unix socket.
+ * Extending inherit's logic to unix sockets created by socketpair(..) syscall.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+
+typedef void (*sighandler_t)(int);
+typedef unsigned long ulong;
+
+/* colors */
+#define CS_PARENT "\033[00;32m"
+#define CS_CHILD "\033[00;33m"
+#define CS_DUMP "\033[00;34m"
+#define CS_RESTORE "\033[00;35m"
+#define CE "\033[0m"
+
+#define die(fmt, ...) do { \
+ fprintf(stderr, fmt ": %m\n", __VA_ARGS__); \
+ if (getpid() == parent_pid) { \
+ (void)kill(0, 9); \
+ exit(1); \
+ } \
+ _exit(1); \
+} while (0)
+
+#define READ_FD 0 /* pipe read fd */
+#define WRITE_FD 1 /* pipe write fd */
+#define CLASH_FD 3 /* force inherit fd clash */
+
+#define MAX_FORKS 3 /* child, checkpoint, restore */
+
+#define CRIU_BINARY "../../criu/criu"
+#define IMG_DIR "images"
+#define DUMP_LOG_FILE "dump.log"
+#define RESTORE_LOG_FILE "restore.log"
+#define RESTORE_PID_FILE "restore.pid"
+#define INHERIT_FD_OPTION "--inherit-fd"
+#define OLD_LOG_FILE "/tmp/oldlog"
+#define NEW_LOG_FILE "/tmp/newlog"
+
+/*
+ * Command line options (see usage()).
+ */
+
+char *cli_flags = "hm:nv";
+int max_msgs = 10;
+int vflag;
+int nflag;
+
+char pid_number[8];
+char inh_unixsk_opt[16];
+char inh_unixsk_arg[64];
+char external_sk_ino[32];
+
+char *dump_argv[] = {
+ "criu", "dump",
+ "-D", IMG_DIR, "-o", DUMP_LOG_FILE,
+ "-v4",
+ external_sk_ino,
+ "-t", pid_number,
+ NULL
+};
+
+char *restore_argv[] = {
+ "criu", "restore", "-d",
+ "-D", IMG_DIR, "-o", RESTORE_LOG_FILE,
+ "--pidfile", RESTORE_PID_FILE,
+ "-v4", "-x",
+ inh_unixsk_opt, inh_unixsk_arg,
+ NULL
+};
+
+int max_forks;
+int parent_pid;
+int child_pid;
+int criu_dump_pid;
+int criu_restore_pid;
+
+/* prototypes */
+void chld_handler(int signum);
+int parent(int *socketfd, const char *ino_child_sk);
+int child(int *socketfd, int dupfd, int newfd);
+void checkpoint_child(int child_pid, int *old_socket_namefd);
+void restore_child(int *new_socketfd, const char *old_socket_name);
+void write_to_fd(int fd, char *name, int i, int newline);
+void ls_proc_fd(int fd);
+char *socket_name(int fd);
+ino_t socket_inode(int fd);
+char *who(pid_t pid);
+void socketpair_safe(int socketfd[2]);
+pid_t fork_safe(void);
+void signal_safe(int signum, sighandler_t handler);
+int open_safe(char *pathname, int flags);
+void close_safe(int fd);
+void write_safe(int fd, char *buf, int count);
+int read_safe(int fd, char *buf, int count);
+int dup_safe(int oldfd);
+void move_fd(int oldfd, int newfd);
+void mkdir_safe(char *dirname, int mode);
+void unlink_safe(char *pathname);
+void execv_safe(char *path, char *argv[], int ls);
+pid_t waitpid_safe(pid_t pid, int *status, int options, int id);
+void prctl_safe(int option, ulong arg2, ulong arg3, ulong arg4, ulong arg5);
+int dup2_safe(int oldfd, int newfd);
+
+void usage(char *cmd)
+{
+ printf("Usage: %s [%s]\n", cmd, cli_flags);
+ printf("-h\tprint this help and exit\n");
+ printf("-m\tcount of send messages (by default 10 will send from child) \n");
+ printf("-n\tdo not use the %s option\n", INHERIT_FD_OPTION);
+ printf("-v\tverbose mode (list contents of /proc/<pid>/fd)\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ int opt;
+ int socketfd[2];
+
+ while ((opt = getopt(argc, argv, cli_flags)) != -1) {
+ switch (opt) {
+ case 'h':
+ usage(argv[0]);
+ return 0;
+ case 'm':
+ max_msgs = atoi(optarg);
+ break;
+ case 'n':
+ nflag++;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ case '?':
+ if ('m' == optopt)
+ fprintf (stderr, "Option -%c requires an argument.\n", optopt);
+ else
+ fprintf (
+ stderr,
+ "Unknown option character `\\x%x'.\n",
+ optopt);
+ return 1;
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+ mkdir_safe(IMG_DIR, 0700);
+
+ socketpair_safe(socketfd);
+ child_pid = fork_safe();
+ if (child_pid > 0) {
+ parent_pid = getpid();
+
+ signal_safe(SIGCHLD, chld_handler);
+ prctl_safe(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
+
+ snprintf(external_sk_ino, sizeof(external_sk_ino), "--ext-unix-sk=%u",
+ (unsigned int)socket_inode(socketfd[WRITE_FD]));
+
+ char unix_sk_ino[32] = {0};
+ strcpy(unix_sk_ino, socket_name(socketfd[WRITE_FD]));
+ close_safe(socketfd[WRITE_FD]);
+ ret = parent(socketfd, unix_sk_ino);
+ } else {
+ /* child */
+ int dupfd = -1;
+ int openfd = -1;
+ int logfd;
+
+ child_pid = getpid();
+
+ close_safe(socketfd[READ_FD]);
+ setsid();
+ logfd = open_safe(OLD_LOG_FILE, O_WRONLY | O_APPEND | O_CREAT);
+ dup2_safe(logfd, 1);
+ dup2_safe(logfd, 2);
+ close(logfd);
+ close(0);
+
+ ret = child(socketfd, dupfd, openfd);
+ }
+
+ return ret;
+}
+
+/*
+ * Parent reads message from its pipe with the child.
+ * After a couple of messages, it checkpoints the child
+ * which causes the child to exit. Parent then creates
+ * a new pipe and restores the child.
+ */
+int parent(int *socketfd, const char *ino_child_sk)
+{
+ char buf[32];
+ int nread;
+
+ nread = 0;
+ while (max_forks <= MAX_FORKS) {
+ if (read_safe(socketfd[READ_FD], buf, sizeof buf) == 0)
+ continue;
+ nread++;
+ if (vflag && nread == 1)
+ ls_proc_fd(-1);
+
+ printf(
+ "%s read %s from %s\n",
+ who(0), buf,
+ socket_name(socketfd[READ_FD]));
+
+
+ if (nread == (max_msgs / 2)) {
+ checkpoint_child(child_pid, socketfd);
+
+ if (!nflag) {
+ close_safe(socketfd[READ_FD]);
+
+ /* create a new one */
+ printf("%s creating a new socket\n", who(0));
+ socketpair_safe(socketfd);
+ }
+
+ restore_child(socketfd, ino_child_sk);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Child sends a total of max_messages messages to its
+ * parent, half before checkpoint and half after restore.
+ */
+int child(int *socketfd, int dupfd, int openfd)
+{
+ int i;
+ int fd;
+ int num_wfds;
+ struct timespec req = { 1, 0 };
+
+ /*
+ * Count the number of pipe descriptors we'll be
+ * writing to. At least 1 (for socketfd[WRITE_FD])
+ * and at most 3.
+ */
+ num_wfds = 1;
+ if (dupfd >= 0)
+ num_wfds++;
+ if (openfd >= 0)
+ num_wfds++;
+
+ for (i = 0; i < max_msgs; i++) {
+ /* print first time and after checkpoint */
+ if (vflag && (i == 0 || i == (max_msgs / 2)))
+ ls_proc_fd(-1);
+
+ switch (i % num_wfds) {
+ case 0: fd = socketfd[WRITE_FD]; break;
+ case 1: fd = openfd; break;
+ case 2: fd = openfd; break;
+ }
+
+ write_to_fd(fd, socket_name(socketfd[WRITE_FD]), i+1, 0);
+ /*
+ * Since sleep will be interrupted by C/R, make sure
+ * to sleep an entire second to minimize the chance of
+ * writing before criu restore has exited. If criu is
+ * still around and we write to a broken pipe, we'll be
+ * killed but SIGCHLD will be delivered to criu instead
+ * of parent.
+ */
+ while (nanosleep(&req, NULL))
+ ;
+ printf("\n");
+ }
+
+ return 0;
+}
+
+void chld_handler(int signum)
+{
+ int status;
+ pid_t pid;
+
+ pid = waitpid_safe(-1, &status, WNOHANG, 1);
+ if (WIFEXITED(status))
+ status = WEXITSTATUS(status);
+ if (pid == child_pid) {
+ printf("%s %s exited with status %d\n", who(0),
+ who(pid), status);
+ /* if child exited successfully, we're done */
+ if (status == 0)
+ exit(0);
+ /* checkpoint kills the child */
+ if (status != 9)
+ exit(status);
+ }
+}
+
+void checkpoint_child(int child_pid, int *socketfd)
+{
+ /* prepare -t <pid> */
+ snprintf(pid_number, sizeof pid_number, "%d", child_pid);
+
+ criu_dump_pid = fork_safe();
+ if (criu_dump_pid > 0) {
+ int status;
+ pid_t pid;
+
+ pid = waitpid_safe(criu_dump_pid, &status, 0, 2);
+ if (WIFEXITED(status))
+ status = WEXITSTATUS(status);
+ printf("%s %s exited with status %d\n", who(0),
+ who(pid), status);
+ if (status)
+ exit(status);
+ } else {
+ close(socketfd[READ_FD]);
+ criu_dump_pid = getpid();
+ execv_safe(CRIU_BINARY, dump_argv, 0);
+ }
+}
+
+void restore_child(int *new_socketfd, const char *old_sock_name)
+{
+ char buf[64];
+
+ criu_restore_pid = fork_safe();
+ if (criu_restore_pid > 0) {
+ int status;
+ pid_t pid;
+
+ if (!nflag)
+ close_safe(new_socketfd[WRITE_FD]);
+
+ pid = waitpid_safe(criu_restore_pid, &status, 0, 3);
+ if (WIFEXITED(status))
+ status = WEXITSTATUS(status);
+
+ printf("%s %s exited with status %d\n", who(0),
+ who(pid), status);
+
+ if (status)
+ exit(status);
+ } else {
+ criu_restore_pid = getpid();
+
+ if (!nflag) {
+ close_safe(new_socketfd[READ_FD]);
+ move_fd(new_socketfd[WRITE_FD], CLASH_FD);
+
+ /* --inherit-fd fd[CLASH_FD]:socket[xxxxxx] */
+ snprintf(inh_unixsk_opt, sizeof inh_unixsk_opt,
+ "%s", INHERIT_FD_OPTION);
+ snprintf(inh_unixsk_arg, sizeof inh_unixsk_arg, "fd[%d]:%s",
+ CLASH_FD, old_sock_name);
+
+ restore_argv[11] = inh_unixsk_opt;
+ restore_argv[13] = NULL;
+ } else
+ restore_argv[11] = NULL;
+
+ snprintf(buf, sizeof buf, "%s/%s", IMG_DIR, RESTORE_PID_FILE);
+ unlink_safe(buf);
+ execv_safe(CRIU_BINARY, restore_argv, 1);
+ }
+}
+
+void write_to_fd(int fd, char *name, int i, int newline)
+{
+ int n;
+ char buf[16]; /* fit "hello d\n" for small d */
+
+ n = snprintf(buf, sizeof buf, "hello %d", i);
+
+ printf("%s writing %s to %s via fd %d\n", who(0), buf, name, fd);
+
+ if (newline) {
+ buf[n++] = '\n';
+ buf[n] = '\0';
+ }
+ write_safe(fd, buf, strlen(buf));
+}
+
+void ls_proc_fd(int fd)
+{
+ char cmd[128];
+
+ if (fd == -1)
+ snprintf(cmd, sizeof cmd, "ls -l /proc/%d/fd", getpid());
+ else
+ snprintf(cmd, sizeof cmd, "ls -l /proc/%d/fd/%d", getpid(), fd);
+ printf("%s %s\n", who(0), cmd);
+ system(cmd);
+}
+
+char *socket_name(int fd)
+{
+ static char sock_name[64];
+ char path[64];
+
+ snprintf(path, sizeof path, "/proc/self/fd/%d", fd);
+ if (readlink(path, sock_name, sizeof sock_name) == -1)
+ die("readlink: path=%s", path);
+ return sock_name;
+}
+
+ino_t socket_inode(int fd)
+{
+ struct stat sbuf;
+
+ if (fstat(fd, &sbuf) == -1)
+ die("fstat: fd=%i", fd);
+
+ return sbuf.st_ino;
+}
+
+/*
+ * Use two buffers to support two calls to
+ * this function in a printf argument list.
+ */
+char *who(pid_t pid)
+{
+ static char pidstr1[64];
+ static char pidstr2[64];
+ static char *cp;
+ char *np;
+ char *ep;
+ int p;
+
+ p = pid ? pid : getpid();
+ if (p == parent_pid) {
+ np = "parent";
+ ep = CS_PARENT;
+ } else if (p == child_pid) {
+ np = "child";
+ ep = CS_CHILD;
+ } else if (p == criu_dump_pid) {
+ np = "dump";
+ ep = CS_DUMP;
+ } else if (p == criu_restore_pid) {
+ np = "restore";
+ ep = CS_RESTORE;
+ } else
+ np = "???";
+
+ cp = (cp == pidstr1) ? pidstr2 : pidstr1;
+ snprintf(cp, sizeof pidstr1, "%s[%s %d]", pid ? "" : ep, np, p);
+ return cp;
+}
+
+void socketpair_safe(int socketfd[2])
+{
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, socketfd) == -1)
+ die("socketpair %p", socketfd);
+}
+
+pid_t fork_safe(void)
+{
+ pid_t pid;
+
+ if ((pid = fork()) == -1)
+ die("fork: pid=%d", pid);
+ max_forks++;
+ return pid;
+}
+
+void signal_safe(int signum, sighandler_t handler)
+{
+ if (signal(signum, handler) == SIG_ERR)
+ die("signal: signum=%d", signum);
+}
+
+int open_safe(char *pathname, int flags)
+{
+ int fd;
+
+ if ((fd = open(pathname, flags, 0777)) == -1)
+ die("open: pathname=%s", pathname);
+ return fd;
+}
+
+void close_safe(int fd)
+{
+ if (close(fd) == -1)
+ die("close: fd=%d", fd);
+}
+
+void write_safe(int fd, char *buf, int count)
+{
+ if (write(fd, buf, count) != count) {
+ die("write: fd=%d buf=\"%s\" count=%d errno=%d",
+ fd, buf, count, errno);
+ }
+}
+
+int read_safe(int fd, char *buf, int count)
+{
+ int n;
+
+ if ((n = read(fd, buf, count)) < 0)
+ die("read: fd=%d count=%d", fd, count);
+ buf[n] = '\0';
+ return n;
+}
+
+int dup_safe(int oldfd)
+{
+ int newfd;
+
+ if ((newfd = dup(oldfd)) == -1)
+ die("dup: oldfd=%d", oldfd);
+ return newfd;
+}
+
+int dup2_safe(int oldfd, int newfd)
+{
+ if (dup2(oldfd, newfd) != newfd)
+ die("dup2: oldfd=%d newfd=%d", oldfd, newfd);
+ return newfd;
+}
+
+void move_fd(int oldfd, int newfd)
+{
+ if (oldfd != newfd) {
+ dup2_safe(oldfd, newfd);
+ close_safe(oldfd);
+ }
+}
+
+void mkdir_safe(char *dirname, int mode)
+{
+ if (mkdir(dirname, mode) == -1 && errno != EEXIST)
+ die("mkdir dirname=%s mode=0x%x\n", dirname, mode);
+}
+
+void unlink_safe(char *pathname)
+{
+ if (unlink(pathname) == -1 && errno != ENOENT) {
+ die("unlink: pathname=%s\n", pathname);
+ }
+}
+
+void execv_safe(char *path, char *argv[], int ls)
+{
+ int i;
+ struct timespec req = { 0, 1000000 };
+
+ printf("\n%s ", who(0));
+ for (i = 0; argv[i] != NULL; i++)
+ printf("%s ", argv[i]);
+ printf("\n");
+
+ /* give parent a chance to wait for us */
+ while (nanosleep(&req, NULL))
+ ;
+
+ if (vflag && ls)
+ ls_proc_fd(-1);
+
+ execv(path, argv);
+ die("execv: path=%s", path);
+}
+
+pid_t waitpid_safe(pid_t pid, int *status, int options, int id)
+{
+ pid_t p;
+
+ p = waitpid(pid, status, options);
+ if (p == -1)
+ fprintf(stderr, "waitpid pid=%d id=%d %m\n", pid, id);
+ return p;
+}
+
+void prctl_safe(int option, ulong arg2, ulong arg3, ulong arg4, ulong arg5)
+{
+ if (prctl(option, arg2, arg3, arg4, arg5) == -1)
+ die("prctl: option=0x%x", option);
+}
diff --git a/test/others/tcp/Makefile b/test/others/tcp/Makefile
new file mode 100644
index 0000000..311d68b
--- /dev/null
+++ b/test/others/tcp/Makefile
@@ -0,0 +1,11 @@
+OBJS=cln srv
+
+all: $(OBJS)
+.PHONY: all
+
+run: all
+ ./run.sh
+
+clean:
+ rm -f $(OBJS)
+.PHONY: clean
diff --git a/test/others/tcp/cln.c b/test/others/tcp/cln.c
new file mode 100644
index 0000000..6275d37
--- /dev/null
+++ b/test/others/tcp/cln.c
@@ -0,0 +1,122 @@
+#include <sys/socket.h>
+#include <linux/types.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+
+#define BUF_SIZE (1024)
+
+static char rbuf[BUF_SIZE];
+static char buf[BUF_SIZE];
+
+static int check_buf(int sk, char *buf, int count)
+{
+ int rd, i;
+
+ printf("Checking for %d bytes\n", count);
+
+ rd = 0;
+ while (rd < count) {
+ int r;
+
+ r = read(sk, rbuf + rd, count - rd);
+ if (r == 0) {
+ printf("Unexpected EOF\n");
+ return 1;
+ }
+
+ if (r < 0) {
+ perror("Can't read buf");
+ return 1;
+ }
+
+ rd += r;
+ }
+
+ for (i = 0; i < count; i++)
+ if (buf[i] != rbuf[i]) {
+ printf("Mismatch on %d byte %d != %d\n",
+ i, (int)buf[i], (int)rbuf[i]);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int serve_new_conn(int in_fd, int sk)
+{
+ printf("New connection\n");
+
+ while (1) {
+ int rd, wr;
+
+ rd = read(in_fd, buf, sizeof(buf));
+ if (rd == 0)
+ break;
+ if (rd < 0) {
+ perror("Can't read from infd");
+ return 1;
+ }
+
+ printf("Read %d bytes, sending to sock\n", rd);
+
+ wr = 0;
+ while (wr < rd) {
+ int w;
+
+ w = write(sk, buf + wr, rd - wr);
+ if (w <= 0) {
+ perror("Can't write to socket");
+ return 1;
+ }
+
+ if (check_buf(sk, buf + wr, w))
+ return 1;
+
+ wr += w;
+ }
+ }
+
+ printf("Done\n");
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int sk, port, ret;
+ struct sockaddr_in addr;
+
+ if (argc < 3) {
+ printf("Need addr, port and iters\n");
+ return -1;
+ }
+
+ sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0) {
+ perror("Can't create socket");
+ return -1;
+ }
+
+ port = atoi(argv[2]);
+ printf("Connecting to %s:%d\n", argv[1], port);
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ ret = inet_aton(argv[1], &addr.sin_addr);
+ if (ret < 0) {
+ perror("Can't convert addr");
+ return -1;
+ }
+ addr.sin_port = htons(port);
+
+ ret = connect(sk, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ perror("Can't connect");
+ return -1;
+ }
+
+ return serve_new_conn(0, sk);
+}
diff --git a/test/others/tcp/run.sh b/test/others/tcp/run.sh
new file mode 100755
index 0000000..c7f86a0
--- /dev/null
+++ b/test/others/tcp/run.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+source ../../env.sh || exit 1
+
+set -x
+
+PORT=12345
+CLN_PIPE="./clnt_pipe"
+SRV_LOG="./srv.log"
+CLN_LOG="./cln.log"
+DDIR="dump"
+
+TEXT=$(hexdump -C /dev/urandom | head -n 1)
+
+echo "Building services"
+
+make clean && make || { echo "Failed to build"; exit 1; }
+rm -rf ${DDIR} ${SRV_LOG} ${CLN_LOG} ${CLN_PIPE}
+mkdir ${DDIR}
+
+echo "Starting server"
+
+setsid ./srv ${PORT} > ${SRV_LOG} 2>&1 &
+SRV_PID=${!}
+
+echo "Starting pipe"
+mkfifo ${CLN_PIPE}
+
+echo "Starting client"
+./cln "127.0.0.1" ${PORT} < ${CLN_PIPE} > ${CLN_LOG} &
+CLN_PID=${!}
+
+exec 3>${CLN_PIPE}
+echo "Make it run"
+echo "${TEXT}" >&3
+
+function fail {
+ echo FAIL
+
+( exec >&2
+
+ echo "$@"
+ kill -9 ${CLN_PID}
+ kill -9 ${SRV_PID}
+ echo ${CLN_LOG}:
+ cat ${CLN_LOG}
+)
+ exit 1
+}
+
+kill -s 0 ${CLN_PID} || fail "Client is dead"
+
+echo "Suspend server"
+${CRIU} dump -D ${DDIR} -o dump.log -t ${SRV_PID} --tcp-established -vvvv || fail "Fail to dump server"
+sleep 1
+echo "Resume server"
+${CRIU} restore -D ${DDIR} -o restore.log -d --tcp-established -vvvv --close 3 || fail "Fail to restore server"
+
+echo "Make client run again"
+echo "${TEXT}" >&3
+
+echo "Collect results"
+exec 3>&-
+wait ${CLN_PID} || fail "Client exits abruptly"
+kill -9 ${SRV_PID}
+
+echo PASS
diff --git a/test/others/tcp/srv.c b/test/others/tcp/srv.c
new file mode 100644
index 0000000..656cc01
--- /dev/null
+++ b/test/others/tcp/srv.c
@@ -0,0 +1,112 @@
+#include <sys/socket.h>
+#include <linux/types.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+
+static int serve_new_conn(int sk)
+{
+ int rd, wr;
+ char buf[1024];
+
+ printf("New connection\n");
+
+ while (1) {
+ rd = read(sk, buf, sizeof(buf));
+ if (!rd)
+ break;
+
+ if (rd < 0) {
+ perror("Can't read socket");
+ return 1;
+ }
+
+ wr = 0;
+ while (wr < rd) {
+ int w;
+
+ w = write(sk, buf + wr, rd - wr);
+ if (w <= 0) {
+ perror("Can't write socket");
+ return 1;
+ }
+
+ wr += w;
+ }
+ }
+
+ printf("Done\n");
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int sk, port, ret;
+ struct sockaddr_in addr;
+
+ if (argc < 2) {
+ printf("Need port\n");
+ return -1;
+ }
+
+ /*
+ * Let kids die themselves
+ */
+
+ signal(SIGCHLD, SIG_IGN);
+
+ sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0) {
+ perror("Can't create socket");
+ return -1;
+ }
+
+ port = atoi(argv[1]);
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_port = htons(port);
+
+ printf("Binding to port %d\n", port);
+
+ ret = bind(sk, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ perror("Can't bind socket");
+ return -1;
+ }
+
+ ret = listen(sk, 16);
+ if (ret < 0) {
+ perror("Can't put sock to listen");
+ return -1;
+ }
+
+ printf("Waiting for connections\n");
+ while (1) {
+ int ask, pid;
+
+ ask = accept(sk, NULL, NULL);
+ if (ask < 0) {
+ perror("Can't accept new conn");
+ return -1;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ perror("Can't fork");
+ return -1;
+ }
+
+ if (pid > 0)
+ close(ask);
+ else {
+ close(sk);
+ ret = serve_new_conn(ask);
+ exit(ret);
+ }
+ }
+}
diff --git a/test/others/unix-callback/Makefile b/test/others/unix-callback/Makefile
new file mode 100644
index 0000000..f2993c5
--- /dev/null
+++ b/test/others/unix-callback/Makefile
@@ -0,0 +1,22 @@
+all: unix-lib.so unix-server unix-client syslog-lib.so
+
+run: all
+ ./run.sh
+
+unix.pb-c.c: unix.proto
+ protoc-c --proto_path=. --c_out=. unix.proto
+
+unix-lib.so: unix-lib.c unix.pb-c.c
+ gcc -g -Werror -Wall -shared -nostartfiles unix-lib.c unix.pb-c.c -o unix-lib.so -iquote ../../include -fPIC
+
+syslog-lib.so: syslog-lib.c
+ gcc -g -Werror -Wall -shared -nostartfiles syslog-lib.c -o syslog-lib.so -iquote ../../include -fPIC
+
+unix-server: unix-server.c
+ gcc -Werror -Wall -o unix-server unix-server.c
+
+unix-client: unix-client.c
+ gcc -Werror -Wall -o unix-client unix-client.c
+
+clean:
+ rm -rf data unix-lib.so unix-server unix-client syslog-lib.so output pid unix.pb-c.*
diff --git a/test/others/unix-callback/lib/syslog-lib.so b/test/others/unix-callback/lib/syslog-lib.so
new file mode 120000
index 0000000..6a2d849
--- /dev/null
+++ b/test/others/unix-callback/lib/syslog-lib.so
@@ -0,0 +1 @@
+../syslog-lib.so
\ No newline at end of file
diff --git a/test/others/unix-callback/lib/unix-lib.so b/test/others/unix-callback/lib/unix-lib.so
new file mode 120000
index 0000000..19c491e
--- /dev/null
+++ b/test/others/unix-callback/lib/unix-lib.so
@@ -0,0 +1 @@
+../unix-lib.so
\ No newline at end of file
diff --git a/test/others/unix-callback/run.sh b/test/others/unix-callback/run.sh
new file mode 100755
index 0000000..ec5b7f5
--- /dev/null
+++ b/test/others/unix-callback/run.sh
@@ -0,0 +1,48 @@
+#!/bin/bash -x
+
+cd `dirname $0`
+
+source ../env.sh || exit 1
+
+rm -rf /tmp/criu.unix.callback.test*
+test -f pid && unlink pid
+test -f output && unlink output
+rm -rf data
+mkdir -p data
+
+./unix-server &
+srv_pid=$!
+
+for i in `seq 20`; do
+ test -f /tmp/criu.unix.callback.test && break
+ sleep 0.1
+done
+
+( setsid ./unix-client < /dev/null &> output ) &
+
+while :; do
+ test -f pid && break
+ sleep 1
+done
+
+pid=`cat pid`
+
+${CRIU} dump -D data -o dump.log -v4 --lib `pwd`/lib -t $pid || exit 1
+kill $srv_pid
+wait $srv_pid
+unlink /tmp/criu.unix.callback.test
+./unix-server &
+srv_pid=$!
+for i in `seq 20`; do
+ test -f /tmp/criu.unix.callback.test && break
+ sleep 0.1
+done
+${CRIU} restore -D data -o restore.log -v4 --lib `pwd`/lib -d || exit 1
+kill $pid
+while :; do
+ cat output | grep PASS && break
+ sleep 1
+done
+
+cat output
+kill $srv_pid
diff --git a/test/others/unix-callback/syslog-lib.c b/test/others/unix-callback/syslog-lib.c
new file mode 100644
index 0000000..c7950ca
--- /dev/null
+++ b/test/others/unix-callback/syslog-lib.c
@@ -0,0 +1,66 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "criu-plugin.h"
+#include "criu-log.h"
+
+extern cr_plugin_dump_unix_sk_t cr_plugin_dump_unix_sk;
+extern cr_plugin_restore_unix_sk_t cr_plugin_restore_unix_sk;
+
+int cr_plugin_dump_unix_sk(int sk, int id)
+{
+ struct sockaddr_un addr;
+ socklen_t addr_len = sizeof(addr);
+ char buf[4096];
+ int fd;
+
+ if (getsockname(sk, (struct sockaddr *) &addr, &addr_len) < 0)
+ return -1;
+
+ if (strncmp(addr.sun_path, "/dev/log", addr_len - sizeof(addr.sun_family)))
+ return -ENOTSUP;
+
+ snprintf(buf, sizeof(buf), "syslog-%x.img", id);
+ fd = open(buf, O_WRONLY | O_CREAT);
+ if (fd < 0)
+ return -1;
+ close(fd);
+
+ return 0;
+}
+
+int cr_plugin_restore_unix_sk(int id)
+{
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+ char buf[4096];
+ int sk, fd;
+
+ snprintf(buf, sizeof(buf), "syslog-%x.img", id);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ return -ENOTSUP;
+ close(fd);
+
+ sk = socket(AF_FILE, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+ if (sk == -1)
+ return sk;
+
+ addr.sun_family = AF_FILE;
+ addr_len = strlen("/dev/log");
+ strncpy(addr.sun_path, "/dev/log", addr_len);
+ addr_len += sizeof(addr.sun_family);
+ if (connect(sk, (struct sockaddr *) &addr, addr_len) == -1) {
+ close(sk);
+ return -1;
+ }
+
+ return sk;
+}
diff --git a/test/others/unix-callback/unix-client.c b/test/others/unix-callback/unix-client.c
new file mode 100644
index 0000000..69808b5
--- /dev/null
+++ b/test/others/unix-callback/unix-client.c
@@ -0,0 +1,121 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/un.h>
+#include <fcntl.h>
+
+#include <syslog.h>
+
+#define SK_NAME "/tmp/criu.unix.callback.test"
+
+#define SK_NR 2
+struct {
+ int id;
+ int sk;
+ int val;
+} sks[SK_NR];
+
+static int create_sock(int i)
+{
+ int ret, id, sk, val = time(NULL) + i * 314;
+ char buf[4096];
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+
+ id = getpid() * 10 + i;
+ sk = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ addr.sun_family = AF_UNIX;
+ addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s%d", SK_NAME, id);
+ addr_len += sizeof(addr.sun_family);
+
+ if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+ perror("bind");
+ return 1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
+ addr_len += sizeof(addr.sun_family);
+
+ if (connect(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+ perror("connect");
+ return 1;
+ }
+
+ printf("init %d\n", val);
+ ret = sprintf(buf, "t%d", val);
+ if (send(sk, buf, ret, 0) < 0) {
+ perror("send");
+ return -1;
+ }
+
+ sks[i].sk = sk;
+ sks[i].val = val;
+
+ return 0;
+}
+
+static int check_sock(int i)
+{
+ int sk = sks[i].sk, val = sks[i].val;
+ char buf[4096];
+
+ if (send(sk, "r", 1, 0) < 0) {
+ perror("send(\"r\")");
+ return -1;
+ }
+
+ if (recv(sk, buf, sizeof(buf), 0) <= 0) {
+ perror("recv");
+ return -1;
+ }
+
+ printf("%s - %d\n", buf, val);
+ if (atoi(buf) != val)
+ return -1;
+
+ return 0;
+}
+
+int main()
+{
+ int i, fd;
+ sigset_t set;
+ int sig;
+
+ for (i = 0; i < SK_NR; i++)
+ if (create_sock(i))
+ return -1;
+
+ fd = open("pid", O_WRONLY | O_CREAT, 0666);
+ if (fd < 0)
+ return 1;
+ dprintf(fd, "%d\n", getpid());
+ close(fd);
+
+ openlog("test", LOG_NDELAY, LOG_USER );
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGTERM);
+ sigprocmask(SIG_BLOCK, &set, NULL);
+ sigwait(&set, &sig);
+
+ syslog(LOG_CRIT, "test message");
+
+ for (i = 0; i < SK_NR; i++)
+ if (check_sock(i))
+ return -1;
+
+ printf("PASS\n");
+ return 0;
+}
+
diff --git a/test/others/unix-callback/unix-lib.c b/test/others/unix-callback/unix-lib.c
new file mode 100644
index 0000000..44b1498
--- /dev/null
+++ b/test/others/unix-callback/unix-lib.c
@@ -0,0 +1,187 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <linux/un.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "criu-plugin.h"
+#include "criu-log.h"
+
+#include "unix.pb-c.h"
+
+extern cr_plugin_init_t cr_plugin_init;
+extern cr_plugin_dump_unix_sk_t cr_plugin_dump_unix_sk;
+extern cr_plugin_restore_unix_sk_t cr_plugin_restore_unix_sk;
+
+#define SK_NAME "/tmp/criu.unix.callback.test"
+static int get_srv_socket(void)
+{
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+ int skd;
+
+ skd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (skd < 0) {
+ pr_perror("socket");
+ return -1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s.dump.%d", SK_NAME, getpid());
+ addr_len += sizeof(addr.sun_family);
+
+ unlink(addr.sun_path);
+ if (bind(skd, (struct sockaddr *) &addr, addr_len) < 0) {
+ pr_perror("bind");
+ return 1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
+ addr_len += sizeof(addr.sun_family);
+
+ if (connect(skd, (struct sockaddr *) &addr, addr_len) < 0) {
+ pr_perror("connect");
+ return -1;
+ }
+
+ return skd;
+}
+
+int cr_plugin_init(void)
+{
+ return 0;
+}
+
+int cr_plugin_dump_unix_sk(int sk, int sk_id)
+{
+ struct sockaddr_un addr;
+ socklen_t addr_len = sizeof(addr);
+ char buf[4096];
+ int skd, id, ret, fd, len;
+ UnixTest e = UNIX_TEST__INIT;
+
+ if (getpeername(sk, (struct sockaddr *) &addr, &addr_len)) {
+ pr_perror("getpeername");
+ return -1;
+ }
+
+ len = addr_len - sizeof(addr.sun_family);
+ if (addr.sun_path[len - 1] == 0)
+ len--;
+
+ if (len != strlen(SK_NAME) ||
+ strncmp(addr.sun_path, SK_NAME, strlen(SK_NAME)))
+ return -ENOTSUP;
+
+ pr_info("Dump the socket %x\n", sk_id);
+ skd = get_srv_socket();
+ if (skd < 0)
+ return -1;
+
+ addr_len = sizeof(struct sockaddr_un);
+
+ if (getsockname(sk, (struct sockaddr *) &addr, &addr_len) < 0)
+ return -1;
+
+ id = atoi(addr.sun_path + strlen(SK_NAME));
+
+ ret = sprintf(buf, "d%d", id) + 1;
+ if (send(skd, buf, ret, 0) < 0) {
+ pr_perror("send");
+ return -1;
+ }
+
+ if (recv(skd, buf, sizeof(buf), 0) <= 0)
+ return -1;
+
+ close(skd);
+
+ e.val = atoi(buf);
+ pr_err("%x: val %d\n", sk_id, e.val);
+ e.name.data = (void *)addr.sun_path;
+ e.name.len = addr_len - sizeof(addr.sun_family);
+
+ snprintf(buf, sizeof(buf), "unix-test-%x.img", sk_id);
+ fd = openat(criu_get_image_dir(), buf, O_WRONLY | O_CREAT, 0600);
+ if (fd < 0)
+ return -1;
+
+ if (unix_test__get_packed_size(&e) > sizeof(buf)) {
+ pr_err("%ld\n", unix_test__get_packed_size(&e));
+ return -1;
+ }
+
+ ret = unix_test__pack(&e, (uint8_t *) buf);
+ if (write(fd, buf, ret) != ret)
+ return -1;
+ close(fd);
+
+ return 0;
+}
+
+int cr_plugin_restore_unix_sk(int sk_id)
+{
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+ int fd, sk, ret;
+ char buf[4096];
+ UnixTest *e;
+
+ snprintf(buf, sizeof(buf), "unix-test-%x.img", sk_id);
+ fd = openat(criu_get_image_dir(), buf, O_RDONLY, 0600);
+ if (fd < 0)
+ return -ENOTSUP;
+
+ ret = read(fd, buf, sizeof(buf));
+ if (ret < 0) {
+ pr_perror("read");
+ return -1;
+ }
+ close(fd);
+
+ e = unix_test__unpack(NULL, ret, (uint8_t *) buf);
+ if (e == NULL)
+ return -1;
+
+ sk = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (sk < 0) {
+ pr_perror("socket");
+ return -1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ memcpy(addr.sun_path, e->name.data, e->name.len);
+ addr_len = sizeof(addr.sun_family) + e->name.len;
+
+ if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+ pr_perror("bind");
+ return -1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
+ addr_len += sizeof(addr.sun_family);
+
+ if (connect(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+ pr_perror("connect");
+ return -1;
+ }
+
+ pr_err("id %d val %d\n", sk_id, e->val);
+ ret = sprintf(buf, "t%d", e->val);
+ if (send(sk, buf, ret, 0) < 0) {
+ pr_perror("send");
+ return -1;
+ }
+
+ return sk;
+}
diff --git a/test/others/unix-callback/unix-server.c b/test/others/unix-callback/unix-server.c
new file mode 100644
index 0000000..8f32f53
--- /dev/null
+++ b/test/others/unix-callback/unix-server.c
@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <linux/un.h>
+
+struct ticket
+{
+ struct ticket *next;
+ int val;
+ int id;
+};
+
+struct ticket *tickets;
+
+#define SK_NAME "/tmp/criu.unix.callback.test"
+
+int main()
+{
+ int sk, ret, id;
+ char buf[4096];
+ struct ticket *t;
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+ struct stat st;
+
+ unlink(SK_NAME);
+
+ sk = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (sk < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
+ addr_len += sizeof(addr.sun_family);
+
+ if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0) {
+ perror("bind");
+ return 1;
+ }
+
+ fstat(sk, &st);
+
+ while (1) {
+ addr_len = sizeof(struct sockaddr_un);
+ ret = recvfrom(sk, buf, sizeof(buf), 0, (struct sockaddr *) &addr, &addr_len);
+ if (ret == 0)
+ return 0;
+ if (ret < 0) {
+ perror("recvfrom");
+ return 1;
+ }
+ id = 0;
+ switch (buf[0]) {
+ case 'l':
+ ret = sprintf(buf, "%ld", st.st_ino);
+ if (sendto(sk, buf, ret + 1, 0, (struct sockaddr *) &addr, addr_len) < 0) {
+ perror("sendto");
+ return -1;
+ }
+ break;
+ case 't': /* ticket */
+ t = malloc(sizeof(struct ticket));
+ if (t == 0) {
+ perror("Can't allocate memory");
+ return 1;
+ }
+
+ t->val = atoi(buf + 1);
+ t->next = tickets;
+ t->id = atoi(addr.sun_path +strlen(SK_NAME));
+ printf("t: id %d val %d\n", t->id, t->val);
+ tickets = t;
+ break;
+ case 'd': /* dump */
+ id = atoi(buf + 1);
+ case 'r': /* request */
+ if (!id)
+ id = atoi(addr.sun_path + strlen(SK_NAME));
+ for (t = tickets; t; t = t->next)
+ if (t->id == id)
+ break;
+ if (t == NULL)
+ return 1;
+ printf("r: id %d val %d\n", id, t->val);
+ ret = sprintf(buf, "%d", t->val);
+ if (sendto(sk, buf, ret + 1, 0, (struct sockaddr *) &addr, addr_len) < 0) {
+ perror("sendto");
+ return 1;
+ }
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/test/others/unix-callback/unix.proto b/test/others/unix-callback/unix.proto
new file mode 100644
index 0000000..fb06fc8
--- /dev/null
+++ b/test/others/unix-callback/unix.proto
@@ -0,0 +1,4 @@
+message unix_test {
+ required uint32 val = 1;
+ required bytes name = 2;
+}
diff --git a/test/overlayfs/Makefile b/test/overlayfs/Makefile
deleted file mode 100644
index 78c246b..0000000
--- a/test/overlayfs/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-run:
- ./run.sh
-
-clean:
- umount -f overlay_test/z
- rm -rf overlay_test output checkpoint
diff --git a/test/overlayfs/run.sh b/test/overlayfs/run.sh
deleted file mode 100755
index 26e6ec2..0000000
--- a/test/overlayfs/run.sh
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/bin/bash
-
-set -eu
-
-CRIU=../../../criu/criu
-
-setup() {
- setup_mount
- setsid sleep 10 3>z/file < /dev/null &> output &
- PROC_PID=$!
- echo "PROC_PID=$PROC_PID"
- sleep 1
-}
-
-setup_mount() {
- mkdir -p overlay_test
- cd overlay_test
- mkdir -p a b c z checkpoint
- mount -t overlay -o lowerdir=a,upperdir=b,workdir=c overlayfs z
-}
-
-check_criu() {
- echo "Dumping $PROC_PID..."
- if ! $CRIU dump -D checkpoint -t "${PROC_PID}"; then
- echo "ERROR! dump failed"
- return 1
- fi
-
- echo "Restoring..."
- if ! $CRIU restore -d -D checkpoint; then
- echo "ERROR! restore failed"
- return 1
- fi
- return 0
-}
-
-cleanup() {
- kill -INT "${PROC_PID}" > /dev/null 2>&1
- umount z
- cd "${ORIG_WD}"
- rm -rf overlay_test
-}
-
-main() {
- ORIG_WD=$(pwd)
- setup
-
- check_criu || {
- cleanup
- exit 1
- }
-
- cleanup
- echo "OverlayFS C/R successful."
- exit 0
-}
-
-main
diff --git a/test/pipes/Makefile b/test/pipes/Makefile
deleted file mode 100644
index 71b16be..0000000
--- a/test/pipes/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-CFLAGS += -Wall
-pipe: pipe.c
-clean:
- rm -f pipe
-run: pipe
- ./pipe - && \
- ./pipe -c && \
- ./pipe -cl && \
- ./pipe -d && \
- ./pipe -o && \
- ./pipe -r && \
- ./pipe -dc && \
- ./pipe -dcl && \
- true
diff --git a/test/pipes/pipe.c b/test/pipes/pipe.c
deleted file mode 100644
index 28b6c99..0000000
--- a/test/pipes/pipe.c
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * A simple demo/test program using criu's --inherit-fd command line
- * option to restore a process with (1) an external pipe and (2) a
- * new log file.
- *
- * Note that it's possible to restore the process without --inherit-fd,
- * but when it reads from or writes to the pipe, it will get a broken
- * pipe signal.
- *
- * Also note that changing the log file during restore has nothing to do
- * with the pipe. It's just a nice feature for cases where it's desirable
- * to have a restored process use a different file then the original one.
- *
- * The parent process spawns a child that will write messages to its
- * parent through a pipe. After a couple of messages, parent invokes
- * criu to checkpoint the child. Since the child exits after checkpoint,
- * its pipe will be broken. Parent sets up a new pipe and invokes criu
- * to restore the child using the new pipe (instead of the old one).
- * The restored child exits after writing a couple more messages.
- *
- * To make sure that fd clashes are correctly handled during restore,
- * child can optionally open a regular file and move it to a clashing fd.
- *
- * Make sure CRIU_BINARY defined below points to the right criu.
- *
- * $ cc -Wall -o pipe pipe.c
- * $ sudo ./pipe -v
- *
- * The following should all succeed:
- *
- * $ sudo ./pipe -q && echo OK
- * $ sudo ./pipe -qc && echo OK
- * $ sudo ./pipe -qcl && echo OK
- * $ sudo ./pipe -qd && echo OK
- * $ sudo ./pipe -qdc && echo OK
- * $ sudo ./pipe -qdcl && echo OK
- *
- * The following should all fail:
- *
- * $ sudo ./pipe -qn || echo $?
- * $ sudo ./pipe -qo || echo $?
- * $ sudo ./pipe -qr || echo $?
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <time.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/wait.h>
-#include <sys/prctl.h>
-
-typedef void (*sighandler_t)(int);
-typedef unsigned long ulong;
-
-/* colors */
-#define CS_PARENT "\033[00;32m"
-#define CS_CHILD "\033[00;33m"
-#define CS_DUMP "\033[00;34m"
-#define CS_RESTORE "\033[00;35m"
-#define CE "\033[0m"
-
-#define die(fmt, ...) do { \
- if (!qflag) \
- fprintf(stderr, fmt ": %m\n", __VA_ARGS__); \
- if (getpid() == parent_pid) { \
- (void)kill(0, 9); \
- exit(1); \
- } \
- _exit(1); \
-} while (0)
-
-#define READ_FD 0 /* pipe read fd */
-#define WRITE_FD 1 /* pipe write fd */
-#define CLASH_FD 3 /* force inherit fd clash */
-
-#define MAX_FORKS 3 /* child, checkpoint, restore */
-
-#define CRIU_BINARY "../../criu"
-#define IMG_DIR "images"
-#define DUMP_LOG_FILE "dump.log"
-#define RESTORE_LOG_FILE "restore.log"
-#define RESTORE_PID_FILE "restore.pid"
-#define INHERIT_FD_OPTION "--inherit-fd"
-#define OLD_LOG_FILE "/tmp/oldlog"
-#define NEW_LOG_FILE "/tmp/newlog"
-
-/*
- * Command line options (see usage()).
- */
-char *cli_flags = "cdhlnoqrv";
-
-int cflag;
-int dflag;
-int lflag;
-int nflag;
-int oflag;
-int qflag;
-int rflag;
-int vflag;
-
-char pid_number[8];
-char inh_pipe_opt[16];
-char inh_pipe_arg[64];
-char inh_file_opt[16];
-char inh_file_arg[64];
-
-char *dump_argv[] = {
- "criu", "dump",
- "-D", IMG_DIR, "-o", DUMP_LOG_FILE,
- "-v4",
- "-t", pid_number,
- NULL
-};
-
-char *restore_argv[] = {
- "criu", "restore", "-d",
- "-D", IMG_DIR, "-o", RESTORE_LOG_FILE,
- "--pidfile", RESTORE_PID_FILE,
- "-v4",
- inh_pipe_opt, inh_pipe_arg,
- inh_file_opt, inh_file_arg,
- NULL
-};
-
-int max_msgs;
-int max_forks;
-int parent_pid;
-int child_pid;
-int criu_dump_pid;
-int criu_restore_pid;
-
-/* prototypes */
-void chld_handler(int signum);
-int parent(int *pipefd);
-int child(int *pipefd, int dupfd, int newfd);
-void checkpoint_child(int child_pid, int *pipefd);
-void restore_child(int *new_pipefd, char *old_pipe_name);
-void write_to_fd(int fd, char *name, int i, int newline);
-void ls_proc_fd(int fd);
-char *pipe_name(int fd);
-char *who(pid_t pid);
-void pipe_safe(int pipefd[2]);
-pid_t fork_safe(void);
-void signal_safe(int signum, sighandler_t handler);
-int open_safe(char *pathname, int flags);
-void close_safe(int fd);
-void write_safe(int fd, char *buf, int count);
-int read_safe(int fd, char *buf, int count);
-int dup_safe(int oldfd);
-void move_fd(int oldfd, int newfd);
-void mkdir_safe(char *dirname, int mode);
-void unlink_safe(char *pathname);
-void execv_safe(char *path, char *argv[], int ls);
-pid_t waitpid_safe(pid_t pid, int *status, int options, int id);
-void prctl_safe(int option, ulong arg2, ulong arg3, ulong arg4, ulong arg5);
-int dup2_safe(int oldfd, int newfd);
-
-void usage(char *cmd)
-{
- printf("Usage: %s [%s]\n", cmd, cli_flags);
- printf("-c\tcause a clash during restore by opening %s as fd %d\n",
- OLD_LOG_FILE, CLASH_FD);
- printf("-d\tdup the pipe and write to it\n");
- printf("-l\tchange log file from %s to %s during restore\n",
- OLD_LOG_FILE, NEW_LOG_FILE);
-
- printf("\n");
- printf("The following flags should cause restore failure\n");
- printf("-n\tdo not use the %s option\n", INHERIT_FD_OPTION);
- printf("-o\topen the pipe via /proc/<pid>/fd and write to it\n");
- printf("-r\tspecify read end of pipe during restore\n");
-
- printf("\n");
- printf("Miscellaneous flags\n");
- printf("-h\tprint this help and exit\n");
- printf("-q\tquiet mode, don't print anything\n");
- printf("-v\tverbose mode (list contents of /proc/<pid>/fd)\n");
-
-}
-
-int main(int argc, char *argv[])
-{
- int ret;
- int opt;
- int pipefd[2];
-
- max_msgs = 4;
- while ((opt = getopt(argc, argv, cli_flags)) != -1) {
- switch (opt) {
- case 'c': cflag++; break;
- case 'd': dflag++; max_msgs += 4; break;
- case 'h': usage(argv[0]); return 0;
- case 'l': lflag++; break;
- case 'n': nflag++; break;
- case 'o': oflag++; max_msgs += 4; break;
- case 'q': qflag++; vflag = 0;break;
- case 'r': rflag++; break;
- case 'v': vflag++; qflag = 0; break;
- default: usage(argv[0]); return 1;
- }
- }
-
- setbuf(stdout, NULL);
- setbuf(stderr, NULL);
- mkdir_safe(IMG_DIR, 0700);
-
- pipe_safe(pipefd);
- child_pid = fork_safe();
- if (child_pid > 0) {
- parent_pid = getpid();
-
- signal_safe(SIGCHLD, chld_handler);
- prctl_safe(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
-
- close_safe(pipefd[WRITE_FD]);
-
- ret = parent(pipefd);
- } else {
- /* child */
- int dupfd = -1;
- int openfd = -1;
- int logfd, flags;
-
- child_pid = getpid();
-
- close_safe(pipefd[READ_FD]);
- setsid();
- logfd = open_safe(OLD_LOG_FILE, O_WRONLY | O_APPEND | O_CREAT);
- dup2_safe(logfd, 1);
- dup2_safe(logfd, 2);
- close(logfd);
- close(0);
-
- /* open a regular file and move it to CLASH_FD */
- if (cflag)
- move_fd(open_safe(OLD_LOG_FILE, O_WRONLY | O_APPEND | O_CREAT), CLASH_FD);
-
- fcntl(pipefd[WRITE_FD], F_SETFL, O_NONBLOCK | O_WRONLY);
- /* open additional descriptors on the pipe and use them all */
- if (dflag)
- dupfd = dup_safe(pipefd[WRITE_FD]);
- if (oflag) {
- char buf[128];
- snprintf(buf, sizeof buf, "/proc/self/fd/%d", pipefd[WRITE_FD]);
- openfd = open_safe(buf, O_WRONLY);
- }
-
- ret = child(pipefd, dupfd, openfd);
-
- flags = fcntl(pipefd[WRITE_FD], F_GETFL, 0);
- if ((flags & O_NONBLOCK) == 0) {
- printf("Unexpected flags %x\n", flags);
- ret = -1;
- }
- }
-
- return ret;
-}
-
-/*
- * Parent reads message from its pipe with the child.
- * After a couple of messages, it checkpoints the child
- * which causes the child to exit. Parent then creates
- * a new pipe and restores the child.
- */
-int parent(int *pipefd)
-{
- char buf[32];
- char old_pipe[32];
- int nread;
-
- nread = 0;
- while (max_forks <= MAX_FORKS) {
- if (read_safe(pipefd[READ_FD], buf, sizeof buf) == 0)
- continue;
- nread++;
- if (vflag && nread == 1)
- ls_proc_fd(-1);
-
- if (!qflag) {
- printf("%s read %s from %s\n", who(0), buf,
- pipe_name(pipefd[READ_FD]));
- }
-
- if (nread == (max_msgs / 2)) {
- checkpoint_child(child_pid, pipefd);
-
- if (!nflag) {
- /* save the old pipe's name before closing it */
- snprintf(old_pipe, sizeof old_pipe, "%s",
- pipe_name(pipefd[READ_FD]));
- close_safe(pipefd[READ_FD]);
-
- /* create a new one */
- if (!qflag)
- printf("%s creating a new pipe\n", who(0));
- pipe_safe(pipefd);
- }
- restore_child(pipefd, old_pipe);
- }
- }
-
- return 0;
-}
-
-/*
- * Child sends a total of max_messages messages to its
- * parent, half before checkpoint and half after restore.
- */
-int child(int *pipefd, int dupfd, int openfd)
-{
- int i;
- int fd;
- int num_wfds;
- struct timespec req = { 1, 0 };
-
- /*
- * Count the number of pipe descriptors we'll be
- * writing to. At least 1 (for pipefd[WRITE_FD])
- * and at most 3.
- */
- num_wfds = 1;
- if (dupfd >= 0)
- num_wfds++;
- if (openfd >= 0)
- num_wfds++;
-
- for (i = 0; i < max_msgs; i++) {
- /* print first time and after checkpoint */
- if (vflag && (i == 0 || i == (max_msgs / 2)))
- ls_proc_fd(-1);
-
- switch (i % num_wfds) {
- case 0: fd = pipefd[WRITE_FD]; break;
- case 1: fd = dflag ? dupfd : openfd; break;
- case 2: fd = openfd; break;
- }
-
- write_to_fd(fd, pipe_name(pipefd[WRITE_FD]), i+1, 0);
- if (cflag)
- write_to_fd(CLASH_FD, "log file", i+1, 1);
-
- /*
- * Since sleep will be interrupted by C/R, make sure
- * to sleep an entire second to minimize the chance of
- * writing before criu restore has exited. If criu is
- * still around and we write to a broken pipe, we'll be
- * killed but SIGCHLD will be delivered to criu instead
- * of parent.
- */
- while (nanosleep(&req, NULL))
- ;
- if (!qflag)
- printf("\n");
- }
-
- return 0;
-}
-
-void chld_handler(int signum)
-{
- int status;
- pid_t pid;
-
- pid = waitpid_safe(-1, &status, WNOHANG, 1);
- if (WIFEXITED(status))
- status = WEXITSTATUS(status);
- if (pid == child_pid) {
- if (!qflag) {
- printf("%s %s exited with status %d\n", who(0),
- who(pid), status);
- }
- /* if child exited successfully, we're done */
- if (status == 0)
- exit(0);
- /* checkpoint kills the child */
- if (status != 9)
- exit(status);
- }
-}
-
-void checkpoint_child(int child_pid, int *pipefd)
-{
- /* prepare -t <pid> */
- snprintf(pid_number, sizeof pid_number, "%d", child_pid);
-
- criu_dump_pid = fork_safe();
- if (criu_dump_pid > 0) {
- int status;
- pid_t pid;
-
- pid = waitpid_safe(criu_dump_pid, &status, 0, 2);
- if (WIFEXITED(status))
- status = WEXITSTATUS(status);
- if (!qflag) {
- printf("%s %s exited with status %d\n", who(0),
- who(pid), status);
- }
- if (status)
- exit(status);
- } else {
- close(pipefd[READ_FD]);
- criu_dump_pid = getpid();
- execv_safe(CRIU_BINARY, dump_argv, 0);
- }
-}
-
-void restore_child(int *new_pipefd, char *old_pipe_name)
-{
- char buf[64];
-
- criu_restore_pid = fork_safe();
- if (criu_restore_pid > 0) {
- int status;
- pid_t pid;
-
- if (!nflag)
- close_safe(new_pipefd[WRITE_FD]);
-
- pid = waitpid_safe(criu_restore_pid, &status, 0, 3);
- if (WIFEXITED(status))
- status = WEXITSTATUS(status);
- if (!qflag) {
- printf("%s %s exited with status %d\n", who(0),
- who(pid), status);
- }
- if (status)
- exit(status);
- } else {
- criu_restore_pid = getpid();
-
- if (!nflag) {
- /*
- * We should close the read descriptor of the new pipe
- * and use its write descriptor to call criu restore.
- * But if rflag was set (for testing purposes), use the
- * read descriptor which should cause the application to
- * fail.
- *
- * Regardless of read or write descriptor, move it to a
- * clashing fd to test inherit fd clash resolve code.
- */
- if (rflag)
- move_fd(new_pipefd[READ_FD], CLASH_FD);
- else {
- close_safe(new_pipefd[READ_FD]);
- move_fd(new_pipefd[WRITE_FD], CLASH_FD);
- }
-
- /* --inherit-fd fd[CLASH_FD]:pipe[xxxxxx] */
- snprintf(inh_pipe_opt, sizeof inh_pipe_opt,
- "%s", INHERIT_FD_OPTION);
- snprintf(inh_pipe_arg, sizeof inh_pipe_arg, "fd[%d]:%s",
- CLASH_FD, old_pipe_name);
-
- if (lflag) {
- /* create a new log file to replace the old one */
- int filefd = open_safe(NEW_LOG_FILE, O_WRONLY | O_APPEND | O_CREAT);
-
- /* --inherit-fd fd[x]:tmp/oldlog */
- snprintf(inh_file_opt, sizeof inh_file_opt,
- "%s", INHERIT_FD_OPTION);
- snprintf(inh_file_arg, sizeof inh_file_arg,
- "fd[%d]:%s", filefd, OLD_LOG_FILE + 1);
-
- restore_argv[12] = inh_file_opt;
- } else
- restore_argv[12] = NULL;
- restore_argv[10] = inh_pipe_opt;
- } else
- restore_argv[10] = NULL;
-
- snprintf(buf, sizeof buf, "%s/%s", IMG_DIR, RESTORE_PID_FILE);
- unlink_safe(buf);
- execv_safe(CRIU_BINARY, restore_argv, 1);
- }
-}
-
-void write_to_fd(int fd, char *name, int i, int newline)
-{
- int n;
- char buf[16]; /* fit "hello d\n" for small d */
-
- n = snprintf(buf, sizeof buf, "hello %d", i);
- if (!qflag)
- printf("%s writing %s to %s via fd %d\n", who(0), buf, name, fd);
-
- if (newline) {
- buf[n++] = '\n';
- buf[n] = '\0';
- }
- write_safe(fd, buf, strlen(buf));
-}
-
-void ls_proc_fd(int fd)
-{
- char cmd[128];
-
- if (qflag)
- return;
-
- if (fd == -1)
- snprintf(cmd, sizeof cmd, "ls -l /proc/%d/fd", getpid());
- else
- snprintf(cmd, sizeof cmd, "ls -l /proc/%d/fd/%d", getpid(), fd);
- printf("%s %s\n", who(0), cmd);
- system(cmd);
-}
-
-char *pipe_name(int fd)
-{
- static char pipe_name[64];
- char path[64];
-
- snprintf(path, sizeof path, "/proc/self/fd/%d", fd);
- if (readlink(path, pipe_name, sizeof pipe_name) == -1)
- die("readlink: path=%s", path);
- return pipe_name;
-}
-
-/*
- * Use two buffers to support two calls to
- * this function in a printf argument list.
- */
-char *who(pid_t pid)
-{
- static char pidstr1[64];
- static char pidstr2[64];
- static char *cp;
- char *np;
- char *ep;
- int p;
-
- p = pid ? pid : getpid();
- if (p == parent_pid) {
- np = "parent";
- ep = CS_PARENT;
- } else if (p == child_pid) {
- np = "child";
- ep = CS_CHILD;
- } else if (p == criu_dump_pid) {
- np = "dump";
- ep = CS_DUMP;
- } else if (p == criu_restore_pid) {
- np = "restore";
- ep = CS_RESTORE;
- } else
- np = "???";
-
- cp = (cp == pidstr1) ? pidstr2 : pidstr1;
- snprintf(cp, sizeof pidstr1, "%s[%s %d]", pid ? "" : ep, np, p);
- return cp;
-}
-
-void pipe_safe(int pipefd[2])
-{
- if (pipe(pipefd) == -1)
- die("pipe: %p", pipefd);
-}
-
-pid_t fork_safe(void)
-{
- pid_t pid;
-
- if ((pid = fork()) == -1)
- die("fork: pid=%d", pid);
- max_forks++;
- return pid;
-}
-
-void signal_safe(int signum, sighandler_t handler)
-{
- if (signal(signum, handler) == SIG_ERR)
- die("signal: signum=%d", signum);
-}
-
-int open_safe(char *pathname, int flags)
-{
- int fd;
-
- if ((fd = open(pathname, flags, 0777)) == -1)
- die("open: pathname=%s", pathname);
- return fd;
-}
-
-void close_safe(int fd)
-{
- if (close(fd) == -1)
- die("close: fd=%d", fd);
-}
-
-void write_safe(int fd, char *buf, int count)
-{
- if (write(fd, buf, count) != count) {
- die("write: fd=%d buf=\"%s\" count=%d errno=%d",
- fd, buf, count, errno);
- }
-}
-
-int read_safe(int fd, char *buf, int count)
-{
- int n;
-
- if ((n = read(fd, buf, count)) < 0)
- die("read: fd=%d count=%d", fd, count);
- buf[n] = '\0';
- return n;
-}
-
-int dup_safe(int oldfd)
-{
- int newfd;
-
- if ((newfd = dup(oldfd)) == -1)
- die("dup: oldfd=%d", oldfd);
- return newfd;
-}
-
-int dup2_safe(int oldfd, int newfd)
-{
- if (dup2(oldfd, newfd) != newfd)
- die("dup2: oldfd=%d newfd=%d", oldfd, newfd);
- return newfd;
-}
-
-void move_fd(int oldfd, int newfd)
-{
- if (oldfd != newfd) {
- dup2_safe(oldfd, newfd);
- close_safe(oldfd);
- }
-}
-
-void mkdir_safe(char *dirname, int mode)
-{
- if (mkdir(dirname, mode) == -1 && errno != EEXIST)
- die("mkdir dirname=%s mode=0x%x\n", dirname, mode);
-}
-
-void unlink_safe(char *pathname)
-{
- if (unlink(pathname) == -1 && errno != ENOENT) {
- die("unlink: pathname=%s\n", pathname);
- }
-}
-
-void execv_safe(char *path, char *argv[], int ls)
-{
- int i;
- struct timespec req = { 0, 1000000 };
-
- if (!qflag) {
- printf("\n%s ", who(0));
- for (i = 0; argv[i] != NULL; i++)
- printf("%s ", argv[i]);
- printf("\n");
- }
-
- /* give parent a chance to wait for us */
- while (nanosleep(&req, NULL))
- ;
-
- if (vflag && ls)
- ls_proc_fd(-1);
-
- execv(path, argv);
- die("execv: path=%s", path);
-}
-
-pid_t waitpid_safe(pid_t pid, int *status, int options, int id)
-{
- pid_t p;
-
- p = waitpid(pid, status, options);
- if (p == -1)
- fprintf(stderr, "waitpid pid=%d id=%d %m\n", pid, id);
- return p;
-}
-
-void prctl_safe(int option, ulong arg2, ulong arg3, ulong arg4, ulong arg5)
-{
- if (prctl(option, arg2, arg3, arg4, arg5) == -1)
- die("prctl: option=0x%x", option);
-}
diff --git a/test/rpc/.gitignore b/test/rpc/.gitignore
deleted file mode 100644
index 75fca39..0000000
--- a/test/rpc/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-rpc.pb-c.*
-*_pb2.py
-test-c
diff --git a/test/rpc/Makefile b/test/rpc/Makefile
deleted file mode 100644
index 88b9f36..0000000
--- a/test/rpc/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-all: test-c rpc_pb2.py criu
-.PHONY: all
-
-CFLAGS += -g -Werror -Wall -I.
-LDFLAGS += -lprotobuf-c
-
-run: all
- mkdir -p build
- chmod a+rwx build
- sudo -g '#1000' -u '#1000' ./run.sh
-
-criu: ../../criu/criu
- cp ../../criu/criu $@
- chmod u+s $@
-
-test-c: rpc.pb-c.o test-c.o
-
-test-c.o: test-c.c rpc.pb-c.c
-
-rpc_pb2.py: rpc.proto
- protoc --proto_path=. --python_out=. rpc.proto
-
-rpc.pb-c.c: rpc.proto
- protoc-c --proto_path=. --c_out=. rpc.proto
-
-clean:
- rm -rf build rpc.pb-c.o test-c.o test-c rpc.pb-c.c rpc.pb-c.h rpc_pb2.py rpc_pb2.pyc criu
-.PHONY: clean
diff --git a/test/rpc/errno.py b/test/rpc/errno.py
deleted file mode 100755
index 666dfff..0000000
--- a/test/rpc/errno.py
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/usr/bin/python
-# Test criu errno
-
-import socket, os, imp, sys, errno
-import rpc_pb2 as rpc
-import argparse
-
-parser = argparse.ArgumentParser(description="Test errno reported by CRIU RPC")
-parser.add_argument('socket', type = str, help = "CRIU service socket")
-parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed")
-
-args = vars(parser.parse_args())
-
-# Prepare dir for images
-class test:
- def __init__(self):
- self.imgs_fd = os.open(args['dir'], os.O_DIRECTORY)
- self.s = -1
- self._MAX_MSG_SIZE = 1024
-
- def connect(self):
- self.s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
- self.s.connect(args['socket'])
-
- def get_base_req(self):
- req = rpc.criu_req()
- req.opts.log_level = 4
- req.opts.images_dir_fd = self.imgs_fd
- return req
-
- def send_req(self, req):
- self.connect()
- self.s.send(req.SerializeToString())
-
- def recv_resp(self):
- resp = rpc.criu_resp()
- resp.ParseFromString(self.s.recv(self._MAX_MSG_SIZE))
- return resp
-
- def check_resp(self, resp, typ, err):
- if resp.type != typ:
- raise Exception('Unexpected responce type ' + str(resp.type))
-
- if resp.success:
- raise Exception('Unexpected success = True')
-
- if err and resp.cr_errno != err:
- raise Exception('Unexpected cr_errno ' + str(resp.cr_errno))
-
- def no_process(self):
- print 'Try to dump unexisting process'
- # Get pid of non-existing process.
- # Suppose max_pid is not taken by any process.
- with open("/proc/sys/kernel/pid_max", "r") as f:
- pid = int(f.readline())
- try:
- os.kill(pid, 0)
- except OSError:
- pass
- else:
- raise Exception('max pid is taken')
-
- # Ask criu to dump non-existing process.
- req = self.get_base_req()
- req.type = rpc.DUMP
- req.opts.pid = pid
-
- self.send_req(req)
- resp = self.recv_resp()
-
- self.check_resp(resp, rpc.DUMP, errno.ESRCH)
-
- print 'Success'
-
- def process_exists(self):
- print 'Try to restore process which pid is already taken by other process'
-
- # Perform self-dump
- req = self.get_base_req()
- req.type = rpc.DUMP
- req.opts.leave_running = True
-
- self.send_req(req)
- resp = self.recv_resp()
-
- if resp.success != True:
- raise Exception('Self-dump failed')
-
- # Ask to restore process from images of ourselves
- req = self.get_base_req()
- req.type = rpc.RESTORE
-
- self.send_req(req)
- resp = self.recv_resp()
-
- self.check_resp(resp, rpc.RESTORE, errno.EEXIST)
-
- print 'Success'
-
- def bad_options(self):
- print 'Try to send criu invalid opts'
-
- # Subdirs are not allowed in log_file
- req = self.get_base_req()
- req.type = rpc.DUMP
- req.opts.log_file = "../file.log"
-
- self.send_req(req)
- resp = self.recv_resp()
-
- self.check_resp(resp, rpc.DUMP, errno.EBADRQC)
-
- print 'Success'
-
- def bad_request(self):
- print 'Try to send criu invalid request type'
-
- req = self.get_base_req()
- req.type = rpc.NOTIFY
-
- self.send_req(req)
- resp = self.recv_resp()
-
- self.check_resp(resp, rpc.EMPTY, None)
-
- print 'Success'
-
- def run(self):
- self.no_process()
- self.process_exists()
- self.bad_options()
- self.bad_request()
-
-t = test()
-t.run()
diff --git a/test/rpc/loop.sh b/test/rpc/loop.sh
deleted file mode 100755
index 0ab34ce..0000000
--- a/test/rpc/loop.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-while :; do
- sleep 1
-done
diff --git a/test/rpc/ps_test.py b/test/rpc/ps_test.py
deleted file mode 100755
index 82e5a50..0000000
--- a/test/rpc/ps_test.py
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/python
-
-import socket, os, imp, sys, errno
-import rpc_pb2 as rpc
-import argparse
-
-parser = argparse.ArgumentParser(description="Test page-server using CRIU RPC")
-parser.add_argument('socket', type = str, help = "CRIU service socket")
-parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed")
-
-args = vars(parser.parse_args())
-
-# Connect to service socket
-s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
-s.connect(args['socket'])
-
-# Start page-server
-print 'Starting page-server'
-req = rpc.criu_req()
-req.type = rpc.PAGE_SERVER
-req.opts.log_file = 'page-server.log'
-req.opts.log_level = 4
-req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY)
-
-s.send(req.SerializeToString())
-
-resp = rpc.criu_resp()
-MAX_MSG_SIZE = 1024
-resp.ParseFromString(s.recv(MAX_MSG_SIZE))
-
-if resp.type != rpc.PAGE_SERVER:
- print 'Unexpected msg type'
- sys.exit(1)
-else:
- if resp.success:
- # check if pid even exists
- try:
- os.kill(resp.ps.pid, 0)
- except OSError as err:
- if err.errno == errno.ESRCH:
- print 'No process with page-server pid %d' %(resp.ps.pid)
- else:
- print 'Can\'t check that process %d exists' %(resp.ps.pid)
- sys.exit(1)
- print 'Success, page-server pid %d started on port %u' %(resp.ps.pid, resp.ps.port)
- else:
- print 'Failed to start page-server'
- sys.exit(1)
-
-
-# Perform self-dump
-print 'Dumping myself using page-server'
-req.type = rpc.DUMP
-req.opts.ps.port = resp.ps.port
-req.opts.log_file = 'dump.log'
-req.opts.leave_running = True
-
-s.close()
-s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
-s.connect(args['socket'])
-s.send(req.SerializeToString())
-
-resp.ParseFromString(s.recv(MAX_MSG_SIZE))
-
-if resp.type != rpc.DUMP:
- print 'Unexpected msg type'
- sys.exit(1)
-else:
- if resp.success:
- print 'Success'
- else:
- print 'Fail'
- sys.exit(1)
diff --git a/test/rpc/restore-loop.py b/test/rpc/restore-loop.py
deleted file mode 100755
index 70cb64e..0000000
--- a/test/rpc/restore-loop.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/python
-
-import socket, os, imp, sys
-import rpc_pb2 as rpc
-import argparse
-
-parser = argparse.ArgumentParser(description="Test ability to restore a process from images using CRIU RPC")
-parser.add_argument('socket', type = str, help = "CRIU service socket")
-parser.add_argument('dir', type = str, help = "Directory where CRIU images could be found")
-
-args = vars(parser.parse_args())
-
-# Connect to service socket
-s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
-s.connect(args['socket'])
-
-# Create criu msg, set it's type to dump request
-# and set dump options. Checkout more options in protobuf/rpc.proto
-req = rpc.criu_req()
-req.type = rpc.RESTORE
-req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY)
-
-# Send request
-s.send(req.SerializeToString())
-
-# Recv response
-resp = rpc.criu_resp()
-MAX_MSG_SIZE = 1024
-resp.ParseFromString(s.recv(MAX_MSG_SIZE))
-
-if resp.type != rpc.RESTORE:
- print 'Unexpected msg type'
- sys.exit(-1)
-else:
- if resp.success:
- print 'Restore success'
- else:
- print 'Restore fail'
- sys.exit(-1)
- print "PID of the restored program is %d\n" %(resp.restore.pid)
diff --git a/test/rpc/rpc.proto b/test/rpc/rpc.proto
deleted file mode 120000
index bc0b0df..0000000
--- a/test/rpc/rpc.proto
+++ /dev/null
@@ -1 +0,0 @@
-../../protobuf/rpc.proto
\ No newline at end of file
diff --git a/test/rpc/run.sh b/test/rpc/run.sh
deleted file mode 100755
index ed99add..0000000
--- a/test/rpc/run.sh
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/bin/bash
-
-set -e
-
-CRIU=./criu
-
-export PROTODIR=`readlink -f "${PWD}/../../protobuf"`
-
-echo $PROTODIR
-
-function title_print {
- echo -e "\n**************************************************"
- echo -e "\t\t"$1
- echo -e "**************************************************\n"
-
-}
-
-function start_server {
- title_print "Start service server"
- ${CRIU} service -v4 -W build -o service.log --address criu_service.socket -d --pidfile pidfile
-}
-
-function stop_server {
- title_print "Shutdown service server"
- kill -SIGTERM $(cat build/pidfile)
- unlink build/pidfile
-}
-
-function test_c {
- mkdir -p build/imgs_c
-
- title_print "Run test-c"
- setsid ./test-c build/criu_service.socket build/imgs_c < /dev/null &>> build/output_c
-
- title_print "Restore test-c"
- ${CRIU} restore -v4 -o restore-c.log -D build/imgs_c
-}
-
-function test_py {
- mkdir -p build/imgs_py
-
- title_print "Run test-py"
- setsid ./test.py build/criu_service.socket build/imgs_py < /dev/null &>> build/output_py
-
- title_print "Restore test-py"
- ${CRIU} restore -v4 -o restore-py.log -D build/imgs_py
-}
-
-function test_restore_loop {
- mkdir -p build/imgs_loop
-
- title_print "Run loop.sh"
- setsid ./loop.sh < /dev/null &> build/loop.log &
- P=${!}
- echo "pid ${P}"
-
- title_print "Dump loop.sh"
- ${CRIU} dump -v4 -o dump-loop.log -D build/imgs_loop -t ${P}
-
- title_print "Run restore-loop"
- ./restore-loop.py build/criu_service.socket build/imgs_loop
- kill -SIGTERM ${P}
-}
-
-function test_ps {
- mkdir -p build/imgs_ps
-
- title_print "Run ps_test"
- setsid ./ps_test.py build/criu_service.socket build/imgs_ps < /dev/null &>> build/output_ps
-}
-
-function test_errno {
- mkdir -p build/imgs_errno
-
- title_print "Run cr_errno test"
- setsid ./errno.py build/criu_service.socket build/imgs_errno < /dev/null &>> build/output_errno
-}
-
-trap 'echo "FAIL"; stop_server' EXIT
-
-start_server
-
-test_c
-test_py
-test_restore_loop
-test_ps
-test_errno
-
-stop_server
-
-trap 'echo "Success"' EXIT
diff --git a/test/rpc/test-c.c b/test/rpc/test-c.c
deleted file mode 100644
index 490a07a..0000000
--- a/test/rpc/test-c.c
+++ /dev/null
@@ -1,170 +0,0 @@
-#include "rpc.pb-c.h"
-#include <stdlib.h>
-#include <stdbool.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/fcntl.h>
-#include <stdio.h>
-#include <dirent.h>
-#include <unistd.h>
-
-#define MAX_MSG_SIZE 1024
-
-static CriuResp *recv_resp(int socket_fd)
-{
- unsigned char buf[MAX_MSG_SIZE];
- int len;
- CriuResp *msg = 0;
-
- len = read(socket_fd, buf, MAX_MSG_SIZE);
- if (len == -1) {
- perror("Can't read response");
- return NULL;
- }
-
- msg = criu_resp__unpack(NULL, len, buf);
- if (!msg) {
- perror("Failed unpacking response");
- return NULL;
- }
-
- return msg;
-}
-
-static int send_req(int socket_fd, CriuReq *req)
-{
- unsigned char buf[MAX_MSG_SIZE];
- int len;
-
- len = criu_req__get_packed_size(req);
-
- if (criu_req__pack(req, buf) != len) {
- perror("Failed packing request");
- return -1;
- }
-
- if (write(socket_fd, buf, len) == -1) {
- perror("Can't send request");
- return -1;
- }
-
- return 0;
-}
-
-int main(int argc, char *argv[])
-{
- CriuReq req = CRIU_REQ__INIT;
- CriuResp *resp = NULL;
- int fd, dir_fd;
- int ret = 0;
- struct sockaddr_un addr;
- socklen_t addr_len;
-
- if (argc != 3) {
- fprintf(stderr, "Usage: test-c criu-service.socket imgs_dir");
- return -1;
- }
-
- /*
- * Open a directory, in which criu will
- * put images
- */
-
- puts(argv[2]);
- dir_fd = open(argv[2], O_DIRECTORY);
- if (dir_fd == -1) {
- perror("Can't open imgs dir");
- return -1;
- }
-
- /*
- * Set "DUMP" type of request.
- * Allocate CriuDumpReq.
- */
- req.type = CRIU_REQ_TYPE__DUMP;
- req.opts = malloc(sizeof(CriuOpts));
- if (!req.opts) {
- perror("Can't allocate memory for dump request");
- return -1;
- }
-
- criu_opts__init(req.opts);
-
- /*
- * Set dump options.
- * Checkout more in protobuf/rpc.proto.
- */
- req.opts->has_leave_running = true;
- req.opts->leave_running = true;
- req.opts->images_dir_fd = dir_fd;
- req.opts->has_log_level = true;
- req.opts->log_level = 4;
-
- /*
- * Connect to service socket
- */
- fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
- if (fd == -1) {
- perror("Can't create socket");
- return -1;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_LOCAL;
-
- strcpy(addr.sun_path, argv[1]);
-
- addr_len = strlen(addr.sun_path) + sizeof(addr.sun_family);
-
- ret = connect(fd, (struct sockaddr *) &addr, addr_len);
- if (ret == -1) {
- perror("Cant connect to socket");
- goto exit;
- }
-
- /*
- * Send request
- */
- ret = send_req(fd, &req);
- if (ret == -1) {
- perror("Can't send request");
- goto exit;
- }
-
- /*
- * Recv response
- */
- resp = recv_resp(fd);
- if (!resp) {
- perror("Can't recv response");
- ret = -1;
- goto exit;
- }
-
- if (resp->type != CRIU_REQ_TYPE__DUMP) {
- perror("Unexpected response type");
- ret = -1;
- goto exit;
- }
-
- /*
- * Check response.
- */
- if (resp->success)
- puts("Success");
- else {
- puts("Fail");
- ret = -1;
- goto exit;
- }
-
- if (resp->dump->has_restored && resp->dump->restored)
- puts("Restored");
-
-exit:
- close(fd);
- close(dir_fd);
- if (resp)
- criu_resp__free_unpacked(resp, NULL);
- return ret;
-}
diff --git a/test/rpc/test.py b/test/rpc/test.py
deleted file mode 100755
index 7154c00..0000000
--- a/test/rpc/test.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/python
-
-import socket, os, imp, sys
-import rpc_pb2 as rpc
-import argparse
-
-parser = argparse.ArgumentParser(description="Test dump/restore using CRIU RPC")
-parser.add_argument('socket', type = str, help = "CRIU service socket")
-parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed")
-
-args = vars(parser.parse_args())
-
-# Connect to service socket
-s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
-s.connect(args['socket'])
-
-# Create criu msg, set it's type to dump request
-# and set dump options. Checkout more options in protobuf/rpc.proto
-req = rpc.criu_req()
-req.type = rpc.DUMP
-req.opts.leave_running = True
-req.opts.log_level = 4
-req.opts.images_dir_fd = os.open(args['dir'], os.O_DIRECTORY)
-
-# Send request
-s.send(req.SerializeToString())
-
-# Recv response
-resp = rpc.criu_resp()
-MAX_MSG_SIZE = 1024
-resp.ParseFromString(s.recv(MAX_MSG_SIZE))
-
-if resp.type != rpc.DUMP:
- print 'Unexpected msg type'
- sys.exit(-1)
-else:
- if resp.success:
- print 'Success'
- else:
- print 'Fail'
- sys.exit(-1)
-
- if resp.dump.restored:
- print 'Restored'
diff --git a/test/security/Makefile b/test/security/Makefile
deleted file mode 100644
index 6eaece1..0000000
--- a/test/security/Makefile
+++ /dev/null
@@ -1,34 +0,0 @@
-DIR := $(shell pwd)/data
-LOOP := $(DIR)/loop.sh
-PIDFILE := $(DIR)/loop.pid
-IMGS := $(DIR)/imgs
-CRIU := $(DIR)/criu
-
-ROOT :=root
-USR1 :=criu-test-user1
-USR2 :=criu-test-user2
-
-export DIR LOOP PIDFILE IMGS CRIU ROOT USR1 USR2
-
-run: testdir users
- ./run.sh
-
-testdir: ../../criu/criu
- mkdir -p $(DIR)
- mkdir -p $(IMGS)
- cp ../../criu/criu $(CRIU)
- chmod u+s $(CRIU)
- cp loop.sh $(LOOP)
- chmod 777 $(DIR)
-
-users:
- -userdel -f $(USR1)
- -userdel -f $(USR2)
- useradd -M -U $(USR1)
- useradd -M -U $(USR2)
- usermod -a -G $(USR2) $(USR1)
-
-clean:
- rm -rf $(DIR)
- -userdel -f $(USR1)
- -userdel -f $(USR2)
diff --git a/test/security/loop.sh b/test/security/loop.sh
deleted file mode 100755
index 0a01053..0000000
--- a/test/security/loop.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-echo $$ > $1.int
-mv $1.int $1
-
-if [ "$2" == "--chgrp" ]; then
- grps=( $(groups) )
- newgrp ${grps[2]}
-fi
-
-while :; do
- sleep 1
-done
diff --git a/test/security/run.sh b/test/security/run.sh
deleted file mode 100755
index e75ab44..0000000
--- a/test/security/run.sh
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/bin/bash
-
-set -x
-
-PID=
-
-function run_as {
- echo "== Run ${LOOP} as $1"
- echo ${PIDFILE}
- rm -f ${PIDFILE}
- su $1 -c "setsid ${LOOP} ${PIDFILE} $2 < /dev/null &> /dev/null &"
- for i in `seq 100`; do
- test -f ${PIDFILE} && break
- sleep 1
- done
- PID=`cat ${PIDFILE}`
- echo ${PID}
-}
-
-function dump_as {
- test -d ${IMGS} && rm -rf ${IMGS}
- mkdir -p ${IMGS}
- echo "== Dump ${PID} as $@"
- su $@ -c "${CRIU} dump --tree ${PID} --images-dir ${IMGS}"
- return $?
-}
-
-function rstr_as {
- echo "== Restore ${IMGS} as $@"
- su $@ -c "${CRIU} restore --images-dir ${IMGS} --restore-detached"
- return $?
-}
-
-function result {
- local BGRED='\033[41m'
- local BGGREEN='\033[42m'
- local NORMAL=$(tput sgr0)
-
- if [ $1 -ne 0 ]; then
- echo -e "${BGRED}FAIL${NORMAL}"
- exit 1
- else
- echo -e "${BGGREEN}PASS${NORMAL}"
- fi
-}
-
-function test_root {
- echo "==== Check that non-root can't dump/restore process owned by root"
-
- run_as ${ROOT}
-
- dump_as ${USR1} ; result $((!$?))
- dump_as ${ROOT} ; result $(($?))
-
- rstr_as ${USR1} ; result $((!$?))
- rstr_as ${ROOT} ; result $(($?))
-
- kill -SIGKILL ${PID}
-}
-
-function test_other {
- echo "==== Check that user2 can't dump/restore process owned by user1"
-
- run_as ${USR1}
-
- dump_as ${USR2} ; result $((!$?))
- dump_as ${USR1} ; result $(($?))
-
- rstr_as ${USR2} ; result $((!$?))
- rstr_as ${USR1} ; result $(($?))
-
- kill -SIGKILL ${PID}
-}
-
-function test_own {
- echo "==== Check that user1 can dump/restore his own process that changes it's gid to one from groups"
-
- run_as ${USR1} "--chgrp"
-
- dump_as ${USR1} ; result $(($?))
-
- rstr_as ${USR1} ; result $(($?))
-
- kill -SIGKILL ${PID}
-}
-
-test_root
-test_other
-test_own
diff --git a/test/socketpairs/Makefile b/test/socketpairs/Makefile
deleted file mode 100644
index dbb152c..0000000
--- a/test/socketpairs/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-CFLAGS += -Wall
-socketpair: socketpair.c
-clean:
- rm -f socketpair
-run: socketpair
- ./socketpair && \
- ./socketpair -v && \
- ./socketpair -m4 && \
- true
diff --git a/test/socketpairs/socketpair.c b/test/socketpairs/socketpair.c
deleted file mode 100644
index 900c3d6..0000000
--- a/test/socketpairs/socketpair.c
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- * A simple demo/test program using criu's --inherit-fd command line
- * option to restore a process with an external unix socket.
- * Extending inherit's logic to unix sockets created by socketpair(..) syscall.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <time.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/wait.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-
-typedef void (*sighandler_t)(int);
-typedef unsigned long ulong;
-
-/* colors */
-#define CS_PARENT "\033[00;32m"
-#define CS_CHILD "\033[00;33m"
-#define CS_DUMP "\033[00;34m"
-#define CS_RESTORE "\033[00;35m"
-#define CE "\033[0m"
-
-#define die(fmt, ...) do { \
- fprintf(stderr, fmt ": %m\n", __VA_ARGS__); \
- if (getpid() == parent_pid) { \
- (void)kill(0, 9); \
- exit(1); \
- } \
- _exit(1); \
-} while (0)
-
-#define READ_FD 0 /* pipe read fd */
-#define WRITE_FD 1 /* pipe write fd */
-#define CLASH_FD 3 /* force inherit fd clash */
-
-#define MAX_FORKS 3 /* child, checkpoint, restore */
-
-#define CRIU_BINARY "../../criu/criu"
-#define IMG_DIR "images"
-#define DUMP_LOG_FILE "dump.log"
-#define RESTORE_LOG_FILE "restore.log"
-#define RESTORE_PID_FILE "restore.pid"
-#define INHERIT_FD_OPTION "--inherit-fd"
-#define OLD_LOG_FILE "/tmp/oldlog"
-#define NEW_LOG_FILE "/tmp/newlog"
-
-/*
- * Command line options (see usage()).
- */
-
-char *cli_flags = "hm:nv";
-int max_msgs = 10;
-int vflag;
-int nflag;
-
-char pid_number[8];
-char inh_unixsk_opt[16];
-char inh_unixsk_arg[64];
-char external_sk_ino[32];
-
-char *dump_argv[] = {
- "criu", "dump",
- "-D", IMG_DIR, "-o", DUMP_LOG_FILE,
- "-v4",
- external_sk_ino,
- "-t", pid_number,
- NULL
-};
-
-char *restore_argv[] = {
- "criu", "restore", "-d",
- "-D", IMG_DIR, "-o", RESTORE_LOG_FILE,
- "--pidfile", RESTORE_PID_FILE,
- "-v4", "-x",
- inh_unixsk_opt, inh_unixsk_arg,
- NULL
-};
-
-int max_forks;
-int parent_pid;
-int child_pid;
-int criu_dump_pid;
-int criu_restore_pid;
-
-/* prototypes */
-void chld_handler(int signum);
-int parent(int *socketfd, const char *ino_child_sk);
-int child(int *socketfd, int dupfd, int newfd);
-void checkpoint_child(int child_pid, int *old_socket_namefd);
-void restore_child(int *new_socketfd, const char *old_socket_name);
-void write_to_fd(int fd, char *name, int i, int newline);
-void ls_proc_fd(int fd);
-char *socket_name(int fd);
-ino_t socket_inode(int fd);
-char *who(pid_t pid);
-void socketpair_safe(int socketfd[2]);
-pid_t fork_safe(void);
-void signal_safe(int signum, sighandler_t handler);
-int open_safe(char *pathname, int flags);
-void close_safe(int fd);
-void write_safe(int fd, char *buf, int count);
-int read_safe(int fd, char *buf, int count);
-int dup_safe(int oldfd);
-void move_fd(int oldfd, int newfd);
-void mkdir_safe(char *dirname, int mode);
-void unlink_safe(char *pathname);
-void execv_safe(char *path, char *argv[], int ls);
-pid_t waitpid_safe(pid_t pid, int *status, int options, int id);
-void prctl_safe(int option, ulong arg2, ulong arg3, ulong arg4, ulong arg5);
-int dup2_safe(int oldfd, int newfd);
-
-void usage(char *cmd)
-{
- printf("Usage: %s [%s]\n", cmd, cli_flags);
- printf("-h\tprint this help and exit\n");
- printf("-m\tcount of send messages (by default 10 will send from child) \n");
- printf("-n\tdo not use the %s option\n", INHERIT_FD_OPTION);
- printf("-v\tverbose mode (list contents of /proc/<pid>/fd)\n");
-}
-
-int main(int argc, char *argv[])
-{
- int ret;
- int opt;
- int socketfd[2];
-
- while ((opt = getopt(argc, argv, cli_flags)) != -1) {
- switch (opt) {
- case 'h':
- usage(argv[0]);
- return 0;
- case 'm':
- max_msgs = atoi(optarg);
- break;
- case 'n':
- nflag++;
- break;
- case 'v':
- vflag++;
- break;
- case '?':
- if ('m' == optopt)
- fprintf (stderr, "Option -%c requires an argument.\n", optopt);
- else
- fprintf (
- stderr,
- "Unknown option character `\\x%x'.\n",
- optopt);
- return 1;
- default:
- usage(argv[0]);
- return 1;
- }
- }
-
- setbuf(stdout, NULL);
- setbuf(stderr, NULL);
- mkdir_safe(IMG_DIR, 0700);
-
- socketpair_safe(socketfd);
- child_pid = fork_safe();
- if (child_pid > 0) {
- parent_pid = getpid();
-
- signal_safe(SIGCHLD, chld_handler);
- prctl_safe(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
-
- snprintf(external_sk_ino, sizeof(external_sk_ino), "--ext-unix-sk=%u",
- (unsigned int)socket_inode(socketfd[WRITE_FD]));
-
- char unix_sk_ino[32] = {0};
- strcpy(unix_sk_ino, socket_name(socketfd[WRITE_FD]));
- close_safe(socketfd[WRITE_FD]);
- ret = parent(socketfd, unix_sk_ino);
- } else {
- /* child */
- int dupfd = -1;
- int openfd = -1;
- int logfd;
-
- child_pid = getpid();
-
- close_safe(socketfd[READ_FD]);
- setsid();
- logfd = open_safe(OLD_LOG_FILE, O_WRONLY | O_APPEND | O_CREAT);
- dup2_safe(logfd, 1);
- dup2_safe(logfd, 2);
- close(logfd);
- close(0);
-
- ret = child(socketfd, dupfd, openfd);
- }
-
- return ret;
-}
-
-/*
- * Parent reads message from its pipe with the child.
- * After a couple of messages, it checkpoints the child
- * which causes the child to exit. Parent then creates
- * a new pipe and restores the child.
- */
-int parent(int *socketfd, const char *ino_child_sk)
-{
- char buf[32];
- int nread;
-
- nread = 0;
- while (max_forks <= MAX_FORKS) {
- if (read_safe(socketfd[READ_FD], buf, sizeof buf) == 0)
- continue;
- nread++;
- if (vflag && nread == 1)
- ls_proc_fd(-1);
-
- printf(
- "%s read %s from %s\n",
- who(0), buf,
- socket_name(socketfd[READ_FD]));
-
-
- if (nread == (max_msgs / 2)) {
- checkpoint_child(child_pid, socketfd);
-
- if (!nflag) {
- close_safe(socketfd[READ_FD]);
-
- /* create a new one */
- printf("%s creating a new socket\n", who(0));
- socketpair_safe(socketfd);
- }
-
- restore_child(socketfd, ino_child_sk);
- }
- }
-
- return 0;
-}
-
-/*
- * Child sends a total of max_messages messages to its
- * parent, half before checkpoint and half after restore.
- */
-int child(int *socketfd, int dupfd, int openfd)
-{
- int i;
- int fd;
- int num_wfds;
- struct timespec req = { 1, 0 };
-
- /*
- * Count the number of pipe descriptors we'll be
- * writing to. At least 1 (for socketfd[WRITE_FD])
- * and at most 3.
- */
- num_wfds = 1;
- if (dupfd >= 0)
- num_wfds++;
- if (openfd >= 0)
- num_wfds++;
-
- for (i = 0; i < max_msgs; i++) {
- /* print first time and after checkpoint */
- if (vflag && (i == 0 || i == (max_msgs / 2)))
- ls_proc_fd(-1);
-
- switch (i % num_wfds) {
- case 0: fd = socketfd[WRITE_FD]; break;
- case 1: fd = openfd; break;
- case 2: fd = openfd; break;
- }
-
- write_to_fd(fd, socket_name(socketfd[WRITE_FD]), i+1, 0);
- /*
- * Since sleep will be interrupted by C/R, make sure
- * to sleep an entire second to minimize the chance of
- * writing before criu restore has exited. If criu is
- * still around and we write to a broken pipe, we'll be
- * killed but SIGCHLD will be delivered to criu instead
- * of parent.
- */
- while (nanosleep(&req, NULL))
- ;
- printf("\n");
- }
-
- return 0;
-}
-
-void chld_handler(int signum)
-{
- int status;
- pid_t pid;
-
- pid = waitpid_safe(-1, &status, WNOHANG, 1);
- if (WIFEXITED(status))
- status = WEXITSTATUS(status);
- if (pid == child_pid) {
- printf("%s %s exited with status %d\n", who(0),
- who(pid), status);
- /* if child exited successfully, we're done */
- if (status == 0)
- exit(0);
- /* checkpoint kills the child */
- if (status != 9)
- exit(status);
- }
-}
-
-void checkpoint_child(int child_pid, int *socketfd)
-{
- /* prepare -t <pid> */
- snprintf(pid_number, sizeof pid_number, "%d", child_pid);
-
- criu_dump_pid = fork_safe();
- if (criu_dump_pid > 0) {
- int status;
- pid_t pid;
-
- pid = waitpid_safe(criu_dump_pid, &status, 0, 2);
- if (WIFEXITED(status))
- status = WEXITSTATUS(status);
- printf("%s %s exited with status %d\n", who(0),
- who(pid), status);
- if (status)
- exit(status);
- } else {
- close(socketfd[READ_FD]);
- criu_dump_pid = getpid();
- execv_safe(CRIU_BINARY, dump_argv, 0);
- }
-}
-
-void restore_child(int *new_socketfd, const char *old_sock_name)
-{
- char buf[64];
-
- criu_restore_pid = fork_safe();
- if (criu_restore_pid > 0) {
- int status;
- pid_t pid;
-
- if (!nflag)
- close_safe(new_socketfd[WRITE_FD]);
-
- pid = waitpid_safe(criu_restore_pid, &status, 0, 3);
- if (WIFEXITED(status))
- status = WEXITSTATUS(status);
-
- printf("%s %s exited with status %d\n", who(0),
- who(pid), status);
-
- if (status)
- exit(status);
- } else {
- criu_restore_pid = getpid();
-
- if (!nflag) {
- close_safe(new_socketfd[READ_FD]);
- move_fd(new_socketfd[WRITE_FD], CLASH_FD);
-
- /* --inherit-fd fd[CLASH_FD]:socket[xxxxxx] */
- snprintf(inh_unixsk_opt, sizeof inh_unixsk_opt,
- "%s", INHERIT_FD_OPTION);
- snprintf(inh_unixsk_arg, sizeof inh_unixsk_arg, "fd[%d]:%s",
- CLASH_FD, old_sock_name);
-
- restore_argv[11] = inh_unixsk_opt;
- restore_argv[13] = NULL;
- } else
- restore_argv[11] = NULL;
-
- snprintf(buf, sizeof buf, "%s/%s", IMG_DIR, RESTORE_PID_FILE);
- unlink_safe(buf);
- execv_safe(CRIU_BINARY, restore_argv, 1);
- }
-}
-
-void write_to_fd(int fd, char *name, int i, int newline)
-{
- int n;
- char buf[16]; /* fit "hello d\n" for small d */
-
- n = snprintf(buf, sizeof buf, "hello %d", i);
-
- printf("%s writing %s to %s via fd %d\n", who(0), buf, name, fd);
-
- if (newline) {
- buf[n++] = '\n';
- buf[n] = '\0';
- }
- write_safe(fd, buf, strlen(buf));
-}
-
-void ls_proc_fd(int fd)
-{
- char cmd[128];
-
- if (fd == -1)
- snprintf(cmd, sizeof cmd, "ls -l /proc/%d/fd", getpid());
- else
- snprintf(cmd, sizeof cmd, "ls -l /proc/%d/fd/%d", getpid(), fd);
- printf("%s %s\n", who(0), cmd);
- system(cmd);
-}
-
-char *socket_name(int fd)
-{
- static char sock_name[64];
- char path[64];
-
- snprintf(path, sizeof path, "/proc/self/fd/%d", fd);
- if (readlink(path, sock_name, sizeof sock_name) == -1)
- die("readlink: path=%s", path);
- return sock_name;
-}
-
-ino_t socket_inode(int fd)
-{
- struct stat sbuf;
-
- if (fstat(fd, &sbuf) == -1)
- die("fstat: fd=%i", fd);
-
- return sbuf.st_ino;
-}
-
-/*
- * Use two buffers to support two calls to
- * this function in a printf argument list.
- */
-char *who(pid_t pid)
-{
- static char pidstr1[64];
- static char pidstr2[64];
- static char *cp;
- char *np;
- char *ep;
- int p;
-
- p = pid ? pid : getpid();
- if (p == parent_pid) {
- np = "parent";
- ep = CS_PARENT;
- } else if (p == child_pid) {
- np = "child";
- ep = CS_CHILD;
- } else if (p == criu_dump_pid) {
- np = "dump";
- ep = CS_DUMP;
- } else if (p == criu_restore_pid) {
- np = "restore";
- ep = CS_RESTORE;
- } else
- np = "???";
-
- cp = (cp == pidstr1) ? pidstr2 : pidstr1;
- snprintf(cp, sizeof pidstr1, "%s[%s %d]", pid ? "" : ep, np, p);
- return cp;
-}
-
-void socketpair_safe(int socketfd[2])
-{
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, socketfd) == -1)
- die("socketpair %p", socketfd);
-}
-
-pid_t fork_safe(void)
-{
- pid_t pid;
-
- if ((pid = fork()) == -1)
- die("fork: pid=%d", pid);
- max_forks++;
- return pid;
-}
-
-void signal_safe(int signum, sighandler_t handler)
-{
- if (signal(signum, handler) == SIG_ERR)
- die("signal: signum=%d", signum);
-}
-
-int open_safe(char *pathname, int flags)
-{
- int fd;
-
- if ((fd = open(pathname, flags, 0777)) == -1)
- die("open: pathname=%s", pathname);
- return fd;
-}
-
-void close_safe(int fd)
-{
- if (close(fd) == -1)
- die("close: fd=%d", fd);
-}
-
-void write_safe(int fd, char *buf, int count)
-{
- if (write(fd, buf, count) != count) {
- die("write: fd=%d buf=\"%s\" count=%d errno=%d",
- fd, buf, count, errno);
- }
-}
-
-int read_safe(int fd, char *buf, int count)
-{
- int n;
-
- if ((n = read(fd, buf, count)) < 0)
- die("read: fd=%d count=%d", fd, count);
- buf[n] = '\0';
- return n;
-}
-
-int dup_safe(int oldfd)
-{
- int newfd;
-
- if ((newfd = dup(oldfd)) == -1)
- die("dup: oldfd=%d", oldfd);
- return newfd;
-}
-
-int dup2_safe(int oldfd, int newfd)
-{
- if (dup2(oldfd, newfd) != newfd)
- die("dup2: oldfd=%d newfd=%d", oldfd, newfd);
- return newfd;
-}
-
-void move_fd(int oldfd, int newfd)
-{
- if (oldfd != newfd) {
- dup2_safe(oldfd, newfd);
- close_safe(oldfd);
- }
-}
-
-void mkdir_safe(char *dirname, int mode)
-{
- if (mkdir(dirname, mode) == -1 && errno != EEXIST)
- die("mkdir dirname=%s mode=0x%x\n", dirname, mode);
-}
-
-void unlink_safe(char *pathname)
-{
- if (unlink(pathname) == -1 && errno != ENOENT) {
- die("unlink: pathname=%s\n", pathname);
- }
-}
-
-void execv_safe(char *path, char *argv[], int ls)
-{
- int i;
- struct timespec req = { 0, 1000000 };
-
- printf("\n%s ", who(0));
- for (i = 0; argv[i] != NULL; i++)
- printf("%s ", argv[i]);
- printf("\n");
-
- /* give parent a chance to wait for us */
- while (nanosleep(&req, NULL))
- ;
-
- if (vflag && ls)
- ls_proc_fd(-1);
-
- execv(path, argv);
- die("execv: path=%s", path);
-}
-
-pid_t waitpid_safe(pid_t pid, int *status, int options, int id)
-{
- pid_t p;
-
- p = waitpid(pid, status, options);
- if (p == -1)
- fprintf(stderr, "waitpid pid=%d id=%d %m\n", pid, id);
- return p;
-}
-
-void prctl_safe(int option, ulong arg2, ulong arg3, ulong arg4, ulong arg5)
-{
- if (prctl(option, arg2, arg3, arg4, arg5) == -1)
- die("prctl: option=0x%x", option);
-}
diff --git a/test/tcp/Makefile b/test/tcp/Makefile
deleted file mode 100644
index 311d68b..0000000
--- a/test/tcp/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-OBJS=cln srv
-
-all: $(OBJS)
-.PHONY: all
-
-run: all
- ./run.sh
-
-clean:
- rm -f $(OBJS)
-.PHONY: clean
diff --git a/test/tcp/cln.c b/test/tcp/cln.c
deleted file mode 100644
index 6275d37..0000000
--- a/test/tcp/cln.c
+++ /dev/null
@@ -1,122 +0,0 @@
-#include <sys/socket.h>
-#include <linux/types.h>
-#include <sys/types.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <signal.h>
-
-#define BUF_SIZE (1024)
-
-static char rbuf[BUF_SIZE];
-static char buf[BUF_SIZE];
-
-static int check_buf(int sk, char *buf, int count)
-{
- int rd, i;
-
- printf("Checking for %d bytes\n", count);
-
- rd = 0;
- while (rd < count) {
- int r;
-
- r = read(sk, rbuf + rd, count - rd);
- if (r == 0) {
- printf("Unexpected EOF\n");
- return 1;
- }
-
- if (r < 0) {
- perror("Can't read buf");
- return 1;
- }
-
- rd += r;
- }
-
- for (i = 0; i < count; i++)
- if (buf[i] != rbuf[i]) {
- printf("Mismatch on %d byte %d != %d\n",
- i, (int)buf[i], (int)rbuf[i]);
- return 1;
- }
-
- return 0;
-}
-
-static int serve_new_conn(int in_fd, int sk)
-{
- printf("New connection\n");
-
- while (1) {
- int rd, wr;
-
- rd = read(in_fd, buf, sizeof(buf));
- if (rd == 0)
- break;
- if (rd < 0) {
- perror("Can't read from infd");
- return 1;
- }
-
- printf("Read %d bytes, sending to sock\n", rd);
-
- wr = 0;
- while (wr < rd) {
- int w;
-
- w = write(sk, buf + wr, rd - wr);
- if (w <= 0) {
- perror("Can't write to socket");
- return 1;
- }
-
- if (check_buf(sk, buf + wr, w))
- return 1;
-
- wr += w;
- }
- }
-
- printf("Done\n");
- return 0;
-}
-
-int main(int argc, char **argv)
-{
- int sk, port, ret;
- struct sockaddr_in addr;
-
- if (argc < 3) {
- printf("Need addr, port and iters\n");
- return -1;
- }
-
- sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sk < 0) {
- perror("Can't create socket");
- return -1;
- }
-
- port = atoi(argv[2]);
- printf("Connecting to %s:%d\n", argv[1], port);
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- ret = inet_aton(argv[1], &addr.sin_addr);
- if (ret < 0) {
- perror("Can't convert addr");
- return -1;
- }
- addr.sin_port = htons(port);
-
- ret = connect(sk, (struct sockaddr *)&addr, sizeof(addr));
- if (ret < 0) {
- perror("Can't connect");
- return -1;
- }
-
- return serve_new_conn(0, sk);
-}
diff --git a/test/tcp/run.sh b/test/tcp/run.sh
deleted file mode 100755
index 702879d..0000000
--- a/test/tcp/run.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/bash
-
-source ../env.sh || exit 1
-
-set -x
-
-PORT=12345
-CLN_PIPE="./clnt_pipe"
-SRV_LOG="./srv.log"
-CLN_LOG="./cln.log"
-DDIR="dump"
-
-TEXT=$(hexdump -C /dev/urandom | head -n 1)
-
-echo "Building services"
-
-make clean && make || { echo "Failed to build"; exit 1; }
-rm -rf ${DDIR} ${SRV_LOG} ${CLN_LOG} ${CLN_PIPE}
-mkdir ${DDIR}
-
-echo "Starting server"
-
-setsid ./srv ${PORT} > ${SRV_LOG} 2>&1 &
-SRV_PID=${!}
-
-echo "Starting pipe"
-mkfifo ${CLN_PIPE}
-
-echo "Starting client"
-./cln "127.0.0.1" ${PORT} < ${CLN_PIPE} > ${CLN_LOG} &
-CLN_PID=${!}
-
-exec 3>${CLN_PIPE}
-echo "Make it run"
-echo "${TEXT}" >&3
-
-function fail {
- echo FAIL
-
-( exec >&2
-
- echo "$@"
- kill -9 ${CLN_PID}
- kill -9 ${SRV_PID}
- echo ${CLN_LOG}:
- cat ${CLN_LOG}
-)
- exit 1
-}
-
-kill -s 0 ${CLN_PID} || fail "Client is dead"
-
-echo "Suspend server"
-${CRIU} dump -D ${DDIR} -o dump.log -t ${SRV_PID} --tcp-established -vvvv || fail "Fail to dump server"
-sleep 1
-echo "Resume server"
-${CRIU} restore -D ${DDIR} -o restore.log -d --tcp-established -vvvv --close 3 || fail "Fail to restore server"
-
-echo "Make client run again"
-echo "${TEXT}" >&3
-
-echo "Collect results"
-exec 3>&-
-wait ${CLN_PID} || fail "Client exits abruptly"
-kill -9 ${SRV_PID}
-
-echo PASS
diff --git a/test/tcp/srv.c b/test/tcp/srv.c
deleted file mode 100644
index 656cc01..0000000
--- a/test/tcp/srv.c
+++ /dev/null
@@ -1,112 +0,0 @@
-#include <sys/socket.h>
-#include <linux/types.h>
-#include <sys/types.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <signal.h>
-
-static int serve_new_conn(int sk)
-{
- int rd, wr;
- char buf[1024];
-
- printf("New connection\n");
-
- while (1) {
- rd = read(sk, buf, sizeof(buf));
- if (!rd)
- break;
-
- if (rd < 0) {
- perror("Can't read socket");
- return 1;
- }
-
- wr = 0;
- while (wr < rd) {
- int w;
-
- w = write(sk, buf + wr, rd - wr);
- if (w <= 0) {
- perror("Can't write socket");
- return 1;
- }
-
- wr += w;
- }
- }
-
- printf("Done\n");
- return 0;
-}
-
-int main(int argc, char **argv)
-{
- int sk, port, ret;
- struct sockaddr_in addr;
-
- if (argc < 2) {
- printf("Need port\n");
- return -1;
- }
-
- /*
- * Let kids die themselves
- */
-
- signal(SIGCHLD, SIG_IGN);
-
- sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sk < 0) {
- perror("Can't create socket");
- return -1;
- }
-
- port = atoi(argv[1]);
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_port = htons(port);
-
- printf("Binding to port %d\n", port);
-
- ret = bind(sk, (struct sockaddr *)&addr, sizeof(addr));
- if (ret < 0) {
- perror("Can't bind socket");
- return -1;
- }
-
- ret = listen(sk, 16);
- if (ret < 0) {
- perror("Can't put sock to listen");
- return -1;
- }
-
- printf("Waiting for connections\n");
- while (1) {
- int ask, pid;
-
- ask = accept(sk, NULL, NULL);
- if (ask < 0) {
- perror("Can't accept new conn");
- return -1;
- }
-
- pid = fork();
- if (pid < 0) {
- perror("Can't fork");
- return -1;
- }
-
- if (pid > 0)
- close(ask);
- else {
- close(sk);
- ret = serve_new_conn(ask);
- exit(ret);
- }
- }
-}
diff --git a/test/unix-callback/Makefile b/test/unix-callback/Makefile
deleted file mode 100644
index f2993c5..0000000
--- a/test/unix-callback/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-all: unix-lib.so unix-server unix-client syslog-lib.so
-
-run: all
- ./run.sh
-
-unix.pb-c.c: unix.proto
- protoc-c --proto_path=. --c_out=. unix.proto
-
-unix-lib.so: unix-lib.c unix.pb-c.c
- gcc -g -Werror -Wall -shared -nostartfiles unix-lib.c unix.pb-c.c -o unix-lib.so -iquote ../../include -fPIC
-
-syslog-lib.so: syslog-lib.c
- gcc -g -Werror -Wall -shared -nostartfiles syslog-lib.c -o syslog-lib.so -iquote ../../include -fPIC
-
-unix-server: unix-server.c
- gcc -Werror -Wall -o unix-server unix-server.c
-
-unix-client: unix-client.c
- gcc -Werror -Wall -o unix-client unix-client.c
-
-clean:
- rm -rf data unix-lib.so unix-server unix-client syslog-lib.so output pid unix.pb-c.*
diff --git a/test/unix-callback/lib/syslog-lib.so b/test/unix-callback/lib/syslog-lib.so
deleted file mode 120000
index 6a2d849..0000000
--- a/test/unix-callback/lib/syslog-lib.so
+++ /dev/null
@@ -1 +0,0 @@
-../syslog-lib.so
\ No newline at end of file
diff --git a/test/unix-callback/lib/unix-lib.so b/test/unix-callback/lib/unix-lib.so
deleted file mode 120000
index 19c491e..0000000
--- a/test/unix-callback/lib/unix-lib.so
+++ /dev/null
@@ -1 +0,0 @@
-../unix-lib.so
\ No newline at end of file
diff --git a/test/unix-callback/run.sh b/test/unix-callback/run.sh
deleted file mode 100755
index ec5b7f5..0000000
--- a/test/unix-callback/run.sh
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/bash -x
-
-cd `dirname $0`
-
-source ../env.sh || exit 1
-
-rm -rf /tmp/criu.unix.callback.test*
-test -f pid && unlink pid
-test -f output && unlink output
-rm -rf data
-mkdir -p data
-
-./unix-server &
-srv_pid=$!
-
-for i in `seq 20`; do
- test -f /tmp/criu.unix.callback.test && break
- sleep 0.1
-done
-
-( setsid ./unix-client < /dev/null &> output ) &
-
-while :; do
- test -f pid && break
- sleep 1
-done
-
-pid=`cat pid`
-
-${CRIU} dump -D data -o dump.log -v4 --lib `pwd`/lib -t $pid || exit 1
-kill $srv_pid
-wait $srv_pid
-unlink /tmp/criu.unix.callback.test
-./unix-server &
-srv_pid=$!
-for i in `seq 20`; do
- test -f /tmp/criu.unix.callback.test && break
- sleep 0.1
-done
-${CRIU} restore -D data -o restore.log -v4 --lib `pwd`/lib -d || exit 1
-kill $pid
-while :; do
- cat output | grep PASS && break
- sleep 1
-done
-
-cat output
-kill $srv_pid
diff --git a/test/unix-callback/syslog-lib.c b/test/unix-callback/syslog-lib.c
deleted file mode 100644
index c7950ca..0000000
--- a/test/unix-callback/syslog-lib.c
+++ /dev/null
@@ -1,66 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include "criu-plugin.h"
-#include "criu-log.h"
-
-extern cr_plugin_dump_unix_sk_t cr_plugin_dump_unix_sk;
-extern cr_plugin_restore_unix_sk_t cr_plugin_restore_unix_sk;
-
-int cr_plugin_dump_unix_sk(int sk, int id)
-{
- struct sockaddr_un addr;
- socklen_t addr_len = sizeof(addr);
- char buf[4096];
- int fd;
-
- if (getsockname(sk, (struct sockaddr *) &addr, &addr_len) < 0)
- return -1;
-
- if (strncmp(addr.sun_path, "/dev/log", addr_len - sizeof(addr.sun_family)))
- return -ENOTSUP;
-
- snprintf(buf, sizeof(buf), "syslog-%x.img", id);
- fd = open(buf, O_WRONLY | O_CREAT);
- if (fd < 0)
- return -1;
- close(fd);
-
- return 0;
-}
-
-int cr_plugin_restore_unix_sk(int id)
-{
- struct sockaddr_un addr;
- socklen_t addr_len;
- char buf[4096];
- int sk, fd;
-
- snprintf(buf, sizeof(buf), "syslog-%x.img", id);
- fd = open(buf, O_RDONLY);
- if (fd < 0)
- return -ENOTSUP;
- close(fd);
-
- sk = socket(AF_FILE, SOCK_DGRAM|SOCK_CLOEXEC, 0);
- if (sk == -1)
- return sk;
-
- addr.sun_family = AF_FILE;
- addr_len = strlen("/dev/log");
- strncpy(addr.sun_path, "/dev/log", addr_len);
- addr_len += sizeof(addr.sun_family);
- if (connect(sk, (struct sockaddr *) &addr, addr_len) == -1) {
- close(sk);
- return -1;
- }
-
- return sk;
-}
diff --git a/test/unix-callback/unix-client.c b/test/unix-callback/unix-client.c
deleted file mode 100644
index 69808b5..0000000
--- a/test/unix-callback/unix-client.c
+++ /dev/null
@@ -1,121 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <signal.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <linux/un.h>
-#include <fcntl.h>
-
-#include <syslog.h>
-
-#define SK_NAME "/tmp/criu.unix.callback.test"
-
-#define SK_NR 2
-struct {
- int id;
- int sk;
- int val;
-} sks[SK_NR];
-
-static int create_sock(int i)
-{
- int ret, id, sk, val = time(NULL) + i * 314;
- char buf[4096];
- struct sockaddr_un addr;
- socklen_t addr_len;
-
- id = getpid() * 10 + i;
- sk = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (sk < 0)
- return -1;
-
- addr.sun_family = AF_UNIX;
- addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s%d", SK_NAME, id);
- addr_len += sizeof(addr.sun_family);
-
- if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0) {
- perror("bind");
- return 1;
- }
-
- addr.sun_family = AF_UNIX;
- addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
- addr_len += sizeof(addr.sun_family);
-
- if (connect(sk, (struct sockaddr *) &addr, addr_len) < 0) {
- perror("connect");
- return 1;
- }
-
- printf("init %d\n", val);
- ret = sprintf(buf, "t%d", val);
- if (send(sk, buf, ret, 0) < 0) {
- perror("send");
- return -1;
- }
-
- sks[i].sk = sk;
- sks[i].val = val;
-
- return 0;
-}
-
-static int check_sock(int i)
-{
- int sk = sks[i].sk, val = sks[i].val;
- char buf[4096];
-
- if (send(sk, "r", 1, 0) < 0) {
- perror("send(\"r\")");
- return -1;
- }
-
- if (recv(sk, buf, sizeof(buf), 0) <= 0) {
- perror("recv");
- return -1;
- }
-
- printf("%s - %d\n", buf, val);
- if (atoi(buf) != val)
- return -1;
-
- return 0;
-}
-
-int main()
-{
- int i, fd;
- sigset_t set;
- int sig;
-
- for (i = 0; i < SK_NR; i++)
- if (create_sock(i))
- return -1;
-
- fd = open("pid", O_WRONLY | O_CREAT, 0666);
- if (fd < 0)
- return 1;
- dprintf(fd, "%d\n", getpid());
- close(fd);
-
- openlog("test", LOG_NDELAY, LOG_USER );
-
- sigemptyset(&set);
- sigaddset(&set, SIGTERM);
- sigprocmask(SIG_BLOCK, &set, NULL);
- sigwait(&set, &sig);
-
- syslog(LOG_CRIT, "test message");
-
- for (i = 0; i < SK_NR; i++)
- if (check_sock(i))
- return -1;
-
- printf("PASS\n");
- return 0;
-}
-
diff --git a/test/unix-callback/unix-lib.c b/test/unix-callback/unix-lib.c
deleted file mode 100644
index 44b1498..0000000
--- a/test/unix-callback/unix-lib.c
+++ /dev/null
@@ -1,187 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <errno.h>
-
-#include <sys/socket.h>
-#include <linux/un.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "criu-plugin.h"
-#include "criu-log.h"
-
-#include "unix.pb-c.h"
-
-extern cr_plugin_init_t cr_plugin_init;
-extern cr_plugin_dump_unix_sk_t cr_plugin_dump_unix_sk;
-extern cr_plugin_restore_unix_sk_t cr_plugin_restore_unix_sk;
-
-#define SK_NAME "/tmp/criu.unix.callback.test"
-static int get_srv_socket(void)
-{
- struct sockaddr_un addr;
- socklen_t addr_len;
- int skd;
-
- skd = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (skd < 0) {
- pr_perror("socket");
- return -1;
- }
-
- addr.sun_family = AF_UNIX;
- addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s.dump.%d", SK_NAME, getpid());
- addr_len += sizeof(addr.sun_family);
-
- unlink(addr.sun_path);
- if (bind(skd, (struct sockaddr *) &addr, addr_len) < 0) {
- pr_perror("bind");
- return 1;
- }
-
- addr.sun_family = AF_UNIX;
- addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
- addr_len += sizeof(addr.sun_family);
-
- if (connect(skd, (struct sockaddr *) &addr, addr_len) < 0) {
- pr_perror("connect");
- return -1;
- }
-
- return skd;
-}
-
-int cr_plugin_init(void)
-{
- return 0;
-}
-
-int cr_plugin_dump_unix_sk(int sk, int sk_id)
-{
- struct sockaddr_un addr;
- socklen_t addr_len = sizeof(addr);
- char buf[4096];
- int skd, id, ret, fd, len;
- UnixTest e = UNIX_TEST__INIT;
-
- if (getpeername(sk, (struct sockaddr *) &addr, &addr_len)) {
- pr_perror("getpeername");
- return -1;
- }
-
- len = addr_len - sizeof(addr.sun_family);
- if (addr.sun_path[len - 1] == 0)
- len--;
-
- if (len != strlen(SK_NAME) ||
- strncmp(addr.sun_path, SK_NAME, strlen(SK_NAME)))
- return -ENOTSUP;
-
- pr_info("Dump the socket %x\n", sk_id);
- skd = get_srv_socket();
- if (skd < 0)
- return -1;
-
- addr_len = sizeof(struct sockaddr_un);
-
- if (getsockname(sk, (struct sockaddr *) &addr, &addr_len) < 0)
- return -1;
-
- id = atoi(addr.sun_path + strlen(SK_NAME));
-
- ret = sprintf(buf, "d%d", id) + 1;
- if (send(skd, buf, ret, 0) < 0) {
- pr_perror("send");
- return -1;
- }
-
- if (recv(skd, buf, sizeof(buf), 0) <= 0)
- return -1;
-
- close(skd);
-
- e.val = atoi(buf);
- pr_err("%x: val %d\n", sk_id, e.val);
- e.name.data = (void *)addr.sun_path;
- e.name.len = addr_len - sizeof(addr.sun_family);
-
- snprintf(buf, sizeof(buf), "unix-test-%x.img", sk_id);
- fd = openat(criu_get_image_dir(), buf, O_WRONLY | O_CREAT, 0600);
- if (fd < 0)
- return -1;
-
- if (unix_test__get_packed_size(&e) > sizeof(buf)) {
- pr_err("%ld\n", unix_test__get_packed_size(&e));
- return -1;
- }
-
- ret = unix_test__pack(&e, (uint8_t *) buf);
- if (write(fd, buf, ret) != ret)
- return -1;
- close(fd);
-
- return 0;
-}
-
-int cr_plugin_restore_unix_sk(int sk_id)
-{
- struct sockaddr_un addr;
- socklen_t addr_len;
- int fd, sk, ret;
- char buf[4096];
- UnixTest *e;
-
- snprintf(buf, sizeof(buf), "unix-test-%x.img", sk_id);
- fd = openat(criu_get_image_dir(), buf, O_RDONLY, 0600);
- if (fd < 0)
- return -ENOTSUP;
-
- ret = read(fd, buf, sizeof(buf));
- if (ret < 0) {
- pr_perror("read");
- return -1;
- }
- close(fd);
-
- e = unix_test__unpack(NULL, ret, (uint8_t *) buf);
- if (e == NULL)
- return -1;
-
- sk = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (sk < 0) {
- pr_perror("socket");
- return -1;
- }
-
- addr.sun_family = AF_UNIX;
- memcpy(addr.sun_path, e->name.data, e->name.len);
- addr_len = sizeof(addr.sun_family) + e->name.len;
-
- if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0) {
- pr_perror("bind");
- return -1;
- }
-
- addr.sun_family = AF_UNIX;
- addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
- addr_len += sizeof(addr.sun_family);
-
- if (connect(sk, (struct sockaddr *) &addr, addr_len) < 0) {
- pr_perror("connect");
- return -1;
- }
-
- pr_err("id %d val %d\n", sk_id, e->val);
- ret = sprintf(buf, "t%d", e->val);
- if (send(sk, buf, ret, 0) < 0) {
- pr_perror("send");
- return -1;
- }
-
- return sk;
-}
diff --git a/test/unix-callback/unix-server.c b/test/unix-callback/unix-server.c
deleted file mode 100644
index 8f32f53..0000000
--- a/test/unix-callback/unix-server.c
+++ /dev/null
@@ -1,104 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <linux/un.h>
-
-struct ticket
-{
- struct ticket *next;
- int val;
- int id;
-};
-
-struct ticket *tickets;
-
-#define SK_NAME "/tmp/criu.unix.callback.test"
-
-int main()
-{
- int sk, ret, id;
- char buf[4096];
- struct ticket *t;
- struct sockaddr_un addr;
- socklen_t addr_len;
- struct stat st;
-
- unlink(SK_NAME);
-
- sk = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (sk < 0) {
- perror("socket");
- return -1;
- }
-
- addr.sun_family = AF_UNIX;
- addr_len = snprintf(addr.sun_path, UNIX_PATH_MAX, SK_NAME);
- addr_len += sizeof(addr.sun_family);
-
- if (bind(sk, (struct sockaddr *) &addr, addr_len) < 0) {
- perror("bind");
- return 1;
- }
-
- fstat(sk, &st);
-
- while (1) {
- addr_len = sizeof(struct sockaddr_un);
- ret = recvfrom(sk, buf, sizeof(buf), 0, (struct sockaddr *) &addr, &addr_len);
- if (ret == 0)
- return 0;
- if (ret < 0) {
- perror("recvfrom");
- return 1;
- }
- id = 0;
- switch (buf[0]) {
- case 'l':
- ret = sprintf(buf, "%ld", st.st_ino);
- if (sendto(sk, buf, ret + 1, 0, (struct sockaddr *) &addr, addr_len) < 0) {
- perror("sendto");
- return -1;
- }
- break;
- case 't': /* ticket */
- t = malloc(sizeof(struct ticket));
- if (t == 0) {
- perror("Can't allocate memory");
- return 1;
- }
-
- t->val = atoi(buf + 1);
- t->next = tickets;
- t->id = atoi(addr.sun_path +strlen(SK_NAME));
- printf("t: id %d val %d\n", t->id, t->val);
- tickets = t;
- break;
- case 'd': /* dump */
- id = atoi(buf + 1);
- case 'r': /* request */
- if (!id)
- id = atoi(addr.sun_path + strlen(SK_NAME));
- for (t = tickets; t; t = t->next)
- if (t->id == id)
- break;
- if (t == NULL)
- return 1;
- printf("r: id %d val %d\n", id, t->val);
- ret = sprintf(buf, "%d", t->val);
- if (sendto(sk, buf, ret + 1, 0, (struct sockaddr *) &addr, addr_len) < 0) {
- perror("sendto");
- return 1;
- }
- break;
- default:
- return -1;
- }
- }
-
- return 0;
-}
diff --git a/test/unix-callback/unix.proto b/test/unix-callback/unix.proto
deleted file mode 100644
index fb06fc8..0000000
--- a/test/unix-callback/unix.proto
+++ /dev/null
@@ -1,4 +0,0 @@
-message unix_test {
- required uint32 val = 1;
- required bytes name = 2;
-}
--
2.5.0
More information about the CRIU
mailing list