[CRIU] [PATCH] compel: test -- Add example-1

Cyrill Gorcunov gorcunov at openvz.org
Thu Nov 24 09:12:30 PST 2016


Here is a trivial example of using compel library.
How to build and run.

 - prepare compel

	make compel/compel-host
	make compel/plugins/std.built-in.o
	make compel/plugins/fds.built-in.o

 - prepare example

	make -C compel/test/example-1 all

 - run example

	sudo 	compel/test/example-1/run.sh 	\
		compel/test/example-1/donor 	\
		compel/test/example-1/modifier 	\
		pie.txt 2

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 compel/test/example-1/Makefile       |  47 ++++++++++++
 compel/test/example-1/donor.c        |  56 +++++++++++++++
 compel/test/example-1/log.c          |  44 ++++++++++++
 compel/test/example-1/log.h          |  45 ++++++++++++
 compel/test/example-1/modifier-pie.c |  34 +++++++++
 compel/test/example-1/modifier.c     | 136 +++++++++++++++++++++++++++++++++++
 compel/test/example-1/run.sh         |  11 +++
 7 files changed, 373 insertions(+)
 create mode 100644 compel/test/example-1/Makefile
 create mode 100644 compel/test/example-1/donor.c
 create mode 100644 compel/test/example-1/log.c
 create mode 100644 compel/test/example-1/log.h
 create mode 100644 compel/test/example-1/modifier-pie.c
 create mode 100644 compel/test/example-1/modifier.c
 create mode 100755 compel/test/example-1/run.sh

diff --git a/compel/test/example-1/Makefile b/compel/test/example-1/Makefile
new file mode 100644
index 000000000000..f8fd0c8f2f6f
--- /dev/null
+++ b/compel/test/example-1/Makefile
@@ -0,0 +1,47 @@
+CFLAGS			+= -O2
+CFLAGS			+= -I ../../../compel/include/uapi
+CFLAGS			+= -I ../../../compel/plugins/include/uapi
+CFLAGS			+= -iquote ../../../include
+
+ifeq ($(ARCH),)
+        ARCH := x86
+endif
+
+compel_pack_lds		:= ../../../compel/arch/$(ARCH)/scripts/compel-pack.lds.S
+ifneq ($(filter-out clean mrproper,$(MAKECMDGOALS)),)
+CFLAGS_modifier-pie.o	:= $(shell ../../../compel/compel-host --arch=$(ARCH) cflags)
+endif
+
+clean:
+	rm -f ./*.[od]
+	rm -f ./donor
+	rm -f ./modifier
+	rm -f ./modifierpie-blob.h
+
+%.o: %.c
+	gcc -c $(CFLAGS) $(CFLAGS_$(@)) -o $@ $^
+
+modifierpie.o: modifier-pie.o ../../../compel/plugins/std.built-in.o ../../../compel/plugins/fds.built-in.o
+	ld -r -T $(compel_pack_lds) -o $@ $^
+
+modifierpie-blob.h: modifierpie.o ../../../compel/compel-host
+	../../../compel/compel-host hgen -f 	$<	\
+                -l 4					\
+                -v modifier_relocs			\
+		-p modifier_blob_offset__		\
+		-s modifier_blob			\
+		-r modifier_nr_gotpcrel			\
+		-u ../../../compel/include/uapi	        \
+		-o $@
+
+modifier.o: | modifierpie-blob.h
+
+modifier: modifier.o log.o ../../../compel/libcompel.a
+	gcc $(LDFLAGS) -o $@ $^
+
+donor: donor.o log.o
+	gcc $(LDFLAGS) -o $@ $^
+
+all: donor modifier
+	@true
+.PHONY: all
diff --git a/compel/test/example-1/donor.c b/compel/test/example-1/donor.c
new file mode 100644
index 000000000000..f4bb022d0333
--- /dev/null
+++ b/compel/test/example-1/donor.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <sys/types.h>
+
+static int variable = 1;
+
+/* argv[1] -- info path, argv[2] -- new value */
+int main(int argc, char *argv[])
+{
+	int expected = 0, nr_waits = 20;
+	char info[128];
+	int i, fd, size;
+
+	if (argc < 3) {
+		printf("FAIL: Not enough params passed\n");
+		exit(1);
+	}
+
+	expected = atoi(argv[2]);
+
+	printf("INFO: donor %d variable %p value %d => %d\n",
+	       getpid(), &variable, variable, expected);
+
+	fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0644);
+	if (fd < 0) {
+		printf("FAIL: Can't open %s: %m\n", argv[1]);
+		exit(1);
+	}
+
+	snprintf(info, sizeof(info), "%d %p\n", getpid(), &variable);
+	size = strlen(info);
+	if (write(fd, info, size) != size) {
+		printf("FAIL: Incomplete write of data\n");
+		exit(1);
+	}
+	close(fd);
+
+	for (i = 0; i < nr_waits; i++) {
+		printf("INFO: %d: %s (got %d expected %d nr %d/%d)\n",
+		       getpid(),
+		       expected == variable ? "Match" : "Mismatch",
+		       variable, expected, i, nr_waits);
+		if (expected == variable) {
+			printf("PASS: %d\n", getpid());
+			exit(0);
+		}
+		sleep(1);
+	}
+
+	printf("FAIL: %d\n", getpid());
+	return 1;
+}
diff --git a/compel/test/example-1/log.c b/compel/test/example-1/log.c
new file mode 100644
index 000000000000..a3493a94d777
--- /dev/null
+++ b/compel/test/example-1/log.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "log.h"
+
+static unsigned int current_loglevel = LOG_DEBUG;
+
+unsigned int log_get_loglevel(void)
+{
+	return current_loglevel;
+}
+
+void __print_on_level(unsigned int loglevel, const char *format, va_list params)
+{
+	int size, ret, off = 0;
+	int __errno = errno;
+	char buffer[1024];
+
+	if (loglevel != LOG_MSG && loglevel > current_loglevel)
+		return;
+
+	size = vsnprintf(buffer, sizeof(buffer), format, params);
+
+	while (off < size) {
+		ret = write(STDOUT_FILENO, buffer + off, size - off);
+		if (ret <= 0)
+			break;
+		off += ret;
+	}
+	errno =  __errno;
+}
+
+void print_on_level(unsigned int loglevel, const char *format, ...)
+{
+	va_list params;
+
+	va_start(params, format);
+	__print_on_level(loglevel, format, params);
+	va_end(params);
+}
diff --git a/compel/test/example-1/log.h b/compel/test/example-1/log.h
new file mode 100644
index 000000000000..8b7f90094ed8
--- /dev/null
+++ b/compel/test/example-1/log.h
@@ -0,0 +1,45 @@
+#ifndef EXAMPLE_1_LOG_H__
+#define EXAMPLE_1_LOG_H__
+
+#include <compel/loglevels.h>
+
+extern unsigned int log_get_loglevel(void);
+extern void __print_on_level(unsigned int loglevel, const char *format, va_list params);
+extern void print_on_level(unsigned int loglevel, const char *format, ...);
+
+#ifndef LOG_PREFIX
+# define LOG_PREFIX
+#endif
+
+#define pr_msg(fmt, ...)						\
+	print_on_level(LOG_MSG,						\
+		       fmt, ##__VA_ARGS__)
+
+#define pr_info(fmt, ...)						\
+	print_on_level(LOG_INFO,					\
+		       LOG_PREFIX fmt, ##__VA_ARGS__)
+
+#define pr_err(fmt, ...)						\
+	print_on_level(LOG_ERROR,					\
+		       "Error (%s:%d): " LOG_PREFIX fmt,		\
+		       __FILE__, __LINE__, ##__VA_ARGS__)
+
+#define pr_err_once(fmt, ...)						\
+	print_once(LOG_ERROR, fmt, ##__VA_ARGS__)
+
+#define pr_warn(fmt, ...)						\
+	print_on_level(LOG_WARN,					\
+		       "Warn  (%s:%d): " LOG_PREFIX fmt,		\
+		       __FILE__, __LINE__, ##__VA_ARGS__)
+
+#define pr_warn_once(fmt, ...)						\
+	print_once(LOG_WARN, fmt, ##__VA_ARGS__)
+
+#define pr_debug(fmt, ...)						\
+	print_on_level(LOG_DEBUG,					\
+		       LOG_PREFIX fmt, ##__VA_ARGS__)
+
+#define pr_perror(fmt, ...)						\
+	pr_err(fmt ": %s\n", ##__VA_ARGS__, strerror(errno))
+
+#endif /* EXAMPLE_1_LOG_H__ */
diff --git a/compel/test/example-1/modifier-pie.c b/compel/test/example-1/modifier-pie.c
new file mode 100644
index 000000000000..4a3b5826c40e
--- /dev/null
+++ b/compel/test/example-1/modifier-pie.c
@@ -0,0 +1,34 @@
+#include <errno.h>
+
+#include <compel/plugins/std/syscall.h>
+#include <compel/plugins/std/string.h>
+#include <compel/plugins/std/log.h>
+
+#include <compel/infect-rpc.h>
+
+/*
+ * These are stubs for std compel plugin.
+ */
+int compel_main(void *arg_p, unsigned int arg_s) { return 0; }
+int parasite_trap_cmd(int cmd, void *args) { return 0; }
+void parasite_cleanup(void) { }
+
+#define PARASITE_CMD_MODIFY	PARASITE_USER_CMDS
+
+typedef struct {
+	int	*pvar;
+	int	val;
+} parasite_mod_t;
+
+int parasite_daemon_cmd(int cmd, void *args)
+{
+	std_printf("INFO: modifier-pie: parasite_daemon_cmd %d\n", cmd);
+
+	if (cmd == PARASITE_CMD_MODIFY) {
+		parasite_mod_t *p = args;
+		*p->pvar = p->val;
+		return 0;
+	}
+
+	return -EINVAL;
+}
diff --git a/compel/test/example-1/modifier.c b/compel/test/example-1/modifier.c
new file mode 100644
index 000000000000..354b8801e8b4
--- /dev/null
+++ b/compel/test/example-1/modifier.c
@@ -0,0 +1,136 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <compel/compel.h>
+
+#include "log.h"
+#include "common/list.h"
+#include "common/page.h"
+
+#include "modifierpie-blob.h"
+
+#define CONFIG_PIEGEN
+#define pie_size(__pie_name)	(round_up(sizeof(__pie_name##_blob) + \
+			__pie_name ## _nr_gotpcrel * sizeof(long), page_size()))
+
+extern int compel_stop_task(pid_t pid);
+
+#define PARASITE_CMD_MODIFY	PARASITE_USER_CMDS
+
+typedef struct {
+	int	*pvar;
+	int	val;
+} parasite_mod_t;
+
+/* argv[1] -- info path, argv[2] -- new value */
+int main(int argc, char *argv[])
+{
+	struct parasite_blob_desc *pbd;
+	struct parasite_ctl *ctl;
+	struct infect_ctx *ictx;
+	parasite_mod_t *mod;
+	char line[128];
+	FILE *f;
+	int i;
+
+	pid_t donor_pid;
+	int *variable;
+
+	if (argc < 2) {
+		pr_err("FAIL: Two args required\n");
+		exit(1);
+	}
+
+	compel_log_init(__print_on_level, 4);
+
+	for (i = 0; i < 10; i++) {
+		if (access(argv[1], R_OK)) {
+			sleep(3);
+			continue;
+		}
+		sleep(1);
+		break;
+	}
+
+	if (i >= 10) {
+		pr_err("FAIL: Can't access %s\n", argv[1]);
+		exit(1);
+	}
+
+	f = fopen(argv[1], "r");
+	if (!f) {
+		pr_perror("FAIL: Can't open %s", argv[1]);
+		exit(1);
+	}
+
+	if (!fgets(line, sizeof(line), f)) {
+		pr_err("FAIL: Can't read data from %s\n", argv[1]);
+		exit(1);
+	}
+	fclose(f);
+
+	if (sscanf(line, "%d %p", &donor_pid, &variable) != 2) {
+		pr_err("FAIL: Can't parse data from %s\n", argv[1]);
+		exit(1);
+	}
+
+	if (compel_stop_task(donor_pid) < 0) {
+		pr_err("FAIL: Can't stop task %d\n", donor_pid);
+		exit(1);
+	}
+
+	ctl = compel_prepare(donor_pid);
+	if (!ctl) {
+		pr_err("FAIL: Can't prepare compel for %d\n", donor_pid);
+		exit(1);
+	}
+
+	ictx = compel_infect_ctx(ctl);
+	ictx->log_fd = STDOUT_FILENO;
+
+	pbd			= compel_parasite_blob_desc(ctl);
+	pbd->mem		= modifier_blob;
+	pbd->bsize		= sizeof(modifier_blob);
+	pbd->size		= pie_size(modifier);
+	pbd->parasite_ip_off	= modifier_blob_offset____export_parasite_head_start;
+	pbd->addr_cmd_off	= modifier_blob_offset____export_parasite_cmd;
+	pbd->addr_arg_off	= modifier_blob_offset____export_parasite_args;
+	pbd->relocs		= modifier_relocs;
+	pbd->nr_relocs		= sizeof(modifier_relocs) / sizeof(modifier_relocs[0]);
+
+	if (compel_infect(ctl, 1, 16 << 10) < 0) {
+		pr_err("FAIL: Can't infect %d\n", donor_pid);
+		if (compel_cure(ctl))
+			pr_err("FAIL: Can't cure %d\n", donor_pid);
+		exit(1);
+	}
+
+	mod = compel_parasite_args(ctl, parasite_mod_t);
+	mod->pvar = (int *)(unsigned long)variable;
+	mod->val = atoi(argv[2]);
+
+	if (compel_rpc_call_sync(PARASITE_CMD_MODIFY, ctl)) {
+		pr_err("FAIL: Parasite cmd %d for %d failer\n",
+		       PARASITE_CMD_MODIFY, donor_pid);
+		if (compel_cure(ctl))
+			pr_err("FAIL: Can't cure %d\n", donor_pid);
+		exit(1);
+	}
+
+	if (compel_stop_daemon(ctl)) {
+		pr_err("FAIL: Can't stop daemon for %d\n", donor_pid);
+		if (compel_cure(ctl))
+			pr_err("FAIL: Can't cure %d\n", donor_pid);
+		exit(1);
+	}
+
+	if (compel_cure(ctl)) {
+		pr_err("FAIL: Can't cure %d\n", donor_pid);
+		exit(1);
+	}
+
+	return 0;
+}
diff --git a/compel/test/example-1/run.sh b/compel/test/example-1/run.sh
new file mode 100755
index 000000000000..b0e221472546
--- /dev/null
+++ b/compel/test/example-1/run.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+set -x
+donor=$1
+modifier=$2
+file=$3
+value=$4
+
+$donor $file $value &
+sleep 1
+$modifier $file $value
-- 
2.7.4



More information about the CRIU mailing list