[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