From e6562db0423e6019154baf05beb02ff3da02f3bb Mon Sep 17 00:00:00 2001
From: Alice Frosi <afrosi@redhat.com>
Date: Fri, 24 Mar 2023 16:08:46 +0100
Subject: Re-arrange repository structure

---
 Makefile                            |   25 +-
 common/common.c                     |   51 +
 common/common.h                     |    6 +
 common/gluten.h                     |  138 +++
 debug/Makefile                      |   37 +
 debug/bpf_dbg.c                     |   32 +
 debug/build.c                       |   33 +
 debug/disasm.c                      |  281 +++++
 debug/disasm.h                      |   14 +
 operations.c                        |  361 ++++++
 operations.h                        |   26 +
 seitan-cooker/Makefile              |   20 +
 seitan-cooker/calls.c               |   18 +
 seitan-cooker/calls.h               |   23 +
 seitan-cooker/calls/net.c           |  174 +++
 seitan-cooker/calls/net.h           |   11 +
 seitan-cooker/cooker.h              |   99 ++
 seitan-cooker/emit.c                |   27 +
 seitan-cooker/emit.h                |   12 +
 seitan-cooker/example.hjson         |   67 ++
 seitan-cooker/example.hjson.license |    2 +
 seitan-cooker/filter.c              |  299 +++++
 seitan-cooker/filter.h              |   39 +
 seitan-cooker/gluten.c              |   44 +
 seitan-cooker/gluten.h              |   36 +
 seitan-cooker/main.c                |   28 +
 seitan-cooker/parse.c               |  237 ++++
 seitan-cooker/parse.h               |   11 +
 seitan-cooker/parson.c              | 2080 +++++++++++++++++++++++++++++++++++
 seitan-cooker/parson.h              |  240 ++++
 seitan-cooker/util.c                |   29 +
 seitan-cooker/util.h                |   22 +
 seitan-eater/.Makefile.swp          |  Bin 0 -> 12288 bytes
 seitan-eater/Makefile               |   22 +
 seitan-eater/eater.c                |  143 +++
 seitan.c                            |  435 ++++++++
 src/common/common.c                 |   51 -
 src/common/common.h                 |    6 -
 src/common/gluten.h                 |  138 ---
 src/cooker/Makefile                 |   20 -
 src/cooker/calls.c                  |   18 -
 src/cooker/calls.h                  |   23 -
 src/cooker/calls/net.c              |  174 ---
 src/cooker/calls/net.h              |   11 -
 src/cooker/cooker.h                 |   99 --
 src/cooker/emit.c                   |   27 -
 src/cooker/emit.h                   |   12 -
 src/cooker/example.hjson            |   67 --
 src/cooker/example.hjson.license    |    2 -
 src/cooker/filter.c                 |  299 -----
 src/cooker/filter.h                 |   39 -
 src/cooker/gluten.c                 |   44 -
 src/cooker/gluten.h                 |   36 -
 src/cooker/main.c                   |   28 -
 src/cooker/parse.c                  |  237 ----
 src/cooker/parse.h                  |   11 -
 src/cooker/parson.c                 | 2080 -----------------------------------
 src/cooker/parson.h                 |  240 ----
 src/cooker/util.c                   |   29 -
 src/cooker/util.h                   |   22 -
 src/debug/Makefile                  |   37 -
 src/debug/bpf_dbg.c                 |   32 -
 src/debug/build.c                   |   33 -
 src/debug/disasm.c                  |  281 -----
 src/debug/disasm.h                  |   14 -
 src/eater/Makefile                  |   22 -
 src/eater/eater.c                   |  143 ---
 src/seitan/Makefile                 |   35 -
 src/seitan/operations.c             |  361 ------
 src/seitan/operations.h             |   26 -
 src/seitan/seitan.c                 |  435 --------
 71 files changed, 5113 insertions(+), 5141 deletions(-)
 create mode 100644 common/common.c
 create mode 100644 common/common.h
 create mode 100644 common/gluten.h
 create mode 100644 debug/Makefile
 create mode 100644 debug/bpf_dbg.c
 create mode 100644 debug/build.c
 create mode 100644 debug/disasm.c
 create mode 100644 debug/disasm.h
 create mode 100644 operations.c
 create mode 100644 operations.h
 create mode 100644 seitan-cooker/Makefile
 create mode 100644 seitan-cooker/calls.c
 create mode 100644 seitan-cooker/calls.h
 create mode 100644 seitan-cooker/calls/net.c
 create mode 100644 seitan-cooker/calls/net.h
 create mode 100644 seitan-cooker/cooker.h
 create mode 100644 seitan-cooker/emit.c
 create mode 100644 seitan-cooker/emit.h
 create mode 100644 seitan-cooker/example.hjson
 create mode 100644 seitan-cooker/example.hjson.license
 create mode 100644 seitan-cooker/filter.c
 create mode 100644 seitan-cooker/filter.h
 create mode 100644 seitan-cooker/gluten.c
 create mode 100644 seitan-cooker/gluten.h
 create mode 100644 seitan-cooker/main.c
 create mode 100644 seitan-cooker/parse.c
 create mode 100644 seitan-cooker/parse.h
 create mode 100644 seitan-cooker/parson.c
 create mode 100644 seitan-cooker/parson.h
 create mode 100644 seitan-cooker/util.c
 create mode 100644 seitan-cooker/util.h
 create mode 100644 seitan-eater/.Makefile.swp
 create mode 100644 seitan-eater/Makefile
 create mode 100644 seitan-eater/eater.c
 create mode 100644 seitan.c
 delete mode 100644 src/common/common.c
 delete mode 100644 src/common/common.h
 delete mode 100644 src/common/gluten.h
 delete mode 100644 src/cooker/Makefile
 delete mode 100644 src/cooker/calls.c
 delete mode 100644 src/cooker/calls.h
 delete mode 100644 src/cooker/calls/net.c
 delete mode 100644 src/cooker/calls/net.h
 delete mode 100644 src/cooker/cooker.h
 delete mode 100644 src/cooker/emit.c
 delete mode 100644 src/cooker/emit.h
 delete mode 100644 src/cooker/example.hjson
 delete mode 100644 src/cooker/example.hjson.license
 delete mode 100644 src/cooker/filter.c
 delete mode 100644 src/cooker/filter.h
 delete mode 100644 src/cooker/gluten.c
 delete mode 100644 src/cooker/gluten.h
 delete mode 100644 src/cooker/main.c
 delete mode 100644 src/cooker/parse.c
 delete mode 100644 src/cooker/parse.h
 delete mode 100644 src/cooker/parson.c
 delete mode 100644 src/cooker/parson.h
 delete mode 100644 src/cooker/util.c
 delete mode 100644 src/cooker/util.h
 delete mode 100644 src/debug/Makefile
 delete mode 100644 src/debug/bpf_dbg.c
 delete mode 100644 src/debug/build.c
 delete mode 100644 src/debug/disasm.c
 delete mode 100644 src/debug/disasm.h
 delete mode 100644 src/eater/Makefile
 delete mode 100644 src/eater/eater.c
 delete mode 100644 src/seitan/Makefile
 delete mode 100644 src/seitan/operations.c
 delete mode 100644 src/seitan/operations.h
 delete mode 100644 src/seitan/seitan.c

diff --git a/Makefile b/Makefile
index 10d1606..ad72102 100644
--- a/Makefile
+++ b/Makefile
@@ -7,28 +7,35 @@
 
 DIR := $(shell pwd)
 OUTDIR ?= $(DIR)/
-
 export OUTDIR
 
+COMMON_DIR := $(DIR)/common
+BIN := $(OUTDIR)seitan
+SRCS := seitan.c $(COMMON_DIR)/common.c operations.c
+HEADERS := $(COMMON_DIR)/common.h $(COMMON_DIR)/gluten.h operations.h
+
+CFLAGS += -DTMP_DATA_SIZE=1000
+CFLAGS += -Wall -Wextra -pedantic -I$(COMMON_DIR)
+
 all: cooker eater seitan
 
 cooker:
-	$(MAKE) -C src/cooker
+	$(MAKE) -C seitan-cooker
 
 eater:
-	$(MAKE) -C src/eater
+	$(MAKE) -C seitan-eater
 
 seitan:
-	$(MAKE) -C src/seitan
+	$(CC) $(CFLAGS) -o $(BIN) $(SRCS)
 
 debug:
-	$(MAKE) -C src/debug
+	$(MAKE) -C debug
 
 clean:
-	$(MAKE) -C src/cooker clean
-	$(MAKE) -C src/seitan clean
-	$(MAKE) -C src/eater clean
-	$(MAKE) -C src/debug clean
+	rm -f $(BIN)
+	$(MAKE) -C cooker clean
+	$(MAKE) -C eater clean
+	$(MAKE) -C debug clean
 
 numbers.h:
 	./scripts/nr_syscalls.sh
diff --git a/common/common.c b/common/common.c
new file mode 100644
index 0000000..a8f79a2
--- /dev/null
+++ b/common/common.c
@@ -0,0 +1,51 @@
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+int find_fd_seccomp_notifier(const char *path)
+{
+	char entry[2 * PATH_MAX + 1];
+	char buf[PATH_MAX + 1];
+	struct dirent *dp;
+	ssize_t nbytes;
+	struct stat sb;
+	DIR *dirp;
+
+	if ((dirp = opendir(path)) == NULL) {
+		fprintf(stderr, "failed reading fds from proc: %s \n", path);
+		return -1;
+	}
+	while ((dp = readdir(dirp)) != NULL) {
+		snprintf(entry, sizeof(entry), "%s/%s", path, dp->d_name);
+		if (lstat(entry, &sb) == -1) {
+			perror("lstat");
+		}
+		/* Skip the entry if it isn't a symbolic link */
+		if (!S_ISLNK(sb.st_mode))
+			continue;
+
+		nbytes = readlink(entry, buf, PATH_MAX);
+		if (nbytes == -1) {
+			perror("readlink");
+		}
+		if (nbytes == PATH_MAX) {
+			perror("buffer overflow");
+			continue;
+		}
+		/*
+                 * From man proc: For  file  descriptors  that  have no
+                 * corresponding inode (e.g., file descriptors produced by
+                 * bpf(2)..), the  entry  will be a symbolic link with contents
+                 * of the form:
+                 *      anon_inode:<file-type>
+                 */
+		if (strstr(buf, "anon_inode:seccomp notify") != NULL)
+			return atoi(dp->d_name);
+	}
+	fprintf(stderr, "seccomp notifier not found in %s\n", path);
+	return -1;
+}
diff --git a/common/common.h b/common/common.h
new file mode 100644
index 0000000..487032b
--- /dev/null
+++ b/common/common.h
@@ -0,0 +1,6 @@
+#ifndef COMMON_H_
+#define COMMON_H_
+
+int find_fd_seccomp_notifier(const char *pid);
+
+#endif
diff --git a/common/gluten.h b/common/gluten.h
new file mode 100644
index 0000000..8370cf5
--- /dev/null
+++ b/common/gluten.h
@@ -0,0 +1,138 @@
+#ifndef GLUTEN_H
+#define GLUTEN_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define MAX_FD_INJECTED 10
+
+enum ns_spec_type {
+	NS_NONE,
+	NS_SPEC_TARGET,
+	NS_SPEC_PID,
+	NS_SPEC_PATH,
+};
+
+struct ns_spec {
+	enum ns_spec_type type;
+	union {
+		pid_t pid;
+		char *path;
+	};
+};
+
+/*
+ * enum ns_type - Type of namespaces
+ */
+enum ns_type {
+	NS_CGROUP,
+	NS_IPC,
+	NS_NET,
+	NS_MOUNT,
+	NS_PID,
+	NS_TIME,
+	NS_USER,
+	NS_UTS,
+};
+
+/*
+ * struct op_context - Description of the context where the call needs to be executed
+ * @ns:	Descrption of the each namespace where the call needs to be executed
+ */
+struct op_context {
+	struct ns_spec ns[sizeof(enum ns_type)];
+};
+
+enum op_type {
+	OP_CALL,
+	OP_BLOCK,
+	OP_CONT,
+	OP_INJECT,
+	OP_INJECT_A,
+	OP_RETURN,
+	OP_COPY_ARGS,
+	OP_END,
+	OP_CMP,
+	OP_RESOLVEDFD,
+};
+
+enum value_type {
+	IMMEDIATE,
+	REFERENCE,
+};
+
+struct op_call {
+	long nr;
+	bool has_ret;
+	void *args[6];
+	struct op_context context;
+	uint16_t ret_off;
+};
+
+struct op_block {
+	int32_t error;
+};
+
+struct op_continue {
+	bool cont;
+};
+
+struct op_return {
+	enum value_type type;
+	union {
+		int64_t value;
+		uint16_t value_off;
+	};
+};
+
+struct fd_type {
+	enum value_type type;
+	union {
+		uint32_t fd;
+		uint16_t fd_off;
+	};
+};
+
+struct op_inject {
+	struct fd_type newfd;
+	struct fd_type oldfd;
+};
+
+struct copy_arg {
+	uint16_t args_off;
+	enum value_type type;
+	size_t size;
+};
+
+struct op_copy_args {
+	struct copy_arg args[6];
+};
+
+struct op_cmp {
+	uint16_t s1_off;
+	uint16_t s2_off;
+	size_t size;
+	unsigned int jmp;
+};
+
+struct op_resolvedfd {
+	uint16_t fd_off;
+	uint16_t path_off;
+	size_t path_size;
+	unsigned int jmp;
+};
+
+struct op {
+	enum op_type type;
+	union {
+		struct op_call call;
+		struct op_block block;
+		struct op_continue cont;
+		struct op_return ret;
+		struct op_inject inj;
+		struct op_copy_args copy;
+		struct op_cmp cmp;
+		struct op_resolvedfd resfd;
+	};
+};
+#endif /* GLUTEN_H */
diff --git a/debug/Makefile b/debug/Makefile
new file mode 100644
index 0000000..6ef7900
--- /dev/null
+++ b/debug/Makefile
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# seitan - Syscall Expressive Interpreter, Transformer and Notifier
+#
+# debug/Makefile - Makefile for debug utilities: bpf_dbg
+#
+# Copyright 2023 Red Hat GmbH
+# Author: Alice Frosi <afrosi@redhat.com>
+
+SRCS := bpf_dbg.c  disasm.c
+HEADERS := disasm.h
+BIN := $(OUTDIR)bpf_dbg
+CFLAGS += -Wall -Wextra -pedantic
+
+# TODO: remove this part together with the build binary
+# when cooker is ready
+TARGET := $(shell $(CC) -dumpmachine)
+TARGET_ARCH := $(shell echo $(TARGET) | cut -f1 -d- | tr [A-Z] [a-z])
+TARGET_ARCH := $(shell echo $(TARGET_ARCH) | sed 's/powerpc/ppc/')
+
+AUDIT_ARCH := $(shell echo $(TARGET_ARCH) | tr [a-z] [A-Z] | sed 's/^ARM.*/ARM/')
+AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/I[456]86/I386/')
+AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPC64/PPC/')
+AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPCLE/PPC64LE/')
+
+bpf_dbg: $(SRCS) $(HEADERS)
+	$(CC) $(CFLAGS) -o $(BIN) $(SRCS)
+
+# TODO: remove when cooker is ready
+build: build.c ../cooker/filter.c ../cooker/filter.h ../common/numbers.h
+	$(CC) $(CFLAGS) -I../common -I../cooker -DSEITAN_AUDIT_ARCH=AUDIT_ARCH_$(AUDIT_ARCH)\
+	       	-o $(OUTDIR)build ../cooker/filter.c build.c
+
+all: $(BIN)
+
+clean:
+	rm -f $(BIN) build
diff --git a/debug/bpf_dbg.c b/debug/bpf_dbg.c
new file mode 100644
index 0000000..b84c713
--- /dev/null
+++ b/debug/bpf_dbg.c
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Alice Frosi <afrosi@redhat.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <linux/filter.h>
+#include <unistd.h>
+
+#include "disasm.h"
+
+int main(int argc, char **argv)
+{
+	struct sock_filter *filter;
+	size_t fd, n;
+
+	if (argc < 2) {
+		perror("missing input file");
+		exit(EXIT_FAILURE);
+	}
+	filter = calloc(SIZE_FILTER, sizeof(struct sock_filter));
+	fd = open(argv[1], O_CLOEXEC | O_RDONLY);
+
+	n = read(fd, filter, sizeof(struct sock_filter) * SIZE_FILTER);
+	close(fd);
+	printf("Read %ld entries\n", n / sizeof(struct sock_filter));
+	bpf_disasm_all(filter, n / sizeof(struct sock_filter));
+	free(filter);
+	return 0;
+}
diff --git a/debug/build.c b/debug/build.c
new file mode 100644
index 0000000..93ce97b
--- /dev/null
+++ b/debug/build.c
@@ -0,0 +1,33 @@
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "filter.h"
+
+struct bpf_call calls[] = {
+	{
+		.name = "connect",
+		.args = { 0, 111, 0, 0, 0, 0 },
+		.check_arg = { false, false, false, false, false, false },
+	},
+};
+
+int main(int argc, char **argv)
+{
+	int ret;
+	if (argc < 2) {
+		perror("missing input file");
+		exit(EXIT_FAILURE);
+	}
+	ret = convert_bpf(argv[1], calls, sizeof(calls) / sizeof(calls[0]),
+			  true);
+	if (ret < 0) {
+		perror("converting bpf program");
+		exit(EXIT_FAILURE);
+	}
+	return 0;
+}
diff --git a/debug/disasm.c b/debug/disasm.c
new file mode 100644
index 0000000..fae96b7
--- /dev/null
+++ b/debug/disasm.c
@@ -0,0 +1,281 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Alice Frosi <afrosi@redhat.com>
+ */
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/filter.h>
+
+#include "disasm.h"
+
+/* From linux tools/bpf/bpf_dbg.c */
+#define BPF_LDX_B (BPF_LDX | BPF_B)
+#define BPF_LDX_W (BPF_LDX | BPF_W)
+#define BPF_JMP_JA (BPF_JMP | BPF_JA)
+#define BPF_JMP_JEQ (BPF_JMP | BPF_JEQ)
+#define BPF_JMP_JGT (BPF_JMP | BPF_JGT)
+#define BPF_JMP_JGE (BPF_JMP | BPF_JGE)
+#define BPF_JMP_JSET (BPF_JMP | BPF_JSET)
+#define BPF_ALU_ADD (BPF_ALU | BPF_ADD)
+#define BPF_ALU_SUB (BPF_ALU | BPF_SUB)
+#define BPF_ALU_MUL (BPF_ALU | BPF_MUL)
+#define BPF_ALU_DIV (BPF_ALU | BPF_DIV)
+#define BPF_ALU_MOD (BPF_ALU | BPF_MOD)
+#define BPF_ALU_NEG (BPF_ALU | BPF_NEG)
+#define BPF_ALU_AND (BPF_ALU | BPF_AND)
+#define BPF_ALU_OR (BPF_ALU | BPF_OR)
+#define BPF_ALU_XOR (BPF_ALU | BPF_XOR)
+#define BPF_ALU_LSH (BPF_ALU | BPF_LSH)
+#define BPF_ALU_RSH (BPF_ALU | BPF_RSH)
+#define BPF_MISC_TAX (BPF_MISC | BPF_TAX)
+#define BPF_MISC_TXA (BPF_MISC | BPF_TXA)
+#define BPF_LD_B (BPF_LD | BPF_B)
+#define BPF_LD_H (BPF_LD | BPF_H)
+#define BPF_LD_W (BPF_LD | BPF_W)
+static const char *const op_table[] = {
+	[BPF_ST] = "st",	[BPF_STX] = "stx",     [BPF_LD_B] = "ldb",
+	[BPF_LD_H] = "ldh",	[BPF_LD_W] = "ld",     [BPF_LDX] = "ldx",
+	[BPF_LDX_B] = "ldxb",	[BPF_JMP_JA] = "ja",   [BPF_JMP_JEQ] = "jeq",
+	[BPF_JMP_JGT] = "jgt",	[BPF_JMP_JGE] = "jge", [BPF_JMP_JSET] = "jset",
+	[BPF_ALU_ADD] = "add",	[BPF_ALU_SUB] = "sub", [BPF_ALU_MUL] = "mul",
+	[BPF_ALU_DIV] = "div",	[BPF_ALU_MOD] = "mod", [BPF_ALU_NEG] = "neg",
+	[BPF_ALU_AND] = "and",	[BPF_ALU_OR] = "or",   [BPF_ALU_XOR] = "xor",
+	[BPF_ALU_LSH] = "lsh",	[BPF_ALU_RSH] = "rsh", [BPF_MISC_TAX] = "tax",
+	[BPF_MISC_TXA] = "txa", [BPF_RET] = "ret",
+};
+
+void bpf_disasm(const struct sock_filter f, unsigned int i)
+{
+	const char *op, *fmt;
+	int val = f.k;
+	char buf[256];
+
+	switch (f.code) {
+	case BPF_RET | BPF_K:
+		op = op_table[BPF_RET];
+		fmt = "#%#x";
+		break;
+	case BPF_RET | BPF_A:
+		op = op_table[BPF_RET];
+		fmt = "a";
+		break;
+	case BPF_RET | BPF_X:
+		op = op_table[BPF_RET];
+		fmt = "x";
+		break;
+	case BPF_MISC_TAX:
+		op = op_table[BPF_MISC_TAX];
+		fmt = "";
+		break;
+	case BPF_MISC_TXA:
+		op = op_table[BPF_MISC_TXA];
+		fmt = "";
+		break;
+	case BPF_ST:
+		op = op_table[BPF_ST];
+		fmt = "M[%d]";
+		break;
+	case BPF_STX:
+		op = op_table[BPF_STX];
+		fmt = "M[%d]";
+		break;
+	case BPF_LD_W | BPF_ABS:
+		op = op_table[BPF_LD_W];
+		fmt = "[%d]";
+		break;
+	case BPF_LD_H | BPF_ABS:
+		op = op_table[BPF_LD_H];
+		fmt = "[%d]";
+		break;
+	case BPF_LD_B | BPF_ABS:
+		op = op_table[BPF_LD_B];
+		fmt = "[%d]";
+		break;
+	case BPF_LD_W | BPF_LEN:
+		op = op_table[BPF_LD_W];
+		fmt = "#len";
+		break;
+	case BPF_LD_W | BPF_IND:
+		op = op_table[BPF_LD_W];
+		fmt = "[x+%d]";
+		break;
+	case BPF_LD_H | BPF_IND:
+		op = op_table[BPF_LD_H];
+		fmt = "[x+%d]";
+		break;
+	case BPF_LD_B | BPF_IND:
+		op = op_table[BPF_LD_B];
+		fmt = "[x+%d]";
+		break;
+	case BPF_LD | BPF_IMM:
+		op = op_table[BPF_LD_W];
+		fmt = "#%#x";
+		break;
+	case BPF_LDX | BPF_IMM:
+		op = op_table[BPF_LDX];
+		fmt = "#%#x";
+		break;
+	case BPF_LDX_B | BPF_MSH:
+		op = op_table[BPF_LDX_B];
+		fmt = "4*([%d]&0xf)";
+		break;
+	case BPF_LD | BPF_MEM:
+		op = op_table[BPF_LD_W];
+		fmt = "M[%d]";
+		break;
+	case BPF_LDX | BPF_MEM:
+		op = op_table[BPF_LDX];
+		fmt = "M[%d]";
+		break;
+	case BPF_JMP_JA:
+		op = op_table[BPF_JMP_JA];
+		fmt = "%d";
+		val = i + 1 + f.k;
+		break;
+	case BPF_JMP_JGT | BPF_X:
+		op = op_table[BPF_JMP_JGT];
+		fmt = "x";
+		break;
+	case BPF_JMP_JGT | BPF_K:
+		op = op_table[BPF_JMP_JGT];
+		fmt = "#%#x";
+		break;
+	case BPF_JMP_JGE | BPF_X:
+		op = op_table[BPF_JMP_JGE];
+		fmt = "x";
+		break;
+	case BPF_JMP_JGE | BPF_K:
+		op = op_table[BPF_JMP_JGE];
+		fmt = "#%#x";
+		break;
+	case BPF_JMP_JEQ | BPF_X:
+		op = op_table[BPF_JMP_JEQ];
+		fmt = "x";
+		break;
+	case BPF_JMP_JEQ | BPF_K:
+		op = op_table[BPF_JMP_JEQ];
+		fmt = "#%#x";
+		break;
+	case BPF_JMP_JSET | BPF_X:
+		op = op_table[BPF_JMP_JSET];
+		fmt = "x";
+		break;
+	case BPF_JMP_JSET | BPF_K:
+		op = op_table[BPF_JMP_JSET];
+		fmt = "#%#x";
+		break;
+	case BPF_ALU_NEG:
+		op = op_table[BPF_ALU_NEG];
+		fmt = "";
+		break;
+	case BPF_ALU_LSH | BPF_X:
+		op = op_table[BPF_ALU_LSH];
+		fmt = "x";
+		break;
+	case BPF_ALU_LSH | BPF_K:
+		op = op_table[BPF_ALU_LSH];
+		fmt = "#%d";
+		break;
+	case BPF_ALU_RSH | BPF_X:
+		op = op_table[BPF_ALU_RSH];
+		fmt = "x";
+		break;
+	case BPF_ALU_RSH | BPF_K:
+		op = op_table[BPF_ALU_RSH];
+		fmt = "#%d";
+		break;
+	case BPF_ALU_ADD | BPF_X:
+		op = op_table[BPF_ALU_ADD];
+		fmt = "x";
+		break;
+	case BPF_ALU_ADD | BPF_K:
+		op = op_table[BPF_ALU_ADD];
+		fmt = "#%d";
+		break;
+	case BPF_ALU_SUB | BPF_X:
+		op = op_table[BPF_ALU_SUB];
+		fmt = "x";
+		break;
+	case BPF_ALU_SUB | BPF_K:
+		op = op_table[BPF_ALU_SUB];
+		fmt = "#%d";
+		break;
+	case BPF_ALU_MUL | BPF_X:
+		op = op_table[BPF_ALU_MUL];
+		fmt = "x";
+		break;
+	case BPF_ALU_MUL | BPF_K:
+		op = op_table[BPF_ALU_MUL];
+		fmt = "#%d";
+		break;
+	case BPF_ALU_DIV | BPF_X:
+		op = op_table[BPF_ALU_DIV];
+		fmt = "x";
+		break;
+	case BPF_ALU_DIV | BPF_K:
+		op = op_table[BPF_ALU_DIV];
+		fmt = "#%d";
+		break;
+	case BPF_ALU_MOD | BPF_X:
+		op = op_table[BPF_ALU_MOD];
+		fmt = "x";
+		break;
+	case BPF_ALU_MOD | BPF_K:
+		op = op_table[BPF_ALU_MOD];
+		fmt = "#%d";
+		break;
+	case BPF_ALU_AND | BPF_X:
+		op = op_table[BPF_ALU_AND];
+		fmt = "x";
+		break;
+	case BPF_ALU_AND | BPF_K:
+		op = op_table[BPF_ALU_AND];
+		fmt = "#%#x";
+		break;
+	case BPF_ALU_OR | BPF_X:
+		op = op_table[BPF_ALU_OR];
+		fmt = "x";
+		break;
+	case BPF_ALU_OR | BPF_K:
+		op = op_table[BPF_ALU_OR];
+		fmt = "#%#x";
+		break;
+	case BPF_ALU_XOR | BPF_X:
+		op = op_table[BPF_ALU_XOR];
+		fmt = "x";
+		break;
+	case BPF_ALU_XOR | BPF_K:
+		op = op_table[BPF_ALU_XOR];
+		fmt = "#%#x";
+		break;
+	default:
+		op = "nosup";
+		fmt = "%#x";
+		val = f.code;
+		break;
+	}
+
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf), fmt, val);
+	buf[sizeof(buf) - 1] = 0;
+
+	if ((BPF_CLASS(f.code) == BPF_JMP && BPF_OP(f.code) != BPF_JA)) {
+		printf("l%d:\t%s %s, l%d, l%d\n", i, op, buf, i + 1 + f.jt,
+		       i + 1 + f.jf);
+	} else {
+		printf("l%d:\t%s %s\n", i, op, buf);
+	}
+}
+
+void bpf_disasm_all(const struct sock_filter *f, unsigned int len)
+{
+	unsigned int i;
+	for (i = 0; i < len; i++)
+		bpf_disasm(f[i], i);
+}
diff --git a/debug/disasm.h b/debug/disasm.h
new file mode 100644
index 0000000..c3e3ad9
--- /dev/null
+++ b/debug/disasm.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Alice Frosi <afrosi@redhat.com>
+ */
+
+#ifndef DISASM_H_
+#define DISASM_H_
+
+#define SIZE_FILTER 1024
+
+void bpf_disasm(const struct sock_filter f, unsigned int i);
+void bpf_disasm_all(const struct sock_filter *f, unsigned int len);
+
+#endif
diff --git a/operations.c b/operations.c
new file mode 100644
index 0000000..0327e57
--- /dev/null
+++ b/operations.c
@@ -0,0 +1,361 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Alice Frosi <afrosi@redhat.com>
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <linux/seccomp.h>
+#include <linux/filter.h>
+#include <linux/audit.h>
+#include <errno.h>
+
+#include "gluten.h"
+#include "operations.h"
+
+static bool is_cookie_valid(int notifyFd, uint64_t id)
+{
+	return ioctl(notifyFd, SECCOMP_IOCTL_NOTIF_ID_VALID, &id) == 0;
+}
+
+static int send_target(const struct seccomp_notif_resp *resp, int notifyfd)
+{
+	if (!is_cookie_valid(notifyfd, resp->id)) {
+		fprintf(stderr,
+			"the response id isn't valid\ncheck if the targets has already terminated\n");
+		return -1;
+	}
+	if (ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0) {
+		if (errno != EINPROGRESS) {
+			perror("sending the response");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int send_inject_target(const struct seccomp_notif_addfd *resp,
+			      int notifyfd)
+{
+	if (!is_cookie_valid(notifyfd, resp->id)) {
+		fprintf(stderr,
+			"the response id isn't valid\ncheck if the targets has already terminated\n");
+		return -1;
+	}
+	if (ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_ADDFD, resp) < 0) {
+		if (errno != EINPROGRESS) {
+			perror("sending the response");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static void proc_ns_name(unsigned i, char *ns)
+{
+	switch (i) {
+	case NS_CGROUP:
+		snprintf(ns, PATH_MAX + 1, "cgroup");
+		break;
+	case NS_IPC:
+		snprintf(ns, PATH_MAX + 1, "ipc");
+		break;
+	case NS_NET:
+		snprintf(ns, PATH_MAX + 1, "net");
+		break;
+	case NS_MOUNT:
+		snprintf(ns, PATH_MAX + 1, "mnt");
+		break;
+	case NS_PID:
+		snprintf(ns, PATH_MAX + 1, "pid");
+		break;
+	case NS_USER:
+		snprintf(ns, PATH_MAX + 1, "user");
+		break;
+	case NS_UTS:
+		snprintf(ns, PATH_MAX + 1, "uts");
+		break;
+	case NS_TIME:
+		snprintf(ns, PATH_MAX + 1, "time");
+		break;
+	default:
+		fprintf(stderr, "unrecognized namespace index %d\n", i);
+	}
+}
+
+static int set_namespaces(const struct op_call *a, int tpid)
+{
+	char path[PATH_MAX + 1];
+	char ns_name[PATH_MAX / 2];
+	struct ns_spec ns;
+	int fd;
+	unsigned int i;
+
+	for (i = 0, ns = (a->context).ns[i]; i < sizeof(enum ns_type);
+	     i++, ns = (a->context).ns[i]) {
+		proc_ns_name(i, ns_name);
+		switch (ns.type) {
+		case NS_NONE:
+			continue;
+		case NS_SPEC_TARGET:
+			snprintf(path, sizeof(path), "/proc/%d/ns/%s", tpid,
+				 ns_name);
+			break;
+		case NS_SPEC_PID:
+			snprintf(path, sizeof(path), "/proc/%d/ns/%s", ns.pid,
+				 ns_name);
+			break;
+		case NS_SPEC_PATH:
+			snprintf(path, sizeof(path), "%s", ns.path);
+			break;
+		}
+
+		if ((fd = open(path, O_CLOEXEC)) < 0) {
+			fprintf(stderr, "open for file %s: %s", path,
+				strerror(errno));
+			return -1;
+		}
+
+		if (setns(fd, 0) != 0) {
+			perror("setns");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int execute_syscall(void *args)
+{
+	struct arg_clone *a = (struct arg_clone *)args;
+	const struct op_call *c = a->args;
+
+	if (set_namespaces(a->args, a->pid) < 0) {
+		exit(EXIT_FAILURE);
+	}
+	/* execute syscall */
+	a->ret = syscall(c->nr, c->args[0], c->args[1], c->args[2], c->args[3],
+			 c->args[4], c->args[5]);
+	a->err = errno;
+	if (a->ret < 0) {
+		perror("syscall");
+		exit(EXIT_FAILURE);
+	}
+	exit(0);
+}
+
+int copy_args(struct seccomp_notif *req, struct op_copy_args *copy, void *data,
+	      int notifier)
+{
+	char path[PATH_MAX];
+	unsigned int i;
+	ssize_t nread;
+	void *dest;
+	int fd;
+
+	snprintf(path, sizeof(path), "/proc/%d/mem", req->pid);
+	if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
+		perror("open mem");
+		return -1;
+	}
+
+	/*
+         * Avoid the TOCTOU and check if the read mappings are still valid
+         */
+	if (!is_cookie_valid(notifier, req->id)) {
+		fprintf(stderr, "the seccomp request isn't valid anymore\n");
+		return -1;
+	}
+	for (i = 0; i < 6; i++) {
+		if (copy->args[i].type == REFERENCE) {
+			dest = (uint16_t *)data + copy->args[i].args_off;
+			nread = pread(fd, dest, copy->args[i].size,
+				      req->data.args[i]);
+			if (nread < 0) {
+				perror("pread");
+				return -1;
+			}
+		} else {
+			memcpy((uint16_t *)data + copy->args[i].args_off,
+			       &req->data.args[i], copy->args[i].size);
+		}
+	}
+	close(fd);
+	return 0;
+}
+
+static int resolve_fd(void *data, struct op_resolvedfd *resfd, pid_t pid)
+{
+	char fdpath[PATH_MAX], buf[PATH_MAX];
+	char *path = (char *)((uint16_t *)data + resfd->path_off);
+	int *fd = (int *)((uint16_t *)data + resfd->fd_off);
+	ssize_t nbytes;
+
+	snprintf(fdpath, PATH_MAX, "/proc/%d/fd/%d", pid, *fd);
+	if ((nbytes = readlink(fdpath, buf, resfd->path_size)) < 0) {
+		fprintf(stderr, "error reading %s\n", fdpath);
+		perror("readlink");
+		return -1;
+	}
+	if (strcmp(path, buf) == 0)
+		return 0;
+	else
+		return 1;
+}
+
+int do_call(struct arg_clone *c)
+{
+	char stack[STACK_SIZE];
+	pid_t child;
+
+	c->ret = -1;
+	c->err = 0;
+
+	/* Create a process that will be moved to the namespace */
+	child = clone(execute_syscall, stack + sizeof(stack),
+		      CLONE_FILES | CLONE_VM | SIGCHLD, (void *)c);
+	if (child == -1) {
+		perror("clone");
+		return -1;
+	}
+	wait(NULL);
+	return 0;
+}
+
+static void set_inject_fields(uint64_t id, void *data, const struct op *a,
+			      struct seccomp_notif_addfd *resp)
+{
+	const struct fd_type *new = &(a->inj).newfd;
+	const struct fd_type *old = &(a->inj).oldfd;
+
+	resp->flags = SECCOMP_ADDFD_FLAG_SETFD;
+	resp->id = id;
+	if (new->type == IMMEDIATE)
+		resp->newfd = new->fd;
+	else
+		memcpy(&resp->srcfd, (uint16_t *)data + old->fd_off,
+		       sizeof(resp->srcfd));
+	if (old->type == IMMEDIATE)
+		resp->srcfd = old->fd;
+	else
+		memcpy(&resp->srcfd, (uint16_t *)data + old->fd_off,
+		       sizeof(resp->srcfd));
+	resp->newfd_flags = 0;
+}
+
+int do_operations(void *data, struct op operations[], struct seccomp_notif *req,
+		  unsigned int n_operations, int pid, int notifyfd, uint64_t id)
+{
+	struct seccomp_notif_addfd resp_fd;
+	struct seccomp_notif_resp resp;
+	struct arg_clone c;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < n_operations; i++) {
+		switch (operations[i].type) {
+		case OP_CALL:
+			resp.id = id;
+			resp.val = 0;
+			resp.flags = 0;
+			c.args = &operations[i].call;
+			c.pid = pid;
+			if (do_call(&c) == -1) {
+				resp.error = -1;
+				if (send_target(&resp, notifyfd) == -1)
+					return -1;
+			}
+			if (c.err != 0) {
+				resp.error = -1;
+				if (send_target(&resp, notifyfd) == -1)
+					return c.err;
+			}
+			/*
+			 * The result of the call needs to be save as
+			 * reference
+			 */
+			if (operations[i].call.has_ret) {
+				memcpy((uint16_t *)data +
+					       operations[i].call.ret_off,
+				       &c.ret, sizeof(c.ret));
+			}
+			break;
+		case OP_BLOCK:
+			resp.id = id;
+			resp.val = 0;
+			resp.flags = 0;
+			resp.error = operations[i].block.error;
+			if (send_target(&resp, notifyfd) == -1)
+				return -1;
+			break;
+		case OP_RETURN:
+			resp.id = id;
+			resp.flags = 0;
+			resp.error = 0;
+			if (operations[i].ret.type == IMMEDIATE)
+				resp.val = operations[i].ret.value;
+			else
+				memcpy(&resp.val,
+				       (uint16_t *)data +
+					       operations[i].ret.value_off,
+				       sizeof(resp.val));
+
+			if (send_target(&resp, notifyfd) == -1)
+				return -1;
+			break;
+
+		case OP_CONT:
+			resp.id = id;
+			resp.flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE;
+			resp.error = 0;
+			resp.val = 0;
+			if (send_target(&resp, notifyfd) == -1)
+				return -1;
+			break;
+		case OP_INJECT_A:
+			set_inject_fields(id, data, &operations[i], &resp_fd);
+			resp_fd.flags |= SECCOMP_ADDFD_FLAG_SEND;
+			if (send_inject_target(&resp_fd, notifyfd) == -1)
+				return -1;
+			break;
+		case OP_INJECT:
+			set_inject_fields(id, data, &operations[i], &resp_fd);
+			if (send_inject_target(&resp_fd, notifyfd) == -1)
+				return -1;
+			break;
+		case OP_COPY_ARGS:
+			if (copy_args(req, &operations[i].copy, data,
+				      notifyfd) < 0)
+				return -1;
+			break;
+		case OP_END:
+			return 0;
+		case OP_CMP:
+			if (memcmp((uint16_t *)data + operations[i].cmp.s1_off,
+				   (uint16_t *)data + operations[i].cmp.s2_off,
+				   operations[i].cmp.size) != 0) {
+				i = operations[i].cmp.jmp;
+			}
+			break;
+		case OP_RESOLVEDFD:
+			ret = resolve_fd(data, &operations[i].resfd, pid);
+			if (ret == -1)
+				return -1;
+			else if (ret == 1)
+				i = operations[i].resfd.jmp;
+			break;
+		default:
+			fprintf(stderr, "unknow operation %d \n",
+				operations[i].type);
+		}
+	}
+	return 0;
+}
diff --git a/operations.h b/operations.h
new file mode 100644
index 0000000..3691a50
--- /dev/null
+++ b/operations.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Alice Frosi <afrosi@redhat.com>
+ */
+
+#ifndef ACIONS_H
+#define ACTIONS_H
+
+#include <errno.h>
+#include <linux/seccomp.h>
+
+#define STACK_SIZE (1024 * 1024 / 8)
+#define NS_NUM (sizeof(enum ns_type))
+
+struct arg_clone {
+	const struct op_call *args;
+	pid_t pid;
+	long ret;
+	int err;
+};
+
+int do_call(struct arg_clone *c);
+int do_operations(void *data, struct op operations[], struct seccomp_notif *req,
+		  unsigned int n_operations, int tpid, int notifyfd,
+		  uint64_t id);
+#endif /* ACTIONS_H */
diff --git a/seitan-cooker/Makefile b/seitan-cooker/Makefile
new file mode 100644
index 0000000..8741879
--- /dev/null
+++ b/seitan-cooker/Makefile
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# seitan - Syscall Expressive Interpreter, Transformer and Notifier
+#
+# cooker/Makefile - Makefile for seitan-cooker
+#
+# Copyright 2023 Red Hat GmbH
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+SRCS := calls.c emit.c gluten.c main.c parse.c parson.c util.c calls/net.c
+HEADERS := calls.h cooker.h emit.h gluten.h parse.h parson.h util.h calls/net.h
+BIN := $(OUTDIR)cooker
+
+cooker: $(SRCS) $(HEADERS)
+	$(CC) -O0 -g -Wall -Wextra -pedantic -std=c99 -o $(BIN) $(SRCS)
+
+all: cooker
+
+clean:
+	rm -f cooker
diff --git a/seitan-cooker/calls.c b/seitan-cooker/calls.c
new file mode 100644
index 0000000..74b5a06
--- /dev/null
+++ b/seitan-cooker/calls.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
+ *
+ * cooker/calls.c - Known syscall sets
+ *
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#include "cooker.h"
+#include "calls.h"
+
+#include "calls/net.h"
+
+struct call *call_sets[] = {
+	syscalls_net, NULL,
+};
diff --git a/seitan-cooker/calls.h b/seitan-cooker/calls.h
new file mode 100644
index 0000000..5d46e14
--- /dev/null
+++ b/seitan-cooker/calls.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#ifndef CALLS_H
+#define CALLS_H
+
+/**
+ * struct call - Description of one known system call
+ * @number:	Number from __NR_ macros, architecture dependent
+ * @name:	Name for use in recipes
+ * @args:	NULL-terminated array of argument descriptions
+ */
+struct call {
+	long number;
+	const char *name;
+	struct arg *args;
+};
+
+extern struct call *call_sets[];
+
+#endif /* CALLS_H */
diff --git a/seitan-cooker/calls/net.c b/seitan-cooker/calls/net.c
new file mode 100644
index 0000000..c0949cc
--- /dev/null
+++ b/seitan-cooker/calls/net.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
+ *
+ * cooker/calls/net.c - Description of known networking system calls
+ *
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+/*
+fd = socket(family, type stream/dgram/..., protocol)
+fd = connect(fd, addr, addrlen)
+fd = accept(fd, addr, addrlen)
+n  = sendto(fd, buf, len, flags, dst addr, addrlen)
+n  = recvfrom(fd, buf, len, flags, src addr, addrlen)
+n  = sendmsg(fd, msg, flags)
+n  = recvmsg(fd, msg, flags)
+e  = shutdown(fd, rd/wr/rdwr)
+e  = bind(fd, addr, addrlen)
+e  = listen(fd, backlog)
+e  = getsockname(fd, bound addr, addrlen)
+e  = getpeername(fd, peer addr, addrlen)
+e  = socketpair(family, type stream/dgram/..., sockets[2])
+e  = setsockopt(fd, level, optname, *optval, optlen)
+e  = getsockopt(fd, level, optname, *optval, *optlen)
+n  = recvmmsg(fd, *msgvec, vlen, flags, *timeout)
+n  = sendmmsg(fd, *msgvec, vlen, flags)
+*/
+
+#include <asm-generic/unistd.h>
+#include <sys/syscall.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/un.h>
+#include <linux/netlink.h>
+
+#include "../cooker.h"
+#include "../calls.h"
+
+static struct arg_num af[] = {
+	{ "unix",	AF_UNIX },
+	{ "ipv4",	AF_INET },
+	{ "ipv6",	AF_INET6 },
+	{ "netlink",	AF_NETLINK },
+	{ "packet",	AF_PACKET },
+	{ "vsock",	AF_VSOCK },
+	{ 0 },
+};
+
+static struct arg_num socket_types[] = {
+	{ "stream",	SOCK_STREAM },
+	{ "dgram",	SOCK_DGRAM },
+	{ "seq",	SOCK_SEQPACKET },
+	{ "raw",	SOCK_RAW },
+	{ "packet",	SOCK_PACKET },
+	{ 0 },
+};
+
+static struct arg_num socket_flags[] = {
+	{ "nonblock",	SOCK_NONBLOCK },
+	{ "cloexec",	SOCK_CLOEXEC },
+	{ 0 },
+};
+
+static struct arg_num protocols[] = {
+	{ "ip",		IPPROTO_IP },
+	{ "icmp",	IPPROTO_ICMP },
+	{ "igmp",	IPPROTO_IGMP },
+	{ "tcp",	IPPROTO_TCP },
+	{ "udp",	IPPROTO_UDP },
+	{ "ipv6",	IPPROTO_IPV6 },
+	{ "gre",	IPPROTO_GRE },
+	{ "esp",	IPPROTO_ESP },
+	{ "ah",		IPPROTO_AH },
+	{ "sctp",	IPPROTO_SCTP },
+	{ "udplite",	IPPROTO_UDPLITE },
+	{ "mpls",	IPPROTO_MPLS },
+	{ "raw",	IPPROTO_RAW },
+	{ "mptcp",	IPPROTO_MPTCP },
+	{ 0 },
+};
+
+static struct arg socket_args[] = {
+	{ 0, "family",		ARG_INT,	0, { .d_num = af } },
+	{ 1, "type",		ARG_INTMASK,	0, { .d_num = socket_types } },
+	{ 1, "flags",		ARG_INTFLAGS,	0, { .d_num = socket_flags } },
+	{ 2, "protocol",	ARG_INT,	0, { .d_num = protocols } },
+	{ 0 },
+};
+
+static struct arg_struct connect_addr_unix[] = {
+	{ "path",	ARG_STRING,
+		offsetof(struct sockaddr_un, sun_path),
+		UNIX_PATH_MAX,		{ 0 }
+	},
+	{ 0 },
+};
+
+static struct arg_struct connect_addr_ipv4[] = {
+	{ "port",	ARG_PORT,
+		offsetof(struct sockaddr_in, sin_port),
+		0,			{ 0 }
+	},
+	{ "addr",	ARG_IPV4,
+		offsetof(struct sockaddr_in, sin_addr),
+		0,			{ 0 }
+	},
+	{ 0 },
+};
+
+static struct arg_struct connect_addr_ipv6[] = {
+	{ "port",	ARG_PORT,
+		offsetof(struct sockaddr_in6, sin6_port),
+		0,			{ 0 }
+	},
+	{ "addr",	ARG_IPV6,
+		offsetof(struct sockaddr_in6, sin6_addr),
+		0,			{ 0 }
+	},
+	{ 0 },
+};
+
+static struct arg_struct connect_addr_nl[] = {
+	{ "pid",	ARG_PID,
+		offsetof(struct sockaddr_nl, nl_pid),
+		0,			{ 0 }
+	},
+	{ "groups",	ARG_U32,
+		offsetof(struct sockaddr_in6, sin6_addr),
+		0,			{ 0 }
+	},
+	{ 0 },
+};
+
+static struct arg_struct connect_family = {
+	"family",	ARG_INT,
+		offsetof(struct sockaddr, sa_family),
+		0,			{ .d_num = af }
+};
+
+static struct arg_select_num connect_addr_select_family[] = {
+	{ AF_UNIX,	ARG_STRUCT,	{ .d_struct = connect_addr_unix } },
+	{ AF_INET,	ARG_STRUCT,	{ .d_struct = connect_addr_ipv4 } },
+	{ AF_INET6,	ARG_STRUCT,	{ .d_struct = connect_addr_ipv6 } },
+	{ AF_NETLINK,	ARG_STRUCT,	{ .d_struct = connect_addr_nl } },
+	{ 0 },
+};
+
+static struct arg_select connect_addr_select = {
+	&connect_family, { .d_num = connect_addr_select_family }
+};
+
+static struct arg connect_args[] = {
+	{ 0, "fd",	ARG_INT,	0,
+		{ 0 },
+	},
+	{ 0, "path",	ARG_FDPATH,	0,
+		{ 0 },
+	},
+	{ 1, "addr",	ARG_SELECT,	sizeof(struct sockaddr_storage),
+		{ .d_select = &connect_addr_select },
+	},
+	{ 2, "addrlen",	ARG_LONG,	0,
+		{ 0 },
+	},
+};
+
+struct call syscalls_net[] = {
+	{ __NR_connect,		"connect",		connect_args },
+	{ __NR_socket,		"socket",		socket_args },
+	{ 0 },
+};
diff --git a/seitan-cooker/calls/net.h b/seitan-cooker/calls/net.h
new file mode 100644
index 0000000..105bf4a
--- /dev/null
+++ b/seitan-cooker/calls/net.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#ifndef CALLS_NET_H
+#define CALLS_NET_H
+
+extern struct call syscalls_net[];
+
+#endif /* CALLS_NET_H */
diff --git a/seitan-cooker/cooker.h b/seitan-cooker/cooker.h
new file mode 100644
index 0000000..53aa0db
--- /dev/null
+++ b/seitan-cooker/cooker.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#ifndef COOKER_H
+#define COOKER_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define REFS_MAX			256
+#define CALL_ARGS			6
+
+struct arg_num;
+struct arg_struct;
+struct arg_select;
+
+union arg_value {
+	struct arg_num		*d_num;
+	struct arg_struct	*d_struct;
+	struct arg_select	*d_select;
+};
+
+enum arg_type {
+	ARG_INT,
+	ARG_INTMASK,
+	ARG_INTFLAGS,
+
+	ARG_U32,
+	ARG_U32MASK,
+	ARG_U32FLAGS,
+
+	ARG_LONG,
+	ARG_LONGMASK,
+	ARG_LONGFLAGS,
+
+	ARG_STRING,
+
+	ARG_STRUCT,
+	ARG_SELECT,
+
+	ARG_PID,
+
+	ARG_PORT,
+	ARG_IPV4,
+	ARG_IPV6,
+
+	ARG_FDPATH,
+
+	ARG_TYPE_END,
+};
+
+#define ARG_TYPE_COUNT		(ARG_TYPE_END - 1)
+
+struct arg_num {
+	char *name;
+	long long value;
+};
+
+struct arg_struct {
+	char *name;
+	enum arg_type type;
+	size_t offset;
+
+	size_t strlen;
+
+	union arg_value desc;
+};
+
+struct arg_select_num {
+	long long value;
+
+	enum arg_type type;
+	union arg_value desc;
+};
+
+struct arg_select {
+	struct arg_struct *field;
+
+	union {
+		struct arg_select_num *d_num;
+	} desc;
+};
+
+struct arg {
+	int pos;
+	char *name;
+
+	enum arg_type type;
+	size_t size;
+
+	union arg_value desc;
+};
+
+#endif /* COOKER_H */
diff --git a/seitan-cooker/emit.c b/seitan-cooker/emit.c
new file mode 100644
index 0000000..a82529c
--- /dev/null
+++ b/seitan-cooker/emit.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
+ *
+ * cooker/emit.c - Generate gluten (bytecode) instructions
+ *
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#include "cooker.h"
+#include "gluten.h"
+#include "util.h"
+
+int emit_nr(struct gluten_ctx *g, long number)
+{
+	debug("   %i: OP_NR %li, < >", g->ip++, number);
+
+	return 0;
+}
+
+int emit_load(struct gluten_ctx *g, int offset, int index, size_t len)
+{
+	debug("   %i: OP_LOAD #%i < %i (%lu)", g->ip++, offset, index, len);
+
+	return 0;
+}
diff --git a/seitan-cooker/emit.h b/seitan-cooker/emit.h
new file mode 100644
index 0000000..74264b1
--- /dev/null
+++ b/seitan-cooker/emit.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#ifndef EMIT_H
+#define EMIT_H
+
+int emit_nr(struct gluten_ctx *g, long number);
+int emit_load(struct gluten_ctx *g, int offset, int index, size_t len);
+
+#endif /* EMIT_H */
diff --git a/seitan-cooker/example.hjson b/seitan-cooker/example.hjson
new file mode 100644
index 0000000..45ed339
--- /dev/null
+++ b/seitan-cooker/example.hjson
@@ -0,0 +1,67 @@
+[
+  {
+    "match": [ /* qemu-pr-helper and similar */
+      { "connect": { "addr": { "family": "unix", "path": "/var/run/pr-helper.sock" }, "fd": { "ref": "fd" } } }
+    ],
+    "call": { "connect": { "addr": { "family": "unix", "path": "/var/run/pr-helper.sock" }, "ret": "y" } },
+    "inject": { "what": "fd", "new": { "ref": "y" }, "old": { "ref": "fd" }, "return": 0 }
+  },
+  {
+    "match": [ /* qemu creates a tap interface */
+      { "ioctl": { "path": "/dev/net/tun", "request": "TUNSETIFF", "ifr": { "name": "tap0", "flags": "IFF_TUN" } } }
+    ],
+    "limit": { "scope": "process", "count": 1 },
+    "call": { "ioctl": { "request": "TUNSETIFF", "path": "/dev/net/tun", "ifr": { "name": "tap0", "flags": "IFF_TUN", "ret": "x" } } },
+    "return": { "ref": "x" }
+  },
+  {
+    "match": [ /* CVE-2022-0185-style */
+      { "unshare": { "flags": { "has": { "newuser": true, "newnet": false } } } }
+    ],
+    "block": { }
+  },
+  {
+    "match": [ /* passt */
+      { "unshare": { "flags": { "has": [ "ipc", "mount", "uts", "pid" ] } } }
+    ],
+    "block": { }
+  },
+  {
+    "match": [ /* Giuseppe's example */
+      { "mknod": { "path": { "ref": "path" }, "mode": "c", "major": 1, "minor": { "in": [ 3, 5, 7, 8, 9 ], "ref": "minor" } } }
+    ],
+    "context": { "userns": "init", "mountns": "caller" },
+    "call": { "mknod": { "path": { "ref": "path" }, "mode": "c", "major": 1, "minor": { "ref": "minor" }, "ret": "x" } },
+    "inject": { "what": "fd", "new": { "ref": "x" } },
+    "return": { "ref": "x" }
+  }
+]
+
+/*
+ * INTFLAGS, LONGFLAGS, U32FLAGS
+ *
+ * "field": { "in": [ "ipc", "mount", "uts" ] }
+ *   flags & set
+ *   !!(flags & (ipc | mount | ns))
+ *
+ * "field": { "all": [ "ipc", "mount", "uts" ] }
+ *   flags & set == set
+ *   flags & (ipc | mount | ns) == (ipc | mount | ns)
+ *
+ * "field": { "not": [ "ipc", "mount", "uts" ] }
+ *   !(flags & set)
+ *
+ * "field": { "ipc": false, "mount": true, "uts": false }
+ *   flags & set == set
+ *   !(flags & ipc) && (flags & mount) && !(flags & utc)
+ *
+ * "field": { "ipc" }
+ *   flags == ipc
+ *
+ * INTMASK
+ *   value = (target value & known values)
+ *
+ * INT, LONG, U32
+ *   "arg": { "in": [ 0, 1 ] }
+ *   arg == 0 || arg == 1
+ */
diff --git a/seitan-cooker/example.hjson.license b/seitan-cooker/example.hjson.license
new file mode 100644
index 0000000..2e3bd69
--- /dev/null
+++ b/seitan-cooker/example.hjson.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: 2023 Red Hat GmbH <sbrivio@redhat.com>
+SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/seitan-cooker/filter.c b/seitan-cooker/filter.c
new file mode 100644
index 0000000..dbda7ca
--- /dev/null
+++ b/seitan-cooker/filter.c
@@ -0,0 +1,299 @@
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "numbers.h"
+#include "filter.h"
+
+#define N_SYSCALL sizeof(numbers) / sizeof(numbers[0])
+
+static int compare_key(const void *key, const void *base)
+{
+	return strcmp((const char *)key,
+		      ((struct syscall_numbers *)base)->name);
+}
+
+int compare_bpf_call_names(const void *a, const void *b)
+{
+	return strcmp(((struct bpf_call *)a)->name,
+		      ((struct bpf_call *)b)->name);
+}
+
+static int compare_table_nr(const void *a, const void *b)
+{
+	return (((struct syscall_entry *)a)->nr -
+		((struct syscall_entry *)b)->nr);
+}
+
+static unsigned int count_shift_right(unsigned int n)
+{
+	unsigned int i = 0;
+	for (; n > 0; i++) {
+		n = n >> 1;
+	}
+	return i;
+}
+
+static void insert_pair(int jumps[], int arr[], unsigned int level)
+{
+	unsigned int i_a, i;
+	for (i = 0; i < level; i++) {
+		i_a = 2 * i + 1;
+		if (arr[i_a] == EMPTY) {
+			jumps[i] = arr[i_a - 1];
+		} else {
+			jumps[i] = arr[i_a];
+		}
+	}
+}
+
+unsigned int left_child(unsigned int parent_index)
+{
+	unsigned int level = count_shift_right(parent_index + 1);
+	/* 2^(level) -1 gives the beginning of the next interval */
+	unsigned int next_interval = (1 << level) - 1;
+	/* 2^(level -1) -1  gives the beginning of the current interval */
+	unsigned begin = (1 << (level - 1)) - 1;
+	unsigned i = parent_index - begin;
+	return next_interval + 2 * i;
+}
+
+unsigned int right_child(unsigned int parent_index)
+{
+	return left_child(parent_index) + 1;
+}
+
+void create_lookup_nodes(int jumps[], unsigned int n)
+{
+	unsigned int i, index;
+	unsigned int old_interval, interval;
+
+	for (i = 0; i < MAX_JUMPS; i++)
+		jumps[i] = EMPTY;
+
+	if (n < 2) {
+		jumps[0] = 0;
+		return;
+	}
+	old_interval = 1 << count_shift_right(n - 1);
+	interval = old_interval >> 1;
+
+	/* first scan populate the last level of jumps */
+	for (i = interval - 1, index = 1; index < old_interval && index < n;
+	     i++, index += 2) {
+		jumps[i] = index;
+	}
+	if (n % 2 == 1) {
+		jumps[i] = index - 1;
+	}
+	for (old_interval = interval, interval = interval / 2; interval > 0;
+	     old_interval = interval, interval = interval / 2) {
+		insert_pair(&jumps[interval - 1], &jumps[old_interval - 1],
+			    interval);
+	}
+}
+
+long resolve_syscall_nr(const char *name)
+{
+	struct syscall_numbers *p;
+	p = (struct syscall_numbers *)bsearch(
+		name, numbers, sizeof(numbers) / sizeof(numbers[0]),
+		sizeof(numbers[0]), compare_key);
+	if (p == NULL)
+		return -1;
+	return p->number;
+}
+
+/*
+ * Construct a syscall tables ordered by increasing syscall number
+ * @returns number of syscall entries in the table
+ */
+int construct_table(const struct bpf_call *entries, int n,
+		    struct syscall_entry *table)
+{
+	long nr;
+	unsigned int tn;
+	int i;
+
+	tn = 0;
+	for (i = 0; i < n; i++) {
+		table[i].count = 0;
+		table[i].entry = NULL;
+	}
+
+	for (i = 0; i < n; i++) {
+		if (tn > N_SYSCALL - 1)
+			return -1;
+		if (i > 0) {
+			if (strcmp((entries[i]).name, (entries[i - 1]).name) ==
+			    0) {
+				table[tn - 1].count++;
+				continue;
+			}
+		}
+		nr = resolve_syscall_nr((entries[i]).name);
+		if (nr < 0) {
+			fprintf(stderr, "wrong syscall number for %s\n",
+				(entries[i]).name);
+			continue;
+		}
+		table[tn].entry = &entries[i];
+		table[tn].count++;
+		table[tn].nr = nr;
+		tn++;
+	}
+	qsort(table, tn, sizeof(struct syscall_entry), compare_table_nr);
+
+	return tn;
+}
+
+static unsigned get_n_args(const struct syscall_entry *table)
+{
+	unsigned i, k, n;
+	n = 0;
+	for (i = 0; i < table->count; i++)
+		for (k = 0; k < 6; k++)
+			if ((table->entry + i)->check_arg[k])
+				n++;
+	return n;
+}
+
+static unsigned int get_total_args(const struct syscall_entry table[],
+				   unsigned int n_syscall)
+{
+	unsigned int i, n;
+	n = 0;
+	for (i = 0; i < n_syscall; i++) {
+		n += get_n_args(&table[i]);
+	}
+	return n;
+}
+
+unsigned int create_bpf_program_log(struct sock_filter filter[])
+{
+	filter[0] = (struct sock_filter)BPF_STMT(
+		BPF_LD | BPF_W | BPF_ABS,
+		(offsetof(struct seccomp_data, arch)));
+	filter[1] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,
+						 SEITAN_AUDIT_ARCH, 0, 1);
+	filter[2] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K,
+						 SECCOMP_RET_USER_NOTIF);
+	filter[3] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K,
+						 SECCOMP_RET_ALLOW);
+	return 4;
+}
+
+unsigned int create_bfp_program(struct syscall_entry table[],
+				struct sock_filter filter[],
+				unsigned int n_syscall)
+{
+	unsigned int offset_left, offset_right;
+	unsigned int n_args, n_nodes;
+	unsigned int notify, accept;
+	unsigned int i, j, k, size;
+	unsigned int next_offset;
+	int nodes[MAX_JUMPS];
+
+	create_lookup_nodes(nodes, n_syscall);
+
+	size = 3;
+	/* No nodes if there is a single syscall */
+	n_nodes = (1 << count_shift_right(n_syscall - 1)) - 1;
+
+	n_args = get_total_args(table, n_syscall);
+
+	accept = 2 + n_nodes + 2 * n_syscall + n_args + 1;
+	notify = 2 + n_nodes + 2 * n_syscall + n_args + 2;
+
+	/* Pre */
+	/* cppcheck-suppress badBitmaskCheck */
+	filter[0] = (struct sock_filter)BPF_STMT(
+		BPF_LD | BPF_W | BPF_ABS,
+		(offsetof(struct seccomp_data, arch)));
+	filter[1] = (struct sock_filter)BPF_JUMP(
+		BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 0, accept - 2);
+	/* cppcheck-suppress badBitmaskCheck */
+	filter[2] = (struct sock_filter)BPF_STMT(
+		BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr)));
+
+	/* Insert nodes */
+	for (i = 0; i < n_nodes; i++) {
+		if (nodes[i] == EMPTY) {
+			filter[size++] =
+				(struct sock_filter)JUMPA(accept - size);
+		} else {
+			offset_left = left_child(i) - i - 1;
+			offset_right = right_child(i) - i - 1;
+			filter[size++] = (struct sock_filter)JGE(
+				table[nodes[i]].nr, offset_right, offset_left);
+		}
+	}
+
+	next_offset = n_syscall - 1;
+	/* Insert leaves */
+	for (i = 0; i < n_syscall; i++) {
+		filter[size++] = (struct sock_filter)EQ(
+			table[i].nr, next_offset, accept - size);
+		next_offset += get_n_args(&table[i]);
+	}
+
+	/*
+	 * Insert args. Evaluate every args, if it doesn't match continue with
+	 * the following, otherwise notify.
+	 */
+	for (i = 0; i < n_syscall; i++) {
+		for (j = 0; j < (table[i]).count; j++) {
+			for (k = 0; k < 6; k++)
+				if ((table[i].entry + j)->check_arg[k]) {
+					filter[size++] = (struct sock_filter)EQ(
+						(table[i].entry + j)->args[k],
+						notify - size, 0);
+				}
+		}
+		filter[size++] = (struct sock_filter)JUMPA(accept - size);
+	}
+
+	/* Seccomp accept and notify instruction */
+	filter[size++] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K,
+						      SECCOMP_RET_ALLOW);
+	filter[size++] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K,
+						      SECCOMP_RET_USER_NOTIF);
+	return size;
+}
+
+static int compare_names(const void *a, const void *b)
+{
+	return strcmp(((struct syscall_numbers *)a)->name,
+		      ((struct syscall_numbers *)b)->name);
+}
+
+int convert_bpf(char *file, struct bpf_call *entries, int n, bool log)
+{
+	int nt, fd, fsize;
+	struct syscall_entry table[N_SYSCALL];
+	struct sock_filter filter[MAX_FILTER];
+
+	qsort(numbers, sizeof(numbers) / sizeof(numbers[0]), sizeof(numbers[0]),
+	      compare_names);
+
+	qsort(entries, n, sizeof(struct bpf_call), compare_bpf_call_names);
+	nt = construct_table(entries, n, table);
+
+	if (log)
+		fsize = create_bpf_program_log(filter);
+	else
+		fsize = create_bfp_program(table, filter, nt);
+
+	fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
+		  S_IRUSR | S_IWUSR);
+	write(fd, filter, sizeof(struct sock_filter) * fsize);
+
+	close(fd);
+
+	return 0;
+}
diff --git a/seitan-cooker/filter.h b/seitan-cooker/filter.h
new file mode 100644
index 0000000..ee5ab12
--- /dev/null
+++ b/seitan-cooker/filter.h
@@ -0,0 +1,39 @@
+#ifndef FILTER_H_
+#define FILTER_H_
+
+#include <linux/filter.h>
+#include <linux/audit.h>
+#include <linux/seccomp.h>
+
+#define JGE(nr, right, left) \
+	BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, (nr), (right), (left))
+#define JUMPA(jump) BPF_JUMP(BPF_JMP | BPF_JA, (jump), 0, 0)
+#define EQ(nr, a1, a2) BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (nr), (a1), (a2))
+
+#define MAX_FILTER 1024
+
+#define MAX_JUMPS 128
+#define EMPTY -1
+
+struct bpf_call {
+	char *name;
+	int args[6];
+	bool check_arg[6];
+};
+
+struct syscall_entry {
+	unsigned int count;
+	long nr;
+	const struct bpf_call *entry;
+};
+
+void create_lookup_nodes(int jumps[], unsigned int n);
+unsigned int left_child(unsigned int parent_index);
+unsigned int right_child(unsigned int parent_index);
+
+unsigned int create_bfp_program(struct syscall_entry table[],
+				struct sock_filter filter[],
+				unsigned int n_syscall);
+int convert_bpf(char *file, struct bpf_call *entries, int n, bool log);
+
+#endif
diff --git a/seitan-cooker/gluten.c b/seitan-cooker/gluten.c
new file mode 100644
index 0000000..1116e6b
--- /dev/null
+++ b/seitan-cooker/gluten.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
+ *
+ * cooker/gluten.c - gluten (bytecode) file and layout functions
+ *
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#include "cooker.h"
+#include "gluten.h"
+#include "util.h"
+
+#define GLUTEN_INST_SIZE		BUFSIZ
+#define GLUTEN_DATA_SIZE		BUFSIZ
+
+static char gluten[GLUTEN_INST_SIZE + GLUTEN_DATA_SIZE];
+
+static size_t gluten_arg_storage[ARG_TYPE_COUNT] = {
+	[ARG_INT]	= sizeof(int),
+	[ARG_INTMASK]	= sizeof(int),
+};
+
+int gluten_alloc(struct gluten_ctx *g, size_t size)
+{
+	debug("   allocating %lu at offset %i", size, g->sp);
+	if ((g->sp += size) >= GLUTEN_DATA_SIZE)
+		die("Temporary data size exceeded");
+
+	return g->sp - size;
+}
+
+int gluten_alloc_type(struct gluten_ctx *g, enum arg_type type)
+{
+	return gluten_alloc(g, gluten_arg_storage[type]);
+}
+
+int gluten_init(struct gluten_ctx *g)
+{
+	g->gluten = gluten;
+
+	return 0;
+}
diff --git a/seitan-cooker/gluten.h b/seitan-cooker/gluten.h
new file mode 100644
index 0000000..440029d
--- /dev/null
+++ b/seitan-cooker/gluten.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#ifndef GLUTEN_H
+#define GLUTEN_H
+
+struct gluten_arg_data {
+	int offset;
+	size_t len;
+};
+
+struct gluten_ref_data {
+	int name;
+	int offset;
+	size_t len;
+};
+
+struct gluten_ctx {
+	int ip;
+	int lr;
+	int sp;
+	char *gluten;
+
+	struct gluten_arg_data match_dst[CALL_ARGS];
+	struct gluten_arg_data call_src[CALL_ARGS];
+
+	struct gluten_ref_data refs[REFS_MAX];
+};
+
+int gluten_alloc(struct gluten_ctx *g, size_t size);
+int gluten_alloc_type(struct gluten_ctx *g, enum arg_type type);
+int gluten_init(struct gluten_ctx *g);
+
+#endif /* GLUTEN_H */
diff --git a/seitan-cooker/main.c b/seitan-cooker/main.c
new file mode 100644
index 0000000..9965cff
--- /dev/null
+++ b/seitan-cooker/main.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
+ *
+ * cooker/main.c - Entry point of seitan-cooker, the gluten (bytecode) generator
+ *
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#include "cooker.h"
+#include "gluten.h"
+#include "parse.h"
+
+int main(int argc, char **argv)
+{
+	struct gluten_ctx g = { 0 };
+
+	/* TODO: Options and usage */
+	(void)argc;
+	(void)argv;
+
+	gluten_init(&g);
+
+	parse_file(&g, argv[1]);
+
+	return 0;
+}
diff --git a/seitan-cooker/parse.c b/seitan-cooker/parse.c
new file mode 100644
index 0000000..9d8a7be
--- /dev/null
+++ b/seitan-cooker/parse.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
+ *
+ * cooker/parse.c - JSON recipe parsing
+ *
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#include "parson.h"
+#include "calls.h"
+#include "cooker.h"
+#include "gluten.h"
+#include "emit.h"
+#include "util.h"
+
+#include "calls/net.h"
+
+struct rule_parser {
+	const char *type;
+	int (*fn)(struct gluten_ctx *g, JSON_Value *value);
+};
+
+static int parse_match_load(struct gluten_ctx *g, struct arg *a)
+{
+	if (!a->size || g->match_dst[a->pos].len)
+		return 0;
+
+	g->match_dst[a->pos].offset = gluten_alloc(g, a->size);
+	g->match_dst[a->pos].len = a->size;
+
+	emit_load(g, g->match_dst[a->pos].offset, a->pos, a->size);
+
+	return 0;
+}
+
+static long long parse_match_expr_num(struct arg_num *desc, JSON_Value *value)
+{
+	const char *s = NULL;
+	long long n;
+
+	if (desc) {
+		s = json_value_get_string(value);
+		for (; desc->name && s && strcmp(s, desc->name); desc++);
+		if (s && !desc->name)
+			die("   Invalid value %s", s);
+
+		n = desc->value;
+	}
+
+	if (!s) {
+		if (json_value_get_type(value) != JSONNumber)
+			die("   Invalid value type");
+
+		n = json_value_get_number(value);
+	}
+
+	return n;
+}
+
+static int parse_match_key(struct gluten_ctx *g, int index, enum arg_type type,
+			   union arg_value desc, JSON_Value *value)
+{
+	JSON_Object *tmp;
+	const char *ref;
+
+	(void)index;
+
+	if (json_value_get_type(value) == JSONObject &&
+	    (tmp = json_value_get_object(value)) &&
+	    (ref = json_object_get_string(tmp, "ref"))) {
+		debug("   setting reference '%s'", ref);
+		gluten_alloc_type(g, type);
+		value = json_object_get_value(tmp, "value");
+	}
+
+	if (!value)
+		return 0;
+
+	switch (type) {
+	case ARG_INTFLAGS:
+	case ARG_LONGFLAGS:
+	case ARG_U32FLAGS:
+		/* fetch/combine expr algebra loop */
+	case ARG_INTMASK:
+		/* calculate mask first */
+	case ARG_INT:
+	case ARG_LONG:
+	case ARG_U32:
+		parse_match_expr_num(desc.d_num, value);
+		//emit_cmp(...);
+	default:
+		;
+	}
+
+	return 0;
+}
+
+static int parse_match_arg(struct gluten_ctx *g, const char *name,
+			   JSON_Value *value, struct arg *a)
+{
+	debug("  Parsing match argument %s", name);
+
+	parse_match_load(g, a);
+	parse_match_key(g, a->pos, a->type, a->desc, value);
+
+	return 0;
+}
+
+static int parse_match(struct gluten_ctx *g, JSON_Object *obj, struct arg *args)
+{
+	unsigned count = 0;
+	struct arg *a;
+
+	for (a = args; a->name; a++) {
+		JSON_Value *value;
+
+		if ((value = json_object_get_value(obj, a->name))) {
+			count++;
+			parse_match_arg(g, a->name, value, a);
+		}
+	}
+
+	if (count != json_object_get_count(obj))
+		die("  Stray elements in match");
+
+	return 0;
+}
+
+static int parse_matches(struct gluten_ctx *g, JSON_Value *value)
+{
+	JSON_Array *matches = json_value_get_array(value);
+	unsigned i;
+
+	for (i = 0; i < json_array_get_count(matches); i++) {
+		JSON_Object *match, *args;
+		struct call **set, *call;
+		const char *name;
+
+		g->lr = g->ip;
+		g->sp = 0;
+
+		match = json_array_get_object(matches, i);
+		name = json_object_get_name(match, 0);
+		args = json_object_get_object(match, name);
+		debug(" Parsing match %i: %s", i, name);
+
+		for (set = call_sets, call = set[0]; *set; call++) {
+			if (!call->name) {
+				set++;
+				continue;
+			}
+
+			if (!strcmp(name, call->name)) {
+				debug("  Found handler for %s", name);
+				emit_nr(g, call->number);
+
+				parse_match(g, args, call->args);
+				break;
+			}
+		}
+
+		if (!*set)
+			die("  Unknown system call: %s", name);
+	}
+
+	return 0;
+}
+
+static int parse_call(struct gluten_ctx *g, JSON_Value *value)
+{
+	(void)g;
+	(void)value;
+	return 0;
+}
+
+static int parse_inject(struct gluten_ctx *g, JSON_Value *value)
+{
+	(void)g;
+	(void)value;
+	return 0;
+}
+
+struct rule_parser parsers[] = {
+	{ "match", parse_matches },
+	{ "call", parse_call },
+	{ "inject", parse_inject },
+	{ NULL, NULL },
+};
+
+static int parse_block(struct gluten_ctx *g, JSON_Object *block)
+{
+	unsigned i;
+
+	for (i = 0; i < json_object_get_count(block); i++) {
+		struct rule_parser *parser;
+		JSON_Value *rule;
+		const char *type;
+
+		type = json_object_get_name(block, i);
+		rule = json_object_get_value(block, type);
+
+		for (parser = parsers; parser->type; parser++) {
+			if (!strcmp(type, parser->type)) {
+				parser->fn(g, rule);
+				break;
+			}
+		}
+
+		if (!parser->type)
+			die(" Invalid rule type: \"%s\"", type);
+	}
+
+	return 0;
+}
+
+int parse_file(struct gluten_ctx *g, const char *path)
+{
+	JSON_Array *blocks;
+	JSON_Value *root;
+	JSON_Object *obj;
+	unsigned i;
+
+	root = json_parse_file_with_comments(path);
+	if (json_value_get_type(root) != JSONArray)
+		die("Invalid input file %s", path);
+
+	blocks = json_value_get_array(root);
+	for (i = 0; i < json_array_get_count(blocks); i++) {
+		obj = json_array_get_object(blocks, i);
+		debug("Parsing block %i", i);
+		parse_block(g, obj);
+	}
+
+	return 0;
+}
diff --git a/seitan-cooker/parse.h b/seitan-cooker/parse.h
new file mode 100644
index 0000000..cb4a2f2
--- /dev/null
+++ b/seitan-cooker/parse.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#ifndef PARSE_H
+#define PARSE_H
+
+int parse_file(struct gluten_ctx *g, const char *path);
+
+#endif /* PARSE_H */
diff --git a/seitan-cooker/parson.c b/seitan-cooker/parson.c
new file mode 100644
index 0000000..a7a844a
--- /dev/null
+++ b/seitan-cooker/parson.c
@@ -0,0 +1,2080 @@
+/*
+ SPDX-License-Identifier: MIT
+
+ Parson ( http://kgabis.github.com/parson/ )
+ Copyright (c) 2012 - 2019 Krzysztof Gabis
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+#ifdef _MSC_VER
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif /* _CRT_SECURE_NO_WARNINGS */
+#endif /* _MSC_VER */
+
+#include "parson.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <errno.h>
+
+/* Apparently sscanf is not implemented in some "standard" libraries, so don't use it, if you
+ * don't have to. */
+#define sscanf THINK_TWICE_ABOUT_USING_SSCANF
+
+#define STARTING_CAPACITY 16
+#define MAX_NESTING       2048
+
+#define FLOAT_FORMAT "%1.17g" /* do not increase precision without incresing NUM_BUF_SIZE */
+#define NUM_BUF_SIZE 64 /* double printed with "%1.17g" shouldn't be longer than 25 bytes so let's be paranoid and use 64 */
+
+#define SIZEOF_TOKEN(a)       (sizeof(a) - 1)
+#define SKIP_CHAR(str)        ((*str)++)
+#define SKIP_WHITESPACES(str) while (isspace((unsigned char)(**str))) { SKIP_CHAR(str); }
+#define MAX(a, b)             ((a) > (b) ? (a) : (b))
+
+#undef malloc
+#undef free
+
+#if defined(isnan) && defined(isinf)
+#define IS_NUMBER_INVALID(x) (isnan((x)) || isinf((x)))
+#else
+#define IS_NUMBER_INVALID(x) (((x) * 0.0) != 0.0)
+#endif
+
+static JSON_Malloc_Function parson_malloc = malloc;
+static JSON_Free_Function parson_free = free;
+
+static int parson_escape_slashes = 1;
+
+#define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */
+
+/* Type definitions */
+typedef union json_value_value {
+    char        *string;
+    double       number;
+    JSON_Object *object;
+    JSON_Array  *array;
+    int          boolean;
+    int          null;
+} JSON_Value_Value;
+
+struct json_value_t {
+    JSON_Value      *parent;
+    JSON_Value_Type  type;
+    JSON_Value_Value value;
+};
+
+struct json_object_t {
+    JSON_Value  *wrapping_value;
+    char       **names;
+    JSON_Value **values;
+    size_t       count;
+    size_t       capacity;
+};
+
+struct json_array_t {
+    JSON_Value  *wrapping_value;
+    JSON_Value **items;
+    size_t       count;
+    size_t       capacity;
+};
+
+/* Various */
+static char * read_file(const char *filename);
+static void   remove_comments(char *string, const char *start_token, const char *end_token);
+static char * parson_strndup(const char *string, size_t n);
+static char * parson_strdup(const char *string);
+static int    hex_char_to_int(char c);
+static int    parse_utf16_hex(const char *string, unsigned int *result);
+static int    num_bytes_in_utf8_sequence(unsigned char c);
+static int    verify_utf8_sequence(const unsigned char *string, int *len);
+static int    is_valid_utf8(const char *string, size_t string_len);
+static int    is_decimal(const char *string, size_t length);
+
+/* JSON Object */
+static JSON_Object * json_object_init(JSON_Value *wrapping_value);
+static JSON_Status   json_object_add(JSON_Object *object, const char *name, JSON_Value *value);
+static JSON_Status   json_object_addn(JSON_Object *object, const char *name, size_t name_len, JSON_Value *value);
+static JSON_Status   json_object_resize(JSON_Object *object, size_t new_capacity);
+static JSON_Value  * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len);
+static JSON_Status   json_object_remove_internal(JSON_Object *object, const char *name, int free_value);
+static JSON_Status   json_object_dotremove_internal(JSON_Object *object, const char *name, int free_value);
+static void          json_object_free(JSON_Object *object);
+
+/* JSON Array */
+static JSON_Array * json_array_init(JSON_Value *wrapping_value);
+static JSON_Status  json_array_add(JSON_Array *array, JSON_Value *value);
+static JSON_Status  json_array_resize(JSON_Array *array, size_t new_capacity);
+static void         json_array_free(JSON_Array *array);
+
+/* JSON Value */
+static JSON_Value * json_value_init_string_no_copy(char *string);
+
+/* Parser */
+static JSON_Status  skip_quotes(const char **string);
+static int          parse_utf16(const char **unprocessed, char **processed);
+static char *       process_string(const char *input, size_t len);
+static char *       get_quoted_string(const char **string);
+static JSON_Value * parse_object_value(const char **string, size_t nesting);
+static JSON_Value * parse_array_value(const char **string, size_t nesting);
+static JSON_Value * parse_string_value(const char **string);
+static JSON_Value * parse_boolean_value(const char **string);
+static JSON_Value * parse_number_value(const char **string);
+static JSON_Value * parse_null_value(const char **string);
+static JSON_Value * parse_value(const char **string, size_t nesting);
+
+/* Serialization */
+static int    json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf);
+static int    json_serialize_string(const char *string, char *buf);
+static int    append_indent(char *buf, int level);
+static int    append_string(char *buf, const char *string);
+
+/* Various */
+static char * parson_strndup(const char *string, size_t n) {
+    char *output_string = (char*)parson_malloc(n + 1);
+    if (!output_string) {
+        return NULL;
+    }
+    output_string[n] = '\0';
+    strncpy(output_string, string, n);
+    return output_string;
+}
+
+static char * parson_strdup(const char *string) {
+    return parson_strndup(string, strlen(string));
+}
+
+static int hex_char_to_int(char c) {
+    if (c >= '0' && c <= '9') {
+        return c - '0';
+    } else if (c >= 'a' && c <= 'f') {
+        return c - 'a' + 10;
+    } else if (c >= 'A' && c <= 'F') {
+        return c - 'A' + 10;
+    }
+    return -1;
+}
+
+static int parse_utf16_hex(const char *s, unsigned int *result) {
+    int x1, x2, x3, x4;
+    if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0' || s[3] == '\0') {
+        return 0;
+    }
+    x1 = hex_char_to_int(s[0]);
+    x2 = hex_char_to_int(s[1]);
+    x3 = hex_char_to_int(s[2]);
+    x4 = hex_char_to_int(s[3]);
+    if (x1 == -1 || x2 == -1 || x3 == -1 || x4 == -1) {
+        return 0;
+    }
+    *result = (unsigned int)((x1 << 12) | (x2 << 8) | (x3 << 4) | x4);
+    return 1;
+}
+
+static int num_bytes_in_utf8_sequence(unsigned char c) {
+    if (c == 0xC0 || c == 0xC1 || c > 0xF4 || IS_CONT(c)) {
+        return 0;
+    } else if ((c & 0x80) == 0) {    /* 0xxxxxxx */
+        return 1;
+    } else if ((c & 0xE0) == 0xC0) { /* 110xxxxx */
+        return 2;
+    } else if ((c & 0xF0) == 0xE0) { /* 1110xxxx */
+        return 3;
+    } else if ((c & 0xF8) == 0xF0) { /* 11110xxx */
+        return 4;
+    }
+    return 0; /* won't happen */
+}
+
+static int verify_utf8_sequence(const unsigned char *string, int *len) {
+    unsigned int cp = 0;
+    *len = num_bytes_in_utf8_sequence(string[0]);
+
+    if (*len == 1) {
+        cp = string[0];
+    } else if (*len == 2 && IS_CONT(string[1])) {
+        cp = string[0] & 0x1F;
+        cp = (cp << 6) | (string[1] & 0x3F);
+    } else if (*len == 3 && IS_CONT(string[1]) && IS_CONT(string[2])) {
+        cp = ((unsigned char)string[0]) & 0xF;
+        cp = (cp << 6) | (string[1] & 0x3F);
+        cp = (cp << 6) | (string[2] & 0x3F);
+    } else if (*len == 4 && IS_CONT(string[1]) && IS_CONT(string[2]) && IS_CONT(string[3])) {
+        cp = string[0] & 0x7;
+        cp = (cp << 6) | (string[1] & 0x3F);
+        cp = (cp << 6) | (string[2] & 0x3F);
+        cp = (cp << 6) | (string[3] & 0x3F);
+    } else {
+        return 0;
+    }
+
+    /* overlong encodings */
+    if ((cp < 0x80    && *len > 1) ||
+        (cp < 0x800   && *len > 2) ||
+        (cp < 0x10000 && *len > 3)) {
+        return 0;
+    }
+
+    /* invalid unicode */
+    if (cp > 0x10FFFF) {
+        return 0;
+    }
+
+    /* surrogate halves */
+    if (cp >= 0xD800 && cp <= 0xDFFF) {
+        return 0;
+    }
+
+    return 1;
+}
+
+static int is_valid_utf8(const char *string, size_t string_len) {
+    int len = 0;
+    const char *string_end =  string + string_len;
+    while (string < string_end) {
+        if (!verify_utf8_sequence((const unsigned char*)string, &len)) {
+            return 0;
+        }
+        string += len;
+    }
+    return 1;
+}
+
+static int is_decimal(const char *string, size_t length) {
+    if (length > 1 && string[0] == '0' && string[1] != '.') {
+        return 0;
+    }
+    if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') {
+        return 0;
+    }
+    while (length--) {
+        if (strchr("xX", string[length])) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static char * read_file(const char * filename) {
+    FILE *fp = fopen(filename, "r");
+    size_t size_to_read = 0;
+    size_t size_read = 0;
+    long pos;
+    char *file_contents;
+    if (!fp) {
+        return NULL;
+    }
+    fseek(fp, 0L, SEEK_END);
+    pos = ftell(fp);
+    if (pos < 0) {
+        fclose(fp);
+        return NULL;
+    }
+    size_to_read = pos;
+    rewind(fp);
+    file_contents = (char*)parson_malloc(sizeof(char) * (size_to_read + 1));
+    if (!file_contents) {
+        fclose(fp);
+        return NULL;
+    }
+    size_read = fread(file_contents, 1, size_to_read, fp);
+    if (size_read == 0 || ferror(fp)) {
+        fclose(fp);
+        parson_free(file_contents);
+        return NULL;
+    }
+    fclose(fp);
+    file_contents[size_read] = '\0';
+    return file_contents;
+}
+
+static void remove_comments(char *string, const char *start_token, const char *end_token) {
+    int in_string = 0, escaped = 0;
+    size_t i;
+    char *ptr = NULL, current_char;
+    size_t start_token_len = strlen(start_token);
+    size_t end_token_len = strlen(end_token);
+    if (start_token_len == 0 || end_token_len == 0) {
+        return;
+    }
+    while ((current_char = *string) != '\0') {
+        if (current_char == '\\' && !escaped) {
+            escaped = 1;
+            string++;
+            continue;
+        } else if (current_char == '\"' && !escaped) {
+            in_string = !in_string;
+        } else if (!in_string && strncmp(string, start_token, start_token_len) == 0) {
+            for(i = 0; i < start_token_len; i++) {
+                string[i] = ' ';
+            }
+            string = string + start_token_len;
+            ptr = strstr(string, end_token);
+            if (!ptr) {
+                return;
+            }
+            for (i = 0; i < (ptr - string) + end_token_len; i++) {
+                string[i] = ' ';
+            }
+            string = ptr + end_token_len - 1;
+        }
+        escaped = 0;
+        string++;
+    }
+}
+
+/* JSON Object */
+static JSON_Object * json_object_init(JSON_Value *wrapping_value) {
+    JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object));
+    if (new_obj == NULL) {
+        return NULL;
+    }
+    new_obj->wrapping_value = wrapping_value;
+    new_obj->names = (char**)NULL;
+    new_obj->values = (JSON_Value**)NULL;
+    new_obj->capacity = 0;
+    new_obj->count = 0;
+    return new_obj;
+}
+
+static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value) {
+    if (name == NULL) {
+        return JSONFailure;
+    }
+    return json_object_addn(object, name, strlen(name), value);
+}
+
+static JSON_Status json_object_addn(JSON_Object *object, const char *name, size_t name_len, JSON_Value *value) {
+    size_t index = 0;
+    if (object == NULL || name == NULL || value == NULL) {
+        return JSONFailure;
+    }
+    if (json_object_getn_value(object, name, name_len) != NULL) {
+        return JSONFailure;
+    }
+    if (object->count >= object->capacity) {
+        size_t new_capacity = MAX(object->capacity * 2, STARTING_CAPACITY);
+        if (json_object_resize(object, new_capacity) == JSONFailure) {
+            return JSONFailure;
+        }
+    }
+    index = object->count;
+    object->names[index] = parson_strndup(name, name_len);
+    if (object->names[index] == NULL) {
+        return JSONFailure;
+    }
+    value->parent = json_object_get_wrapping_value(object);
+    object->values[index] = value;
+    object->count++;
+    return JSONSuccess;
+}
+
+static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity) {
+    char **temp_names = NULL;
+    JSON_Value **temp_values = NULL;
+
+    if ((object->names == NULL && object->values != NULL) ||
+        (object->names != NULL && object->values == NULL) ||
+        new_capacity == 0) {
+            return JSONFailure; /* Shouldn't happen */
+    }
+    temp_names = (char**)parson_malloc(new_capacity * sizeof(char*));
+    if (temp_names == NULL) {
+        return JSONFailure;
+    }
+    temp_values = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*));
+    if (temp_values == NULL) {
+        parson_free(temp_names);
+        return JSONFailure;
+    }
+    if (object->names != NULL && object->values != NULL && object->count > 0) {
+        memcpy(temp_names, object->names, object->count * sizeof(char*));
+        memcpy(temp_values, object->values, object->count * sizeof(JSON_Value*));
+    }
+    parson_free(object->names);
+    parson_free(object->values);
+    object->names = temp_names;
+    object->values = temp_values;
+    object->capacity = new_capacity;
+    return JSONSuccess;
+}
+
+static JSON_Value * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len) {
+    size_t i, name_length;
+    for (i = 0; i < json_object_get_count(object); i++) {
+        name_length = strlen(object->names[i]);
+        if (name_length != name_len) {
+            continue;
+        }
+        if (strncmp(object->names[i], name, name_len) == 0) {
+            return object->values[i];
+        }
+    }
+    return NULL;
+}
+
+static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, int free_value) {
+    size_t i = 0, last_item_index = 0;
+    if (object == NULL || json_object_get_value(object, name) == NULL) {
+        return JSONFailure;
+    }
+    last_item_index = json_object_get_count(object) - 1;
+    for (i = 0; i < json_object_get_count(object); i++) {
+        if (strcmp(object->names[i], name) == 0) {
+            parson_free(object->names[i]);
+            if (free_value) {
+                json_value_free(object->values[i]);
+            }
+            if (i != last_item_index) { /* Replace key value pair with one from the end */
+                object->names[i] = object->names[last_item_index];
+                object->values[i] = object->values[last_item_index];
+            }
+            object->count -= 1;
+            return JSONSuccess;
+        }
+    }
+    return JSONFailure; /* No execution path should end here */
+}
+
+static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, int free_value) {
+    JSON_Value *temp_value = NULL;
+    JSON_Object *temp_object = NULL;
+    const char *dot_pos = strchr(name, '.');
+    if (dot_pos == NULL) {
+        return json_object_remove_internal(object, name, free_value);
+    }
+    temp_value = json_object_getn_value(object, name, dot_pos - name);
+    if (json_value_get_type(temp_value) != JSONObject) {
+        return JSONFailure;
+    }
+    temp_object = json_value_get_object(temp_value);
+    return json_object_dotremove_internal(temp_object, dot_pos + 1, free_value);
+}
+
+static void json_object_free(JSON_Object *object) {
+    size_t i;
+    for (i = 0; i < object->count; i++) {
+        parson_free(object->names[i]);
+        json_value_free(object->values[i]);
+    }
+    parson_free(object->names);
+    parson_free(object->values);
+    parson_free(object);
+}
+
+/* JSON Array */
+static JSON_Array * json_array_init(JSON_Value *wrapping_value) {
+    JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array));
+    if (new_array == NULL) {
+        return NULL;
+    }
+    new_array->wrapping_value = wrapping_value;
+    new_array->items = (JSON_Value**)NULL;
+    new_array->capacity = 0;
+    new_array->count = 0;
+    return new_array;
+}
+
+static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value) {
+    if (array->count >= array->capacity) {
+        size_t new_capacity = MAX(array->capacity * 2, STARTING_CAPACITY);
+        if (json_array_resize(array, new_capacity) == JSONFailure) {
+            return JSONFailure;
+        }
+    }
+    value->parent = json_array_get_wrapping_value(array);
+    array->items[array->count] = value;
+    array->count++;
+    return JSONSuccess;
+}
+
+static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity) {
+    JSON_Value **new_items = NULL;
+    if (new_capacity == 0) {
+        return JSONFailure;
+    }
+    new_items = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*));
+    if (new_items == NULL) {
+        return JSONFailure;
+    }
+    if (array->items != NULL && array->count > 0) {
+        memcpy(new_items, array->items, array->count * sizeof(JSON_Value*));
+    }
+    parson_free(array->items);
+    array->items = new_items;
+    array->capacity = new_capacity;
+    return JSONSuccess;
+}
+
+static void json_array_free(JSON_Array *array) {
+    size_t i;
+    for (i = 0; i < array->count; i++) {
+        json_value_free(array->items[i]);
+    }
+    parson_free(array->items);
+    parson_free(array);
+}
+
+/* JSON Value */
+static JSON_Value * json_value_init_string_no_copy(char *string) {
+    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+    if (!new_value) {
+        return NULL;
+    }
+    new_value->parent = NULL;
+    new_value->type = JSONString;
+    new_value->value.string = string;
+    return new_value;
+}
+
+/* Parser */
+static JSON_Status skip_quotes(const char **string) {
+    if (**string != '\"') {
+        return JSONFailure;
+    }
+    SKIP_CHAR(string);
+    while (**string != '\"') {
+        if (**string == '\0') {
+            return JSONFailure;
+        } else if (**string == '\\') {
+            SKIP_CHAR(string);
+            if (**string == '\0') {
+                return JSONFailure;
+            }
+        }
+        SKIP_CHAR(string);
+    }
+    SKIP_CHAR(string);
+    return JSONSuccess;
+}
+
+static int parse_utf16(const char **unprocessed, char **processed) {
+    unsigned int cp, lead, trail;
+    int parse_succeeded = 0;
+    char *processed_ptr = *processed;
+    const char *unprocessed_ptr = *unprocessed;
+    unprocessed_ptr++; /* skips u */
+    parse_succeeded = parse_utf16_hex(unprocessed_ptr, &cp);
+    if (!parse_succeeded) {
+        return JSONFailure;
+    }
+    if (cp < 0x80) {
+        processed_ptr[0] = (char)cp; /* 0xxxxxxx */
+    } else if (cp < 0x800) {
+        processed_ptr[0] = ((cp >> 6) & 0x1F) | 0xC0; /* 110xxxxx */
+        processed_ptr[1] = ((cp)      & 0x3F) | 0x80; /* 10xxxxxx */
+        processed_ptr += 1;
+    } else if (cp < 0xD800 || cp > 0xDFFF) {
+        processed_ptr[0] = ((cp >> 12) & 0x0F) | 0xE0; /* 1110xxxx */
+        processed_ptr[1] = ((cp >> 6)  & 0x3F) | 0x80; /* 10xxxxxx */
+        processed_ptr[2] = ((cp)       & 0x3F) | 0x80; /* 10xxxxxx */
+        processed_ptr += 2;
+    } else if (cp >= 0xD800 && cp <= 0xDBFF) { /* lead surrogate (0xD800..0xDBFF) */
+        lead = cp;
+        unprocessed_ptr += 4; /* should always be within the buffer, otherwise previous sscanf would fail */
+        if (*unprocessed_ptr++ != '\\' || *unprocessed_ptr++ != 'u') {
+            return JSONFailure;
+        }
+        parse_succeeded = parse_utf16_hex(unprocessed_ptr, &trail);
+        if (!parse_succeeded || trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */
+            return JSONFailure;
+        }
+        cp = ((((lead - 0xD800) & 0x3FF) << 10) | ((trail - 0xDC00) & 0x3FF)) + 0x010000;
+        processed_ptr[0] = (((cp >> 18) & 0x07) | 0xF0); /* 11110xxx */
+        processed_ptr[1] = (((cp >> 12) & 0x3F) | 0x80); /* 10xxxxxx */
+        processed_ptr[2] = (((cp >> 6)  & 0x3F) | 0x80); /* 10xxxxxx */
+        processed_ptr[3] = (((cp)       & 0x3F) | 0x80); /* 10xxxxxx */
+        processed_ptr += 3;
+    } else { /* trail surrogate before lead surrogate */
+        return JSONFailure;
+    }
+    unprocessed_ptr += 3;
+    *processed = processed_ptr;
+    *unprocessed = unprocessed_ptr;
+    return JSONSuccess;
+}
+
+
+/* Copies and processes passed string up to supplied length.
+Example: "\u006Corem ipsum" -> lorem ipsum */
+static char* process_string(const char *input, size_t len) {
+    const char *input_ptr = input;
+    size_t initial_size = (len + 1) * sizeof(char);
+    size_t final_size = 0;
+    char *output = NULL, *output_ptr = NULL, *resized_output = NULL;
+    output = (char*)parson_malloc(initial_size);
+    if (output == NULL) {
+        goto error;
+    }
+    output_ptr = output;
+    while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < len) {
+        if (*input_ptr == '\\') {
+            input_ptr++;
+            switch (*input_ptr) {
+                case '\"': *output_ptr = '\"'; break;
+                case '\\': *output_ptr = '\\'; break;
+                case '/':  *output_ptr = '/';  break;
+                case 'b':  *output_ptr = '\b'; break;
+                case 'f':  *output_ptr = '\f'; break;
+                case 'n':  *output_ptr = '\n'; break;
+                case 'r':  *output_ptr = '\r'; break;
+                case 't':  *output_ptr = '\t'; break;
+                case 'u':
+                    if (parse_utf16(&input_ptr, &output_ptr) == JSONFailure) {
+                        goto error;
+                    }
+                    break;
+                default:
+                    goto error;
+            }
+        } else if ((unsigned char)*input_ptr < 0x20) {
+            goto error; /* 0x00-0x19 are invalid characters for json string (http://www.ietf.org/rfc/rfc4627.txt) */
+        } else {
+            *output_ptr = *input_ptr;
+        }
+        output_ptr++;
+        input_ptr++;
+    }
+    *output_ptr = '\0';
+    /* resize to new length */
+    final_size = (size_t)(output_ptr-output) + 1;
+    /* todo: don't resize if final_size == initial_size */
+    resized_output = (char*)parson_malloc(final_size);
+    if (resized_output == NULL) {
+        goto error;
+    }
+    memcpy(resized_output, output, final_size);
+    parson_free(output);
+    return resized_output;
+error:
+    parson_free(output);
+    return NULL;
+}
+
+/* Return processed contents of a string between quotes and
+   skips passed argument to a matching quote. */
+static char * get_quoted_string(const char **string) {
+    const char *string_start = *string;
+    size_t string_len = 0;
+    JSON_Status status = skip_quotes(string);
+    if (status != JSONSuccess) {
+        return NULL;
+    }
+    string_len = *string - string_start - 2; /* length without quotes */
+    return process_string(string_start + 1, string_len);
+}
+
+static JSON_Value * parse_value(const char **string, size_t nesting) {
+    if (nesting > MAX_NESTING) {
+        return NULL;
+    }
+    SKIP_WHITESPACES(string);
+    switch (**string) {
+        case '{':
+            return parse_object_value(string, nesting + 1);
+        case '[':
+            return parse_array_value(string, nesting + 1);
+        case '\"':
+            return parse_string_value(string);
+        case 'f': case 't':
+            return parse_boolean_value(string);
+        case '-':
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+            return parse_number_value(string);
+        case 'n':
+            return parse_null_value(string);
+        default:
+            return NULL;
+    }
+}
+
+static JSON_Value * parse_object_value(const char **string, size_t nesting) {
+    JSON_Value *output_value = NULL, *new_value = NULL;
+    JSON_Object *output_object = NULL;
+    char *new_key = NULL;
+    output_value = json_value_init_object();
+    if (output_value == NULL) {
+        return NULL;
+    }
+    if (**string != '{') {
+        json_value_free(output_value);
+        return NULL;
+    }
+    output_object = json_value_get_object(output_value);
+    SKIP_CHAR(string);
+    SKIP_WHITESPACES(string);
+    if (**string == '}') { /* empty object */
+        SKIP_CHAR(string);
+        return output_value;
+    }
+    while (**string != '\0') {
+        new_key = get_quoted_string(string);
+        if (new_key == NULL) {
+            json_value_free(output_value);
+            return NULL;
+        }
+        SKIP_WHITESPACES(string);
+        if (**string != ':') {
+            parson_free(new_key);
+            json_value_free(output_value);
+            return NULL;
+        }
+        SKIP_CHAR(string);
+        new_value = parse_value(string, nesting);
+        if (new_value == NULL) {
+            parson_free(new_key);
+            json_value_free(output_value);
+            return NULL;
+        }
+        if (json_object_add(output_object, new_key, new_value) == JSONFailure) {
+            parson_free(new_key);
+            json_value_free(new_value);
+            json_value_free(output_value);
+            return NULL;
+        }
+        parson_free(new_key);
+        SKIP_WHITESPACES(string);
+        if (**string != ',') {
+            break;
+        }
+        SKIP_CHAR(string);
+        SKIP_WHITESPACES(string);
+    }
+    SKIP_WHITESPACES(string);
+    if (**string != '}' || /* Trim object after parsing is over */
+        json_object_resize(output_object, json_object_get_count(output_object)) == JSONFailure) {
+            json_value_free(output_value);
+            return NULL;
+    }
+    SKIP_CHAR(string);
+    return output_value;
+}
+
+static JSON_Value * parse_array_value(const char **string, size_t nesting) {
+    JSON_Value *output_value = NULL, *new_array_value = NULL;
+    JSON_Array *output_array = NULL;
+    output_value = json_value_init_array();
+    if (output_value == NULL) {
+        return NULL;
+    }
+    if (**string != '[') {
+        json_value_free(output_value);
+        return NULL;
+    }
+    output_array = json_value_get_array(output_value);
+    SKIP_CHAR(string);
+    SKIP_WHITESPACES(string);
+    if (**string == ']') { /* empty array */
+        SKIP_CHAR(string);
+        return output_value;
+    }
+    while (**string != '\0') {
+        new_array_value = parse_value(string, nesting);
+        if (new_array_value == NULL) {
+            json_value_free(output_value);
+            return NULL;
+        }
+        if (json_array_add(output_array, new_array_value) == JSONFailure) {
+            json_value_free(new_array_value);
+            json_value_free(output_value);
+            return NULL;
+        }
+        SKIP_WHITESPACES(string);
+        if (**string != ',') {
+            break;
+        }
+        SKIP_CHAR(string);
+        SKIP_WHITESPACES(string);
+    }
+    SKIP_WHITESPACES(string);
+    if (**string != ']' || /* Trim array after parsing is over */
+        json_array_resize(output_array, json_array_get_count(output_array)) == JSONFailure) {
+            json_value_free(output_value);
+            return NULL;
+    }
+    SKIP_CHAR(string);
+    return output_value;
+}
+
+static JSON_Value * parse_string_value(const char **string) {
+    JSON_Value *value = NULL;
+    char *new_string = get_quoted_string(string);
+    if (new_string == NULL) {
+        return NULL;
+    }
+    value = json_value_init_string_no_copy(new_string);
+    if (value == NULL) {
+        parson_free(new_string);
+        return NULL;
+    }
+    return value;
+}
+
+static JSON_Value * parse_boolean_value(const char **string) {
+    size_t true_token_size = SIZEOF_TOKEN("true");
+    size_t false_token_size = SIZEOF_TOKEN("false");
+    if (strncmp("true", *string, true_token_size) == 0) {
+        *string += true_token_size;
+        return json_value_init_boolean(1);
+    } else if (strncmp("false", *string, false_token_size) == 0) {
+        *string += false_token_size;
+        return json_value_init_boolean(0);
+    }
+    return NULL;
+}
+
+static JSON_Value * parse_number_value(const char **string) {
+    char *end;
+    double number = 0;
+    errno = 0;
+    number = strtod(*string, &end);
+    if (errno || !is_decimal(*string, end - *string)) {
+        return NULL;
+    }
+    *string = end;
+    return json_value_init_number(number);
+}
+
+static JSON_Value * parse_null_value(const char **string) {
+    size_t token_size = SIZEOF_TOKEN("null");
+    if (strncmp("null", *string, token_size) == 0) {
+        *string += token_size;
+        return json_value_init_null();
+    }
+    return NULL;
+}
+
+/* Serialization */
+#define APPEND_STRING(str) do { written = append_string(buf, (str));\
+                                if (written < 0) { return -1; }\
+                                if (buf != NULL) { buf += written; }\
+                                written_total += written; } while(0)
+
+#define APPEND_INDENT(level) do { written = append_indent(buf, (level));\
+                                  if (written < 0) { return -1; }\
+                                  if (buf != NULL) { buf += written; }\
+                                  written_total += written; } while(0)
+
+static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf)
+{
+    const char *key = NULL, *string = NULL;
+    JSON_Value *temp_value = NULL;
+    JSON_Array *array = NULL;
+    JSON_Object *object = NULL;
+    size_t i = 0, count = 0;
+    double num = 0.0;
+    int written = -1, written_total = 0;
+
+    switch (json_value_get_type(value)) {
+        case JSONArray:
+            array = json_value_get_array(value);
+            count = json_array_get_count(array);
+            APPEND_STRING("[");
+            if (count > 0 && is_pretty) {
+                APPEND_STRING("\n");
+            }
+            for (i = 0; i < count; i++) {
+                if (is_pretty) {
+                    APPEND_INDENT(level+1);
+                }
+                temp_value = json_array_get_value(array, i);
+                written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf);
+                if (written < 0) {
+                    return -1;
+                }
+                if (buf != NULL) {
+                    buf += written;
+                }
+                written_total += written;
+                if (i < (count - 1)) {
+                    APPEND_STRING(",");
+                }
+                if (is_pretty) {
+                    APPEND_STRING("\n");
+                }
+            }
+            if (count > 0 && is_pretty) {
+                APPEND_INDENT(level);
+            }
+            APPEND_STRING("]");
+            return written_total;
+        case JSONObject:
+            object = json_value_get_object(value);
+            count  = json_object_get_count(object);
+            APPEND_STRING("{");
+            if (count > 0 && is_pretty) {
+                APPEND_STRING("\n");
+            }
+            for (i = 0; i < count; i++) {
+                key = json_object_get_name(object, i);
+                if (key == NULL) {
+                    return -1;
+                }
+                if (is_pretty) {
+                    APPEND_INDENT(level+1);
+                }
+                written = json_serialize_string(key, buf);
+                if (written < 0) {
+                    return -1;
+                }
+                if (buf != NULL) {
+                    buf += written;
+                }
+                written_total += written;
+                APPEND_STRING(":");
+                if (is_pretty) {
+                    APPEND_STRING(" ");
+                }
+                temp_value = json_object_get_value(object, key);
+                written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf);
+                if (written < 0) {
+                    return -1;
+                }
+                if (buf != NULL) {
+                    buf += written;
+                }
+                written_total += written;
+                if (i < (count - 1)) {
+                    APPEND_STRING(",");
+                }
+                if (is_pretty) {
+                    APPEND_STRING("\n");
+                }
+            }
+            if (count > 0 && is_pretty) {
+                APPEND_INDENT(level);
+            }
+            APPEND_STRING("}");
+            return written_total;
+        case JSONString:
+            string = json_value_get_string(value);
+            if (string == NULL) {
+                return -1;
+            }
+            written = json_serialize_string(string, buf);
+            if (written < 0) {
+                return -1;
+            }
+            if (buf != NULL) {
+                buf += written;
+            }
+            written_total += written;
+            return written_total;
+        case JSONBoolean:
+            if (json_value_get_boolean(value)) {
+                APPEND_STRING("true");
+            } else {
+                APPEND_STRING("false");
+            }
+            return written_total;
+        case JSONNumber:
+            num = json_value_get_number(value);
+            if (buf != NULL) {
+                num_buf = buf;
+            }
+            written = sprintf(num_buf, FLOAT_FORMAT, num);
+            if (written < 0) {
+                return -1;
+            }
+            if (buf != NULL) {
+                buf += written;
+            }
+            written_total += written;
+            return written_total;
+        case JSONNull:
+            APPEND_STRING("null");
+            return written_total;
+        case JSONError:
+            return -1;
+        default:
+            return -1;
+    }
+}
+
+static int json_serialize_string(const char *string, char *buf) {
+    size_t i = 0, len = strlen(string);
+    char c = '\0';
+    int written = -1, written_total = 0;
+    APPEND_STRING("\"");
+    for (i = 0; i < len; i++) {
+        c = string[i];
+        switch (c) {
+            case '\"': APPEND_STRING("\\\""); break;
+            case '\\': APPEND_STRING("\\\\"); break;
+            case '\b': APPEND_STRING("\\b"); break;
+            case '\f': APPEND_STRING("\\f"); break;
+            case '\n': APPEND_STRING("\\n"); break;
+            case '\r': APPEND_STRING("\\r"); break;
+            case '\t': APPEND_STRING("\\t"); break;
+            case '\x00': APPEND_STRING("\\u0000"); break;
+            case '\x01': APPEND_STRING("\\u0001"); break;
+            case '\x02': APPEND_STRING("\\u0002"); break;
+            case '\x03': APPEND_STRING("\\u0003"); break;
+            case '\x04': APPEND_STRING("\\u0004"); break;
+            case '\x05': APPEND_STRING("\\u0005"); break;
+            case '\x06': APPEND_STRING("\\u0006"); break;
+            case '\x07': APPEND_STRING("\\u0007"); break;
+            /* '\x08' duplicate: '\b' */
+            /* '\x09' duplicate: '\t' */
+            /* '\x0a' duplicate: '\n' */
+            case '\x0b': APPEND_STRING("\\u000b"); break;
+            /* '\x0c' duplicate: '\f' */
+            /* '\x0d' duplicate: '\r' */
+            case '\x0e': APPEND_STRING("\\u000e"); break;
+            case '\x0f': APPEND_STRING("\\u000f"); break;
+            case '\x10': APPEND_STRING("\\u0010"); break;
+            case '\x11': APPEND_STRING("\\u0011"); break;
+            case '\x12': APPEND_STRING("\\u0012"); break;
+            case '\x13': APPEND_STRING("\\u0013"); break;
+            case '\x14': APPEND_STRING("\\u0014"); break;
+            case '\x15': APPEND_STRING("\\u0015"); break;
+            case '\x16': APPEND_STRING("\\u0016"); break;
+            case '\x17': APPEND_STRING("\\u0017"); break;
+            case '\x18': APPEND_STRING("\\u0018"); break;
+            case '\x19': APPEND_STRING("\\u0019"); break;
+            case '\x1a': APPEND_STRING("\\u001a"); break;
+            case '\x1b': APPEND_STRING("\\u001b"); break;
+            case '\x1c': APPEND_STRING("\\u001c"); break;
+            case '\x1d': APPEND_STRING("\\u001d"); break;
+            case '\x1e': APPEND_STRING("\\u001e"); break;
+            case '\x1f': APPEND_STRING("\\u001f"); break;
+            case '/':
+                if (parson_escape_slashes) {
+                    APPEND_STRING("\\/");  /* to make json embeddable in xml\/html */
+                } else {
+                    APPEND_STRING("/");
+                }
+                break;
+            default:
+                if (buf != NULL) {
+                    buf[0] = c;
+                    buf += 1;
+                }
+                written_total += 1;
+                break;
+        }
+    }
+    APPEND_STRING("\"");
+    return written_total;
+}
+
+static int append_indent(char *buf, int level) {
+    int i;
+    int written = -1, written_total = 0;
+    for (i = 0; i < level; i++) {
+        APPEND_STRING("    ");
+    }
+    return written_total;
+}
+
+static int append_string(char *buf, const char *string) {
+    if (buf == NULL) {
+        return (int)strlen(string);
+    }
+    return sprintf(buf, "%s", string);
+}
+
+#undef APPEND_STRING
+#undef APPEND_INDENT
+
+/* Parser API */
+JSON_Value * json_parse_file(const char *filename) {
+    char *file_contents = read_file(filename);
+    JSON_Value *output_value = NULL;
+    if (file_contents == NULL) {
+        return NULL;
+    }
+    output_value = json_parse_string(file_contents);
+    parson_free(file_contents);
+    return output_value;
+}
+
+JSON_Value * json_parse_file_with_comments(const char *filename) {
+    char *file_contents = read_file(filename);
+    JSON_Value *output_value = NULL;
+    if (file_contents == NULL) {
+        return NULL;
+    }
+    output_value = json_parse_string_with_comments(file_contents);
+    parson_free(file_contents);
+    return output_value;
+}
+
+JSON_Value * json_parse_string(const char *string) {
+    if (string == NULL) {
+        return NULL;
+    }
+    if (string[0] == '\xEF' && string[1] == '\xBB' && string[2] == '\xBF') {
+        string = string + 3; /* Support for UTF-8 BOM */
+    }
+    return parse_value((const char**)&string, 0);
+}
+
+JSON_Value * json_parse_string_with_comments(const char *string) {
+    JSON_Value *result = NULL;
+    char *string_mutable_copy = NULL, *string_mutable_copy_ptr = NULL;
+    string_mutable_copy = parson_strdup(string);
+    if (string_mutable_copy == NULL) {
+        return NULL;
+    }
+    remove_comments(string_mutable_copy, "/*", "*/");
+    remove_comments(string_mutable_copy, "//", "\n");
+    string_mutable_copy_ptr = string_mutable_copy;
+    result = parse_value((const char**)&string_mutable_copy_ptr, 0);
+    parson_free(string_mutable_copy);
+    return result;
+}
+
+/* JSON Object API */
+
+JSON_Value * json_object_get_value(const JSON_Object *object, const char *name) {
+    if (object == NULL || name == NULL) {
+        return NULL;
+    }
+    return json_object_getn_value(object, name, strlen(name));
+}
+
+const char * json_object_get_string(const JSON_Object *object, const char *name) {
+    return json_value_get_string(json_object_get_value(object, name));
+}
+
+double json_object_get_number(const JSON_Object *object, const char *name) {
+    return json_value_get_number(json_object_get_value(object, name));
+}
+
+JSON_Object * json_object_get_object(const JSON_Object *object, const char *name) {
+    return json_value_get_object(json_object_get_value(object, name));
+}
+
+JSON_Array * json_object_get_array(const JSON_Object *object, const char *name) {
+    return json_value_get_array(json_object_get_value(object, name));
+}
+
+int json_object_get_boolean(const JSON_Object *object, const char *name) {
+    return json_value_get_boolean(json_object_get_value(object, name));
+}
+
+JSON_Value * json_object_dotget_value(const JSON_Object *object, const char *name) {
+    const char *dot_position = strchr(name, '.');
+    if (!dot_position) {
+        return json_object_get_value(object, name);
+    }
+    object = json_value_get_object(json_object_getn_value(object, name, dot_position - name));
+    return json_object_dotget_value(object, dot_position + 1);
+}
+
+const char * json_object_dotget_string(const JSON_Object *object, const char *name) {
+    return json_value_get_string(json_object_dotget_value(object, name));
+}
+
+double json_object_dotget_number(const JSON_Object *object, const char *name) {
+    return json_value_get_number(json_object_dotget_value(object, name));
+}
+
+JSON_Object * json_object_dotget_object(const JSON_Object *object, const char *name) {
+    return json_value_get_object(json_object_dotget_value(object, name));
+}
+
+JSON_Array * json_object_dotget_array(const JSON_Object *object, const char *name) {
+    return json_value_get_array(json_object_dotget_value(object, name));
+}
+
+int json_object_dotget_boolean(const JSON_Object *object, const char *name) {
+    return json_value_get_boolean(json_object_dotget_value(object, name));
+}
+
+size_t json_object_get_count(const JSON_Object *object) {
+    return object ? object->count : 0;
+}
+
+const char * json_object_get_name(const JSON_Object *object, size_t index) {
+    if (object == NULL || index >= json_object_get_count(object)) {
+        return NULL;
+    }
+    return object->names[index];
+}
+
+JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index) {
+    if (object == NULL || index >= json_object_get_count(object)) {
+        return NULL;
+    }
+    return object->values[index];
+}
+
+JSON_Value *json_object_get_wrapping_value(const JSON_Object *object) {
+    return object->wrapping_value;
+}
+
+int json_object_has_value (const JSON_Object *object, const char *name) {
+    return json_object_get_value(object, name) != NULL;
+}
+
+int json_object_has_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type) {
+    JSON_Value *val = json_object_get_value(object, name);
+    return val != NULL && json_value_get_type(val) == type;
+}
+
+int json_object_dothas_value (const JSON_Object *object, const char *name) {
+    return json_object_dotget_value(object, name) != NULL;
+}
+
+int json_object_dothas_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type) {
+    JSON_Value *val = json_object_dotget_value(object, name);
+    return val != NULL && json_value_get_type(val) == type;
+}
+
+/* JSON Array API */
+JSON_Value * json_array_get_value(const JSON_Array *array, size_t index) {
+    if (array == NULL || index >= json_array_get_count(array)) {
+        return NULL;
+    }
+    return array->items[index];
+}
+
+const char * json_array_get_string(const JSON_Array *array, size_t index) {
+    return json_value_get_string(json_array_get_value(array, index));
+}
+
+double json_array_get_number(const JSON_Array *array, size_t index) {
+    return json_value_get_number(json_array_get_value(array, index));
+}
+
+JSON_Object * json_array_get_object(const JSON_Array *array, size_t index) {
+    return json_value_get_object(json_array_get_value(array, index));
+}
+
+JSON_Array * json_array_get_array(const JSON_Array *array, size_t index) {
+    return json_value_get_array(json_array_get_value(array, index));
+}
+
+int json_array_get_boolean(const JSON_Array *array, size_t index) {
+    return json_value_get_boolean(json_array_get_value(array, index));
+}
+
+size_t json_array_get_count(const JSON_Array *array) {
+    return array ? array->count : 0;
+}
+
+JSON_Value * json_array_get_wrapping_value(const JSON_Array *array) {
+    return array->wrapping_value;
+}
+
+/* JSON Value API */
+JSON_Value_Type json_value_get_type(const JSON_Value *value) {
+    return value ? value->type : JSONError;
+}
+
+JSON_Object * json_value_get_object(const JSON_Value *value) {
+    return json_value_get_type(value) == JSONObject ? value->value.object : NULL;
+}
+
+JSON_Array * json_value_get_array(const JSON_Value *value) {
+    return json_value_get_type(value) == JSONArray ? value->value.array : NULL;
+}
+
+const char * json_value_get_string(const JSON_Value *value) {
+    return json_value_get_type(value) == JSONString ? value->value.string : NULL;
+}
+
+double json_value_get_number(const JSON_Value *value) {
+    return json_value_get_type(value) == JSONNumber ? value->value.number : 0;
+}
+
+int json_value_get_boolean(const JSON_Value *value) {
+    return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1;
+}
+
+JSON_Value * json_value_get_parent (const JSON_Value *value) {
+    return value ? value->parent : NULL;
+}
+
+void json_value_free(JSON_Value *value) {
+    switch (json_value_get_type(value)) {
+        case JSONObject:
+            json_object_free(value->value.object);
+            break;
+        case JSONString:
+            parson_free(value->value.string);
+            break;
+        case JSONArray:
+            json_array_free(value->value.array);
+            break;
+        default:
+            break;
+    }
+    parson_free(value);
+}
+
+JSON_Value * json_value_init_object(void) {
+    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+    if (!new_value) {
+        return NULL;
+    }
+    new_value->parent = NULL;
+    new_value->type = JSONObject;
+    new_value->value.object = json_object_init(new_value);
+    if (!new_value->value.object) {
+        parson_free(new_value);
+        return NULL;
+    }
+    return new_value;
+}
+
+JSON_Value * json_value_init_array(void) {
+    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+    if (!new_value) {
+        return NULL;
+    }
+    new_value->parent = NULL;
+    new_value->type = JSONArray;
+    new_value->value.array = json_array_init(new_value);
+    if (!new_value->value.array) {
+        parson_free(new_value);
+        return NULL;
+    }
+    return new_value;
+}
+
+JSON_Value * json_value_init_string(const char *string) {
+    char *copy = NULL;
+    JSON_Value *value;
+    size_t string_len = 0;
+    if (string == NULL) {
+        return NULL;
+    }
+    string_len = strlen(string);
+    if (!is_valid_utf8(string, string_len)) {
+        return NULL;
+    }
+    copy = parson_strndup(string, string_len);
+    if (copy == NULL) {
+        return NULL;
+    }
+    value = json_value_init_string_no_copy(copy);
+    if (value == NULL) {
+        parson_free(copy);
+    }
+    return value;
+}
+
+JSON_Value * json_value_init_number(double number) {
+    JSON_Value *new_value = NULL;
+    if (IS_NUMBER_INVALID(number)) {
+        return NULL;
+    }
+    new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+    if (new_value == NULL) {
+        return NULL;
+    }
+    new_value->parent = NULL;
+    new_value->type = JSONNumber;
+    new_value->value.number = number;
+    return new_value;
+}
+
+JSON_Value * json_value_init_boolean(int boolean) {
+    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+    if (!new_value) {
+        return NULL;
+    }
+    new_value->parent = NULL;
+    new_value->type = JSONBoolean;
+    new_value->value.boolean = boolean ? 1 : 0;
+    return new_value;
+}
+
+JSON_Value * json_value_init_null(void) {
+    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+    if (!new_value) {
+        return NULL;
+    }
+    new_value->parent = NULL;
+    new_value->type = JSONNull;
+    return new_value;
+}
+
+JSON_Value * json_value_deep_copy(const JSON_Value *value) {
+    size_t i = 0;
+    JSON_Value *return_value = NULL, *temp_value_copy = NULL, *temp_value = NULL;
+    const char *temp_string = NULL, *temp_key = NULL;
+    char *temp_string_copy = NULL;
+    JSON_Array *temp_array = NULL, *temp_array_copy = NULL;
+    JSON_Object *temp_object = NULL, *temp_object_copy = NULL;
+
+    switch (json_value_get_type(value)) {
+        case JSONArray:
+            temp_array = json_value_get_array(value);
+            return_value = json_value_init_array();
+            if (return_value == NULL) {
+                return NULL;
+            }
+            temp_array_copy = json_value_get_array(return_value);
+            for (i = 0; i < json_array_get_count(temp_array); i++) {
+                temp_value = json_array_get_value(temp_array, i);
+                temp_value_copy = json_value_deep_copy(temp_value);
+                if (temp_value_copy == NULL) {
+                    json_value_free(return_value);
+                    return NULL;
+                }
+                if (json_array_add(temp_array_copy, temp_value_copy) == JSONFailure) {
+                    json_value_free(return_value);
+                    json_value_free(temp_value_copy);
+                    return NULL;
+                }
+            }
+            return return_value;
+        case JSONObject:
+            temp_object = json_value_get_object(value);
+            return_value = json_value_init_object();
+            if (return_value == NULL) {
+                return NULL;
+            }
+            temp_object_copy = json_value_get_object(return_value);
+            for (i = 0; i < json_object_get_count(temp_object); i++) {
+                temp_key = json_object_get_name(temp_object, i);
+                temp_value = json_object_get_value(temp_object, temp_key);
+                temp_value_copy = json_value_deep_copy(temp_value);
+                if (temp_value_copy == NULL) {
+                    json_value_free(return_value);
+                    return NULL;
+                }
+                if (json_object_add(temp_object_copy, temp_key, temp_value_copy) == JSONFailure) {
+                    json_value_free(return_value);
+                    json_value_free(temp_value_copy);
+                    return NULL;
+                }
+            }
+            return return_value;
+        case JSONBoolean:
+            return json_value_init_boolean(json_value_get_boolean(value));
+        case JSONNumber:
+            return json_value_init_number(json_value_get_number(value));
+        case JSONString:
+            temp_string = json_value_get_string(value);
+            if (temp_string == NULL) {
+                return NULL;
+            }
+            temp_string_copy = parson_strdup(temp_string);
+            if (temp_string_copy == NULL) {
+                return NULL;
+            }
+            return_value = json_value_init_string_no_copy(temp_string_copy);
+            if (return_value == NULL) {
+                parson_free(temp_string_copy);
+            }
+            return return_value;
+        case JSONNull:
+            return json_value_init_null();
+        case JSONError:
+            return NULL;
+        default:
+            return NULL;
+    }
+}
+
+size_t json_serialization_size(const JSON_Value *value) {
+    char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */
+    int res = json_serialize_to_buffer_r(value, NULL, 0, 0, num_buf);
+    return res < 0 ? 0 : (size_t)(res + 1);
+}
+
+JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) {
+    int written = -1;
+    size_t needed_size_in_bytes = json_serialization_size(value);
+    if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) {
+        return JSONFailure;
+    }
+    written = json_serialize_to_buffer_r(value, buf, 0, 0, NULL);
+    if (written < 0) {
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename) {
+    JSON_Status return_code = JSONSuccess;
+    FILE *fp = NULL;
+    char *serialized_string = json_serialize_to_string(value);
+    if (serialized_string == NULL) {
+        return JSONFailure;
+    }
+    fp = fopen(filename, "w");
+    if (fp == NULL) {
+        json_free_serialized_string(serialized_string);
+        return JSONFailure;
+    }
+    if (fputs(serialized_string, fp) == EOF) {
+        return_code = JSONFailure;
+    }
+    if (fclose(fp) == EOF) {
+        return_code = JSONFailure;
+    }
+    json_free_serialized_string(serialized_string);
+    return return_code;
+}
+
+char * json_serialize_to_string(const JSON_Value *value) {
+    JSON_Status serialization_result = JSONFailure;
+    size_t buf_size_bytes = json_serialization_size(value);
+    char *buf = NULL;
+    if (buf_size_bytes == 0) {
+        return NULL;
+    }
+    buf = (char*)parson_malloc(buf_size_bytes);
+    if (buf == NULL) {
+        return NULL;
+    }
+    serialization_result = json_serialize_to_buffer(value, buf, buf_size_bytes);
+    if (serialization_result == JSONFailure) {
+        json_free_serialized_string(buf);
+        return NULL;
+    }
+    return buf;
+}
+
+size_t json_serialization_size_pretty(const JSON_Value *value) {
+    char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */
+    int res = json_serialize_to_buffer_r(value, NULL, 0, 1, num_buf);
+    return res < 0 ? 0 : (size_t)(res + 1);
+}
+
+JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) {
+    int written = -1;
+    size_t needed_size_in_bytes = json_serialization_size_pretty(value);
+    if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) {
+        return JSONFailure;
+    }
+    written = json_serialize_to_buffer_r(value, buf, 0, 1, NULL);
+    if (written < 0) {
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename) {
+    JSON_Status return_code = JSONSuccess;
+    FILE *fp = NULL;
+    char *serialized_string = json_serialize_to_string_pretty(value);
+    if (serialized_string == NULL) {
+        return JSONFailure;
+    }
+    fp = fopen(filename, "w");
+    if (fp == NULL) {
+        json_free_serialized_string(serialized_string);
+        return JSONFailure;
+    }
+    if (fputs(serialized_string, fp) == EOF) {
+        return_code = JSONFailure;
+    }
+    if (fclose(fp) == EOF) {
+        return_code = JSONFailure;
+    }
+    json_free_serialized_string(serialized_string);
+    return return_code;
+}
+
+char * json_serialize_to_string_pretty(const JSON_Value *value) {
+    JSON_Status serialization_result = JSONFailure;
+    size_t buf_size_bytes = json_serialization_size_pretty(value);
+    char *buf = NULL;
+    if (buf_size_bytes == 0) {
+        return NULL;
+    }
+    buf = (char*)parson_malloc(buf_size_bytes);
+    if (buf == NULL) {
+        return NULL;
+    }
+    serialization_result = json_serialize_to_buffer_pretty(value, buf, buf_size_bytes);
+    if (serialization_result == JSONFailure) {
+        json_free_serialized_string(buf);
+        return NULL;
+    }
+    return buf;
+}
+
+void json_free_serialized_string(char *string) {
+    parson_free(string);
+}
+
+JSON_Status json_array_remove(JSON_Array *array, size_t ix) {
+    size_t to_move_bytes = 0;
+    if (array == NULL || ix >= json_array_get_count(array)) {
+        return JSONFailure;
+    }
+    json_value_free(json_array_get_value(array, ix));
+    to_move_bytes = (json_array_get_count(array) - 1 - ix) * sizeof(JSON_Value*);
+    memmove(array->items + ix, array->items + ix + 1, to_move_bytes);
+    array->count -= 1;
+    return JSONSuccess;
+}
+
+JSON_Status json_array_replace_value(JSON_Array *array, size_t ix, JSON_Value *value) {
+    if (array == NULL || value == NULL || value->parent != NULL || ix >= json_array_get_count(array)) {
+        return JSONFailure;
+    }
+    json_value_free(json_array_get_value(array, ix));
+    value->parent = json_array_get_wrapping_value(array);
+    array->items[ix] = value;
+    return JSONSuccess;
+}
+
+JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string) {
+    JSON_Value *value = json_value_init_string(string);
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_array_replace_value(array, i, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number) {
+    JSON_Value *value = json_value_init_number(number);
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_array_replace_value(array, i, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean) {
+    JSON_Value *value = json_value_init_boolean(boolean);
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_array_replace_value(array, i, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_array_replace_null(JSON_Array *array, size_t i) {
+    JSON_Value *value = json_value_init_null();
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_array_replace_value(array, i, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_array_clear(JSON_Array *array) {
+    size_t i = 0;
+    if (array == NULL) {
+        return JSONFailure;
+    }
+    for (i = 0; i < json_array_get_count(array); i++) {
+        json_value_free(json_array_get_value(array, i));
+    }
+    array->count = 0;
+    return JSONSuccess;
+}
+
+JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value) {
+    if (array == NULL || value == NULL || value->parent != NULL) {
+        return JSONFailure;
+    }
+    return json_array_add(array, value);
+}
+
+JSON_Status json_array_append_string(JSON_Array *array, const char *string) {
+    JSON_Value *value = json_value_init_string(string);
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_array_append_value(array, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_array_append_number(JSON_Array *array, double number) {
+    JSON_Value *value = json_value_init_number(number);
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_array_append_value(array, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_array_append_boolean(JSON_Array *array, int boolean) {
+    JSON_Value *value = json_value_init_boolean(boolean);
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_array_append_value(array, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_array_append_null(JSON_Array *array) {
+    JSON_Value *value = json_value_init_null();
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_array_append_value(array, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value) {
+    size_t i = 0;
+    JSON_Value *old_value;
+    if (object == NULL || name == NULL || value == NULL || value->parent != NULL) {
+        return JSONFailure;
+    }
+    old_value = json_object_get_value(object, name);
+    if (old_value != NULL) { /* free and overwrite old value */
+        json_value_free(old_value);
+        for (i = 0; i < json_object_get_count(object); i++) {
+            if (strcmp(object->names[i], name) == 0) {
+                value->parent = json_object_get_wrapping_value(object);
+                object->values[i] = value;
+                return JSONSuccess;
+            }
+        }
+    }
+    /* add new key value pair */
+    return json_object_add(object, name, value);
+}
+
+JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string) {
+    JSON_Value *value = json_value_init_string(string);
+    JSON_Status status = json_object_set_value(object, name, value);
+    if (status == JSONFailure) {
+        json_value_free(value);
+    }
+    return status;
+}
+
+JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) {
+    JSON_Value *value = json_value_init_number(number);
+    JSON_Status status = json_object_set_value(object, name, value);
+    if (status == JSONFailure) {
+        json_value_free(value);
+    }
+    return status;
+}
+
+JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean) {
+    JSON_Value *value = json_value_init_boolean(boolean);
+    JSON_Status status = json_object_set_value(object, name, value);
+    if (status == JSONFailure) {
+        json_value_free(value);
+    }
+    return status;
+}
+
+JSON_Status json_object_set_null(JSON_Object *object, const char *name) {
+    JSON_Value *value = json_value_init_null();
+    JSON_Status status = json_object_set_value(object, name, value);
+    if (status == JSONFailure) {
+        json_value_free(value);
+    }
+    return status;
+}
+
+JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value) {
+    const char *dot_pos = NULL;
+    JSON_Value *temp_value = NULL, *new_value = NULL;
+    JSON_Object *temp_object = NULL, *new_object = NULL;
+    JSON_Status status = JSONFailure;
+    size_t name_len = 0;
+    if (object == NULL || name == NULL || value == NULL) {
+        return JSONFailure;
+    }
+    dot_pos = strchr(name, '.');
+    if (dot_pos == NULL) {
+        return json_object_set_value(object, name, value);
+    }
+    name_len = dot_pos - name;
+    temp_value = json_object_getn_value(object, name, name_len);
+    if (temp_value) {
+        /* Don't overwrite existing non-object (unlike json_object_set_value, but it shouldn't be changed at this point) */
+        if (json_value_get_type(temp_value) != JSONObject) {
+            return JSONFailure;
+        }
+        temp_object = json_value_get_object(temp_value);
+        return json_object_dotset_value(temp_object, dot_pos + 1, value);
+    }
+    new_value = json_value_init_object();
+    if (new_value == NULL) {
+        return JSONFailure;
+    }
+    new_object = json_value_get_object(new_value);
+    status = json_object_dotset_value(new_object, dot_pos + 1, value);
+    if (status != JSONSuccess) {
+        json_value_free(new_value);
+        return JSONFailure;
+    }
+    status = json_object_addn(object, name, name_len, new_value);
+    if (status != JSONSuccess) {
+        json_object_dotremove_internal(new_object, dot_pos + 1, 0);
+        json_value_free(new_value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string) {
+    JSON_Value *value = json_value_init_string(string);
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_object_dotset_value(object, name, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number) {
+    JSON_Value *value = json_value_init_number(number);
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_object_dotset_value(object, name, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean) {
+    JSON_Value *value = json_value_init_boolean(boolean);
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_object_dotset_value(object, name, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_object_dotset_null(JSON_Object *object, const char *name) {
+    JSON_Value *value = json_value_init_null();
+    if (value == NULL) {
+        return JSONFailure;
+    }
+    if (json_object_dotset_value(object, name, value) == JSONFailure) {
+        json_value_free(value);
+        return JSONFailure;
+    }
+    return JSONSuccess;
+}
+
+JSON_Status json_object_remove(JSON_Object *object, const char *name) {
+    return json_object_remove_internal(object, name, 1);
+}
+
+JSON_Status json_object_dotremove(JSON_Object *object, const char *name) {
+    return json_object_dotremove_internal(object, name, 1);
+}
+
+JSON_Status json_object_clear(JSON_Object *object) {
+    size_t i = 0;
+    if (object == NULL) {
+        return JSONFailure;
+    }
+    for (i = 0; i < json_object_get_count(object); i++) {
+        parson_free(object->names[i]);
+        json_value_free(object->values[i]);
+    }
+    object->count = 0;
+    return JSONSuccess;
+}
+
+JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) {
+    JSON_Value *temp_schema_value = NULL, *temp_value = NULL;
+    JSON_Array *schema_array = NULL, *value_array = NULL;
+    JSON_Object *schema_object = NULL, *value_object = NULL;
+    JSON_Value_Type schema_type = JSONError, value_type = JSONError;
+    const char *key = NULL;
+    size_t i = 0, count = 0;
+    if (schema == NULL || value == NULL) {
+        return JSONFailure;
+    }
+    schema_type = json_value_get_type(schema);
+    value_type = json_value_get_type(value);
+    if (schema_type != value_type && schema_type != JSONNull) { /* null represents all values */
+        return JSONFailure;
+    }
+    switch (schema_type) {
+        case JSONArray:
+            schema_array = json_value_get_array(schema);
+            value_array = json_value_get_array(value);
+            count = json_array_get_count(schema_array);
+            if (count == 0) {
+                return JSONSuccess; /* Empty array allows all types */
+            }
+            /* Get first value from array, rest is ignored */
+            temp_schema_value = json_array_get_value(schema_array, 0);
+            for (i = 0; i < json_array_get_count(value_array); i++) {
+                temp_value = json_array_get_value(value_array, i);
+                if (json_validate(temp_schema_value, temp_value) == JSONFailure) {
+                    return JSONFailure;
+                }
+            }
+            return JSONSuccess;
+        case JSONObject:
+            schema_object = json_value_get_object(schema);
+            value_object = json_value_get_object(value);
+            count = json_object_get_count(schema_object);
+            if (count == 0) {
+                return JSONSuccess; /* Empty object allows all objects */
+            } else if (json_object_get_count(value_object) < count) {
+                return JSONFailure; /* Tested object mustn't have less name-value pairs than schema */
+            }
+            for (i = 0; i < count; i++) {
+                key = json_object_get_name(schema_object, i);
+                temp_schema_value = json_object_get_value(schema_object, key);
+                temp_value = json_object_get_value(value_object, key);
+                if (temp_value == NULL) {
+                    return JSONFailure;
+                }
+                if (json_validate(temp_schema_value, temp_value) == JSONFailure) {
+                    return JSONFailure;
+                }
+            }
+            return JSONSuccess;
+        case JSONString: case JSONNumber: case JSONBoolean: case JSONNull:
+            return JSONSuccess; /* equality already tested before switch */
+        case JSONError: default:
+            return JSONFailure;
+    }
+}
+
+int json_value_equals(const JSON_Value *a, const JSON_Value *b) {
+    JSON_Object *a_object = NULL, *b_object = NULL;
+    JSON_Array *a_array = NULL, *b_array = NULL;
+    const char *a_string = NULL, *b_string = NULL;
+    const char *key = NULL;
+    size_t a_count = 0, b_count = 0, i = 0;
+    JSON_Value_Type a_type, b_type;
+    a_type = json_value_get_type(a);
+    b_type = json_value_get_type(b);
+    if (a_type != b_type) {
+        return 0;
+    }
+    switch (a_type) {
+        case JSONArray:
+            a_array = json_value_get_array(a);
+            b_array = json_value_get_array(b);
+            a_count = json_array_get_count(a_array);
+            b_count = json_array_get_count(b_array);
+            if (a_count != b_count) {
+                return 0;
+            }
+            for (i = 0; i < a_count; i++) {
+                if (!json_value_equals(json_array_get_value(a_array, i),
+                                       json_array_get_value(b_array, i))) {
+                    return 0;
+                }
+            }
+            return 1;
+        case JSONObject:
+            a_object = json_value_get_object(a);
+            b_object = json_value_get_object(b);
+            a_count = json_object_get_count(a_object);
+            b_count = json_object_get_count(b_object);
+            if (a_count != b_count) {
+                return 0;
+            }
+            for (i = 0; i < a_count; i++) {
+                key = json_object_get_name(a_object, i);
+                if (!json_value_equals(json_object_get_value(a_object, key),
+                                       json_object_get_value(b_object, key))) {
+                    return 0;
+                }
+            }
+            return 1;
+        case JSONString:
+            a_string = json_value_get_string(a);
+            b_string = json_value_get_string(b);
+            if (a_string == NULL || b_string == NULL) {
+                return 0; /* shouldn't happen */
+            }
+            return strcmp(a_string, b_string) == 0;
+        case JSONBoolean:
+            return json_value_get_boolean(a) == json_value_get_boolean(b);
+        case JSONNumber:
+            return fabs(json_value_get_number(a) - json_value_get_number(b)) < 0.000001; /* EPSILON */
+        case JSONError:
+            return 1;
+        case JSONNull:
+            return 1;
+        default:
+            return 1;
+    }
+}
+
+JSON_Value_Type json_type(const JSON_Value *value) {
+    return json_value_get_type(value);
+}
+
+JSON_Object * json_object (const JSON_Value *value) {
+    return json_value_get_object(value);
+}
+
+JSON_Array * json_array  (const JSON_Value *value) {
+    return json_value_get_array(value);
+}
+
+const char * json_string (const JSON_Value *value) {
+    return json_value_get_string(value);
+}
+
+double json_number (const JSON_Value *value) {
+    return json_value_get_number(value);
+}
+
+int json_boolean(const JSON_Value *value) {
+    return json_value_get_boolean(value);
+}
+
+void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun) {
+    parson_malloc = malloc_fun;
+    parson_free = free_fun;
+}
+
+void json_set_escape_slashes(int escape_slashes) {
+    parson_escape_slashes = escape_slashes;
+}
diff --git a/seitan-cooker/parson.h b/seitan-cooker/parson.h
new file mode 100644
index 0000000..186fcb0
--- /dev/null
+++ b/seitan-cooker/parson.h
@@ -0,0 +1,240 @@
+/*
+ SPDX-License-Identifier: MIT
+
+ Parson ( http://kgabis.github.com/parson/ )
+ Copyright (c) 2012 - 2019 Krzysztof Gabis
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef parson_parson_h
+#define parson_parson_h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h>   /* size_t */
+
+/* Types and enums */
+typedef struct json_object_t JSON_Object;
+typedef struct json_array_t  JSON_Array;
+typedef struct json_value_t  JSON_Value;
+
+enum json_value_type {
+    JSONError   = -1,
+    JSONNull    = 1,
+    JSONString  = 2,
+    JSONNumber  = 3,
+    JSONObject  = 4,
+    JSONArray   = 5,
+    JSONBoolean = 6
+};
+typedef int JSON_Value_Type;
+
+enum json_result_t {
+    JSONSuccess = 0,
+    JSONFailure = -1
+};
+typedef int JSON_Status;
+
+typedef void * (*JSON_Malloc_Function)(size_t);
+typedef void   (*JSON_Free_Function)(void *);
+
+/* Call only once, before calling any other function from parson API. If not called, malloc and free
+   from stdlib will be used for all allocations */
+void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun);
+
+/* Sets if slashes should be escaped or not when serializing JSON. By default slashes are escaped.
+ This function sets a global setting and is not thread safe. */
+void json_set_escape_slashes(int escape_slashes);
+
+/* Parses first JSON value in a file, returns NULL in case of error */
+JSON_Value * json_parse_file(const char *filename);
+
+/* Parses first JSON value in a file and ignores comments (/ * * / and //),
+   returns NULL in case of error */
+JSON_Value * json_parse_file_with_comments(const char *filename);
+
+/*  Parses first JSON value in a string, returns NULL in case of error */
+JSON_Value * json_parse_string(const char *string);
+
+/*  Parses first JSON value in a string and ignores comments (/ * * / and //),
+    returns NULL in case of error */
+JSON_Value * json_parse_string_with_comments(const char *string);
+
+/* Serialization */
+size_t      json_serialization_size(const JSON_Value *value); /* returns 0 on fail */
+JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
+JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename);
+char *      json_serialize_to_string(const JSON_Value *value);
+
+/* Pretty serialization */
+size_t      json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */
+JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
+JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename);
+char *      json_serialize_to_string_pretty(const JSON_Value *value);
+
+void        json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */
+
+/* Comparing */
+int  json_value_equals(const JSON_Value *a, const JSON_Value *b);
+
+/* Validation
+   This is *NOT* JSON Schema. It validates json by checking if object have identically
+   named fields with matching types.
+   For example schema {"name":"", "age":0} will validate
+   {"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"},
+   but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}.
+   In case of arrays, only first value in schema is checked against all values in tested array.
+   Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays,
+   null validates values of every type.
+ */
+JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value);
+
+/*
+ * JSON Object
+ */
+JSON_Value  * json_object_get_value  (const JSON_Object *object, const char *name);
+const char  * json_object_get_string (const JSON_Object *object, const char *name);
+JSON_Object * json_object_get_object (const JSON_Object *object, const char *name);
+JSON_Array  * json_object_get_array  (const JSON_Object *object, const char *name);
+double        json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
+int           json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
+
+/* dotget functions enable addressing values with dot notation in nested objects,
+ just like in structs or c++/java/c# objects (e.g. objectA.objectB.value).
+ Because valid names in JSON can contain dots, some values may be inaccessible
+ this way. */
+JSON_Value  * json_object_dotget_value  (const JSON_Object *object, const char *name);
+const char  * json_object_dotget_string (const JSON_Object *object, const char *name);
+JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name);
+JSON_Array  * json_object_dotget_array  (const JSON_Object *object, const char *name);
+double        json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
+int           json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
+
+/* Functions to get available names */
+size_t        json_object_get_count   (const JSON_Object *object);
+const char  * json_object_get_name    (const JSON_Object *object, size_t index);
+JSON_Value  * json_object_get_value_at(const JSON_Object *object, size_t index);
+JSON_Value  * json_object_get_wrapping_value(const JSON_Object *object);
+
+/* Functions to check if object has a value with a specific name. Returned value is 1 if object has
+ * a value and 0 if it doesn't. dothas functions behave exactly like dotget functions. */
+int json_object_has_value        (const JSON_Object *object, const char *name);
+int json_object_has_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
+
+int json_object_dothas_value        (const JSON_Object *object, const char *name);
+int json_object_dothas_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
+
+/* Creates new name-value pair or frees and replaces old value with a new one.
+ * json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value);
+JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string);
+JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number);
+JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean);
+JSON_Status json_object_set_null(JSON_Object *object, const char *name);
+
+/* Works like dotget functions, but creates whole hierarchy if necessary.
+ * json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value);
+JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string);
+JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number);
+JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean);
+JSON_Status json_object_dotset_null(JSON_Object *object, const char *name);
+
+/* Frees and removes name-value pair */
+JSON_Status json_object_remove(JSON_Object *object, const char *name);
+
+/* Works like dotget function, but removes name-value pair only on exact match. */
+JSON_Status json_object_dotremove(JSON_Object *object, const char *key);
+
+/* Removes all name-value pairs in object */
+JSON_Status json_object_clear(JSON_Object *object);
+
+/*
+ *JSON Array
+ */
+JSON_Value  * json_array_get_value  (const JSON_Array *array, size_t index);
+const char  * json_array_get_string (const JSON_Array *array, size_t index);
+JSON_Object * json_array_get_object (const JSON_Array *array, size_t index);
+JSON_Array  * json_array_get_array  (const JSON_Array *array, size_t index);
+double        json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */
+int           json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */
+size_t        json_array_get_count  (const JSON_Array *array);
+JSON_Value  * json_array_get_wrapping_value(const JSON_Array *array);
+
+/* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist.
+ * Order of values in array may change during execution.  */
+JSON_Status json_array_remove(JSON_Array *array, size_t i);
+
+/* Frees and removes from array value at given index and replaces it with given one.
+ * Does nothing and returns JSONFailure if index doesn't exist.
+ * json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value);
+JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string);
+JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number);
+JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean);
+JSON_Status json_array_replace_null(JSON_Array *array, size_t i);
+
+/* Frees and removes all values from array */
+JSON_Status json_array_clear(JSON_Array *array);
+
+/* Appends new value at the end of array.
+ * json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value);
+JSON_Status json_array_append_string(JSON_Array *array, const char *string);
+JSON_Status json_array_append_number(JSON_Array *array, double number);
+JSON_Status json_array_append_boolean(JSON_Array *array, int boolean);
+JSON_Status json_array_append_null(JSON_Array *array);
+
+/*
+ *JSON Value
+ */
+JSON_Value * json_value_init_object (void);
+JSON_Value * json_value_init_array  (void);
+JSON_Value * json_value_init_string (const char *string); /* copies passed string */
+JSON_Value * json_value_init_number (double number);
+JSON_Value * json_value_init_boolean(int boolean);
+JSON_Value * json_value_init_null   (void);
+JSON_Value * json_value_deep_copy   (const JSON_Value *value);
+void         json_value_free        (JSON_Value *value);
+
+JSON_Value_Type json_value_get_type   (const JSON_Value *value);
+JSON_Object *   json_value_get_object (const JSON_Value *value);
+JSON_Array  *   json_value_get_array  (const JSON_Value *value);
+const char  *   json_value_get_string (const JSON_Value *value);
+double          json_value_get_number (const JSON_Value *value);
+int             json_value_get_boolean(const JSON_Value *value);
+JSON_Value  *   json_value_get_parent (const JSON_Value *value);
+
+/* Same as above, but shorter */
+JSON_Value_Type json_type   (const JSON_Value *value);
+JSON_Object *   json_object (const JSON_Value *value);
+JSON_Array  *   json_array  (const JSON_Value *value);
+const char  *   json_string (const JSON_Value *value);
+double          json_number (const JSON_Value *value);
+int             json_boolean(const JSON_Value *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/seitan-cooker/util.c b/seitan-cooker/util.c
new file mode 100644
index 0000000..a2ecce0
--- /dev/null
+++ b/seitan-cooker/util.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
+ *
+ * cooker/util.c - Convenience routines
+ *
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#define logfn(name)							\
+void name(const char *format, ...) {					\
+	va_list args;							\
+									\
+	va_start(args, format);						\
+	(void)vfprintf(stderr, format, args); 				\
+	va_end(args);							\
+	if (format[strlen(format)] != '\n')				\
+		fprintf(stderr, "\n");					\
+}
+
+logfn(err)
+logfn(info)
+logfn(debug)
+
diff --git a/seitan-cooker/util.h b/seitan-cooker/util.h
new file mode 100644
index 0000000..84dc3db
--- /dev/null
+++ b/seitan-cooker/util.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * Copyright 2023 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#define BIT(n)			(1UL << (n))
+
+void err(const char *format, ...);
+void info(const char *format, ...);
+void debug(const char *format, ...);
+
+#define die(...)							\
+	do {								\
+		fprintf(stderr, "%s:%i: ", __FILE__, __LINE__);		\
+		err(__VA_ARGS__);					\
+		exit(EXIT_FAILURE);					\
+	} while (0)
+
+#endif /* UTIL_H */
diff --git a/seitan-eater/.Makefile.swp b/seitan-eater/.Makefile.swp
new file mode 100644
index 0000000..dbffcaf
Binary files /dev/null and b/seitan-eater/.Makefile.swp differ
diff --git a/seitan-eater/Makefile b/seitan-eater/Makefile
new file mode 100644
index 0000000..c70433f
--- /dev/null
+++ b/seitan-eater/Makefile
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# seitan - Syscall Expressive Interpreter, Transformer and Notifier
+#
+# eater/Makefile - Makefile for seitan-eater
+#
+# Copyright 2023 Red Hat GmbH
+# Author: Alice Frosi <afrosi@redhat.com>
+
+COMMON_DIR :=../common
+SRCS := $(COMMON_DIR)/common.c eater.c
+HEADERS := $(COMMON_DIR)/common.h
+BIN := $(OUTDIR)eater
+CFLAGS += -Wall -Wextra -pedantic -I$(COMMON_DIR)
+
+eater: $(SRCS) $(HEADERS)
+	$(CC) $(CFLAGS) -o $(BIN) $(SRCS)
+
+all: eater
+
+clean:
+	rm -f $(BIN)
diff --git a/seitan-eater/eater.c b/seitan-eater/eater.c
new file mode 100644
index 0000000..96a7b61
--- /dev/null
+++ b/seitan-eater/eater.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+/* SEITAN - Syscall Expressive Interpreter, Transformer and Notifier
+ *
+ * src/eater/eater.c - Load BPF program and execute binary
+ *
+ * Copyright (c) 2022 Red Hat GmbH
+ * Authors: Stefano Brivio <sbrivio@redhat.com>, Alice Frosi <afrosi@redhat.com>
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <argp.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <sys/socket.h>
+#include <signal.h>
+
+#include <linux/audit.h>
+#include <linux/filter.h>
+#include <linux/seccomp.h>
+
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include "common.h"
+
+extern char **environ;
+
+static char doc[] =
+	"Usage: seitan-eater: setain-eater -i <input file> -- program args1 args2...";
+
+/* Eater options */
+static struct argp_option options[] = { { "input", 'i', "FILE", 0,
+					  "BPF filter input file", 0 },
+					{ 0 } };
+
+struct arguments {
+	char *input_file;
+	unsigned int program_index;
+};
+
+static error_t parse_opt(int key, char *arg, struct argp_state *state)
+{
+	struct arguments *arguments = state->input;
+
+	if (state->quoted == 0)
+		arguments->program_index = state->next + 1;
+	switch (key) {
+	case 'i':
+		if (state->quoted == 0)
+			arguments->input_file = arg;
+		break;
+	case ARGP_KEY_END:
+		if (arguments->input_file == NULL)
+			argp_error(state, "missing input file");
+		if (state->argv[arguments->program_index] == NULL)
+			argp_error(state, "missing program");
+		break;
+	}
+
+	return 0;
+}
+
+static struct argp argp = { .options = options,
+			    .parser = parse_opt,
+			    .args_doc = NULL,
+			    .doc = doc,
+			    .children = NULL,
+			    .help_filter = NULL,
+			    .argp_domain = NULL };
+
+static int seccomp(unsigned int operation, unsigned int flags, void *args)
+{
+	return syscall(__NR_seccomp, operation, flags, args);
+}
+
+static void signal_handler(__attribute__((unused)) int s)
+{
+}
+
+/**
+ * main() - Entry point
+ * @argc:	Argument count
+ * @argv:	Seitan-eater and program arguments
+ *
+ * Return: 0 once interrupted, non-zero on failure
+ */
+int main(int argc, char **argv)
+{
+	struct sock_filter filter[1024];
+	struct arguments arguments;
+	struct sock_fprog prog;
+	struct sigaction act;
+	size_t n;
+	int fd, flags;
+
+	argp_parse(&argp, argc, argv, 0, 0, &arguments);
+	fd = open(arguments.input_file, O_CLOEXEC | O_RDONLY);
+	n = read(fd, filter, sizeof(filter));
+	close(fd);
+
+	prog.filter = filter;
+	prog.len = (unsigned short)(n / sizeof(filter[0]));
+	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
+		perror("prctl");
+		exit(EXIT_FAILURE);
+	}
+	if (seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_NEW_LISTENER,
+		    &prog) < 0) {
+		perror("seccomp");
+		exit(EXIT_FAILURE);
+	}
+	/*
+	 * close-on-exec flag is set for the file descriptor by seccomp.
+	 * We want to preserve the fd on the exec in this way we are able
+	 * to easly find the notifier fd if seitan restarts.
+	 */
+	fd = find_fd_seccomp_notifier("/proc/self/fd");
+	flags = fcntl(fd, F_GETFD);
+	if (fcntl(fd, F_SETFD, flags & !FD_CLOEXEC) < 0) {
+		perror("fcntl");
+		exit(EXIT_FAILURE);
+	}
+	act.sa_handler = signal_handler;
+	sigaction(SIGCONT, &act, NULL);
+	pause();
+
+	execvpe(argv[arguments.program_index], &argv[arguments.program_index],
+		environ);
+	if (errno != ENOENT) {
+		perror("execvpe");
+		exit(EXIT_FAILURE);
+	}
+	close(fd);
+	return EXIT_FAILURE;
+}
diff --git a/seitan.c b/seitan.c
new file mode 100644
index 0000000..ff0c54b
--- /dev/null
+++ b/seitan.c
@@ -0,0 +1,435 @@
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+/* SEITAN - Syscall Expressive Interpreter, Transformer and Notifier
+ *
+ * src/seitan/seitan.c - Wait for processes, listen for syscalls, handle them
+ *
+ * Copyright (c) 2022 Red Hat GmbH
+ * Author: Stefano Brivio <sbrivio@redhat.com>, Alice Frosi <afrosi@redhat.com>
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/epoll.h>
+#include <sys/types.h>
+#include <argp.h>
+#include <linux/netlink.h>
+#include <linux/connector.h>
+#include <linux/cn_proc.h>
+
+#include <linux/audit.h>
+#include <linux/filter.h>
+#include <linux/seccomp.h>
+
+#include "common.h"
+#include "gluten.h"
+#include "operations.h"
+
+#define EPOLL_EVENTS 8
+#define errExit(msg)                \
+	do {                        \
+		perror(msg);        \
+		exit(EXIT_FAILURE); \
+	} while (0)
+
+static char doc[] = "Usage: seitan: setain -pid <pid> -i <input file> ";
+
+/* Seitan options */
+static struct argp_option options[] = {
+	{ "input", 'i', "FILE", 0, "Action input file", 0 },
+	{ "output", 'o', "FILE", 0, "Log filtered syscall in the file", 0 },
+	{ "pid", 'p', "pid", 0,
+	  "Pid of process to monitor (cannot be used together with -socket)",
+	  0 },
+	{ "socket", 's', "/tmp/seitan.sock", 0,
+	  "Socket to pass the seccomp notifier fd (cannot be used together with -pid)",
+	  0 },
+	{ 0 }
+};
+
+struct arguments {
+	char *input_file;
+	char *output_file;
+	char *socket;
+	int pid;
+};
+
+static error_t parse_opt(int key, char *arg, struct argp_state *state)
+{
+	struct arguments *arguments = state->input;
+
+	switch (key) {
+	case 'p':
+		arguments->pid = atoi(arg);
+		break;
+	case 'i':
+		arguments->input_file = arg;
+		break;
+	case 'o':
+		arguments->output_file = arg;
+		break;
+	case 's':
+		arguments->socket = arg;
+		break;
+	case ARGP_KEY_END:
+		if (arguments->input_file == NULL)
+			argp_error(state, "missing input file");
+		if (strcmp(arguments->socket, "") > 0 && arguments->pid > 0)
+			argp_error(
+				state,
+				"the -socket and -pid options cannot be used together");
+		break;
+	default:
+		return ARGP_ERR_UNKNOWN;
+	}
+
+	return 0;
+}
+
+static struct argp argp = { .options = options,
+			    .parser = parse_opt,
+			    .args_doc = NULL,
+			    .doc = doc,
+			    .children = NULL,
+			    .help_filter = NULL,
+			    .argp_domain = NULL };
+
+static int nl_init(void)
+{
+	int s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
+	struct sockaddr_nl sa = {
+		.nl_family = AF_NETLINK,
+		.nl_groups = CN_IDX_PROC,
+		.nl_pid = getpid(),
+	};
+	struct req_t {
+		struct nlmsghdr nlh;
+		struct cn_msg cnm;
+		enum proc_cn_mcast_op mop;
+	} __attribute__((packed, aligned(NLMSG_ALIGNTO))) req = {
+		.nlh.nlmsg_type = NLMSG_DONE,
+		.nlh.nlmsg_pid = getpid(),
+
+		.cnm.id.idx = CN_IDX_PROC,
+		.cnm.id.val = CN_VAL_PROC,
+		.cnm.len = sizeof(enum proc_cn_mcast_op),
+
+		.mop = PROC_CN_MCAST_LISTEN,
+	};
+
+	bind(s, (struct sockaddr *)&sa, sizeof(sa));
+
+	req.nlh.nlmsg_len = sizeof(req);
+	send(s, &req, sizeof(req), 0);
+
+	return s;
+}
+
+static int event(int s)
+{
+	char path[PATH_MAX + 1], exe[PATH_MAX + 1];
+	struct proc_event *ev;
+	struct nlmsghdr *nlh;
+	struct cn_msg *cnh;
+	char buf[BUFSIZ];
+	ssize_t n;
+
+	if ((n = recv(s, &buf, sizeof(buf), 0)) <= 0)
+		return -EIO;
+
+	nlh = (struct nlmsghdr *)buf;
+	for (; NLMSG_OK(nlh, n); nlh = NLMSG_NEXT(nlh, n)) {
+		if (nlh->nlmsg_type == NLMSG_NOOP)
+			continue;
+
+		if ((nlh->nlmsg_type == NLMSG_ERROR) ||
+		    (nlh->nlmsg_type == NLMSG_OVERRUN))
+			break;
+
+		cnh = NLMSG_DATA(nlh);
+		ev = (struct proc_event *)cnh->data;
+
+		if (ev->what != PROC_EVENT_EXEC)
+			continue;
+
+		snprintf(path, PATH_MAX, "/proc/%i/exe",
+			 ev->event_data.exec.process_pid);
+
+		readlink(path, exe, PATH_MAX);
+		if (!strcmp(exe, "/usr/local/bin/seitan-eater") ||
+		    !strcmp(exe, "/usr/bin/seitan-eater"))
+			return ev->event_data.exec.process_pid;
+
+		if (nlh->nlmsg_type == NLMSG_DONE)
+			break;
+	}
+
+	return -EAGAIN;
+}
+
+enum transform {
+	NONE,
+	FD1_UNIX,
+	FDRET_SRC,
+	DEV_CHECK,
+};
+
+struct table {
+	enum transform type;
+	long number;
+
+	char arg[6][1024];
+};
+
+static struct table t[16];
+
+static int pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
+			     unsigned int flags)
+{
+	return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
+}
+
+static void unblock_eater(int pidfd)
+{
+	if (pidfd_send_signal(pidfd, SIGCONT, NULL, 0) == -1) {
+		perror("pidfd_send_signal");
+		exit(EXIT_FAILURE);
+	}
+}
+
+int handle(struct seccomp_notif *req, int notifyfd)
+{
+	char path[PATH_MAX + 1];
+	struct sockaddr_un s_un;
+	int fd_unix;
+	unsigned i;
+	int mem;
+
+	for (i = 0; i < sizeof(t) / sizeof(t[0]); i++) {
+		if (t[i].number == req->data.nr)
+			break;
+	}
+
+	if (i == sizeof(t) / sizeof(t[0])) /* Not found */
+		return 1;
+
+	if (t[i].type != FD1_UNIX) /* Not implemented yet */
+		return 1;
+
+	/* FD1_UNIX here */
+	snprintf(path, sizeof(path), "/proc/%i/mem", req->pid);
+	fd_unix = req->data.args[0];
+
+	mem = open(path, O_RDONLY);
+	lseek(mem, req->data.args[1], SEEK_SET);
+	read(mem, &s_un, sizeof(s_un));
+	close(mem);
+
+	if (!strcmp(s_un.sun_path, t[i].arg[0])) {
+		int own_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+
+		struct seccomp_notif_addfd addfd = {
+			.id = req->id,
+			.flags = SECCOMP_ADDFD_FLAG_SEND |
+				 SECCOMP_ADDFD_FLAG_SETFD,
+			.srcfd = own_fd,
+			.newfd = fd_unix,
+		};
+
+		connect(own_fd, &s_un, sizeof(s_un));
+		ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int create_socket(const char *path)
+{
+	struct sockaddr_un addr;
+	int ret, conn;
+	int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0)
+		errExit("error creating UNIX socket");
+
+	strcpy(addr.sun_path, path);
+	addr.sun_family = AF_UNIX;
+	ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+	if (ret < 0)
+		errExit("bind");
+
+	ret = listen(fd, 1);
+	if (ret < 0)
+		errExit("listen");
+	conn = accept(fd, NULL, NULL);
+	if (conn < 0)
+		errExit("accept");
+
+	return conn;
+}
+
+static int recvfd(int sockfd)
+{
+	struct msghdr msgh;
+	struct iovec iov;
+	int data, fd;
+	ssize_t nr;
+
+	union {
+		char buf[CMSG_SPACE(sizeof(int))];
+		struct cmsghdr align;
+	} controlMsg;
+	struct cmsghdr *cmsgp;
+
+	msgh.msg_name = NULL;
+	msgh.msg_namelen = 0;
+
+	msgh.msg_iov = &iov;
+	msgh.msg_iovlen = 1;
+	iov.iov_base = &data;
+	iov.iov_len = sizeof(int);
+
+	msgh.msg_control = controlMsg.buf;
+	msgh.msg_controllen = sizeof(controlMsg.buf);
+
+	nr = recvmsg(sockfd, &msgh, 0);
+	if (nr == -1)
+		errExit("recvmsg");
+
+	cmsgp = CMSG_FIRSTHDR(&msgh);
+
+	if (cmsgp == NULL || cmsgp->cmsg_len != CMSG_LEN(sizeof(int)) ||
+	    cmsgp->cmsg_level != SOL_SOCKET || cmsgp->cmsg_type != SCM_RIGHTS) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	memcpy(&fd, CMSG_DATA(cmsgp), sizeof(int));
+	return fd;
+}
+
+static int write_syscall(int fd, struct seccomp_notif *req)
+{
+	char buf[1000];
+
+	/* TODO: Define format and print syscall with the right arguments */
+	snprintf(buf, sizeof(buf), "nr_syscall=%d\n", req->data.nr);
+	write(fd, buf, strlen(buf));
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int s = nl_init(), ret, pidfd, notifier;
+	char req_b[BUFSIZ];
+	struct epoll_event ev, events[EPOLL_EVENTS];
+	struct seccomp_notif *req = (struct seccomp_notif *)req_b;
+	struct arguments arguments;
+	char path[PATH_MAX + 1];
+	bool running = true;
+	bool output = false;
+	int fd, epollfd;
+	int notifierfd;
+	int nevents, i;
+	int fdout;
+
+	arguments.pid = -1;
+	argp_parse(&argp, argc, argv, 0, 0, &arguments);
+	fd = open(arguments.input_file, O_CLOEXEC | O_RDONLY);
+	read(fd, t, sizeof(t));
+	close(fd);
+
+	if (strcmp(arguments.output_file, "") > 0) {
+		output = true;
+		unlink(arguments.output_file);
+		if ((fdout = open(arguments.output_file,
+				  O_CREAT | O_RDWR | O_TRUNC)) < 0)
+			errExit("open");
+	}
+
+	if (arguments.pid > 0) {
+		if ((pidfd = syscall(SYS_pidfd_open, arguments.pid, 0)) < 0)
+			errExit("pidfd_open");
+		snprintf(path, sizeof(path), "/proc/%d/fd", arguments.pid);
+		if ((notifierfd = find_fd_seccomp_notifier(path)) < 0)
+			errExit("failed getting fd of the notifier");
+		if ((notifier = syscall(SYS_pidfd_getfd, pidfd, notifierfd,
+					0)) < 0)
+			errExit("pidfd_getfd");
+		/* Unblock seitan-loader */
+		unblock_eater(pidfd);
+	} else if (strcmp(arguments.socket, "") > 0) {
+		unlink(arguments.socket);
+		if ((fd = create_socket(arguments.socket)) < 0)
+			exit(EXIT_FAILURE);
+		if ((notifier = recvfd(fd)) < 0)
+			exit(EXIT_FAILURE);
+	} else {
+		while ((ret = event(s)) == -EAGAIN)
+			;
+		if (ret < 0)
+			exit(EXIT_FAILURE);
+	}
+	sleep(1);
+
+	if ((epollfd = epoll_create1(0)) < 0) {
+		perror("epoll_create");
+		exit(EXIT_FAILURE);
+	}
+	ev.events = EPOLLIN;
+	ev.data.fd = notifier;
+	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, notifier, &ev) == -1) {
+		perror("epoll_ctl: notifier");
+		exit(EXIT_FAILURE);
+	}
+
+	while (running) {
+		nevents = epoll_wait(epollfd, events, EPOLL_EVENTS, -1);
+		if (nevents < 0) {
+			perror("epoll_wait");
+			exit(EXIT_FAILURE);
+		}
+		memset(req, 0, sizeof(*req));
+		if (ioctl(notifier, SECCOMP_IOCTL_NOTIF_RECV, req) < 0)
+			errExit("recieving seccomp notification");
+		for (i = 0; i < nevents; ++i) {
+			if (events[i].events & EPOLLHUP) {
+				/* The notifier fd was closed by the target */
+				running = false;
+			} else if (notifier == events[i].data.fd) {
+				/*
+				 * TODO: remove until we parse correctly the
+				 * operations from the bytecode
+				 */
+				struct op operations[] = {
+					{ .type = OP_CONT },
+				};
+				if (do_operations(NULL, operations, req,
+						  sizeof(operations) /
+							  sizeof(operations[0]),
+						  req->pid, notifier,
+						  req->id) == -1)
+					errExit("failed executing operation");
+
+				if (output)
+					write_syscall(fdout, req);
+			}
+		}
+	}
+	if (strcmp(arguments.socket, "") > 0)
+		unlink(arguments.socket);
+}
diff --git a/src/common/common.c b/src/common/common.c
deleted file mode 100644
index a8f79a2..0000000
--- a/src/common/common.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-
-int find_fd_seccomp_notifier(const char *path)
-{
-	char entry[2 * PATH_MAX + 1];
-	char buf[PATH_MAX + 1];
-	struct dirent *dp;
-	ssize_t nbytes;
-	struct stat sb;
-	DIR *dirp;
-
-	if ((dirp = opendir(path)) == NULL) {
-		fprintf(stderr, "failed reading fds from proc: %s \n", path);
-		return -1;
-	}
-	while ((dp = readdir(dirp)) != NULL) {
-		snprintf(entry, sizeof(entry), "%s/%s", path, dp->d_name);
-		if (lstat(entry, &sb) == -1) {
-			perror("lstat");
-		}
-		/* Skip the entry if it isn't a symbolic link */
-		if (!S_ISLNK(sb.st_mode))
-			continue;
-
-		nbytes = readlink(entry, buf, PATH_MAX);
-		if (nbytes == -1) {
-			perror("readlink");
-		}
-		if (nbytes == PATH_MAX) {
-			perror("buffer overflow");
-			continue;
-		}
-		/*
-                 * From man proc: For  file  descriptors  that  have no
-                 * corresponding inode (e.g., file descriptors produced by
-                 * bpf(2)..), the  entry  will be a symbolic link with contents
-                 * of the form:
-                 *      anon_inode:<file-type>
-                 */
-		if (strstr(buf, "anon_inode:seccomp notify") != NULL)
-			return atoi(dp->d_name);
-	}
-	fprintf(stderr, "seccomp notifier not found in %s\n", path);
-	return -1;
-}
diff --git a/src/common/common.h b/src/common/common.h
deleted file mode 100644
index 487032b..0000000
--- a/src/common/common.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef COMMON_H_
-#define COMMON_H_
-
-int find_fd_seccomp_notifier(const char *pid);
-
-#endif
diff --git a/src/common/gluten.h b/src/common/gluten.h
deleted file mode 100644
index 8370cf5..0000000
--- a/src/common/gluten.h
+++ /dev/null
@@ -1,138 +0,0 @@
-#ifndef GLUTEN_H
-#define GLUTEN_H
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#define MAX_FD_INJECTED 10
-
-enum ns_spec_type {
-	NS_NONE,
-	NS_SPEC_TARGET,
-	NS_SPEC_PID,
-	NS_SPEC_PATH,
-};
-
-struct ns_spec {
-	enum ns_spec_type type;
-	union {
-		pid_t pid;
-		char *path;
-	};
-};
-
-/*
- * enum ns_type - Type of namespaces
- */
-enum ns_type {
-	NS_CGROUP,
-	NS_IPC,
-	NS_NET,
-	NS_MOUNT,
-	NS_PID,
-	NS_TIME,
-	NS_USER,
-	NS_UTS,
-};
-
-/*
- * struct op_context - Description of the context where the call needs to be executed
- * @ns:	Descrption of the each namespace where the call needs to be executed
- */
-struct op_context {
-	struct ns_spec ns[sizeof(enum ns_type)];
-};
-
-enum op_type {
-	OP_CALL,
-	OP_BLOCK,
-	OP_CONT,
-	OP_INJECT,
-	OP_INJECT_A,
-	OP_RETURN,
-	OP_COPY_ARGS,
-	OP_END,
-	OP_CMP,
-	OP_RESOLVEDFD,
-};
-
-enum value_type {
-	IMMEDIATE,
-	REFERENCE,
-};
-
-struct op_call {
-	long nr;
-	bool has_ret;
-	void *args[6];
-	struct op_context context;
-	uint16_t ret_off;
-};
-
-struct op_block {
-	int32_t error;
-};
-
-struct op_continue {
-	bool cont;
-};
-
-struct op_return {
-	enum value_type type;
-	union {
-		int64_t value;
-		uint16_t value_off;
-	};
-};
-
-struct fd_type {
-	enum value_type type;
-	union {
-		uint32_t fd;
-		uint16_t fd_off;
-	};
-};
-
-struct op_inject {
-	struct fd_type newfd;
-	struct fd_type oldfd;
-};
-
-struct copy_arg {
-	uint16_t args_off;
-	enum value_type type;
-	size_t size;
-};
-
-struct op_copy_args {
-	struct copy_arg args[6];
-};
-
-struct op_cmp {
-	uint16_t s1_off;
-	uint16_t s2_off;
-	size_t size;
-	unsigned int jmp;
-};
-
-struct op_resolvedfd {
-	uint16_t fd_off;
-	uint16_t path_off;
-	size_t path_size;
-	unsigned int jmp;
-};
-
-struct op {
-	enum op_type type;
-	union {
-		struct op_call call;
-		struct op_block block;
-		struct op_continue cont;
-		struct op_return ret;
-		struct op_inject inj;
-		struct op_copy_args copy;
-		struct op_cmp cmp;
-		struct op_resolvedfd resfd;
-	};
-};
-#endif /* GLUTEN_H */
diff --git a/src/cooker/Makefile b/src/cooker/Makefile
deleted file mode 100644
index 8741879..0000000
--- a/src/cooker/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# seitan - Syscall Expressive Interpreter, Transformer and Notifier
-#
-# cooker/Makefile - Makefile for seitan-cooker
-#
-# Copyright 2023 Red Hat GmbH
-# Author: Stefano Brivio <sbrivio@redhat.com>
-
-SRCS := calls.c emit.c gluten.c main.c parse.c parson.c util.c calls/net.c
-HEADERS := calls.h cooker.h emit.h gluten.h parse.h parson.h util.h calls/net.h
-BIN := $(OUTDIR)cooker
-
-cooker: $(SRCS) $(HEADERS)
-	$(CC) -O0 -g -Wall -Wextra -pedantic -std=c99 -o $(BIN) $(SRCS)
-
-all: cooker
-
-clean:
-	rm -f cooker
diff --git a/src/cooker/calls.c b/src/cooker/calls.c
deleted file mode 100644
index 74b5a06..0000000
--- a/src/cooker/calls.c
+++ /dev/null
@@ -1,18 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
- *
- * cooker/calls.c - Known syscall sets
- *
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#include "cooker.h"
-#include "calls.h"
-
-#include "calls/net.h"
-
-struct call *call_sets[] = {
-	syscalls_net, NULL,
-};
diff --git a/src/cooker/calls.h b/src/cooker/calls.h
deleted file mode 100644
index 5d46e14..0000000
--- a/src/cooker/calls.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#ifndef CALLS_H
-#define CALLS_H
-
-/**
- * struct call - Description of one known system call
- * @number:	Number from __NR_ macros, architecture dependent
- * @name:	Name for use in recipes
- * @args:	NULL-terminated array of argument descriptions
- */
-struct call {
-	long number;
-	const char *name;
-	struct arg *args;
-};
-
-extern struct call *call_sets[];
-
-#endif /* CALLS_H */
diff --git a/src/cooker/calls/net.c b/src/cooker/calls/net.c
deleted file mode 100644
index c0949cc..0000000
--- a/src/cooker/calls/net.c
+++ /dev/null
@@ -1,174 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
- *
- * cooker/calls/net.c - Description of known networking system calls
- *
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-/*
-fd = socket(family, type stream/dgram/..., protocol)
-fd = connect(fd, addr, addrlen)
-fd = accept(fd, addr, addrlen)
-n  = sendto(fd, buf, len, flags, dst addr, addrlen)
-n  = recvfrom(fd, buf, len, flags, src addr, addrlen)
-n  = sendmsg(fd, msg, flags)
-n  = recvmsg(fd, msg, flags)
-e  = shutdown(fd, rd/wr/rdwr)
-e  = bind(fd, addr, addrlen)
-e  = listen(fd, backlog)
-e  = getsockname(fd, bound addr, addrlen)
-e  = getpeername(fd, peer addr, addrlen)
-e  = socketpair(family, type stream/dgram/..., sockets[2])
-e  = setsockopt(fd, level, optname, *optval, optlen)
-e  = getsockopt(fd, level, optname, *optval, *optlen)
-n  = recvmmsg(fd, *msgvec, vlen, flags, *timeout)
-n  = sendmmsg(fd, *msgvec, vlen, flags)
-*/
-
-#include <asm-generic/unistd.h>
-#include <sys/syscall.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <linux/un.h>
-#include <linux/netlink.h>
-
-#include "../cooker.h"
-#include "../calls.h"
-
-static struct arg_num af[] = {
-	{ "unix",	AF_UNIX },
-	{ "ipv4",	AF_INET },
-	{ "ipv6",	AF_INET6 },
-	{ "netlink",	AF_NETLINK },
-	{ "packet",	AF_PACKET },
-	{ "vsock",	AF_VSOCK },
-	{ 0 },
-};
-
-static struct arg_num socket_types[] = {
-	{ "stream",	SOCK_STREAM },
-	{ "dgram",	SOCK_DGRAM },
-	{ "seq",	SOCK_SEQPACKET },
-	{ "raw",	SOCK_RAW },
-	{ "packet",	SOCK_PACKET },
-	{ 0 },
-};
-
-static struct arg_num socket_flags[] = {
-	{ "nonblock",	SOCK_NONBLOCK },
-	{ "cloexec",	SOCK_CLOEXEC },
-	{ 0 },
-};
-
-static struct arg_num protocols[] = {
-	{ "ip",		IPPROTO_IP },
-	{ "icmp",	IPPROTO_ICMP },
-	{ "igmp",	IPPROTO_IGMP },
-	{ "tcp",	IPPROTO_TCP },
-	{ "udp",	IPPROTO_UDP },
-	{ "ipv6",	IPPROTO_IPV6 },
-	{ "gre",	IPPROTO_GRE },
-	{ "esp",	IPPROTO_ESP },
-	{ "ah",		IPPROTO_AH },
-	{ "sctp",	IPPROTO_SCTP },
-	{ "udplite",	IPPROTO_UDPLITE },
-	{ "mpls",	IPPROTO_MPLS },
-	{ "raw",	IPPROTO_RAW },
-	{ "mptcp",	IPPROTO_MPTCP },
-	{ 0 },
-};
-
-static struct arg socket_args[] = {
-	{ 0, "family",		ARG_INT,	0, { .d_num = af } },
-	{ 1, "type",		ARG_INTMASK,	0, { .d_num = socket_types } },
-	{ 1, "flags",		ARG_INTFLAGS,	0, { .d_num = socket_flags } },
-	{ 2, "protocol",	ARG_INT,	0, { .d_num = protocols } },
-	{ 0 },
-};
-
-static struct arg_struct connect_addr_unix[] = {
-	{ "path",	ARG_STRING,
-		offsetof(struct sockaddr_un, sun_path),
-		UNIX_PATH_MAX,		{ 0 }
-	},
-	{ 0 },
-};
-
-static struct arg_struct connect_addr_ipv4[] = {
-	{ "port",	ARG_PORT,
-		offsetof(struct sockaddr_in, sin_port),
-		0,			{ 0 }
-	},
-	{ "addr",	ARG_IPV4,
-		offsetof(struct sockaddr_in, sin_addr),
-		0,			{ 0 }
-	},
-	{ 0 },
-};
-
-static struct arg_struct connect_addr_ipv6[] = {
-	{ "port",	ARG_PORT,
-		offsetof(struct sockaddr_in6, sin6_port),
-		0,			{ 0 }
-	},
-	{ "addr",	ARG_IPV6,
-		offsetof(struct sockaddr_in6, sin6_addr),
-		0,			{ 0 }
-	},
-	{ 0 },
-};
-
-static struct arg_struct connect_addr_nl[] = {
-	{ "pid",	ARG_PID,
-		offsetof(struct sockaddr_nl, nl_pid),
-		0,			{ 0 }
-	},
-	{ "groups",	ARG_U32,
-		offsetof(struct sockaddr_in6, sin6_addr),
-		0,			{ 0 }
-	},
-	{ 0 },
-};
-
-static struct arg_struct connect_family = {
-	"family",	ARG_INT,
-		offsetof(struct sockaddr, sa_family),
-		0,			{ .d_num = af }
-};
-
-static struct arg_select_num connect_addr_select_family[] = {
-	{ AF_UNIX,	ARG_STRUCT,	{ .d_struct = connect_addr_unix } },
-	{ AF_INET,	ARG_STRUCT,	{ .d_struct = connect_addr_ipv4 } },
-	{ AF_INET6,	ARG_STRUCT,	{ .d_struct = connect_addr_ipv6 } },
-	{ AF_NETLINK,	ARG_STRUCT,	{ .d_struct = connect_addr_nl } },
-	{ 0 },
-};
-
-static struct arg_select connect_addr_select = {
-	&connect_family, { .d_num = connect_addr_select_family }
-};
-
-static struct arg connect_args[] = {
-	{ 0, "fd",	ARG_INT,	0,
-		{ 0 },
-	},
-	{ 0, "path",	ARG_FDPATH,	0,
-		{ 0 },
-	},
-	{ 1, "addr",	ARG_SELECT,	sizeof(struct sockaddr_storage),
-		{ .d_select = &connect_addr_select },
-	},
-	{ 2, "addrlen",	ARG_LONG,	0,
-		{ 0 },
-	},
-};
-
-struct call syscalls_net[] = {
-	{ __NR_connect,		"connect",		connect_args },
-	{ __NR_socket,		"socket",		socket_args },
-	{ 0 },
-};
diff --git a/src/cooker/calls/net.h b/src/cooker/calls/net.h
deleted file mode 100644
index 105bf4a..0000000
--- a/src/cooker/calls/net.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#ifndef CALLS_NET_H
-#define CALLS_NET_H
-
-extern struct call syscalls_net[];
-
-#endif /* CALLS_NET_H */
diff --git a/src/cooker/cooker.h b/src/cooker/cooker.h
deleted file mode 100644
index 53aa0db..0000000
--- a/src/cooker/cooker.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#ifndef COOKER_H
-#define COOKER_H
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define REFS_MAX			256
-#define CALL_ARGS			6
-
-struct arg_num;
-struct arg_struct;
-struct arg_select;
-
-union arg_value {
-	struct arg_num		*d_num;
-	struct arg_struct	*d_struct;
-	struct arg_select	*d_select;
-};
-
-enum arg_type {
-	ARG_INT,
-	ARG_INTMASK,
-	ARG_INTFLAGS,
-
-	ARG_U32,
-	ARG_U32MASK,
-	ARG_U32FLAGS,
-
-	ARG_LONG,
-	ARG_LONGMASK,
-	ARG_LONGFLAGS,
-
-	ARG_STRING,
-
-	ARG_STRUCT,
-	ARG_SELECT,
-
-	ARG_PID,
-
-	ARG_PORT,
-	ARG_IPV4,
-	ARG_IPV6,
-
-	ARG_FDPATH,
-
-	ARG_TYPE_END,
-};
-
-#define ARG_TYPE_COUNT		(ARG_TYPE_END - 1)
-
-struct arg_num {
-	char *name;
-	long long value;
-};
-
-struct arg_struct {
-	char *name;
-	enum arg_type type;
-	size_t offset;
-
-	size_t strlen;
-
-	union arg_value desc;
-};
-
-struct arg_select_num {
-	long long value;
-
-	enum arg_type type;
-	union arg_value desc;
-};
-
-struct arg_select {
-	struct arg_struct *field;
-
-	union {
-		struct arg_select_num *d_num;
-	} desc;
-};
-
-struct arg {
-	int pos;
-	char *name;
-
-	enum arg_type type;
-	size_t size;
-
-	union arg_value desc;
-};
-
-#endif /* COOKER_H */
diff --git a/src/cooker/emit.c b/src/cooker/emit.c
deleted file mode 100644
index a82529c..0000000
--- a/src/cooker/emit.c
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
- *
- * cooker/emit.c - Generate gluten (bytecode) instructions
- *
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#include "cooker.h"
-#include "gluten.h"
-#include "util.h"
-
-int emit_nr(struct gluten_ctx *g, long number)
-{
-	debug("   %i: OP_NR %li, < >", g->ip++, number);
-
-	return 0;
-}
-
-int emit_load(struct gluten_ctx *g, int offset, int index, size_t len)
-{
-	debug("   %i: OP_LOAD #%i < %i (%lu)", g->ip++, offset, index, len);
-
-	return 0;
-}
diff --git a/src/cooker/emit.h b/src/cooker/emit.h
deleted file mode 100644
index 74264b1..0000000
--- a/src/cooker/emit.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#ifndef EMIT_H
-#define EMIT_H
-
-int emit_nr(struct gluten_ctx *g, long number);
-int emit_load(struct gluten_ctx *g, int offset, int index, size_t len);
-
-#endif /* EMIT_H */
diff --git a/src/cooker/example.hjson b/src/cooker/example.hjson
deleted file mode 100644
index 45ed339..0000000
--- a/src/cooker/example.hjson
+++ /dev/null
@@ -1,67 +0,0 @@
-[
-  {
-    "match": [ /* qemu-pr-helper and similar */
-      { "connect": { "addr": { "family": "unix", "path": "/var/run/pr-helper.sock" }, "fd": { "ref": "fd" } } }
-    ],
-    "call": { "connect": { "addr": { "family": "unix", "path": "/var/run/pr-helper.sock" }, "ret": "y" } },
-    "inject": { "what": "fd", "new": { "ref": "y" }, "old": { "ref": "fd" }, "return": 0 }
-  },
-  {
-    "match": [ /* qemu creates a tap interface */
-      { "ioctl": { "path": "/dev/net/tun", "request": "TUNSETIFF", "ifr": { "name": "tap0", "flags": "IFF_TUN" } } }
-    ],
-    "limit": { "scope": "process", "count": 1 },
-    "call": { "ioctl": { "request": "TUNSETIFF", "path": "/dev/net/tun", "ifr": { "name": "tap0", "flags": "IFF_TUN", "ret": "x" } } },
-    "return": { "ref": "x" }
-  },
-  {
-    "match": [ /* CVE-2022-0185-style */
-      { "unshare": { "flags": { "has": { "newuser": true, "newnet": false } } } }
-    ],
-    "block": { }
-  },
-  {
-    "match": [ /* passt */
-      { "unshare": { "flags": { "has": [ "ipc", "mount", "uts", "pid" ] } } }
-    ],
-    "block": { }
-  },
-  {
-    "match": [ /* Giuseppe's example */
-      { "mknod": { "path": { "ref": "path" }, "mode": "c", "major": 1, "minor": { "in": [ 3, 5, 7, 8, 9 ], "ref": "minor" } } }
-    ],
-    "context": { "userns": "init", "mountns": "caller" },
-    "call": { "mknod": { "path": { "ref": "path" }, "mode": "c", "major": 1, "minor": { "ref": "minor" }, "ret": "x" } },
-    "inject": { "what": "fd", "new": { "ref": "x" } },
-    "return": { "ref": "x" }
-  }
-]
-
-/*
- * INTFLAGS, LONGFLAGS, U32FLAGS
- *
- * "field": { "in": [ "ipc", "mount", "uts" ] }
- *   flags & set
- *   !!(flags & (ipc | mount | ns))
- *
- * "field": { "all": [ "ipc", "mount", "uts" ] }
- *   flags & set == set
- *   flags & (ipc | mount | ns) == (ipc | mount | ns)
- *
- * "field": { "not": [ "ipc", "mount", "uts" ] }
- *   !(flags & set)
- *
- * "field": { "ipc": false, "mount": true, "uts": false }
- *   flags & set == set
- *   !(flags & ipc) && (flags & mount) && !(flags & utc)
- *
- * "field": { "ipc" }
- *   flags == ipc
- *
- * INTMASK
- *   value = (target value & known values)
- *
- * INT, LONG, U32
- *   "arg": { "in": [ 0, 1 ] }
- *   arg == 0 || arg == 1
- */
diff --git a/src/cooker/example.hjson.license b/src/cooker/example.hjson.license
deleted file mode 100644
index 2e3bd69..0000000
--- a/src/cooker/example.hjson.license
+++ /dev/null
@@ -1,2 +0,0 @@
-SPDX-FileCopyrightText: 2023 Red Hat GmbH <sbrivio@redhat.com>
-SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/src/cooker/filter.c b/src/cooker/filter.c
deleted file mode 100644
index dbda7ca..0000000
--- a/src/cooker/filter.c
+++ /dev/null
@@ -1,299 +0,0 @@
-#define _GNU_SOURCE
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "numbers.h"
-#include "filter.h"
-
-#define N_SYSCALL sizeof(numbers) / sizeof(numbers[0])
-
-static int compare_key(const void *key, const void *base)
-{
-	return strcmp((const char *)key,
-		      ((struct syscall_numbers *)base)->name);
-}
-
-int compare_bpf_call_names(const void *a, const void *b)
-{
-	return strcmp(((struct bpf_call *)a)->name,
-		      ((struct bpf_call *)b)->name);
-}
-
-static int compare_table_nr(const void *a, const void *b)
-{
-	return (((struct syscall_entry *)a)->nr -
-		((struct syscall_entry *)b)->nr);
-}
-
-static unsigned int count_shift_right(unsigned int n)
-{
-	unsigned int i = 0;
-	for (; n > 0; i++) {
-		n = n >> 1;
-	}
-	return i;
-}
-
-static void insert_pair(int jumps[], int arr[], unsigned int level)
-{
-	unsigned int i_a, i;
-	for (i = 0; i < level; i++) {
-		i_a = 2 * i + 1;
-		if (arr[i_a] == EMPTY) {
-			jumps[i] = arr[i_a - 1];
-		} else {
-			jumps[i] = arr[i_a];
-		}
-	}
-}
-
-unsigned int left_child(unsigned int parent_index)
-{
-	unsigned int level = count_shift_right(parent_index + 1);
-	/* 2^(level) -1 gives the beginning of the next interval */
-	unsigned int next_interval = (1 << level) - 1;
-	/* 2^(level -1) -1  gives the beginning of the current interval */
-	unsigned begin = (1 << (level - 1)) - 1;
-	unsigned i = parent_index - begin;
-	return next_interval + 2 * i;
-}
-
-unsigned int right_child(unsigned int parent_index)
-{
-	return left_child(parent_index) + 1;
-}
-
-void create_lookup_nodes(int jumps[], unsigned int n)
-{
-	unsigned int i, index;
-	unsigned int old_interval, interval;
-
-	for (i = 0; i < MAX_JUMPS; i++)
-		jumps[i] = EMPTY;
-
-	if (n < 2) {
-		jumps[0] = 0;
-		return;
-	}
-	old_interval = 1 << count_shift_right(n - 1);
-	interval = old_interval >> 1;
-
-	/* first scan populate the last level of jumps */
-	for (i = interval - 1, index = 1; index < old_interval && index < n;
-	     i++, index += 2) {
-		jumps[i] = index;
-	}
-	if (n % 2 == 1) {
-		jumps[i] = index - 1;
-	}
-	for (old_interval = interval, interval = interval / 2; interval > 0;
-	     old_interval = interval, interval = interval / 2) {
-		insert_pair(&jumps[interval - 1], &jumps[old_interval - 1],
-			    interval);
-	}
-}
-
-long resolve_syscall_nr(const char *name)
-{
-	struct syscall_numbers *p;
-	p = (struct syscall_numbers *)bsearch(
-		name, numbers, sizeof(numbers) / sizeof(numbers[0]),
-		sizeof(numbers[0]), compare_key);
-	if (p == NULL)
-		return -1;
-	return p->number;
-}
-
-/*
- * Construct a syscall tables ordered by increasing syscall number
- * @returns number of syscall entries in the table
- */
-int construct_table(const struct bpf_call *entries, int n,
-		    struct syscall_entry *table)
-{
-	long nr;
-	unsigned int tn;
-	int i;
-
-	tn = 0;
-	for (i = 0; i < n; i++) {
-		table[i].count = 0;
-		table[i].entry = NULL;
-	}
-
-	for (i = 0; i < n; i++) {
-		if (tn > N_SYSCALL - 1)
-			return -1;
-		if (i > 0) {
-			if (strcmp((entries[i]).name, (entries[i - 1]).name) ==
-			    0) {
-				table[tn - 1].count++;
-				continue;
-			}
-		}
-		nr = resolve_syscall_nr((entries[i]).name);
-		if (nr < 0) {
-			fprintf(stderr, "wrong syscall number for %s\n",
-				(entries[i]).name);
-			continue;
-		}
-		table[tn].entry = &entries[i];
-		table[tn].count++;
-		table[tn].nr = nr;
-		tn++;
-	}
-	qsort(table, tn, sizeof(struct syscall_entry), compare_table_nr);
-
-	return tn;
-}
-
-static unsigned get_n_args(const struct syscall_entry *table)
-{
-	unsigned i, k, n;
-	n = 0;
-	for (i = 0; i < table->count; i++)
-		for (k = 0; k < 6; k++)
-			if ((table->entry + i)->check_arg[k])
-				n++;
-	return n;
-}
-
-static unsigned int get_total_args(const struct syscall_entry table[],
-				   unsigned int n_syscall)
-{
-	unsigned int i, n;
-	n = 0;
-	for (i = 0; i < n_syscall; i++) {
-		n += get_n_args(&table[i]);
-	}
-	return n;
-}
-
-unsigned int create_bpf_program_log(struct sock_filter filter[])
-{
-	filter[0] = (struct sock_filter)BPF_STMT(
-		BPF_LD | BPF_W | BPF_ABS,
-		(offsetof(struct seccomp_data, arch)));
-	filter[1] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,
-						 SEITAN_AUDIT_ARCH, 0, 1);
-	filter[2] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K,
-						 SECCOMP_RET_USER_NOTIF);
-	filter[3] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K,
-						 SECCOMP_RET_ALLOW);
-	return 4;
-}
-
-unsigned int create_bfp_program(struct syscall_entry table[],
-				struct sock_filter filter[],
-				unsigned int n_syscall)
-{
-	unsigned int offset_left, offset_right;
-	unsigned int n_args, n_nodes;
-	unsigned int notify, accept;
-	unsigned int i, j, k, size;
-	unsigned int next_offset;
-	int nodes[MAX_JUMPS];
-
-	create_lookup_nodes(nodes, n_syscall);
-
-	size = 3;
-	/* No nodes if there is a single syscall */
-	n_nodes = (1 << count_shift_right(n_syscall - 1)) - 1;
-
-	n_args = get_total_args(table, n_syscall);
-
-	accept = 2 + n_nodes + 2 * n_syscall + n_args + 1;
-	notify = 2 + n_nodes + 2 * n_syscall + n_args + 2;
-
-	/* Pre */
-	/* cppcheck-suppress badBitmaskCheck */
-	filter[0] = (struct sock_filter)BPF_STMT(
-		BPF_LD | BPF_W | BPF_ABS,
-		(offsetof(struct seccomp_data, arch)));
-	filter[1] = (struct sock_filter)BPF_JUMP(
-		BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 0, accept - 2);
-	/* cppcheck-suppress badBitmaskCheck */
-	filter[2] = (struct sock_filter)BPF_STMT(
-		BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr)));
-
-	/* Insert nodes */
-	for (i = 0; i < n_nodes; i++) {
-		if (nodes[i] == EMPTY) {
-			filter[size++] =
-				(struct sock_filter)JUMPA(accept - size);
-		} else {
-			offset_left = left_child(i) - i - 1;
-			offset_right = right_child(i) - i - 1;
-			filter[size++] = (struct sock_filter)JGE(
-				table[nodes[i]].nr, offset_right, offset_left);
-		}
-	}
-
-	next_offset = n_syscall - 1;
-	/* Insert leaves */
-	for (i = 0; i < n_syscall; i++) {
-		filter[size++] = (struct sock_filter)EQ(
-			table[i].nr, next_offset, accept - size);
-		next_offset += get_n_args(&table[i]);
-	}
-
-	/*
-	 * Insert args. Evaluate every args, if it doesn't match continue with
-	 * the following, otherwise notify.
-	 */
-	for (i = 0; i < n_syscall; i++) {
-		for (j = 0; j < (table[i]).count; j++) {
-			for (k = 0; k < 6; k++)
-				if ((table[i].entry + j)->check_arg[k]) {
-					filter[size++] = (struct sock_filter)EQ(
-						(table[i].entry + j)->args[k],
-						notify - size, 0);
-				}
-		}
-		filter[size++] = (struct sock_filter)JUMPA(accept - size);
-	}
-
-	/* Seccomp accept and notify instruction */
-	filter[size++] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K,
-						      SECCOMP_RET_ALLOW);
-	filter[size++] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K,
-						      SECCOMP_RET_USER_NOTIF);
-	return size;
-}
-
-static int compare_names(const void *a, const void *b)
-{
-	return strcmp(((struct syscall_numbers *)a)->name,
-		      ((struct syscall_numbers *)b)->name);
-}
-
-int convert_bpf(char *file, struct bpf_call *entries, int n, bool log)
-{
-	int nt, fd, fsize;
-	struct syscall_entry table[N_SYSCALL];
-	struct sock_filter filter[MAX_FILTER];
-
-	qsort(numbers, sizeof(numbers) / sizeof(numbers[0]), sizeof(numbers[0]),
-	      compare_names);
-
-	qsort(entries, n, sizeof(struct bpf_call), compare_bpf_call_names);
-	nt = construct_table(entries, n, table);
-
-	if (log)
-		fsize = create_bpf_program_log(filter);
-	else
-		fsize = create_bfp_program(table, filter, nt);
-
-	fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
-		  S_IRUSR | S_IWUSR);
-	write(fd, filter, sizeof(struct sock_filter) * fsize);
-
-	close(fd);
-
-	return 0;
-}
diff --git a/src/cooker/filter.h b/src/cooker/filter.h
deleted file mode 100644
index ee5ab12..0000000
--- a/src/cooker/filter.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef FILTER_H_
-#define FILTER_H_
-
-#include <linux/filter.h>
-#include <linux/audit.h>
-#include <linux/seccomp.h>
-
-#define JGE(nr, right, left) \
-	BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, (nr), (right), (left))
-#define JUMPA(jump) BPF_JUMP(BPF_JMP | BPF_JA, (jump), 0, 0)
-#define EQ(nr, a1, a2) BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (nr), (a1), (a2))
-
-#define MAX_FILTER 1024
-
-#define MAX_JUMPS 128
-#define EMPTY -1
-
-struct bpf_call {
-	char *name;
-	int args[6];
-	bool check_arg[6];
-};
-
-struct syscall_entry {
-	unsigned int count;
-	long nr;
-	const struct bpf_call *entry;
-};
-
-void create_lookup_nodes(int jumps[], unsigned int n);
-unsigned int left_child(unsigned int parent_index);
-unsigned int right_child(unsigned int parent_index);
-
-unsigned int create_bfp_program(struct syscall_entry table[],
-				struct sock_filter filter[],
-				unsigned int n_syscall);
-int convert_bpf(char *file, struct bpf_call *entries, int n, bool log);
-
-#endif
diff --git a/src/cooker/gluten.c b/src/cooker/gluten.c
deleted file mode 100644
index 1116e6b..0000000
--- a/src/cooker/gluten.c
+++ /dev/null
@@ -1,44 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
- *
- * cooker/gluten.c - gluten (bytecode) file and layout functions
- *
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#include "cooker.h"
-#include "gluten.h"
-#include "util.h"
-
-#define GLUTEN_INST_SIZE		BUFSIZ
-#define GLUTEN_DATA_SIZE		BUFSIZ
-
-static char gluten[GLUTEN_INST_SIZE + GLUTEN_DATA_SIZE];
-
-static size_t gluten_arg_storage[ARG_TYPE_COUNT] = {
-	[ARG_INT]	= sizeof(int),
-	[ARG_INTMASK]	= sizeof(int),
-};
-
-int gluten_alloc(struct gluten_ctx *g, size_t size)
-{
-	debug("   allocating %lu at offset %i", size, g->sp);
-	if ((g->sp += size) >= GLUTEN_DATA_SIZE)
-		die("Temporary data size exceeded");
-
-	return g->sp - size;
-}
-
-int gluten_alloc_type(struct gluten_ctx *g, enum arg_type type)
-{
-	return gluten_alloc(g, gluten_arg_storage[type]);
-}
-
-int gluten_init(struct gluten_ctx *g)
-{
-	g->gluten = gluten;
-
-	return 0;
-}
diff --git a/src/cooker/gluten.h b/src/cooker/gluten.h
deleted file mode 100644
index 440029d..0000000
--- a/src/cooker/gluten.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#ifndef GLUTEN_H
-#define GLUTEN_H
-
-struct gluten_arg_data {
-	int offset;
-	size_t len;
-};
-
-struct gluten_ref_data {
-	int name;
-	int offset;
-	size_t len;
-};
-
-struct gluten_ctx {
-	int ip;
-	int lr;
-	int sp;
-	char *gluten;
-
-	struct gluten_arg_data match_dst[CALL_ARGS];
-	struct gluten_arg_data call_src[CALL_ARGS];
-
-	struct gluten_ref_data refs[REFS_MAX];
-};
-
-int gluten_alloc(struct gluten_ctx *g, size_t size);
-int gluten_alloc_type(struct gluten_ctx *g, enum arg_type type);
-int gluten_init(struct gluten_ctx *g);
-
-#endif /* GLUTEN_H */
diff --git a/src/cooker/main.c b/src/cooker/main.c
deleted file mode 100644
index 9965cff..0000000
--- a/src/cooker/main.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
- *
- * cooker/main.c - Entry point of seitan-cooker, the gluten (bytecode) generator
- *
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#include "cooker.h"
-#include "gluten.h"
-#include "parse.h"
-
-int main(int argc, char **argv)
-{
-	struct gluten_ctx g = { 0 };
-
-	/* TODO: Options and usage */
-	(void)argc;
-	(void)argv;
-
-	gluten_init(&g);
-
-	parse_file(&g, argv[1]);
-
-	return 0;
-}
diff --git a/src/cooker/parse.c b/src/cooker/parse.c
deleted file mode 100644
index 9d8a7be..0000000
--- a/src/cooker/parse.c
+++ /dev/null
@@ -1,237 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
- *
- * cooker/parse.c - JSON recipe parsing
- *
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#include "parson.h"
-#include "calls.h"
-#include "cooker.h"
-#include "gluten.h"
-#include "emit.h"
-#include "util.h"
-
-#include "calls/net.h"
-
-struct rule_parser {
-	const char *type;
-	int (*fn)(struct gluten_ctx *g, JSON_Value *value);
-};
-
-static int parse_match_load(struct gluten_ctx *g, struct arg *a)
-{
-	if (!a->size || g->match_dst[a->pos].len)
-		return 0;
-
-	g->match_dst[a->pos].offset = gluten_alloc(g, a->size);
-	g->match_dst[a->pos].len = a->size;
-
-	emit_load(g, g->match_dst[a->pos].offset, a->pos, a->size);
-
-	return 0;
-}
-
-static long long parse_match_expr_num(struct arg_num *desc, JSON_Value *value)
-{
-	const char *s = NULL;
-	long long n;
-
-	if (desc) {
-		s = json_value_get_string(value);
-		for (; desc->name && s && strcmp(s, desc->name); desc++);
-		if (s && !desc->name)
-			die("   Invalid value %s", s);
-
-		n = desc->value;
-	}
-
-	if (!s) {
-		if (json_value_get_type(value) != JSONNumber)
-			die("   Invalid value type");
-
-		n = json_value_get_number(value);
-	}
-
-	return n;
-}
-
-static int parse_match_key(struct gluten_ctx *g, int index, enum arg_type type,
-			   union arg_value desc, JSON_Value *value)
-{
-	JSON_Object *tmp;
-	const char *ref;
-
-	(void)index;
-
-	if (json_value_get_type(value) == JSONObject &&
-	    (tmp = json_value_get_object(value)) &&
-	    (ref = json_object_get_string(tmp, "ref"))) {
-		debug("   setting reference '%s'", ref);
-		gluten_alloc_type(g, type);
-		value = json_object_get_value(tmp, "value");
-	}
-
-	if (!value)
-		return 0;
-
-	switch (type) {
-	case ARG_INTFLAGS:
-	case ARG_LONGFLAGS:
-	case ARG_U32FLAGS:
-		/* fetch/combine expr algebra loop */
-	case ARG_INTMASK:
-		/* calculate mask first */
-	case ARG_INT:
-	case ARG_LONG:
-	case ARG_U32:
-		parse_match_expr_num(desc.d_num, value);
-		//emit_cmp(...);
-	default:
-		;
-	}
-
-	return 0;
-}
-
-static int parse_match_arg(struct gluten_ctx *g, const char *name,
-			   JSON_Value *value, struct arg *a)
-{
-	debug("  Parsing match argument %s", name);
-
-	parse_match_load(g, a);
-	parse_match_key(g, a->pos, a->type, a->desc, value);
-
-	return 0;
-}
-
-static int parse_match(struct gluten_ctx *g, JSON_Object *obj, struct arg *args)
-{
-	unsigned count = 0;
-	struct arg *a;
-
-	for (a = args; a->name; a++) {
-		JSON_Value *value;
-
-		if ((value = json_object_get_value(obj, a->name))) {
-			count++;
-			parse_match_arg(g, a->name, value, a);
-		}
-	}
-
-	if (count != json_object_get_count(obj))
-		die("  Stray elements in match");
-
-	return 0;
-}
-
-static int parse_matches(struct gluten_ctx *g, JSON_Value *value)
-{
-	JSON_Array *matches = json_value_get_array(value);
-	unsigned i;
-
-	for (i = 0; i < json_array_get_count(matches); i++) {
-		JSON_Object *match, *args;
-		struct call **set, *call;
-		const char *name;
-
-		g->lr = g->ip;
-		g->sp = 0;
-
-		match = json_array_get_object(matches, i);
-		name = json_object_get_name(match, 0);
-		args = json_object_get_object(match, name);
-		debug(" Parsing match %i: %s", i, name);
-
-		for (set = call_sets, call = set[0]; *set; call++) {
-			if (!call->name) {
-				set++;
-				continue;
-			}
-
-			if (!strcmp(name, call->name)) {
-				debug("  Found handler for %s", name);
-				emit_nr(g, call->number);
-
-				parse_match(g, args, call->args);
-				break;
-			}
-		}
-
-		if (!*set)
-			die("  Unknown system call: %s", name);
-	}
-
-	return 0;
-}
-
-static int parse_call(struct gluten_ctx *g, JSON_Value *value)
-{
-	(void)g;
-	(void)value;
-	return 0;
-}
-
-static int parse_inject(struct gluten_ctx *g, JSON_Value *value)
-{
-	(void)g;
-	(void)value;
-	return 0;
-}
-
-struct rule_parser parsers[] = {
-	{ "match", parse_matches },
-	{ "call", parse_call },
-	{ "inject", parse_inject },
-	{ NULL, NULL },
-};
-
-static int parse_block(struct gluten_ctx *g, JSON_Object *block)
-{
-	unsigned i;
-
-	for (i = 0; i < json_object_get_count(block); i++) {
-		struct rule_parser *parser;
-		JSON_Value *rule;
-		const char *type;
-
-		type = json_object_get_name(block, i);
-		rule = json_object_get_value(block, type);
-
-		for (parser = parsers; parser->type; parser++) {
-			if (!strcmp(type, parser->type)) {
-				parser->fn(g, rule);
-				break;
-			}
-		}
-
-		if (!parser->type)
-			die(" Invalid rule type: \"%s\"", type);
-	}
-
-	return 0;
-}
-
-int parse_file(struct gluten_ctx *g, const char *path)
-{
-	JSON_Array *blocks;
-	JSON_Value *root;
-	JSON_Object *obj;
-	unsigned i;
-
-	root = json_parse_file_with_comments(path);
-	if (json_value_get_type(root) != JSONArray)
-		die("Invalid input file %s", path);
-
-	blocks = json_value_get_array(root);
-	for (i = 0; i < json_array_get_count(blocks); i++) {
-		obj = json_array_get_object(blocks, i);
-		debug("Parsing block %i", i);
-		parse_block(g, obj);
-	}
-
-	return 0;
-}
diff --git a/src/cooker/parse.h b/src/cooker/parse.h
deleted file mode 100644
index cb4a2f2..0000000
--- a/src/cooker/parse.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#ifndef PARSE_H
-#define PARSE_H
-
-int parse_file(struct gluten_ctx *g, const char *path);
-
-#endif /* PARSE_H */
diff --git a/src/cooker/parson.c b/src/cooker/parson.c
deleted file mode 100644
index a7a844a..0000000
--- a/src/cooker/parson.c
+++ /dev/null
@@ -1,2080 +0,0 @@
-/*
- SPDX-License-Identifier: MIT
-
- Parson ( http://kgabis.github.com/parson/ )
- Copyright (c) 2012 - 2019 Krzysztof Gabis
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-*/
-#ifdef _MSC_VER
-#ifndef _CRT_SECURE_NO_WARNINGS
-#define _CRT_SECURE_NO_WARNINGS
-#endif /* _CRT_SECURE_NO_WARNINGS */
-#endif /* _MSC_VER */
-
-#include "parson.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <math.h>
-#include <errno.h>
-
-/* Apparently sscanf is not implemented in some "standard" libraries, so don't use it, if you
- * don't have to. */
-#define sscanf THINK_TWICE_ABOUT_USING_SSCANF
-
-#define STARTING_CAPACITY 16
-#define MAX_NESTING       2048
-
-#define FLOAT_FORMAT "%1.17g" /* do not increase precision without incresing NUM_BUF_SIZE */
-#define NUM_BUF_SIZE 64 /* double printed with "%1.17g" shouldn't be longer than 25 bytes so let's be paranoid and use 64 */
-
-#define SIZEOF_TOKEN(a)       (sizeof(a) - 1)
-#define SKIP_CHAR(str)        ((*str)++)
-#define SKIP_WHITESPACES(str) while (isspace((unsigned char)(**str))) { SKIP_CHAR(str); }
-#define MAX(a, b)             ((a) > (b) ? (a) : (b))
-
-#undef malloc
-#undef free
-
-#if defined(isnan) && defined(isinf)
-#define IS_NUMBER_INVALID(x) (isnan((x)) || isinf((x)))
-#else
-#define IS_NUMBER_INVALID(x) (((x) * 0.0) != 0.0)
-#endif
-
-static JSON_Malloc_Function parson_malloc = malloc;
-static JSON_Free_Function parson_free = free;
-
-static int parson_escape_slashes = 1;
-
-#define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */
-
-/* Type definitions */
-typedef union json_value_value {
-    char        *string;
-    double       number;
-    JSON_Object *object;
-    JSON_Array  *array;
-    int          boolean;
-    int          null;
-} JSON_Value_Value;
-
-struct json_value_t {
-    JSON_Value      *parent;
-    JSON_Value_Type  type;
-    JSON_Value_Value value;
-};
-
-struct json_object_t {
-    JSON_Value  *wrapping_value;
-    char       **names;
-    JSON_Value **values;
-    size_t       count;
-    size_t       capacity;
-};
-
-struct json_array_t {
-    JSON_Value  *wrapping_value;
-    JSON_Value **items;
-    size_t       count;
-    size_t       capacity;
-};
-
-/* Various */
-static char * read_file(const char *filename);
-static void   remove_comments(char *string, const char *start_token, const char *end_token);
-static char * parson_strndup(const char *string, size_t n);
-static char * parson_strdup(const char *string);
-static int    hex_char_to_int(char c);
-static int    parse_utf16_hex(const char *string, unsigned int *result);
-static int    num_bytes_in_utf8_sequence(unsigned char c);
-static int    verify_utf8_sequence(const unsigned char *string, int *len);
-static int    is_valid_utf8(const char *string, size_t string_len);
-static int    is_decimal(const char *string, size_t length);
-
-/* JSON Object */
-static JSON_Object * json_object_init(JSON_Value *wrapping_value);
-static JSON_Status   json_object_add(JSON_Object *object, const char *name, JSON_Value *value);
-static JSON_Status   json_object_addn(JSON_Object *object, const char *name, size_t name_len, JSON_Value *value);
-static JSON_Status   json_object_resize(JSON_Object *object, size_t new_capacity);
-static JSON_Value  * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len);
-static JSON_Status   json_object_remove_internal(JSON_Object *object, const char *name, int free_value);
-static JSON_Status   json_object_dotremove_internal(JSON_Object *object, const char *name, int free_value);
-static void          json_object_free(JSON_Object *object);
-
-/* JSON Array */
-static JSON_Array * json_array_init(JSON_Value *wrapping_value);
-static JSON_Status  json_array_add(JSON_Array *array, JSON_Value *value);
-static JSON_Status  json_array_resize(JSON_Array *array, size_t new_capacity);
-static void         json_array_free(JSON_Array *array);
-
-/* JSON Value */
-static JSON_Value * json_value_init_string_no_copy(char *string);
-
-/* Parser */
-static JSON_Status  skip_quotes(const char **string);
-static int          parse_utf16(const char **unprocessed, char **processed);
-static char *       process_string(const char *input, size_t len);
-static char *       get_quoted_string(const char **string);
-static JSON_Value * parse_object_value(const char **string, size_t nesting);
-static JSON_Value * parse_array_value(const char **string, size_t nesting);
-static JSON_Value * parse_string_value(const char **string);
-static JSON_Value * parse_boolean_value(const char **string);
-static JSON_Value * parse_number_value(const char **string);
-static JSON_Value * parse_null_value(const char **string);
-static JSON_Value * parse_value(const char **string, size_t nesting);
-
-/* Serialization */
-static int    json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf);
-static int    json_serialize_string(const char *string, char *buf);
-static int    append_indent(char *buf, int level);
-static int    append_string(char *buf, const char *string);
-
-/* Various */
-static char * parson_strndup(const char *string, size_t n) {
-    char *output_string = (char*)parson_malloc(n + 1);
-    if (!output_string) {
-        return NULL;
-    }
-    output_string[n] = '\0';
-    strncpy(output_string, string, n);
-    return output_string;
-}
-
-static char * parson_strdup(const char *string) {
-    return parson_strndup(string, strlen(string));
-}
-
-static int hex_char_to_int(char c) {
-    if (c >= '0' && c <= '9') {
-        return c - '0';
-    } else if (c >= 'a' && c <= 'f') {
-        return c - 'a' + 10;
-    } else if (c >= 'A' && c <= 'F') {
-        return c - 'A' + 10;
-    }
-    return -1;
-}
-
-static int parse_utf16_hex(const char *s, unsigned int *result) {
-    int x1, x2, x3, x4;
-    if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0' || s[3] == '\0') {
-        return 0;
-    }
-    x1 = hex_char_to_int(s[0]);
-    x2 = hex_char_to_int(s[1]);
-    x3 = hex_char_to_int(s[2]);
-    x4 = hex_char_to_int(s[3]);
-    if (x1 == -1 || x2 == -1 || x3 == -1 || x4 == -1) {
-        return 0;
-    }
-    *result = (unsigned int)((x1 << 12) | (x2 << 8) | (x3 << 4) | x4);
-    return 1;
-}
-
-static int num_bytes_in_utf8_sequence(unsigned char c) {
-    if (c == 0xC0 || c == 0xC1 || c > 0xF4 || IS_CONT(c)) {
-        return 0;
-    } else if ((c & 0x80) == 0) {    /* 0xxxxxxx */
-        return 1;
-    } else if ((c & 0xE0) == 0xC0) { /* 110xxxxx */
-        return 2;
-    } else if ((c & 0xF0) == 0xE0) { /* 1110xxxx */
-        return 3;
-    } else if ((c & 0xF8) == 0xF0) { /* 11110xxx */
-        return 4;
-    }
-    return 0; /* won't happen */
-}
-
-static int verify_utf8_sequence(const unsigned char *string, int *len) {
-    unsigned int cp = 0;
-    *len = num_bytes_in_utf8_sequence(string[0]);
-
-    if (*len == 1) {
-        cp = string[0];
-    } else if (*len == 2 && IS_CONT(string[1])) {
-        cp = string[0] & 0x1F;
-        cp = (cp << 6) | (string[1] & 0x3F);
-    } else if (*len == 3 && IS_CONT(string[1]) && IS_CONT(string[2])) {
-        cp = ((unsigned char)string[0]) & 0xF;
-        cp = (cp << 6) | (string[1] & 0x3F);
-        cp = (cp << 6) | (string[2] & 0x3F);
-    } else if (*len == 4 && IS_CONT(string[1]) && IS_CONT(string[2]) && IS_CONT(string[3])) {
-        cp = string[0] & 0x7;
-        cp = (cp << 6) | (string[1] & 0x3F);
-        cp = (cp << 6) | (string[2] & 0x3F);
-        cp = (cp << 6) | (string[3] & 0x3F);
-    } else {
-        return 0;
-    }
-
-    /* overlong encodings */
-    if ((cp < 0x80    && *len > 1) ||
-        (cp < 0x800   && *len > 2) ||
-        (cp < 0x10000 && *len > 3)) {
-        return 0;
-    }
-
-    /* invalid unicode */
-    if (cp > 0x10FFFF) {
-        return 0;
-    }
-
-    /* surrogate halves */
-    if (cp >= 0xD800 && cp <= 0xDFFF) {
-        return 0;
-    }
-
-    return 1;
-}
-
-static int is_valid_utf8(const char *string, size_t string_len) {
-    int len = 0;
-    const char *string_end =  string + string_len;
-    while (string < string_end) {
-        if (!verify_utf8_sequence((const unsigned char*)string, &len)) {
-            return 0;
-        }
-        string += len;
-    }
-    return 1;
-}
-
-static int is_decimal(const char *string, size_t length) {
-    if (length > 1 && string[0] == '0' && string[1] != '.') {
-        return 0;
-    }
-    if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') {
-        return 0;
-    }
-    while (length--) {
-        if (strchr("xX", string[length])) {
-            return 0;
-        }
-    }
-    return 1;
-}
-
-static char * read_file(const char * filename) {
-    FILE *fp = fopen(filename, "r");
-    size_t size_to_read = 0;
-    size_t size_read = 0;
-    long pos;
-    char *file_contents;
-    if (!fp) {
-        return NULL;
-    }
-    fseek(fp, 0L, SEEK_END);
-    pos = ftell(fp);
-    if (pos < 0) {
-        fclose(fp);
-        return NULL;
-    }
-    size_to_read = pos;
-    rewind(fp);
-    file_contents = (char*)parson_malloc(sizeof(char) * (size_to_read + 1));
-    if (!file_contents) {
-        fclose(fp);
-        return NULL;
-    }
-    size_read = fread(file_contents, 1, size_to_read, fp);
-    if (size_read == 0 || ferror(fp)) {
-        fclose(fp);
-        parson_free(file_contents);
-        return NULL;
-    }
-    fclose(fp);
-    file_contents[size_read] = '\0';
-    return file_contents;
-}
-
-static void remove_comments(char *string, const char *start_token, const char *end_token) {
-    int in_string = 0, escaped = 0;
-    size_t i;
-    char *ptr = NULL, current_char;
-    size_t start_token_len = strlen(start_token);
-    size_t end_token_len = strlen(end_token);
-    if (start_token_len == 0 || end_token_len == 0) {
-        return;
-    }
-    while ((current_char = *string) != '\0') {
-        if (current_char == '\\' && !escaped) {
-            escaped = 1;
-            string++;
-            continue;
-        } else if (current_char == '\"' && !escaped) {
-            in_string = !in_string;
-        } else if (!in_string && strncmp(string, start_token, start_token_len) == 0) {
-            for(i = 0; i < start_token_len; i++) {
-                string[i] = ' ';
-            }
-            string = string + start_token_len;
-            ptr = strstr(string, end_token);
-            if (!ptr) {
-                return;
-            }
-            for (i = 0; i < (ptr - string) + end_token_len; i++) {
-                string[i] = ' ';
-            }
-            string = ptr + end_token_len - 1;
-        }
-        escaped = 0;
-        string++;
-    }
-}
-
-/* JSON Object */
-static JSON_Object * json_object_init(JSON_Value *wrapping_value) {
-    JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object));
-    if (new_obj == NULL) {
-        return NULL;
-    }
-    new_obj->wrapping_value = wrapping_value;
-    new_obj->names = (char**)NULL;
-    new_obj->values = (JSON_Value**)NULL;
-    new_obj->capacity = 0;
-    new_obj->count = 0;
-    return new_obj;
-}
-
-static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value) {
-    if (name == NULL) {
-        return JSONFailure;
-    }
-    return json_object_addn(object, name, strlen(name), value);
-}
-
-static JSON_Status json_object_addn(JSON_Object *object, const char *name, size_t name_len, JSON_Value *value) {
-    size_t index = 0;
-    if (object == NULL || name == NULL || value == NULL) {
-        return JSONFailure;
-    }
-    if (json_object_getn_value(object, name, name_len) != NULL) {
-        return JSONFailure;
-    }
-    if (object->count >= object->capacity) {
-        size_t new_capacity = MAX(object->capacity * 2, STARTING_CAPACITY);
-        if (json_object_resize(object, new_capacity) == JSONFailure) {
-            return JSONFailure;
-        }
-    }
-    index = object->count;
-    object->names[index] = parson_strndup(name, name_len);
-    if (object->names[index] == NULL) {
-        return JSONFailure;
-    }
-    value->parent = json_object_get_wrapping_value(object);
-    object->values[index] = value;
-    object->count++;
-    return JSONSuccess;
-}
-
-static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity) {
-    char **temp_names = NULL;
-    JSON_Value **temp_values = NULL;
-
-    if ((object->names == NULL && object->values != NULL) ||
-        (object->names != NULL && object->values == NULL) ||
-        new_capacity == 0) {
-            return JSONFailure; /* Shouldn't happen */
-    }
-    temp_names = (char**)parson_malloc(new_capacity * sizeof(char*));
-    if (temp_names == NULL) {
-        return JSONFailure;
-    }
-    temp_values = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*));
-    if (temp_values == NULL) {
-        parson_free(temp_names);
-        return JSONFailure;
-    }
-    if (object->names != NULL && object->values != NULL && object->count > 0) {
-        memcpy(temp_names, object->names, object->count * sizeof(char*));
-        memcpy(temp_values, object->values, object->count * sizeof(JSON_Value*));
-    }
-    parson_free(object->names);
-    parson_free(object->values);
-    object->names = temp_names;
-    object->values = temp_values;
-    object->capacity = new_capacity;
-    return JSONSuccess;
-}
-
-static JSON_Value * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len) {
-    size_t i, name_length;
-    for (i = 0; i < json_object_get_count(object); i++) {
-        name_length = strlen(object->names[i]);
-        if (name_length != name_len) {
-            continue;
-        }
-        if (strncmp(object->names[i], name, name_len) == 0) {
-            return object->values[i];
-        }
-    }
-    return NULL;
-}
-
-static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, int free_value) {
-    size_t i = 0, last_item_index = 0;
-    if (object == NULL || json_object_get_value(object, name) == NULL) {
-        return JSONFailure;
-    }
-    last_item_index = json_object_get_count(object) - 1;
-    for (i = 0; i < json_object_get_count(object); i++) {
-        if (strcmp(object->names[i], name) == 0) {
-            parson_free(object->names[i]);
-            if (free_value) {
-                json_value_free(object->values[i]);
-            }
-            if (i != last_item_index) { /* Replace key value pair with one from the end */
-                object->names[i] = object->names[last_item_index];
-                object->values[i] = object->values[last_item_index];
-            }
-            object->count -= 1;
-            return JSONSuccess;
-        }
-    }
-    return JSONFailure; /* No execution path should end here */
-}
-
-static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, int free_value) {
-    JSON_Value *temp_value = NULL;
-    JSON_Object *temp_object = NULL;
-    const char *dot_pos = strchr(name, '.');
-    if (dot_pos == NULL) {
-        return json_object_remove_internal(object, name, free_value);
-    }
-    temp_value = json_object_getn_value(object, name, dot_pos - name);
-    if (json_value_get_type(temp_value) != JSONObject) {
-        return JSONFailure;
-    }
-    temp_object = json_value_get_object(temp_value);
-    return json_object_dotremove_internal(temp_object, dot_pos + 1, free_value);
-}
-
-static void json_object_free(JSON_Object *object) {
-    size_t i;
-    for (i = 0; i < object->count; i++) {
-        parson_free(object->names[i]);
-        json_value_free(object->values[i]);
-    }
-    parson_free(object->names);
-    parson_free(object->values);
-    parson_free(object);
-}
-
-/* JSON Array */
-static JSON_Array * json_array_init(JSON_Value *wrapping_value) {
-    JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array));
-    if (new_array == NULL) {
-        return NULL;
-    }
-    new_array->wrapping_value = wrapping_value;
-    new_array->items = (JSON_Value**)NULL;
-    new_array->capacity = 0;
-    new_array->count = 0;
-    return new_array;
-}
-
-static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value) {
-    if (array->count >= array->capacity) {
-        size_t new_capacity = MAX(array->capacity * 2, STARTING_CAPACITY);
-        if (json_array_resize(array, new_capacity) == JSONFailure) {
-            return JSONFailure;
-        }
-    }
-    value->parent = json_array_get_wrapping_value(array);
-    array->items[array->count] = value;
-    array->count++;
-    return JSONSuccess;
-}
-
-static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity) {
-    JSON_Value **new_items = NULL;
-    if (new_capacity == 0) {
-        return JSONFailure;
-    }
-    new_items = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*));
-    if (new_items == NULL) {
-        return JSONFailure;
-    }
-    if (array->items != NULL && array->count > 0) {
-        memcpy(new_items, array->items, array->count * sizeof(JSON_Value*));
-    }
-    parson_free(array->items);
-    array->items = new_items;
-    array->capacity = new_capacity;
-    return JSONSuccess;
-}
-
-static void json_array_free(JSON_Array *array) {
-    size_t i;
-    for (i = 0; i < array->count; i++) {
-        json_value_free(array->items[i]);
-    }
-    parson_free(array->items);
-    parson_free(array);
-}
-
-/* JSON Value */
-static JSON_Value * json_value_init_string_no_copy(char *string) {
-    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
-    if (!new_value) {
-        return NULL;
-    }
-    new_value->parent = NULL;
-    new_value->type = JSONString;
-    new_value->value.string = string;
-    return new_value;
-}
-
-/* Parser */
-static JSON_Status skip_quotes(const char **string) {
-    if (**string != '\"') {
-        return JSONFailure;
-    }
-    SKIP_CHAR(string);
-    while (**string != '\"') {
-        if (**string == '\0') {
-            return JSONFailure;
-        } else if (**string == '\\') {
-            SKIP_CHAR(string);
-            if (**string == '\0') {
-                return JSONFailure;
-            }
-        }
-        SKIP_CHAR(string);
-    }
-    SKIP_CHAR(string);
-    return JSONSuccess;
-}
-
-static int parse_utf16(const char **unprocessed, char **processed) {
-    unsigned int cp, lead, trail;
-    int parse_succeeded = 0;
-    char *processed_ptr = *processed;
-    const char *unprocessed_ptr = *unprocessed;
-    unprocessed_ptr++; /* skips u */
-    parse_succeeded = parse_utf16_hex(unprocessed_ptr, &cp);
-    if (!parse_succeeded) {
-        return JSONFailure;
-    }
-    if (cp < 0x80) {
-        processed_ptr[0] = (char)cp; /* 0xxxxxxx */
-    } else if (cp < 0x800) {
-        processed_ptr[0] = ((cp >> 6) & 0x1F) | 0xC0; /* 110xxxxx */
-        processed_ptr[1] = ((cp)      & 0x3F) | 0x80; /* 10xxxxxx */
-        processed_ptr += 1;
-    } else if (cp < 0xD800 || cp > 0xDFFF) {
-        processed_ptr[0] = ((cp >> 12) & 0x0F) | 0xE0; /* 1110xxxx */
-        processed_ptr[1] = ((cp >> 6)  & 0x3F) | 0x80; /* 10xxxxxx */
-        processed_ptr[2] = ((cp)       & 0x3F) | 0x80; /* 10xxxxxx */
-        processed_ptr += 2;
-    } else if (cp >= 0xD800 && cp <= 0xDBFF) { /* lead surrogate (0xD800..0xDBFF) */
-        lead = cp;
-        unprocessed_ptr += 4; /* should always be within the buffer, otherwise previous sscanf would fail */
-        if (*unprocessed_ptr++ != '\\' || *unprocessed_ptr++ != 'u') {
-            return JSONFailure;
-        }
-        parse_succeeded = parse_utf16_hex(unprocessed_ptr, &trail);
-        if (!parse_succeeded || trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */
-            return JSONFailure;
-        }
-        cp = ((((lead - 0xD800) & 0x3FF) << 10) | ((trail - 0xDC00) & 0x3FF)) + 0x010000;
-        processed_ptr[0] = (((cp >> 18) & 0x07) | 0xF0); /* 11110xxx */
-        processed_ptr[1] = (((cp >> 12) & 0x3F) | 0x80); /* 10xxxxxx */
-        processed_ptr[2] = (((cp >> 6)  & 0x3F) | 0x80); /* 10xxxxxx */
-        processed_ptr[3] = (((cp)       & 0x3F) | 0x80); /* 10xxxxxx */
-        processed_ptr += 3;
-    } else { /* trail surrogate before lead surrogate */
-        return JSONFailure;
-    }
-    unprocessed_ptr += 3;
-    *processed = processed_ptr;
-    *unprocessed = unprocessed_ptr;
-    return JSONSuccess;
-}
-
-
-/* Copies and processes passed string up to supplied length.
-Example: "\u006Corem ipsum" -> lorem ipsum */
-static char* process_string(const char *input, size_t len) {
-    const char *input_ptr = input;
-    size_t initial_size = (len + 1) * sizeof(char);
-    size_t final_size = 0;
-    char *output = NULL, *output_ptr = NULL, *resized_output = NULL;
-    output = (char*)parson_malloc(initial_size);
-    if (output == NULL) {
-        goto error;
-    }
-    output_ptr = output;
-    while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < len) {
-        if (*input_ptr == '\\') {
-            input_ptr++;
-            switch (*input_ptr) {
-                case '\"': *output_ptr = '\"'; break;
-                case '\\': *output_ptr = '\\'; break;
-                case '/':  *output_ptr = '/';  break;
-                case 'b':  *output_ptr = '\b'; break;
-                case 'f':  *output_ptr = '\f'; break;
-                case 'n':  *output_ptr = '\n'; break;
-                case 'r':  *output_ptr = '\r'; break;
-                case 't':  *output_ptr = '\t'; break;
-                case 'u':
-                    if (parse_utf16(&input_ptr, &output_ptr) == JSONFailure) {
-                        goto error;
-                    }
-                    break;
-                default:
-                    goto error;
-            }
-        } else if ((unsigned char)*input_ptr < 0x20) {
-            goto error; /* 0x00-0x19 are invalid characters for json string (http://www.ietf.org/rfc/rfc4627.txt) */
-        } else {
-            *output_ptr = *input_ptr;
-        }
-        output_ptr++;
-        input_ptr++;
-    }
-    *output_ptr = '\0';
-    /* resize to new length */
-    final_size = (size_t)(output_ptr-output) + 1;
-    /* todo: don't resize if final_size == initial_size */
-    resized_output = (char*)parson_malloc(final_size);
-    if (resized_output == NULL) {
-        goto error;
-    }
-    memcpy(resized_output, output, final_size);
-    parson_free(output);
-    return resized_output;
-error:
-    parson_free(output);
-    return NULL;
-}
-
-/* Return processed contents of a string between quotes and
-   skips passed argument to a matching quote. */
-static char * get_quoted_string(const char **string) {
-    const char *string_start = *string;
-    size_t string_len = 0;
-    JSON_Status status = skip_quotes(string);
-    if (status != JSONSuccess) {
-        return NULL;
-    }
-    string_len = *string - string_start - 2; /* length without quotes */
-    return process_string(string_start + 1, string_len);
-}
-
-static JSON_Value * parse_value(const char **string, size_t nesting) {
-    if (nesting > MAX_NESTING) {
-        return NULL;
-    }
-    SKIP_WHITESPACES(string);
-    switch (**string) {
-        case '{':
-            return parse_object_value(string, nesting + 1);
-        case '[':
-            return parse_array_value(string, nesting + 1);
-        case '\"':
-            return parse_string_value(string);
-        case 'f': case 't':
-            return parse_boolean_value(string);
-        case '-':
-        case '0': case '1': case '2': case '3': case '4':
-        case '5': case '6': case '7': case '8': case '9':
-            return parse_number_value(string);
-        case 'n':
-            return parse_null_value(string);
-        default:
-            return NULL;
-    }
-}
-
-static JSON_Value * parse_object_value(const char **string, size_t nesting) {
-    JSON_Value *output_value = NULL, *new_value = NULL;
-    JSON_Object *output_object = NULL;
-    char *new_key = NULL;
-    output_value = json_value_init_object();
-    if (output_value == NULL) {
-        return NULL;
-    }
-    if (**string != '{') {
-        json_value_free(output_value);
-        return NULL;
-    }
-    output_object = json_value_get_object(output_value);
-    SKIP_CHAR(string);
-    SKIP_WHITESPACES(string);
-    if (**string == '}') { /* empty object */
-        SKIP_CHAR(string);
-        return output_value;
-    }
-    while (**string != '\0') {
-        new_key = get_quoted_string(string);
-        if (new_key == NULL) {
-            json_value_free(output_value);
-            return NULL;
-        }
-        SKIP_WHITESPACES(string);
-        if (**string != ':') {
-            parson_free(new_key);
-            json_value_free(output_value);
-            return NULL;
-        }
-        SKIP_CHAR(string);
-        new_value = parse_value(string, nesting);
-        if (new_value == NULL) {
-            parson_free(new_key);
-            json_value_free(output_value);
-            return NULL;
-        }
-        if (json_object_add(output_object, new_key, new_value) == JSONFailure) {
-            parson_free(new_key);
-            json_value_free(new_value);
-            json_value_free(output_value);
-            return NULL;
-        }
-        parson_free(new_key);
-        SKIP_WHITESPACES(string);
-        if (**string != ',') {
-            break;
-        }
-        SKIP_CHAR(string);
-        SKIP_WHITESPACES(string);
-    }
-    SKIP_WHITESPACES(string);
-    if (**string != '}' || /* Trim object after parsing is over */
-        json_object_resize(output_object, json_object_get_count(output_object)) == JSONFailure) {
-            json_value_free(output_value);
-            return NULL;
-    }
-    SKIP_CHAR(string);
-    return output_value;
-}
-
-static JSON_Value * parse_array_value(const char **string, size_t nesting) {
-    JSON_Value *output_value = NULL, *new_array_value = NULL;
-    JSON_Array *output_array = NULL;
-    output_value = json_value_init_array();
-    if (output_value == NULL) {
-        return NULL;
-    }
-    if (**string != '[') {
-        json_value_free(output_value);
-        return NULL;
-    }
-    output_array = json_value_get_array(output_value);
-    SKIP_CHAR(string);
-    SKIP_WHITESPACES(string);
-    if (**string == ']') { /* empty array */
-        SKIP_CHAR(string);
-        return output_value;
-    }
-    while (**string != '\0') {
-        new_array_value = parse_value(string, nesting);
-        if (new_array_value == NULL) {
-            json_value_free(output_value);
-            return NULL;
-        }
-        if (json_array_add(output_array, new_array_value) == JSONFailure) {
-            json_value_free(new_array_value);
-            json_value_free(output_value);
-            return NULL;
-        }
-        SKIP_WHITESPACES(string);
-        if (**string != ',') {
-            break;
-        }
-        SKIP_CHAR(string);
-        SKIP_WHITESPACES(string);
-    }
-    SKIP_WHITESPACES(string);
-    if (**string != ']' || /* Trim array after parsing is over */
-        json_array_resize(output_array, json_array_get_count(output_array)) == JSONFailure) {
-            json_value_free(output_value);
-            return NULL;
-    }
-    SKIP_CHAR(string);
-    return output_value;
-}
-
-static JSON_Value * parse_string_value(const char **string) {
-    JSON_Value *value = NULL;
-    char *new_string = get_quoted_string(string);
-    if (new_string == NULL) {
-        return NULL;
-    }
-    value = json_value_init_string_no_copy(new_string);
-    if (value == NULL) {
-        parson_free(new_string);
-        return NULL;
-    }
-    return value;
-}
-
-static JSON_Value * parse_boolean_value(const char **string) {
-    size_t true_token_size = SIZEOF_TOKEN("true");
-    size_t false_token_size = SIZEOF_TOKEN("false");
-    if (strncmp("true", *string, true_token_size) == 0) {
-        *string += true_token_size;
-        return json_value_init_boolean(1);
-    } else if (strncmp("false", *string, false_token_size) == 0) {
-        *string += false_token_size;
-        return json_value_init_boolean(0);
-    }
-    return NULL;
-}
-
-static JSON_Value * parse_number_value(const char **string) {
-    char *end;
-    double number = 0;
-    errno = 0;
-    number = strtod(*string, &end);
-    if (errno || !is_decimal(*string, end - *string)) {
-        return NULL;
-    }
-    *string = end;
-    return json_value_init_number(number);
-}
-
-static JSON_Value * parse_null_value(const char **string) {
-    size_t token_size = SIZEOF_TOKEN("null");
-    if (strncmp("null", *string, token_size) == 0) {
-        *string += token_size;
-        return json_value_init_null();
-    }
-    return NULL;
-}
-
-/* Serialization */
-#define APPEND_STRING(str) do { written = append_string(buf, (str));\
-                                if (written < 0) { return -1; }\
-                                if (buf != NULL) { buf += written; }\
-                                written_total += written; } while(0)
-
-#define APPEND_INDENT(level) do { written = append_indent(buf, (level));\
-                                  if (written < 0) { return -1; }\
-                                  if (buf != NULL) { buf += written; }\
-                                  written_total += written; } while(0)
-
-static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf)
-{
-    const char *key = NULL, *string = NULL;
-    JSON_Value *temp_value = NULL;
-    JSON_Array *array = NULL;
-    JSON_Object *object = NULL;
-    size_t i = 0, count = 0;
-    double num = 0.0;
-    int written = -1, written_total = 0;
-
-    switch (json_value_get_type(value)) {
-        case JSONArray:
-            array = json_value_get_array(value);
-            count = json_array_get_count(array);
-            APPEND_STRING("[");
-            if (count > 0 && is_pretty) {
-                APPEND_STRING("\n");
-            }
-            for (i = 0; i < count; i++) {
-                if (is_pretty) {
-                    APPEND_INDENT(level+1);
-                }
-                temp_value = json_array_get_value(array, i);
-                written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf);
-                if (written < 0) {
-                    return -1;
-                }
-                if (buf != NULL) {
-                    buf += written;
-                }
-                written_total += written;
-                if (i < (count - 1)) {
-                    APPEND_STRING(",");
-                }
-                if (is_pretty) {
-                    APPEND_STRING("\n");
-                }
-            }
-            if (count > 0 && is_pretty) {
-                APPEND_INDENT(level);
-            }
-            APPEND_STRING("]");
-            return written_total;
-        case JSONObject:
-            object = json_value_get_object(value);
-            count  = json_object_get_count(object);
-            APPEND_STRING("{");
-            if (count > 0 && is_pretty) {
-                APPEND_STRING("\n");
-            }
-            for (i = 0; i < count; i++) {
-                key = json_object_get_name(object, i);
-                if (key == NULL) {
-                    return -1;
-                }
-                if (is_pretty) {
-                    APPEND_INDENT(level+1);
-                }
-                written = json_serialize_string(key, buf);
-                if (written < 0) {
-                    return -1;
-                }
-                if (buf != NULL) {
-                    buf += written;
-                }
-                written_total += written;
-                APPEND_STRING(":");
-                if (is_pretty) {
-                    APPEND_STRING(" ");
-                }
-                temp_value = json_object_get_value(object, key);
-                written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf);
-                if (written < 0) {
-                    return -1;
-                }
-                if (buf != NULL) {
-                    buf += written;
-                }
-                written_total += written;
-                if (i < (count - 1)) {
-                    APPEND_STRING(",");
-                }
-                if (is_pretty) {
-                    APPEND_STRING("\n");
-                }
-            }
-            if (count > 0 && is_pretty) {
-                APPEND_INDENT(level);
-            }
-            APPEND_STRING("}");
-            return written_total;
-        case JSONString:
-            string = json_value_get_string(value);
-            if (string == NULL) {
-                return -1;
-            }
-            written = json_serialize_string(string, buf);
-            if (written < 0) {
-                return -1;
-            }
-            if (buf != NULL) {
-                buf += written;
-            }
-            written_total += written;
-            return written_total;
-        case JSONBoolean:
-            if (json_value_get_boolean(value)) {
-                APPEND_STRING("true");
-            } else {
-                APPEND_STRING("false");
-            }
-            return written_total;
-        case JSONNumber:
-            num = json_value_get_number(value);
-            if (buf != NULL) {
-                num_buf = buf;
-            }
-            written = sprintf(num_buf, FLOAT_FORMAT, num);
-            if (written < 0) {
-                return -1;
-            }
-            if (buf != NULL) {
-                buf += written;
-            }
-            written_total += written;
-            return written_total;
-        case JSONNull:
-            APPEND_STRING("null");
-            return written_total;
-        case JSONError:
-            return -1;
-        default:
-            return -1;
-    }
-}
-
-static int json_serialize_string(const char *string, char *buf) {
-    size_t i = 0, len = strlen(string);
-    char c = '\0';
-    int written = -1, written_total = 0;
-    APPEND_STRING("\"");
-    for (i = 0; i < len; i++) {
-        c = string[i];
-        switch (c) {
-            case '\"': APPEND_STRING("\\\""); break;
-            case '\\': APPEND_STRING("\\\\"); break;
-            case '\b': APPEND_STRING("\\b"); break;
-            case '\f': APPEND_STRING("\\f"); break;
-            case '\n': APPEND_STRING("\\n"); break;
-            case '\r': APPEND_STRING("\\r"); break;
-            case '\t': APPEND_STRING("\\t"); break;
-            case '\x00': APPEND_STRING("\\u0000"); break;
-            case '\x01': APPEND_STRING("\\u0001"); break;
-            case '\x02': APPEND_STRING("\\u0002"); break;
-            case '\x03': APPEND_STRING("\\u0003"); break;
-            case '\x04': APPEND_STRING("\\u0004"); break;
-            case '\x05': APPEND_STRING("\\u0005"); break;
-            case '\x06': APPEND_STRING("\\u0006"); break;
-            case '\x07': APPEND_STRING("\\u0007"); break;
-            /* '\x08' duplicate: '\b' */
-            /* '\x09' duplicate: '\t' */
-            /* '\x0a' duplicate: '\n' */
-            case '\x0b': APPEND_STRING("\\u000b"); break;
-            /* '\x0c' duplicate: '\f' */
-            /* '\x0d' duplicate: '\r' */
-            case '\x0e': APPEND_STRING("\\u000e"); break;
-            case '\x0f': APPEND_STRING("\\u000f"); break;
-            case '\x10': APPEND_STRING("\\u0010"); break;
-            case '\x11': APPEND_STRING("\\u0011"); break;
-            case '\x12': APPEND_STRING("\\u0012"); break;
-            case '\x13': APPEND_STRING("\\u0013"); break;
-            case '\x14': APPEND_STRING("\\u0014"); break;
-            case '\x15': APPEND_STRING("\\u0015"); break;
-            case '\x16': APPEND_STRING("\\u0016"); break;
-            case '\x17': APPEND_STRING("\\u0017"); break;
-            case '\x18': APPEND_STRING("\\u0018"); break;
-            case '\x19': APPEND_STRING("\\u0019"); break;
-            case '\x1a': APPEND_STRING("\\u001a"); break;
-            case '\x1b': APPEND_STRING("\\u001b"); break;
-            case '\x1c': APPEND_STRING("\\u001c"); break;
-            case '\x1d': APPEND_STRING("\\u001d"); break;
-            case '\x1e': APPEND_STRING("\\u001e"); break;
-            case '\x1f': APPEND_STRING("\\u001f"); break;
-            case '/':
-                if (parson_escape_slashes) {
-                    APPEND_STRING("\\/");  /* to make json embeddable in xml\/html */
-                } else {
-                    APPEND_STRING("/");
-                }
-                break;
-            default:
-                if (buf != NULL) {
-                    buf[0] = c;
-                    buf += 1;
-                }
-                written_total += 1;
-                break;
-        }
-    }
-    APPEND_STRING("\"");
-    return written_total;
-}
-
-static int append_indent(char *buf, int level) {
-    int i;
-    int written = -1, written_total = 0;
-    for (i = 0; i < level; i++) {
-        APPEND_STRING("    ");
-    }
-    return written_total;
-}
-
-static int append_string(char *buf, const char *string) {
-    if (buf == NULL) {
-        return (int)strlen(string);
-    }
-    return sprintf(buf, "%s", string);
-}
-
-#undef APPEND_STRING
-#undef APPEND_INDENT
-
-/* Parser API */
-JSON_Value * json_parse_file(const char *filename) {
-    char *file_contents = read_file(filename);
-    JSON_Value *output_value = NULL;
-    if (file_contents == NULL) {
-        return NULL;
-    }
-    output_value = json_parse_string(file_contents);
-    parson_free(file_contents);
-    return output_value;
-}
-
-JSON_Value * json_parse_file_with_comments(const char *filename) {
-    char *file_contents = read_file(filename);
-    JSON_Value *output_value = NULL;
-    if (file_contents == NULL) {
-        return NULL;
-    }
-    output_value = json_parse_string_with_comments(file_contents);
-    parson_free(file_contents);
-    return output_value;
-}
-
-JSON_Value * json_parse_string(const char *string) {
-    if (string == NULL) {
-        return NULL;
-    }
-    if (string[0] == '\xEF' && string[1] == '\xBB' && string[2] == '\xBF') {
-        string = string + 3; /* Support for UTF-8 BOM */
-    }
-    return parse_value((const char**)&string, 0);
-}
-
-JSON_Value * json_parse_string_with_comments(const char *string) {
-    JSON_Value *result = NULL;
-    char *string_mutable_copy = NULL, *string_mutable_copy_ptr = NULL;
-    string_mutable_copy = parson_strdup(string);
-    if (string_mutable_copy == NULL) {
-        return NULL;
-    }
-    remove_comments(string_mutable_copy, "/*", "*/");
-    remove_comments(string_mutable_copy, "//", "\n");
-    string_mutable_copy_ptr = string_mutable_copy;
-    result = parse_value((const char**)&string_mutable_copy_ptr, 0);
-    parson_free(string_mutable_copy);
-    return result;
-}
-
-/* JSON Object API */
-
-JSON_Value * json_object_get_value(const JSON_Object *object, const char *name) {
-    if (object == NULL || name == NULL) {
-        return NULL;
-    }
-    return json_object_getn_value(object, name, strlen(name));
-}
-
-const char * json_object_get_string(const JSON_Object *object, const char *name) {
-    return json_value_get_string(json_object_get_value(object, name));
-}
-
-double json_object_get_number(const JSON_Object *object, const char *name) {
-    return json_value_get_number(json_object_get_value(object, name));
-}
-
-JSON_Object * json_object_get_object(const JSON_Object *object, const char *name) {
-    return json_value_get_object(json_object_get_value(object, name));
-}
-
-JSON_Array * json_object_get_array(const JSON_Object *object, const char *name) {
-    return json_value_get_array(json_object_get_value(object, name));
-}
-
-int json_object_get_boolean(const JSON_Object *object, const char *name) {
-    return json_value_get_boolean(json_object_get_value(object, name));
-}
-
-JSON_Value * json_object_dotget_value(const JSON_Object *object, const char *name) {
-    const char *dot_position = strchr(name, '.');
-    if (!dot_position) {
-        return json_object_get_value(object, name);
-    }
-    object = json_value_get_object(json_object_getn_value(object, name, dot_position - name));
-    return json_object_dotget_value(object, dot_position + 1);
-}
-
-const char * json_object_dotget_string(const JSON_Object *object, const char *name) {
-    return json_value_get_string(json_object_dotget_value(object, name));
-}
-
-double json_object_dotget_number(const JSON_Object *object, const char *name) {
-    return json_value_get_number(json_object_dotget_value(object, name));
-}
-
-JSON_Object * json_object_dotget_object(const JSON_Object *object, const char *name) {
-    return json_value_get_object(json_object_dotget_value(object, name));
-}
-
-JSON_Array * json_object_dotget_array(const JSON_Object *object, const char *name) {
-    return json_value_get_array(json_object_dotget_value(object, name));
-}
-
-int json_object_dotget_boolean(const JSON_Object *object, const char *name) {
-    return json_value_get_boolean(json_object_dotget_value(object, name));
-}
-
-size_t json_object_get_count(const JSON_Object *object) {
-    return object ? object->count : 0;
-}
-
-const char * json_object_get_name(const JSON_Object *object, size_t index) {
-    if (object == NULL || index >= json_object_get_count(object)) {
-        return NULL;
-    }
-    return object->names[index];
-}
-
-JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index) {
-    if (object == NULL || index >= json_object_get_count(object)) {
-        return NULL;
-    }
-    return object->values[index];
-}
-
-JSON_Value *json_object_get_wrapping_value(const JSON_Object *object) {
-    return object->wrapping_value;
-}
-
-int json_object_has_value (const JSON_Object *object, const char *name) {
-    return json_object_get_value(object, name) != NULL;
-}
-
-int json_object_has_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type) {
-    JSON_Value *val = json_object_get_value(object, name);
-    return val != NULL && json_value_get_type(val) == type;
-}
-
-int json_object_dothas_value (const JSON_Object *object, const char *name) {
-    return json_object_dotget_value(object, name) != NULL;
-}
-
-int json_object_dothas_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type) {
-    JSON_Value *val = json_object_dotget_value(object, name);
-    return val != NULL && json_value_get_type(val) == type;
-}
-
-/* JSON Array API */
-JSON_Value * json_array_get_value(const JSON_Array *array, size_t index) {
-    if (array == NULL || index >= json_array_get_count(array)) {
-        return NULL;
-    }
-    return array->items[index];
-}
-
-const char * json_array_get_string(const JSON_Array *array, size_t index) {
-    return json_value_get_string(json_array_get_value(array, index));
-}
-
-double json_array_get_number(const JSON_Array *array, size_t index) {
-    return json_value_get_number(json_array_get_value(array, index));
-}
-
-JSON_Object * json_array_get_object(const JSON_Array *array, size_t index) {
-    return json_value_get_object(json_array_get_value(array, index));
-}
-
-JSON_Array * json_array_get_array(const JSON_Array *array, size_t index) {
-    return json_value_get_array(json_array_get_value(array, index));
-}
-
-int json_array_get_boolean(const JSON_Array *array, size_t index) {
-    return json_value_get_boolean(json_array_get_value(array, index));
-}
-
-size_t json_array_get_count(const JSON_Array *array) {
-    return array ? array->count : 0;
-}
-
-JSON_Value * json_array_get_wrapping_value(const JSON_Array *array) {
-    return array->wrapping_value;
-}
-
-/* JSON Value API */
-JSON_Value_Type json_value_get_type(const JSON_Value *value) {
-    return value ? value->type : JSONError;
-}
-
-JSON_Object * json_value_get_object(const JSON_Value *value) {
-    return json_value_get_type(value) == JSONObject ? value->value.object : NULL;
-}
-
-JSON_Array * json_value_get_array(const JSON_Value *value) {
-    return json_value_get_type(value) == JSONArray ? value->value.array : NULL;
-}
-
-const char * json_value_get_string(const JSON_Value *value) {
-    return json_value_get_type(value) == JSONString ? value->value.string : NULL;
-}
-
-double json_value_get_number(const JSON_Value *value) {
-    return json_value_get_type(value) == JSONNumber ? value->value.number : 0;
-}
-
-int json_value_get_boolean(const JSON_Value *value) {
-    return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1;
-}
-
-JSON_Value * json_value_get_parent (const JSON_Value *value) {
-    return value ? value->parent : NULL;
-}
-
-void json_value_free(JSON_Value *value) {
-    switch (json_value_get_type(value)) {
-        case JSONObject:
-            json_object_free(value->value.object);
-            break;
-        case JSONString:
-            parson_free(value->value.string);
-            break;
-        case JSONArray:
-            json_array_free(value->value.array);
-            break;
-        default:
-            break;
-    }
-    parson_free(value);
-}
-
-JSON_Value * json_value_init_object(void) {
-    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
-    if (!new_value) {
-        return NULL;
-    }
-    new_value->parent = NULL;
-    new_value->type = JSONObject;
-    new_value->value.object = json_object_init(new_value);
-    if (!new_value->value.object) {
-        parson_free(new_value);
-        return NULL;
-    }
-    return new_value;
-}
-
-JSON_Value * json_value_init_array(void) {
-    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
-    if (!new_value) {
-        return NULL;
-    }
-    new_value->parent = NULL;
-    new_value->type = JSONArray;
-    new_value->value.array = json_array_init(new_value);
-    if (!new_value->value.array) {
-        parson_free(new_value);
-        return NULL;
-    }
-    return new_value;
-}
-
-JSON_Value * json_value_init_string(const char *string) {
-    char *copy = NULL;
-    JSON_Value *value;
-    size_t string_len = 0;
-    if (string == NULL) {
-        return NULL;
-    }
-    string_len = strlen(string);
-    if (!is_valid_utf8(string, string_len)) {
-        return NULL;
-    }
-    copy = parson_strndup(string, string_len);
-    if (copy == NULL) {
-        return NULL;
-    }
-    value = json_value_init_string_no_copy(copy);
-    if (value == NULL) {
-        parson_free(copy);
-    }
-    return value;
-}
-
-JSON_Value * json_value_init_number(double number) {
-    JSON_Value *new_value = NULL;
-    if (IS_NUMBER_INVALID(number)) {
-        return NULL;
-    }
-    new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
-    if (new_value == NULL) {
-        return NULL;
-    }
-    new_value->parent = NULL;
-    new_value->type = JSONNumber;
-    new_value->value.number = number;
-    return new_value;
-}
-
-JSON_Value * json_value_init_boolean(int boolean) {
-    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
-    if (!new_value) {
-        return NULL;
-    }
-    new_value->parent = NULL;
-    new_value->type = JSONBoolean;
-    new_value->value.boolean = boolean ? 1 : 0;
-    return new_value;
-}
-
-JSON_Value * json_value_init_null(void) {
-    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
-    if (!new_value) {
-        return NULL;
-    }
-    new_value->parent = NULL;
-    new_value->type = JSONNull;
-    return new_value;
-}
-
-JSON_Value * json_value_deep_copy(const JSON_Value *value) {
-    size_t i = 0;
-    JSON_Value *return_value = NULL, *temp_value_copy = NULL, *temp_value = NULL;
-    const char *temp_string = NULL, *temp_key = NULL;
-    char *temp_string_copy = NULL;
-    JSON_Array *temp_array = NULL, *temp_array_copy = NULL;
-    JSON_Object *temp_object = NULL, *temp_object_copy = NULL;
-
-    switch (json_value_get_type(value)) {
-        case JSONArray:
-            temp_array = json_value_get_array(value);
-            return_value = json_value_init_array();
-            if (return_value == NULL) {
-                return NULL;
-            }
-            temp_array_copy = json_value_get_array(return_value);
-            for (i = 0; i < json_array_get_count(temp_array); i++) {
-                temp_value = json_array_get_value(temp_array, i);
-                temp_value_copy = json_value_deep_copy(temp_value);
-                if (temp_value_copy == NULL) {
-                    json_value_free(return_value);
-                    return NULL;
-                }
-                if (json_array_add(temp_array_copy, temp_value_copy) == JSONFailure) {
-                    json_value_free(return_value);
-                    json_value_free(temp_value_copy);
-                    return NULL;
-                }
-            }
-            return return_value;
-        case JSONObject:
-            temp_object = json_value_get_object(value);
-            return_value = json_value_init_object();
-            if (return_value == NULL) {
-                return NULL;
-            }
-            temp_object_copy = json_value_get_object(return_value);
-            for (i = 0; i < json_object_get_count(temp_object); i++) {
-                temp_key = json_object_get_name(temp_object, i);
-                temp_value = json_object_get_value(temp_object, temp_key);
-                temp_value_copy = json_value_deep_copy(temp_value);
-                if (temp_value_copy == NULL) {
-                    json_value_free(return_value);
-                    return NULL;
-                }
-                if (json_object_add(temp_object_copy, temp_key, temp_value_copy) == JSONFailure) {
-                    json_value_free(return_value);
-                    json_value_free(temp_value_copy);
-                    return NULL;
-                }
-            }
-            return return_value;
-        case JSONBoolean:
-            return json_value_init_boolean(json_value_get_boolean(value));
-        case JSONNumber:
-            return json_value_init_number(json_value_get_number(value));
-        case JSONString:
-            temp_string = json_value_get_string(value);
-            if (temp_string == NULL) {
-                return NULL;
-            }
-            temp_string_copy = parson_strdup(temp_string);
-            if (temp_string_copy == NULL) {
-                return NULL;
-            }
-            return_value = json_value_init_string_no_copy(temp_string_copy);
-            if (return_value == NULL) {
-                parson_free(temp_string_copy);
-            }
-            return return_value;
-        case JSONNull:
-            return json_value_init_null();
-        case JSONError:
-            return NULL;
-        default:
-            return NULL;
-    }
-}
-
-size_t json_serialization_size(const JSON_Value *value) {
-    char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */
-    int res = json_serialize_to_buffer_r(value, NULL, 0, 0, num_buf);
-    return res < 0 ? 0 : (size_t)(res + 1);
-}
-
-JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) {
-    int written = -1;
-    size_t needed_size_in_bytes = json_serialization_size(value);
-    if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) {
-        return JSONFailure;
-    }
-    written = json_serialize_to_buffer_r(value, buf, 0, 0, NULL);
-    if (written < 0) {
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename) {
-    JSON_Status return_code = JSONSuccess;
-    FILE *fp = NULL;
-    char *serialized_string = json_serialize_to_string(value);
-    if (serialized_string == NULL) {
-        return JSONFailure;
-    }
-    fp = fopen(filename, "w");
-    if (fp == NULL) {
-        json_free_serialized_string(serialized_string);
-        return JSONFailure;
-    }
-    if (fputs(serialized_string, fp) == EOF) {
-        return_code = JSONFailure;
-    }
-    if (fclose(fp) == EOF) {
-        return_code = JSONFailure;
-    }
-    json_free_serialized_string(serialized_string);
-    return return_code;
-}
-
-char * json_serialize_to_string(const JSON_Value *value) {
-    JSON_Status serialization_result = JSONFailure;
-    size_t buf_size_bytes = json_serialization_size(value);
-    char *buf = NULL;
-    if (buf_size_bytes == 0) {
-        return NULL;
-    }
-    buf = (char*)parson_malloc(buf_size_bytes);
-    if (buf == NULL) {
-        return NULL;
-    }
-    serialization_result = json_serialize_to_buffer(value, buf, buf_size_bytes);
-    if (serialization_result == JSONFailure) {
-        json_free_serialized_string(buf);
-        return NULL;
-    }
-    return buf;
-}
-
-size_t json_serialization_size_pretty(const JSON_Value *value) {
-    char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */
-    int res = json_serialize_to_buffer_r(value, NULL, 0, 1, num_buf);
-    return res < 0 ? 0 : (size_t)(res + 1);
-}
-
-JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) {
-    int written = -1;
-    size_t needed_size_in_bytes = json_serialization_size_pretty(value);
-    if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) {
-        return JSONFailure;
-    }
-    written = json_serialize_to_buffer_r(value, buf, 0, 1, NULL);
-    if (written < 0) {
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename) {
-    JSON_Status return_code = JSONSuccess;
-    FILE *fp = NULL;
-    char *serialized_string = json_serialize_to_string_pretty(value);
-    if (serialized_string == NULL) {
-        return JSONFailure;
-    }
-    fp = fopen(filename, "w");
-    if (fp == NULL) {
-        json_free_serialized_string(serialized_string);
-        return JSONFailure;
-    }
-    if (fputs(serialized_string, fp) == EOF) {
-        return_code = JSONFailure;
-    }
-    if (fclose(fp) == EOF) {
-        return_code = JSONFailure;
-    }
-    json_free_serialized_string(serialized_string);
-    return return_code;
-}
-
-char * json_serialize_to_string_pretty(const JSON_Value *value) {
-    JSON_Status serialization_result = JSONFailure;
-    size_t buf_size_bytes = json_serialization_size_pretty(value);
-    char *buf = NULL;
-    if (buf_size_bytes == 0) {
-        return NULL;
-    }
-    buf = (char*)parson_malloc(buf_size_bytes);
-    if (buf == NULL) {
-        return NULL;
-    }
-    serialization_result = json_serialize_to_buffer_pretty(value, buf, buf_size_bytes);
-    if (serialization_result == JSONFailure) {
-        json_free_serialized_string(buf);
-        return NULL;
-    }
-    return buf;
-}
-
-void json_free_serialized_string(char *string) {
-    parson_free(string);
-}
-
-JSON_Status json_array_remove(JSON_Array *array, size_t ix) {
-    size_t to_move_bytes = 0;
-    if (array == NULL || ix >= json_array_get_count(array)) {
-        return JSONFailure;
-    }
-    json_value_free(json_array_get_value(array, ix));
-    to_move_bytes = (json_array_get_count(array) - 1 - ix) * sizeof(JSON_Value*);
-    memmove(array->items + ix, array->items + ix + 1, to_move_bytes);
-    array->count -= 1;
-    return JSONSuccess;
-}
-
-JSON_Status json_array_replace_value(JSON_Array *array, size_t ix, JSON_Value *value) {
-    if (array == NULL || value == NULL || value->parent != NULL || ix >= json_array_get_count(array)) {
-        return JSONFailure;
-    }
-    json_value_free(json_array_get_value(array, ix));
-    value->parent = json_array_get_wrapping_value(array);
-    array->items[ix] = value;
-    return JSONSuccess;
-}
-
-JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string) {
-    JSON_Value *value = json_value_init_string(string);
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_array_replace_value(array, i, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number) {
-    JSON_Value *value = json_value_init_number(number);
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_array_replace_value(array, i, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean) {
-    JSON_Value *value = json_value_init_boolean(boolean);
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_array_replace_value(array, i, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_array_replace_null(JSON_Array *array, size_t i) {
-    JSON_Value *value = json_value_init_null();
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_array_replace_value(array, i, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_array_clear(JSON_Array *array) {
-    size_t i = 0;
-    if (array == NULL) {
-        return JSONFailure;
-    }
-    for (i = 0; i < json_array_get_count(array); i++) {
-        json_value_free(json_array_get_value(array, i));
-    }
-    array->count = 0;
-    return JSONSuccess;
-}
-
-JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value) {
-    if (array == NULL || value == NULL || value->parent != NULL) {
-        return JSONFailure;
-    }
-    return json_array_add(array, value);
-}
-
-JSON_Status json_array_append_string(JSON_Array *array, const char *string) {
-    JSON_Value *value = json_value_init_string(string);
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_array_append_value(array, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_array_append_number(JSON_Array *array, double number) {
-    JSON_Value *value = json_value_init_number(number);
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_array_append_value(array, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_array_append_boolean(JSON_Array *array, int boolean) {
-    JSON_Value *value = json_value_init_boolean(boolean);
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_array_append_value(array, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_array_append_null(JSON_Array *array) {
-    JSON_Value *value = json_value_init_null();
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_array_append_value(array, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value) {
-    size_t i = 0;
-    JSON_Value *old_value;
-    if (object == NULL || name == NULL || value == NULL || value->parent != NULL) {
-        return JSONFailure;
-    }
-    old_value = json_object_get_value(object, name);
-    if (old_value != NULL) { /* free and overwrite old value */
-        json_value_free(old_value);
-        for (i = 0; i < json_object_get_count(object); i++) {
-            if (strcmp(object->names[i], name) == 0) {
-                value->parent = json_object_get_wrapping_value(object);
-                object->values[i] = value;
-                return JSONSuccess;
-            }
-        }
-    }
-    /* add new key value pair */
-    return json_object_add(object, name, value);
-}
-
-JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string) {
-    JSON_Value *value = json_value_init_string(string);
-    JSON_Status status = json_object_set_value(object, name, value);
-    if (status == JSONFailure) {
-        json_value_free(value);
-    }
-    return status;
-}
-
-JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) {
-    JSON_Value *value = json_value_init_number(number);
-    JSON_Status status = json_object_set_value(object, name, value);
-    if (status == JSONFailure) {
-        json_value_free(value);
-    }
-    return status;
-}
-
-JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean) {
-    JSON_Value *value = json_value_init_boolean(boolean);
-    JSON_Status status = json_object_set_value(object, name, value);
-    if (status == JSONFailure) {
-        json_value_free(value);
-    }
-    return status;
-}
-
-JSON_Status json_object_set_null(JSON_Object *object, const char *name) {
-    JSON_Value *value = json_value_init_null();
-    JSON_Status status = json_object_set_value(object, name, value);
-    if (status == JSONFailure) {
-        json_value_free(value);
-    }
-    return status;
-}
-
-JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value) {
-    const char *dot_pos = NULL;
-    JSON_Value *temp_value = NULL, *new_value = NULL;
-    JSON_Object *temp_object = NULL, *new_object = NULL;
-    JSON_Status status = JSONFailure;
-    size_t name_len = 0;
-    if (object == NULL || name == NULL || value == NULL) {
-        return JSONFailure;
-    }
-    dot_pos = strchr(name, '.');
-    if (dot_pos == NULL) {
-        return json_object_set_value(object, name, value);
-    }
-    name_len = dot_pos - name;
-    temp_value = json_object_getn_value(object, name, name_len);
-    if (temp_value) {
-        /* Don't overwrite existing non-object (unlike json_object_set_value, but it shouldn't be changed at this point) */
-        if (json_value_get_type(temp_value) != JSONObject) {
-            return JSONFailure;
-        }
-        temp_object = json_value_get_object(temp_value);
-        return json_object_dotset_value(temp_object, dot_pos + 1, value);
-    }
-    new_value = json_value_init_object();
-    if (new_value == NULL) {
-        return JSONFailure;
-    }
-    new_object = json_value_get_object(new_value);
-    status = json_object_dotset_value(new_object, dot_pos + 1, value);
-    if (status != JSONSuccess) {
-        json_value_free(new_value);
-        return JSONFailure;
-    }
-    status = json_object_addn(object, name, name_len, new_value);
-    if (status != JSONSuccess) {
-        json_object_dotremove_internal(new_object, dot_pos + 1, 0);
-        json_value_free(new_value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string) {
-    JSON_Value *value = json_value_init_string(string);
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_object_dotset_value(object, name, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number) {
-    JSON_Value *value = json_value_init_number(number);
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_object_dotset_value(object, name, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean) {
-    JSON_Value *value = json_value_init_boolean(boolean);
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_object_dotset_value(object, name, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_object_dotset_null(JSON_Object *object, const char *name) {
-    JSON_Value *value = json_value_init_null();
-    if (value == NULL) {
-        return JSONFailure;
-    }
-    if (json_object_dotset_value(object, name, value) == JSONFailure) {
-        json_value_free(value);
-        return JSONFailure;
-    }
-    return JSONSuccess;
-}
-
-JSON_Status json_object_remove(JSON_Object *object, const char *name) {
-    return json_object_remove_internal(object, name, 1);
-}
-
-JSON_Status json_object_dotremove(JSON_Object *object, const char *name) {
-    return json_object_dotremove_internal(object, name, 1);
-}
-
-JSON_Status json_object_clear(JSON_Object *object) {
-    size_t i = 0;
-    if (object == NULL) {
-        return JSONFailure;
-    }
-    for (i = 0; i < json_object_get_count(object); i++) {
-        parson_free(object->names[i]);
-        json_value_free(object->values[i]);
-    }
-    object->count = 0;
-    return JSONSuccess;
-}
-
-JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) {
-    JSON_Value *temp_schema_value = NULL, *temp_value = NULL;
-    JSON_Array *schema_array = NULL, *value_array = NULL;
-    JSON_Object *schema_object = NULL, *value_object = NULL;
-    JSON_Value_Type schema_type = JSONError, value_type = JSONError;
-    const char *key = NULL;
-    size_t i = 0, count = 0;
-    if (schema == NULL || value == NULL) {
-        return JSONFailure;
-    }
-    schema_type = json_value_get_type(schema);
-    value_type = json_value_get_type(value);
-    if (schema_type != value_type && schema_type != JSONNull) { /* null represents all values */
-        return JSONFailure;
-    }
-    switch (schema_type) {
-        case JSONArray:
-            schema_array = json_value_get_array(schema);
-            value_array = json_value_get_array(value);
-            count = json_array_get_count(schema_array);
-            if (count == 0) {
-                return JSONSuccess; /* Empty array allows all types */
-            }
-            /* Get first value from array, rest is ignored */
-            temp_schema_value = json_array_get_value(schema_array, 0);
-            for (i = 0; i < json_array_get_count(value_array); i++) {
-                temp_value = json_array_get_value(value_array, i);
-                if (json_validate(temp_schema_value, temp_value) == JSONFailure) {
-                    return JSONFailure;
-                }
-            }
-            return JSONSuccess;
-        case JSONObject:
-            schema_object = json_value_get_object(schema);
-            value_object = json_value_get_object(value);
-            count = json_object_get_count(schema_object);
-            if (count == 0) {
-                return JSONSuccess; /* Empty object allows all objects */
-            } else if (json_object_get_count(value_object) < count) {
-                return JSONFailure; /* Tested object mustn't have less name-value pairs than schema */
-            }
-            for (i = 0; i < count; i++) {
-                key = json_object_get_name(schema_object, i);
-                temp_schema_value = json_object_get_value(schema_object, key);
-                temp_value = json_object_get_value(value_object, key);
-                if (temp_value == NULL) {
-                    return JSONFailure;
-                }
-                if (json_validate(temp_schema_value, temp_value) == JSONFailure) {
-                    return JSONFailure;
-                }
-            }
-            return JSONSuccess;
-        case JSONString: case JSONNumber: case JSONBoolean: case JSONNull:
-            return JSONSuccess; /* equality already tested before switch */
-        case JSONError: default:
-            return JSONFailure;
-    }
-}
-
-int json_value_equals(const JSON_Value *a, const JSON_Value *b) {
-    JSON_Object *a_object = NULL, *b_object = NULL;
-    JSON_Array *a_array = NULL, *b_array = NULL;
-    const char *a_string = NULL, *b_string = NULL;
-    const char *key = NULL;
-    size_t a_count = 0, b_count = 0, i = 0;
-    JSON_Value_Type a_type, b_type;
-    a_type = json_value_get_type(a);
-    b_type = json_value_get_type(b);
-    if (a_type != b_type) {
-        return 0;
-    }
-    switch (a_type) {
-        case JSONArray:
-            a_array = json_value_get_array(a);
-            b_array = json_value_get_array(b);
-            a_count = json_array_get_count(a_array);
-            b_count = json_array_get_count(b_array);
-            if (a_count != b_count) {
-                return 0;
-            }
-            for (i = 0; i < a_count; i++) {
-                if (!json_value_equals(json_array_get_value(a_array, i),
-                                       json_array_get_value(b_array, i))) {
-                    return 0;
-                }
-            }
-            return 1;
-        case JSONObject:
-            a_object = json_value_get_object(a);
-            b_object = json_value_get_object(b);
-            a_count = json_object_get_count(a_object);
-            b_count = json_object_get_count(b_object);
-            if (a_count != b_count) {
-                return 0;
-            }
-            for (i = 0; i < a_count; i++) {
-                key = json_object_get_name(a_object, i);
-                if (!json_value_equals(json_object_get_value(a_object, key),
-                                       json_object_get_value(b_object, key))) {
-                    return 0;
-                }
-            }
-            return 1;
-        case JSONString:
-            a_string = json_value_get_string(a);
-            b_string = json_value_get_string(b);
-            if (a_string == NULL || b_string == NULL) {
-                return 0; /* shouldn't happen */
-            }
-            return strcmp(a_string, b_string) == 0;
-        case JSONBoolean:
-            return json_value_get_boolean(a) == json_value_get_boolean(b);
-        case JSONNumber:
-            return fabs(json_value_get_number(a) - json_value_get_number(b)) < 0.000001; /* EPSILON */
-        case JSONError:
-            return 1;
-        case JSONNull:
-            return 1;
-        default:
-            return 1;
-    }
-}
-
-JSON_Value_Type json_type(const JSON_Value *value) {
-    return json_value_get_type(value);
-}
-
-JSON_Object * json_object (const JSON_Value *value) {
-    return json_value_get_object(value);
-}
-
-JSON_Array * json_array  (const JSON_Value *value) {
-    return json_value_get_array(value);
-}
-
-const char * json_string (const JSON_Value *value) {
-    return json_value_get_string(value);
-}
-
-double json_number (const JSON_Value *value) {
-    return json_value_get_number(value);
-}
-
-int json_boolean(const JSON_Value *value) {
-    return json_value_get_boolean(value);
-}
-
-void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun) {
-    parson_malloc = malloc_fun;
-    parson_free = free_fun;
-}
-
-void json_set_escape_slashes(int escape_slashes) {
-    parson_escape_slashes = escape_slashes;
-}
diff --git a/src/cooker/parson.h b/src/cooker/parson.h
deleted file mode 100644
index 186fcb0..0000000
--- a/src/cooker/parson.h
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- SPDX-License-Identifier: MIT
-
- Parson ( http://kgabis.github.com/parson/ )
- Copyright (c) 2012 - 2019 Krzysztof Gabis
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-*/
-
-#ifndef parson_parson_h
-#define parson_parson_h
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#include <stddef.h>   /* size_t */
-
-/* Types and enums */
-typedef struct json_object_t JSON_Object;
-typedef struct json_array_t  JSON_Array;
-typedef struct json_value_t  JSON_Value;
-
-enum json_value_type {
-    JSONError   = -1,
-    JSONNull    = 1,
-    JSONString  = 2,
-    JSONNumber  = 3,
-    JSONObject  = 4,
-    JSONArray   = 5,
-    JSONBoolean = 6
-};
-typedef int JSON_Value_Type;
-
-enum json_result_t {
-    JSONSuccess = 0,
-    JSONFailure = -1
-};
-typedef int JSON_Status;
-
-typedef void * (*JSON_Malloc_Function)(size_t);
-typedef void   (*JSON_Free_Function)(void *);
-
-/* Call only once, before calling any other function from parson API. If not called, malloc and free
-   from stdlib will be used for all allocations */
-void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun);
-
-/* Sets if slashes should be escaped or not when serializing JSON. By default slashes are escaped.
- This function sets a global setting and is not thread safe. */
-void json_set_escape_slashes(int escape_slashes);
-
-/* Parses first JSON value in a file, returns NULL in case of error */
-JSON_Value * json_parse_file(const char *filename);
-
-/* Parses first JSON value in a file and ignores comments (/ * * / and //),
-   returns NULL in case of error */
-JSON_Value * json_parse_file_with_comments(const char *filename);
-
-/*  Parses first JSON value in a string, returns NULL in case of error */
-JSON_Value * json_parse_string(const char *string);
-
-/*  Parses first JSON value in a string and ignores comments (/ * * / and //),
-    returns NULL in case of error */
-JSON_Value * json_parse_string_with_comments(const char *string);
-
-/* Serialization */
-size_t      json_serialization_size(const JSON_Value *value); /* returns 0 on fail */
-JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
-JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename);
-char *      json_serialize_to_string(const JSON_Value *value);
-
-/* Pretty serialization */
-size_t      json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */
-JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
-JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename);
-char *      json_serialize_to_string_pretty(const JSON_Value *value);
-
-void        json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */
-
-/* Comparing */
-int  json_value_equals(const JSON_Value *a, const JSON_Value *b);
-
-/* Validation
-   This is *NOT* JSON Schema. It validates json by checking if object have identically
-   named fields with matching types.
-   For example schema {"name":"", "age":0} will validate
-   {"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"},
-   but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}.
-   In case of arrays, only first value in schema is checked against all values in tested array.
-   Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays,
-   null validates values of every type.
- */
-JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value);
-
-/*
- * JSON Object
- */
-JSON_Value  * json_object_get_value  (const JSON_Object *object, const char *name);
-const char  * json_object_get_string (const JSON_Object *object, const char *name);
-JSON_Object * json_object_get_object (const JSON_Object *object, const char *name);
-JSON_Array  * json_object_get_array  (const JSON_Object *object, const char *name);
-double        json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
-int           json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
-
-/* dotget functions enable addressing values with dot notation in nested objects,
- just like in structs or c++/java/c# objects (e.g. objectA.objectB.value).
- Because valid names in JSON can contain dots, some values may be inaccessible
- this way. */
-JSON_Value  * json_object_dotget_value  (const JSON_Object *object, const char *name);
-const char  * json_object_dotget_string (const JSON_Object *object, const char *name);
-JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name);
-JSON_Array  * json_object_dotget_array  (const JSON_Object *object, const char *name);
-double        json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
-int           json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
-
-/* Functions to get available names */
-size_t        json_object_get_count   (const JSON_Object *object);
-const char  * json_object_get_name    (const JSON_Object *object, size_t index);
-JSON_Value  * json_object_get_value_at(const JSON_Object *object, size_t index);
-JSON_Value  * json_object_get_wrapping_value(const JSON_Object *object);
-
-/* Functions to check if object has a value with a specific name. Returned value is 1 if object has
- * a value and 0 if it doesn't. dothas functions behave exactly like dotget functions. */
-int json_object_has_value        (const JSON_Object *object, const char *name);
-int json_object_has_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
-
-int json_object_dothas_value        (const JSON_Object *object, const char *name);
-int json_object_dothas_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
-
-/* Creates new name-value pair or frees and replaces old value with a new one.
- * json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */
-JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value);
-JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string);
-JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number);
-JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean);
-JSON_Status json_object_set_null(JSON_Object *object, const char *name);
-
-/* Works like dotget functions, but creates whole hierarchy if necessary.
- * json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */
-JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value);
-JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string);
-JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number);
-JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean);
-JSON_Status json_object_dotset_null(JSON_Object *object, const char *name);
-
-/* Frees and removes name-value pair */
-JSON_Status json_object_remove(JSON_Object *object, const char *name);
-
-/* Works like dotget function, but removes name-value pair only on exact match. */
-JSON_Status json_object_dotremove(JSON_Object *object, const char *key);
-
-/* Removes all name-value pairs in object */
-JSON_Status json_object_clear(JSON_Object *object);
-
-/*
- *JSON Array
- */
-JSON_Value  * json_array_get_value  (const JSON_Array *array, size_t index);
-const char  * json_array_get_string (const JSON_Array *array, size_t index);
-JSON_Object * json_array_get_object (const JSON_Array *array, size_t index);
-JSON_Array  * json_array_get_array  (const JSON_Array *array, size_t index);
-double        json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */
-int           json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */
-size_t        json_array_get_count  (const JSON_Array *array);
-JSON_Value  * json_array_get_wrapping_value(const JSON_Array *array);
-
-/* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist.
- * Order of values in array may change during execution.  */
-JSON_Status json_array_remove(JSON_Array *array, size_t i);
-
-/* Frees and removes from array value at given index and replaces it with given one.
- * Does nothing and returns JSONFailure if index doesn't exist.
- * json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */
-JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value);
-JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string);
-JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number);
-JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean);
-JSON_Status json_array_replace_null(JSON_Array *array, size_t i);
-
-/* Frees and removes all values from array */
-JSON_Status json_array_clear(JSON_Array *array);
-
-/* Appends new value at the end of array.
- * json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */
-JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value);
-JSON_Status json_array_append_string(JSON_Array *array, const char *string);
-JSON_Status json_array_append_number(JSON_Array *array, double number);
-JSON_Status json_array_append_boolean(JSON_Array *array, int boolean);
-JSON_Status json_array_append_null(JSON_Array *array);
-
-/*
- *JSON Value
- */
-JSON_Value * json_value_init_object (void);
-JSON_Value * json_value_init_array  (void);
-JSON_Value * json_value_init_string (const char *string); /* copies passed string */
-JSON_Value * json_value_init_number (double number);
-JSON_Value * json_value_init_boolean(int boolean);
-JSON_Value * json_value_init_null   (void);
-JSON_Value * json_value_deep_copy   (const JSON_Value *value);
-void         json_value_free        (JSON_Value *value);
-
-JSON_Value_Type json_value_get_type   (const JSON_Value *value);
-JSON_Object *   json_value_get_object (const JSON_Value *value);
-JSON_Array  *   json_value_get_array  (const JSON_Value *value);
-const char  *   json_value_get_string (const JSON_Value *value);
-double          json_value_get_number (const JSON_Value *value);
-int             json_value_get_boolean(const JSON_Value *value);
-JSON_Value  *   json_value_get_parent (const JSON_Value *value);
-
-/* Same as above, but shorter */
-JSON_Value_Type json_type   (const JSON_Value *value);
-JSON_Object *   json_object (const JSON_Value *value);
-JSON_Array  *   json_array  (const JSON_Value *value);
-const char  *   json_string (const JSON_Value *value);
-double          json_number (const JSON_Value *value);
-int             json_boolean(const JSON_Value *value);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/src/cooker/util.c b/src/cooker/util.c
deleted file mode 100644
index a2ecce0..0000000
--- a/src/cooker/util.c
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-/* seitan - Syscall Expressive Interpreter, Transformer and Notifier
- *
- * cooker/util.c - Convenience routines
- *
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-
-#define logfn(name)							\
-void name(const char *format, ...) {					\
-	va_list args;							\
-									\
-	va_start(args, format);						\
-	(void)vfprintf(stderr, format, args); 				\
-	va_end(args);							\
-	if (format[strlen(format)] != '\n')				\
-		fprintf(stderr, "\n");					\
-}
-
-logfn(err)
-logfn(info)
-logfn(debug)
-
diff --git a/src/cooker/util.h b/src/cooker/util.h
deleted file mode 100644
index 84dc3db..0000000
--- a/src/cooker/util.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>
- */
-
-#ifndef UTIL_H
-#define UTIL_H
-
-#define BIT(n)			(1UL << (n))
-
-void err(const char *format, ...);
-void info(const char *format, ...);
-void debug(const char *format, ...);
-
-#define die(...)							\
-	do {								\
-		fprintf(stderr, "%s:%i: ", __FILE__, __LINE__);		\
-		err(__VA_ARGS__);					\
-		exit(EXIT_FAILURE);					\
-	} while (0)
-
-#endif /* UTIL_H */
diff --git a/src/debug/Makefile b/src/debug/Makefile
deleted file mode 100644
index 6ef7900..0000000
--- a/src/debug/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# seitan - Syscall Expressive Interpreter, Transformer and Notifier
-#
-# debug/Makefile - Makefile for debug utilities: bpf_dbg
-#
-# Copyright 2023 Red Hat GmbH
-# Author: Alice Frosi <afrosi@redhat.com>
-
-SRCS := bpf_dbg.c  disasm.c
-HEADERS := disasm.h
-BIN := $(OUTDIR)bpf_dbg
-CFLAGS += -Wall -Wextra -pedantic
-
-# TODO: remove this part together with the build binary
-# when cooker is ready
-TARGET := $(shell $(CC) -dumpmachine)
-TARGET_ARCH := $(shell echo $(TARGET) | cut -f1 -d- | tr [A-Z] [a-z])
-TARGET_ARCH := $(shell echo $(TARGET_ARCH) | sed 's/powerpc/ppc/')
-
-AUDIT_ARCH := $(shell echo $(TARGET_ARCH) | tr [a-z] [A-Z] | sed 's/^ARM.*/ARM/')
-AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/I[456]86/I386/')
-AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPC64/PPC/')
-AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPCLE/PPC64LE/')
-
-bpf_dbg: $(SRCS) $(HEADERS)
-	$(CC) $(CFLAGS) -o $(BIN) $(SRCS)
-
-# TODO: remove when cooker is ready
-build: build.c ../cooker/filter.c ../cooker/filter.h ../common/numbers.h
-	$(CC) $(CFLAGS) -I../common -I../cooker -DSEITAN_AUDIT_ARCH=AUDIT_ARCH_$(AUDIT_ARCH)\
-	       	-o $(OUTDIR)build ../cooker/filter.c build.c
-
-all: $(BIN)
-
-clean:
-	rm -f $(BIN) build
diff --git a/src/debug/bpf_dbg.c b/src/debug/bpf_dbg.c
deleted file mode 100644
index b84c713..0000000
--- a/src/debug/bpf_dbg.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Alice Frosi <afrosi@redhat.com>
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <linux/filter.h>
-#include <unistd.h>
-
-#include "disasm.h"
-
-int main(int argc, char **argv)
-{
-	struct sock_filter *filter;
-	size_t fd, n;
-
-	if (argc < 2) {
-		perror("missing input file");
-		exit(EXIT_FAILURE);
-	}
-	filter = calloc(SIZE_FILTER, sizeof(struct sock_filter));
-	fd = open(argv[1], O_CLOEXEC | O_RDONLY);
-
-	n = read(fd, filter, sizeof(struct sock_filter) * SIZE_FILTER);
-	close(fd);
-	printf("Read %ld entries\n", n / sizeof(struct sock_filter));
-	bpf_disasm_all(filter, n / sizeof(struct sock_filter));
-	free(filter);
-	return 0;
-}
diff --git a/src/debug/build.c b/src/debug/build.c
deleted file mode 100644
index 93ce97b..0000000
--- a/src/debug/build.c
+++ /dev/null
@@ -1,33 +0,0 @@
-#define _GNU_SOURCE
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "filter.h"
-
-struct bpf_call calls[] = {
-	{
-		.name = "connect",
-		.args = { 0, 111, 0, 0, 0, 0 },
-		.check_arg = { false, false, false, false, false, false },
-	},
-};
-
-int main(int argc, char **argv)
-{
-	int ret;
-	if (argc < 2) {
-		perror("missing input file");
-		exit(EXIT_FAILURE);
-	}
-	ret = convert_bpf(argv[1], calls, sizeof(calls) / sizeof(calls[0]),
-			  true);
-	if (ret < 0) {
-		perror("converting bpf program");
-		exit(EXIT_FAILURE);
-	}
-	return 0;
-}
diff --git a/src/debug/disasm.c b/src/debug/disasm.c
deleted file mode 100644
index fae96b7..0000000
--- a/src/debug/disasm.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Alice Frosi <afrosi@redhat.com>
- */
-
-#define _GNU_SOURCE
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <linux/filter.h>
-
-#include "disasm.h"
-
-/* From linux tools/bpf/bpf_dbg.c */
-#define BPF_LDX_B (BPF_LDX | BPF_B)
-#define BPF_LDX_W (BPF_LDX | BPF_W)
-#define BPF_JMP_JA (BPF_JMP | BPF_JA)
-#define BPF_JMP_JEQ (BPF_JMP | BPF_JEQ)
-#define BPF_JMP_JGT (BPF_JMP | BPF_JGT)
-#define BPF_JMP_JGE (BPF_JMP | BPF_JGE)
-#define BPF_JMP_JSET (BPF_JMP | BPF_JSET)
-#define BPF_ALU_ADD (BPF_ALU | BPF_ADD)
-#define BPF_ALU_SUB (BPF_ALU | BPF_SUB)
-#define BPF_ALU_MUL (BPF_ALU | BPF_MUL)
-#define BPF_ALU_DIV (BPF_ALU | BPF_DIV)
-#define BPF_ALU_MOD (BPF_ALU | BPF_MOD)
-#define BPF_ALU_NEG (BPF_ALU | BPF_NEG)
-#define BPF_ALU_AND (BPF_ALU | BPF_AND)
-#define BPF_ALU_OR (BPF_ALU | BPF_OR)
-#define BPF_ALU_XOR (BPF_ALU | BPF_XOR)
-#define BPF_ALU_LSH (BPF_ALU | BPF_LSH)
-#define BPF_ALU_RSH (BPF_ALU | BPF_RSH)
-#define BPF_MISC_TAX (BPF_MISC | BPF_TAX)
-#define BPF_MISC_TXA (BPF_MISC | BPF_TXA)
-#define BPF_LD_B (BPF_LD | BPF_B)
-#define BPF_LD_H (BPF_LD | BPF_H)
-#define BPF_LD_W (BPF_LD | BPF_W)
-static const char *const op_table[] = {
-	[BPF_ST] = "st",	[BPF_STX] = "stx",     [BPF_LD_B] = "ldb",
-	[BPF_LD_H] = "ldh",	[BPF_LD_W] = "ld",     [BPF_LDX] = "ldx",
-	[BPF_LDX_B] = "ldxb",	[BPF_JMP_JA] = "ja",   [BPF_JMP_JEQ] = "jeq",
-	[BPF_JMP_JGT] = "jgt",	[BPF_JMP_JGE] = "jge", [BPF_JMP_JSET] = "jset",
-	[BPF_ALU_ADD] = "add",	[BPF_ALU_SUB] = "sub", [BPF_ALU_MUL] = "mul",
-	[BPF_ALU_DIV] = "div",	[BPF_ALU_MOD] = "mod", [BPF_ALU_NEG] = "neg",
-	[BPF_ALU_AND] = "and",	[BPF_ALU_OR] = "or",   [BPF_ALU_XOR] = "xor",
-	[BPF_ALU_LSH] = "lsh",	[BPF_ALU_RSH] = "rsh", [BPF_MISC_TAX] = "tax",
-	[BPF_MISC_TXA] = "txa", [BPF_RET] = "ret",
-};
-
-void bpf_disasm(const struct sock_filter f, unsigned int i)
-{
-	const char *op, *fmt;
-	int val = f.k;
-	char buf[256];
-
-	switch (f.code) {
-	case BPF_RET | BPF_K:
-		op = op_table[BPF_RET];
-		fmt = "#%#x";
-		break;
-	case BPF_RET | BPF_A:
-		op = op_table[BPF_RET];
-		fmt = "a";
-		break;
-	case BPF_RET | BPF_X:
-		op = op_table[BPF_RET];
-		fmt = "x";
-		break;
-	case BPF_MISC_TAX:
-		op = op_table[BPF_MISC_TAX];
-		fmt = "";
-		break;
-	case BPF_MISC_TXA:
-		op = op_table[BPF_MISC_TXA];
-		fmt = "";
-		break;
-	case BPF_ST:
-		op = op_table[BPF_ST];
-		fmt = "M[%d]";
-		break;
-	case BPF_STX:
-		op = op_table[BPF_STX];
-		fmt = "M[%d]";
-		break;
-	case BPF_LD_W | BPF_ABS:
-		op = op_table[BPF_LD_W];
-		fmt = "[%d]";
-		break;
-	case BPF_LD_H | BPF_ABS:
-		op = op_table[BPF_LD_H];
-		fmt = "[%d]";
-		break;
-	case BPF_LD_B | BPF_ABS:
-		op = op_table[BPF_LD_B];
-		fmt = "[%d]";
-		break;
-	case BPF_LD_W | BPF_LEN:
-		op = op_table[BPF_LD_W];
-		fmt = "#len";
-		break;
-	case BPF_LD_W | BPF_IND:
-		op = op_table[BPF_LD_W];
-		fmt = "[x+%d]";
-		break;
-	case BPF_LD_H | BPF_IND:
-		op = op_table[BPF_LD_H];
-		fmt = "[x+%d]";
-		break;
-	case BPF_LD_B | BPF_IND:
-		op = op_table[BPF_LD_B];
-		fmt = "[x+%d]";
-		break;
-	case BPF_LD | BPF_IMM:
-		op = op_table[BPF_LD_W];
-		fmt = "#%#x";
-		break;
-	case BPF_LDX | BPF_IMM:
-		op = op_table[BPF_LDX];
-		fmt = "#%#x";
-		break;
-	case BPF_LDX_B | BPF_MSH:
-		op = op_table[BPF_LDX_B];
-		fmt = "4*([%d]&0xf)";
-		break;
-	case BPF_LD | BPF_MEM:
-		op = op_table[BPF_LD_W];
-		fmt = "M[%d]";
-		break;
-	case BPF_LDX | BPF_MEM:
-		op = op_table[BPF_LDX];
-		fmt = "M[%d]";
-		break;
-	case BPF_JMP_JA:
-		op = op_table[BPF_JMP_JA];
-		fmt = "%d";
-		val = i + 1 + f.k;
-		break;
-	case BPF_JMP_JGT | BPF_X:
-		op = op_table[BPF_JMP_JGT];
-		fmt = "x";
-		break;
-	case BPF_JMP_JGT | BPF_K:
-		op = op_table[BPF_JMP_JGT];
-		fmt = "#%#x";
-		break;
-	case BPF_JMP_JGE | BPF_X:
-		op = op_table[BPF_JMP_JGE];
-		fmt = "x";
-		break;
-	case BPF_JMP_JGE | BPF_K:
-		op = op_table[BPF_JMP_JGE];
-		fmt = "#%#x";
-		break;
-	case BPF_JMP_JEQ | BPF_X:
-		op = op_table[BPF_JMP_JEQ];
-		fmt = "x";
-		break;
-	case BPF_JMP_JEQ | BPF_K:
-		op = op_table[BPF_JMP_JEQ];
-		fmt = "#%#x";
-		break;
-	case BPF_JMP_JSET | BPF_X:
-		op = op_table[BPF_JMP_JSET];
-		fmt = "x";
-		break;
-	case BPF_JMP_JSET | BPF_K:
-		op = op_table[BPF_JMP_JSET];
-		fmt = "#%#x";
-		break;
-	case BPF_ALU_NEG:
-		op = op_table[BPF_ALU_NEG];
-		fmt = "";
-		break;
-	case BPF_ALU_LSH | BPF_X:
-		op = op_table[BPF_ALU_LSH];
-		fmt = "x";
-		break;
-	case BPF_ALU_LSH | BPF_K:
-		op = op_table[BPF_ALU_LSH];
-		fmt = "#%d";
-		break;
-	case BPF_ALU_RSH | BPF_X:
-		op = op_table[BPF_ALU_RSH];
-		fmt = "x";
-		break;
-	case BPF_ALU_RSH | BPF_K:
-		op = op_table[BPF_ALU_RSH];
-		fmt = "#%d";
-		break;
-	case BPF_ALU_ADD | BPF_X:
-		op = op_table[BPF_ALU_ADD];
-		fmt = "x";
-		break;
-	case BPF_ALU_ADD | BPF_K:
-		op = op_table[BPF_ALU_ADD];
-		fmt = "#%d";
-		break;
-	case BPF_ALU_SUB | BPF_X:
-		op = op_table[BPF_ALU_SUB];
-		fmt = "x";
-		break;
-	case BPF_ALU_SUB | BPF_K:
-		op = op_table[BPF_ALU_SUB];
-		fmt = "#%d";
-		break;
-	case BPF_ALU_MUL | BPF_X:
-		op = op_table[BPF_ALU_MUL];
-		fmt = "x";
-		break;
-	case BPF_ALU_MUL | BPF_K:
-		op = op_table[BPF_ALU_MUL];
-		fmt = "#%d";
-		break;
-	case BPF_ALU_DIV | BPF_X:
-		op = op_table[BPF_ALU_DIV];
-		fmt = "x";
-		break;
-	case BPF_ALU_DIV | BPF_K:
-		op = op_table[BPF_ALU_DIV];
-		fmt = "#%d";
-		break;
-	case BPF_ALU_MOD | BPF_X:
-		op = op_table[BPF_ALU_MOD];
-		fmt = "x";
-		break;
-	case BPF_ALU_MOD | BPF_K:
-		op = op_table[BPF_ALU_MOD];
-		fmt = "#%d";
-		break;
-	case BPF_ALU_AND | BPF_X:
-		op = op_table[BPF_ALU_AND];
-		fmt = "x";
-		break;
-	case BPF_ALU_AND | BPF_K:
-		op = op_table[BPF_ALU_AND];
-		fmt = "#%#x";
-		break;
-	case BPF_ALU_OR | BPF_X:
-		op = op_table[BPF_ALU_OR];
-		fmt = "x";
-		break;
-	case BPF_ALU_OR | BPF_K:
-		op = op_table[BPF_ALU_OR];
-		fmt = "#%#x";
-		break;
-	case BPF_ALU_XOR | BPF_X:
-		op = op_table[BPF_ALU_XOR];
-		fmt = "x";
-		break;
-	case BPF_ALU_XOR | BPF_K:
-		op = op_table[BPF_ALU_XOR];
-		fmt = "#%#x";
-		break;
-	default:
-		op = "nosup";
-		fmt = "%#x";
-		val = f.code;
-		break;
-	}
-
-	memset(buf, 0, sizeof(buf));
-	snprintf(buf, sizeof(buf), fmt, val);
-	buf[sizeof(buf) - 1] = 0;
-
-	if ((BPF_CLASS(f.code) == BPF_JMP && BPF_OP(f.code) != BPF_JA)) {
-		printf("l%d:\t%s %s, l%d, l%d\n", i, op, buf, i + 1 + f.jt,
-		       i + 1 + f.jf);
-	} else {
-		printf("l%d:\t%s %s\n", i, op, buf);
-	}
-}
-
-void bpf_disasm_all(const struct sock_filter *f, unsigned int len)
-{
-	unsigned int i;
-	for (i = 0; i < len; i++)
-		bpf_disasm(f[i], i);
-}
diff --git a/src/debug/disasm.h b/src/debug/disasm.h
deleted file mode 100644
index c3e3ad9..0000000
--- a/src/debug/disasm.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Alice Frosi <afrosi@redhat.com>
- */
-
-#ifndef DISASM_H_
-#define DISASM_H_
-
-#define SIZE_FILTER 1024
-
-void bpf_disasm(const struct sock_filter f, unsigned int i);
-void bpf_disasm_all(const struct sock_filter *f, unsigned int len);
-
-#endif
diff --git a/src/eater/Makefile b/src/eater/Makefile
deleted file mode 100644
index c70433f..0000000
--- a/src/eater/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# seitan - Syscall Expressive Interpreter, Transformer and Notifier
-#
-# eater/Makefile - Makefile for seitan-eater
-#
-# Copyright 2023 Red Hat GmbH
-# Author: Alice Frosi <afrosi@redhat.com>
-
-COMMON_DIR :=../common
-SRCS := $(COMMON_DIR)/common.c eater.c
-HEADERS := $(COMMON_DIR)/common.h
-BIN := $(OUTDIR)eater
-CFLAGS += -Wall -Wextra -pedantic -I$(COMMON_DIR)
-
-eater: $(SRCS) $(HEADERS)
-	$(CC) $(CFLAGS) -o $(BIN) $(SRCS)
-
-all: eater
-
-clean:
-	rm -f $(BIN)
diff --git a/src/eater/eater.c b/src/eater/eater.c
deleted file mode 100644
index 96a7b61..0000000
--- a/src/eater/eater.c
+++ /dev/null
@@ -1,143 +0,0 @@
-// SPDX-License-Identifier: AGPL-3.0-or-later
-
-/* SEITAN - Syscall Expressive Interpreter, Transformer and Notifier
- *
- * src/eater/eater.c - Load BPF program and execute binary
- *
- * Copyright (c) 2022 Red Hat GmbH
- * Authors: Stefano Brivio <sbrivio@redhat.com>, Alice Frosi <afrosi@redhat.com>
- */
-
-#define _GNU_SOURCE
-#include <errno.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <argp.h>
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-#include <sys/socket.h>
-#include <signal.h>
-
-#include <linux/audit.h>
-#include <linux/filter.h>
-#include <linux/seccomp.h>
-
-#include <dirent.h>
-#include <sys/stat.h>
-
-#include "common.h"
-
-extern char **environ;
-
-static char doc[] =
-	"Usage: seitan-eater: setain-eater -i <input file> -- program args1 args2...";
-
-/* Eater options */
-static struct argp_option options[] = { { "input", 'i', "FILE", 0,
-					  "BPF filter input file", 0 },
-					{ 0 } };
-
-struct arguments {
-	char *input_file;
-	unsigned int program_index;
-};
-
-static error_t parse_opt(int key, char *arg, struct argp_state *state)
-{
-	struct arguments *arguments = state->input;
-
-	if (state->quoted == 0)
-		arguments->program_index = state->next + 1;
-	switch (key) {
-	case 'i':
-		if (state->quoted == 0)
-			arguments->input_file = arg;
-		break;
-	case ARGP_KEY_END:
-		if (arguments->input_file == NULL)
-			argp_error(state, "missing input file");
-		if (state->argv[arguments->program_index] == NULL)
-			argp_error(state, "missing program");
-		break;
-	}
-
-	return 0;
-}
-
-static struct argp argp = { .options = options,
-			    .parser = parse_opt,
-			    .args_doc = NULL,
-			    .doc = doc,
-			    .children = NULL,
-			    .help_filter = NULL,
-			    .argp_domain = NULL };
-
-static int seccomp(unsigned int operation, unsigned int flags, void *args)
-{
-	return syscall(__NR_seccomp, operation, flags, args);
-}
-
-static void signal_handler(__attribute__((unused)) int s)
-{
-}
-
-/**
- * main() - Entry point
- * @argc:	Argument count
- * @argv:	Seitan-eater and program arguments
- *
- * Return: 0 once interrupted, non-zero on failure
- */
-int main(int argc, char **argv)
-{
-	struct sock_filter filter[1024];
-	struct arguments arguments;
-	struct sock_fprog prog;
-	struct sigaction act;
-	size_t n;
-	int fd, flags;
-
-	argp_parse(&argp, argc, argv, 0, 0, &arguments);
-	fd = open(arguments.input_file, O_CLOEXEC | O_RDONLY);
-	n = read(fd, filter, sizeof(filter));
-	close(fd);
-
-	prog.filter = filter;
-	prog.len = (unsigned short)(n / sizeof(filter[0]));
-	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
-		perror("prctl");
-		exit(EXIT_FAILURE);
-	}
-	if (seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_NEW_LISTENER,
-		    &prog) < 0) {
-		perror("seccomp");
-		exit(EXIT_FAILURE);
-	}
-	/*
-	 * close-on-exec flag is set for the file descriptor by seccomp.
-	 * We want to preserve the fd on the exec in this way we are able
-	 * to easly find the notifier fd if seitan restarts.
-	 */
-	fd = find_fd_seccomp_notifier("/proc/self/fd");
-	flags = fcntl(fd, F_GETFD);
-	if (fcntl(fd, F_SETFD, flags & !FD_CLOEXEC) < 0) {
-		perror("fcntl");
-		exit(EXIT_FAILURE);
-	}
-	act.sa_handler = signal_handler;
-	sigaction(SIGCONT, &act, NULL);
-	pause();
-
-	execvpe(argv[arguments.program_index], &argv[arguments.program_index],
-		environ);
-	if (errno != ENOENT) {
-		perror("execvpe");
-		exit(EXIT_FAILURE);
-	}
-	close(fd);
-	return EXIT_FAILURE;
-}
diff --git a/src/seitan/Makefile b/src/seitan/Makefile
deleted file mode 100644
index 8a0c106..0000000
--- a/src/seitan/Makefile
+++ /dev/null
@@ -1,35 +0,0 @@
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# seitan - Syscall Expressive Interpreter, Transformer and Notifier
-#
-# seitan/Makefile - Makefile for seitan
-#
-# Copyright 2023 Red Hat GmbH
-# Author: Alice Frosi <afrosi@redhat.com>
-# Author: Stefano Brivio <sbrivio@redhat.com>
-
-COMMON_DIR :=../common
-SRCS := seitan.c $(COMMON_DIR)/common.c operations.c
-HEADERS := $(COMMON_DIR)/common.h $(COMMON_DIR)/gluten.h operations.h
-BIN := $(OUTDIR)seitan
-
-TARGET := $(shell $(CC) -dumpmachine)
-# Get 'uname -m'-like architecture description for target
-TARGET_ARCH := $(shell echo $(TARGET) | cut -f1 -d- | tr [A-Z] [a-z])
-TARGET_ARCH := $(shell echo $(TARGET_ARCH) | sed 's/powerpc/ppc/')
-
-AUDIT_ARCH := $(shell echo $(TARGET_ARCH) | tr [a-z] [A-Z] | sed 's/^ARM.*/ARM/')
-AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/I[456]86/I386/')
-AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPC64/PPC/')
-AUDIT_ARCH := $(shell echo $(AUDIT_ARCH) | sed 's/PPCLE/PPC64LE/')
-
-CFLAGS += -DTMP_DATA_SIZE=1000
-CFLAGS += -Wall -Wextra -pedantic -I$(COMMON_DIR)
-
-seitan: $(SRCS) $(HEADERS)
-	$(CC) $(CFLAGS) -o $(BIN) $(SRCS)
-
-all: seitan
-
-clean:
-	rm -f $(BIN)
diff --git a/src/seitan/operations.c b/src/seitan/operations.c
deleted file mode 100644
index 0327e57..0000000
--- a/src/seitan/operations.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Alice Frosi <afrosi@redhat.com>
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <sched.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-#include <linux/seccomp.h>
-#include <linux/filter.h>
-#include <linux/audit.h>
-#include <errno.h>
-
-#include "gluten.h"
-#include "operations.h"
-
-static bool is_cookie_valid(int notifyFd, uint64_t id)
-{
-	return ioctl(notifyFd, SECCOMP_IOCTL_NOTIF_ID_VALID, &id) == 0;
-}
-
-static int send_target(const struct seccomp_notif_resp *resp, int notifyfd)
-{
-	if (!is_cookie_valid(notifyfd, resp->id)) {
-		fprintf(stderr,
-			"the response id isn't valid\ncheck if the targets has already terminated\n");
-		return -1;
-	}
-	if (ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0) {
-		if (errno != EINPROGRESS) {
-			perror("sending the response");
-			return -1;
-		}
-	}
-	return 0;
-}
-
-static int send_inject_target(const struct seccomp_notif_addfd *resp,
-			      int notifyfd)
-{
-	if (!is_cookie_valid(notifyfd, resp->id)) {
-		fprintf(stderr,
-			"the response id isn't valid\ncheck if the targets has already terminated\n");
-		return -1;
-	}
-	if (ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_ADDFD, resp) < 0) {
-		if (errno != EINPROGRESS) {
-			perror("sending the response");
-			return -1;
-		}
-	}
-	return 0;
-}
-
-static void proc_ns_name(unsigned i, char *ns)
-{
-	switch (i) {
-	case NS_CGROUP:
-		snprintf(ns, PATH_MAX + 1, "cgroup");
-		break;
-	case NS_IPC:
-		snprintf(ns, PATH_MAX + 1, "ipc");
-		break;
-	case NS_NET:
-		snprintf(ns, PATH_MAX + 1, "net");
-		break;
-	case NS_MOUNT:
-		snprintf(ns, PATH_MAX + 1, "mnt");
-		break;
-	case NS_PID:
-		snprintf(ns, PATH_MAX + 1, "pid");
-		break;
-	case NS_USER:
-		snprintf(ns, PATH_MAX + 1, "user");
-		break;
-	case NS_UTS:
-		snprintf(ns, PATH_MAX + 1, "uts");
-		break;
-	case NS_TIME:
-		snprintf(ns, PATH_MAX + 1, "time");
-		break;
-	default:
-		fprintf(stderr, "unrecognized namespace index %d\n", i);
-	}
-}
-
-static int set_namespaces(const struct op_call *a, int tpid)
-{
-	char path[PATH_MAX + 1];
-	char ns_name[PATH_MAX / 2];
-	struct ns_spec ns;
-	int fd;
-	unsigned int i;
-
-	for (i = 0, ns = (a->context).ns[i]; i < sizeof(enum ns_type);
-	     i++, ns = (a->context).ns[i]) {
-		proc_ns_name(i, ns_name);
-		switch (ns.type) {
-		case NS_NONE:
-			continue;
-		case NS_SPEC_TARGET:
-			snprintf(path, sizeof(path), "/proc/%d/ns/%s", tpid,
-				 ns_name);
-			break;
-		case NS_SPEC_PID:
-			snprintf(path, sizeof(path), "/proc/%d/ns/%s", ns.pid,
-				 ns_name);
-			break;
-		case NS_SPEC_PATH:
-			snprintf(path, sizeof(path), "%s", ns.path);
-			break;
-		}
-
-		if ((fd = open(path, O_CLOEXEC)) < 0) {
-			fprintf(stderr, "open for file %s: %s", path,
-				strerror(errno));
-			return -1;
-		}
-
-		if (setns(fd, 0) != 0) {
-			perror("setns");
-			return -1;
-		}
-	}
-	return 0;
-}
-
-static int execute_syscall(void *args)
-{
-	struct arg_clone *a = (struct arg_clone *)args;
-	const struct op_call *c = a->args;
-
-	if (set_namespaces(a->args, a->pid) < 0) {
-		exit(EXIT_FAILURE);
-	}
-	/* execute syscall */
-	a->ret = syscall(c->nr, c->args[0], c->args[1], c->args[2], c->args[3],
-			 c->args[4], c->args[5]);
-	a->err = errno;
-	if (a->ret < 0) {
-		perror("syscall");
-		exit(EXIT_FAILURE);
-	}
-	exit(0);
-}
-
-int copy_args(struct seccomp_notif *req, struct op_copy_args *copy, void *data,
-	      int notifier)
-{
-	char path[PATH_MAX];
-	unsigned int i;
-	ssize_t nread;
-	void *dest;
-	int fd;
-
-	snprintf(path, sizeof(path), "/proc/%d/mem", req->pid);
-	if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
-		perror("open mem");
-		return -1;
-	}
-
-	/*
-         * Avoid the TOCTOU and check if the read mappings are still valid
-         */
-	if (!is_cookie_valid(notifier, req->id)) {
-		fprintf(stderr, "the seccomp request isn't valid anymore\n");
-		return -1;
-	}
-	for (i = 0; i < 6; i++) {
-		if (copy->args[i].type == REFERENCE) {
-			dest = (uint16_t *)data + copy->args[i].args_off;
-			nread = pread(fd, dest, copy->args[i].size,
-				      req->data.args[i]);
-			if (nread < 0) {
-				perror("pread");
-				return -1;
-			}
-		} else {
-			memcpy((uint16_t *)data + copy->args[i].args_off,
-			       &req->data.args[i], copy->args[i].size);
-		}
-	}
-	close(fd);
-	return 0;
-}
-
-static int resolve_fd(void *data, struct op_resolvedfd *resfd, pid_t pid)
-{
-	char fdpath[PATH_MAX], buf[PATH_MAX];
-	char *path = (char *)((uint16_t *)data + resfd->path_off);
-	int *fd = (int *)((uint16_t *)data + resfd->fd_off);
-	ssize_t nbytes;
-
-	snprintf(fdpath, PATH_MAX, "/proc/%d/fd/%d", pid, *fd);
-	if ((nbytes = readlink(fdpath, buf, resfd->path_size)) < 0) {
-		fprintf(stderr, "error reading %s\n", fdpath);
-		perror("readlink");
-		return -1;
-	}
-	if (strcmp(path, buf) == 0)
-		return 0;
-	else
-		return 1;
-}
-
-int do_call(struct arg_clone *c)
-{
-	char stack[STACK_SIZE];
-	pid_t child;
-
-	c->ret = -1;
-	c->err = 0;
-
-	/* Create a process that will be moved to the namespace */
-	child = clone(execute_syscall, stack + sizeof(stack),
-		      CLONE_FILES | CLONE_VM | SIGCHLD, (void *)c);
-	if (child == -1) {
-		perror("clone");
-		return -1;
-	}
-	wait(NULL);
-	return 0;
-}
-
-static void set_inject_fields(uint64_t id, void *data, const struct op *a,
-			      struct seccomp_notif_addfd *resp)
-{
-	const struct fd_type *new = &(a->inj).newfd;
-	const struct fd_type *old = &(a->inj).oldfd;
-
-	resp->flags = SECCOMP_ADDFD_FLAG_SETFD;
-	resp->id = id;
-	if (new->type == IMMEDIATE)
-		resp->newfd = new->fd;
-	else
-		memcpy(&resp->srcfd, (uint16_t *)data + old->fd_off,
-		       sizeof(resp->srcfd));
-	if (old->type == IMMEDIATE)
-		resp->srcfd = old->fd;
-	else
-		memcpy(&resp->srcfd, (uint16_t *)data + old->fd_off,
-		       sizeof(resp->srcfd));
-	resp->newfd_flags = 0;
-}
-
-int do_operations(void *data, struct op operations[], struct seccomp_notif *req,
-		  unsigned int n_operations, int pid, int notifyfd, uint64_t id)
-{
-	struct seccomp_notif_addfd resp_fd;
-	struct seccomp_notif_resp resp;
-	struct arg_clone c;
-	unsigned int i;
-	int ret;
-
-	for (i = 0; i < n_operations; i++) {
-		switch (operations[i].type) {
-		case OP_CALL:
-			resp.id = id;
-			resp.val = 0;
-			resp.flags = 0;
-			c.args = &operations[i].call;
-			c.pid = pid;
-			if (do_call(&c) == -1) {
-				resp.error = -1;
-				if (send_target(&resp, notifyfd) == -1)
-					return -1;
-			}
-			if (c.err != 0) {
-				resp.error = -1;
-				if (send_target(&resp, notifyfd) == -1)
-					return c.err;
-			}
-			/*
-			 * The result of the call needs to be save as
-			 * reference
-			 */
-			if (operations[i].call.has_ret) {
-				memcpy((uint16_t *)data +
-					       operations[i].call.ret_off,
-				       &c.ret, sizeof(c.ret));
-			}
-			break;
-		case OP_BLOCK:
-			resp.id = id;
-			resp.val = 0;
-			resp.flags = 0;
-			resp.error = operations[i].block.error;
-			if (send_target(&resp, notifyfd) == -1)
-				return -1;
-			break;
-		case OP_RETURN:
-			resp.id = id;
-			resp.flags = 0;
-			resp.error = 0;
-			if (operations[i].ret.type == IMMEDIATE)
-				resp.val = operations[i].ret.value;
-			else
-				memcpy(&resp.val,
-				       (uint16_t *)data +
-					       operations[i].ret.value_off,
-				       sizeof(resp.val));
-
-			if (send_target(&resp, notifyfd) == -1)
-				return -1;
-			break;
-
-		case OP_CONT:
-			resp.id = id;
-			resp.flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE;
-			resp.error = 0;
-			resp.val = 0;
-			if (send_target(&resp, notifyfd) == -1)
-				return -1;
-			break;
-		case OP_INJECT_A:
-			set_inject_fields(id, data, &operations[i], &resp_fd);
-			resp_fd.flags |= SECCOMP_ADDFD_FLAG_SEND;
-			if (send_inject_target(&resp_fd, notifyfd) == -1)
-				return -1;
-			break;
-		case OP_INJECT:
-			set_inject_fields(id, data, &operations[i], &resp_fd);
-			if (send_inject_target(&resp_fd, notifyfd) == -1)
-				return -1;
-			break;
-		case OP_COPY_ARGS:
-			if (copy_args(req, &operations[i].copy, data,
-				      notifyfd) < 0)
-				return -1;
-			break;
-		case OP_END:
-			return 0;
-		case OP_CMP:
-			if (memcmp((uint16_t *)data + operations[i].cmp.s1_off,
-				   (uint16_t *)data + operations[i].cmp.s2_off,
-				   operations[i].cmp.size) != 0) {
-				i = operations[i].cmp.jmp;
-			}
-			break;
-		case OP_RESOLVEDFD:
-			ret = resolve_fd(data, &operations[i].resfd, pid);
-			if (ret == -1)
-				return -1;
-			else if (ret == 1)
-				i = operations[i].resfd.jmp;
-			break;
-		default:
-			fprintf(stderr, "unknow operation %d \n",
-				operations[i].type);
-		}
-	}
-	return 0;
-}
diff --git a/src/seitan/operations.h b/src/seitan/operations.h
deleted file mode 100644
index 3691a50..0000000
--- a/src/seitan/operations.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later
- * Copyright 2023 Red Hat GmbH
- * Author: Alice Frosi <afrosi@redhat.com>
- */
-
-#ifndef ACIONS_H
-#define ACTIONS_H
-
-#include <errno.h>
-#include <linux/seccomp.h>
-
-#define STACK_SIZE (1024 * 1024 / 8)
-#define NS_NUM (sizeof(enum ns_type))
-
-struct arg_clone {
-	const struct op_call *args;
-	pid_t pid;
-	long ret;
-	int err;
-};
-
-int do_call(struct arg_clone *c);
-int do_operations(void *data, struct op operations[], struct seccomp_notif *req,
-		  unsigned int n_operations, int tpid, int notifyfd,
-		  uint64_t id);
-#endif /* ACTIONS_H */
diff --git a/src/seitan/seitan.c b/src/seitan/seitan.c
deleted file mode 100644
index ff0c54b..0000000
--- a/src/seitan/seitan.c
+++ /dev/null
@@ -1,435 +0,0 @@
-// SPDX-License-Identifier: AGPL-3.0-or-later
-
-/* SEITAN - Syscall Expressive Interpreter, Transformer and Notifier
- *
- * src/seitan/seitan.c - Wait for processes, listen for syscalls, handle them
- *
- * Copyright (c) 2022 Red Hat GmbH
- * Author: Stefano Brivio <sbrivio@redhat.com>, Alice Frosi <afrosi@redhat.com>
- */
-
-#define _GNU_SOURCE
-#include <errno.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <limits.h>
-#include <signal.h>
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/epoll.h>
-#include <sys/types.h>
-#include <argp.h>
-#include <linux/netlink.h>
-#include <linux/connector.h>
-#include <linux/cn_proc.h>
-
-#include <linux/audit.h>
-#include <linux/filter.h>
-#include <linux/seccomp.h>
-
-#include "common.h"
-#include "gluten.h"
-#include "operations.h"
-
-#define EPOLL_EVENTS 8
-#define errExit(msg)                \
-	do {                        \
-		perror(msg);        \
-		exit(EXIT_FAILURE); \
-	} while (0)
-
-static char doc[] = "Usage: seitan: setain -pid <pid> -i <input file> ";
-
-/* Seitan options */
-static struct argp_option options[] = {
-	{ "input", 'i', "FILE", 0, "Action input file", 0 },
-	{ "output", 'o', "FILE", 0, "Log filtered syscall in the file", 0 },
-	{ "pid", 'p', "pid", 0,
-	  "Pid of process to monitor (cannot be used together with -socket)",
-	  0 },
-	{ "socket", 's', "/tmp/seitan.sock", 0,
-	  "Socket to pass the seccomp notifier fd (cannot be used together with -pid)",
-	  0 },
-	{ 0 }
-};
-
-struct arguments {
-	char *input_file;
-	char *output_file;
-	char *socket;
-	int pid;
-};
-
-static error_t parse_opt(int key, char *arg, struct argp_state *state)
-{
-	struct arguments *arguments = state->input;
-
-	switch (key) {
-	case 'p':
-		arguments->pid = atoi(arg);
-		break;
-	case 'i':
-		arguments->input_file = arg;
-		break;
-	case 'o':
-		arguments->output_file = arg;
-		break;
-	case 's':
-		arguments->socket = arg;
-		break;
-	case ARGP_KEY_END:
-		if (arguments->input_file == NULL)
-			argp_error(state, "missing input file");
-		if (strcmp(arguments->socket, "") > 0 && arguments->pid > 0)
-			argp_error(
-				state,
-				"the -socket and -pid options cannot be used together");
-		break;
-	default:
-		return ARGP_ERR_UNKNOWN;
-	}
-
-	return 0;
-}
-
-static struct argp argp = { .options = options,
-			    .parser = parse_opt,
-			    .args_doc = NULL,
-			    .doc = doc,
-			    .children = NULL,
-			    .help_filter = NULL,
-			    .argp_domain = NULL };
-
-static int nl_init(void)
-{
-	int s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
-	struct sockaddr_nl sa = {
-		.nl_family = AF_NETLINK,
-		.nl_groups = CN_IDX_PROC,
-		.nl_pid = getpid(),
-	};
-	struct req_t {
-		struct nlmsghdr nlh;
-		struct cn_msg cnm;
-		enum proc_cn_mcast_op mop;
-	} __attribute__((packed, aligned(NLMSG_ALIGNTO))) req = {
-		.nlh.nlmsg_type = NLMSG_DONE,
-		.nlh.nlmsg_pid = getpid(),
-
-		.cnm.id.idx = CN_IDX_PROC,
-		.cnm.id.val = CN_VAL_PROC,
-		.cnm.len = sizeof(enum proc_cn_mcast_op),
-
-		.mop = PROC_CN_MCAST_LISTEN,
-	};
-
-	bind(s, (struct sockaddr *)&sa, sizeof(sa));
-
-	req.nlh.nlmsg_len = sizeof(req);
-	send(s, &req, sizeof(req), 0);
-
-	return s;
-}
-
-static int event(int s)
-{
-	char path[PATH_MAX + 1], exe[PATH_MAX + 1];
-	struct proc_event *ev;
-	struct nlmsghdr *nlh;
-	struct cn_msg *cnh;
-	char buf[BUFSIZ];
-	ssize_t n;
-
-	if ((n = recv(s, &buf, sizeof(buf), 0)) <= 0)
-		return -EIO;
-
-	nlh = (struct nlmsghdr *)buf;
-	for (; NLMSG_OK(nlh, n); nlh = NLMSG_NEXT(nlh, n)) {
-		if (nlh->nlmsg_type == NLMSG_NOOP)
-			continue;
-
-		if ((nlh->nlmsg_type == NLMSG_ERROR) ||
-		    (nlh->nlmsg_type == NLMSG_OVERRUN))
-			break;
-
-		cnh = NLMSG_DATA(nlh);
-		ev = (struct proc_event *)cnh->data;
-
-		if (ev->what != PROC_EVENT_EXEC)
-			continue;
-
-		snprintf(path, PATH_MAX, "/proc/%i/exe",
-			 ev->event_data.exec.process_pid);
-
-		readlink(path, exe, PATH_MAX);
-		if (!strcmp(exe, "/usr/local/bin/seitan-eater") ||
-		    !strcmp(exe, "/usr/bin/seitan-eater"))
-			return ev->event_data.exec.process_pid;
-
-		if (nlh->nlmsg_type == NLMSG_DONE)
-			break;
-	}
-
-	return -EAGAIN;
-}
-
-enum transform {
-	NONE,
-	FD1_UNIX,
-	FDRET_SRC,
-	DEV_CHECK,
-};
-
-struct table {
-	enum transform type;
-	long number;
-
-	char arg[6][1024];
-};
-
-static struct table t[16];
-
-static int pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
-			     unsigned int flags)
-{
-	return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
-}
-
-static void unblock_eater(int pidfd)
-{
-	if (pidfd_send_signal(pidfd, SIGCONT, NULL, 0) == -1) {
-		perror("pidfd_send_signal");
-		exit(EXIT_FAILURE);
-	}
-}
-
-int handle(struct seccomp_notif *req, int notifyfd)
-{
-	char path[PATH_MAX + 1];
-	struct sockaddr_un s_un;
-	int fd_unix;
-	unsigned i;
-	int mem;
-
-	for (i = 0; i < sizeof(t) / sizeof(t[0]); i++) {
-		if (t[i].number == req->data.nr)
-			break;
-	}
-
-	if (i == sizeof(t) / sizeof(t[0])) /* Not found */
-		return 1;
-
-	if (t[i].type != FD1_UNIX) /* Not implemented yet */
-		return 1;
-
-	/* FD1_UNIX here */
-	snprintf(path, sizeof(path), "/proc/%i/mem", req->pid);
-	fd_unix = req->data.args[0];
-
-	mem = open(path, O_RDONLY);
-	lseek(mem, req->data.args[1], SEEK_SET);
-	read(mem, &s_un, sizeof(s_un));
-	close(mem);
-
-	if (!strcmp(s_un.sun_path, t[i].arg[0])) {
-		int own_fd = socket(AF_UNIX, SOCK_STREAM, 0);
-
-		struct seccomp_notif_addfd addfd = {
-			.id = req->id,
-			.flags = SECCOMP_ADDFD_FLAG_SEND |
-				 SECCOMP_ADDFD_FLAG_SETFD,
-			.srcfd = own_fd,
-			.newfd = fd_unix,
-		};
-
-		connect(own_fd, &s_un, sizeof(s_un));
-		ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_ADDFD, &addfd);
-		return 0;
-	}
-
-	return 1;
-}
-
-static int create_socket(const char *path)
-{
-	struct sockaddr_un addr;
-	int ret, conn;
-	int fd = socket(AF_UNIX, SOCK_STREAM, 0);
-	if (fd < 0)
-		errExit("error creating UNIX socket");
-
-	strcpy(addr.sun_path, path);
-	addr.sun_family = AF_UNIX;
-	ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
-	if (ret < 0)
-		errExit("bind");
-
-	ret = listen(fd, 1);
-	if (ret < 0)
-		errExit("listen");
-	conn = accept(fd, NULL, NULL);
-	if (conn < 0)
-		errExit("accept");
-
-	return conn;
-}
-
-static int recvfd(int sockfd)
-{
-	struct msghdr msgh;
-	struct iovec iov;
-	int data, fd;
-	ssize_t nr;
-
-	union {
-		char buf[CMSG_SPACE(sizeof(int))];
-		struct cmsghdr align;
-	} controlMsg;
-	struct cmsghdr *cmsgp;
-
-	msgh.msg_name = NULL;
-	msgh.msg_namelen = 0;
-
-	msgh.msg_iov = &iov;
-	msgh.msg_iovlen = 1;
-	iov.iov_base = &data;
-	iov.iov_len = sizeof(int);
-
-	msgh.msg_control = controlMsg.buf;
-	msgh.msg_controllen = sizeof(controlMsg.buf);
-
-	nr = recvmsg(sockfd, &msgh, 0);
-	if (nr == -1)
-		errExit("recvmsg");
-
-	cmsgp = CMSG_FIRSTHDR(&msgh);
-
-	if (cmsgp == NULL || cmsgp->cmsg_len != CMSG_LEN(sizeof(int)) ||
-	    cmsgp->cmsg_level != SOL_SOCKET || cmsgp->cmsg_type != SCM_RIGHTS) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	memcpy(&fd, CMSG_DATA(cmsgp), sizeof(int));
-	return fd;
-}
-
-static int write_syscall(int fd, struct seccomp_notif *req)
-{
-	char buf[1000];
-
-	/* TODO: Define format and print syscall with the right arguments */
-	snprintf(buf, sizeof(buf), "nr_syscall=%d\n", req->data.nr);
-	write(fd, buf, strlen(buf));
-	return 0;
-}
-
-int main(int argc, char **argv)
-{
-	int s = nl_init(), ret, pidfd, notifier;
-	char req_b[BUFSIZ];
-	struct epoll_event ev, events[EPOLL_EVENTS];
-	struct seccomp_notif *req = (struct seccomp_notif *)req_b;
-	struct arguments arguments;
-	char path[PATH_MAX + 1];
-	bool running = true;
-	bool output = false;
-	int fd, epollfd;
-	int notifierfd;
-	int nevents, i;
-	int fdout;
-
-	arguments.pid = -1;
-	argp_parse(&argp, argc, argv, 0, 0, &arguments);
-	fd = open(arguments.input_file, O_CLOEXEC | O_RDONLY);
-	read(fd, t, sizeof(t));
-	close(fd);
-
-	if (strcmp(arguments.output_file, "") > 0) {
-		output = true;
-		unlink(arguments.output_file);
-		if ((fdout = open(arguments.output_file,
-				  O_CREAT | O_RDWR | O_TRUNC)) < 0)
-			errExit("open");
-	}
-
-	if (arguments.pid > 0) {
-		if ((pidfd = syscall(SYS_pidfd_open, arguments.pid, 0)) < 0)
-			errExit("pidfd_open");
-		snprintf(path, sizeof(path), "/proc/%d/fd", arguments.pid);
-		if ((notifierfd = find_fd_seccomp_notifier(path)) < 0)
-			errExit("failed getting fd of the notifier");
-		if ((notifier = syscall(SYS_pidfd_getfd, pidfd, notifierfd,
-					0)) < 0)
-			errExit("pidfd_getfd");
-		/* Unblock seitan-loader */
-		unblock_eater(pidfd);
-	} else if (strcmp(arguments.socket, "") > 0) {
-		unlink(arguments.socket);
-		if ((fd = create_socket(arguments.socket)) < 0)
-			exit(EXIT_FAILURE);
-		if ((notifier = recvfd(fd)) < 0)
-			exit(EXIT_FAILURE);
-	} else {
-		while ((ret = event(s)) == -EAGAIN)
-			;
-		if (ret < 0)
-			exit(EXIT_FAILURE);
-	}
-	sleep(1);
-
-	if ((epollfd = epoll_create1(0)) < 0) {
-		perror("epoll_create");
-		exit(EXIT_FAILURE);
-	}
-	ev.events = EPOLLIN;
-	ev.data.fd = notifier;
-	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, notifier, &ev) == -1) {
-		perror("epoll_ctl: notifier");
-		exit(EXIT_FAILURE);
-	}
-
-	while (running) {
-		nevents = epoll_wait(epollfd, events, EPOLL_EVENTS, -1);
-		if (nevents < 0) {
-			perror("epoll_wait");
-			exit(EXIT_FAILURE);
-		}
-		memset(req, 0, sizeof(*req));
-		if (ioctl(notifier, SECCOMP_IOCTL_NOTIF_RECV, req) < 0)
-			errExit("recieving seccomp notification");
-		for (i = 0; i < nevents; ++i) {
-			if (events[i].events & EPOLLHUP) {
-				/* The notifier fd was closed by the target */
-				running = false;
-			} else if (notifier == events[i].data.fd) {
-				/*
-				 * TODO: remove until we parse correctly the
-				 * operations from the bytecode
-				 */
-				struct op operations[] = {
-					{ .type = OP_CONT },
-				};
-				if (do_operations(NULL, operations, req,
-						  sizeof(operations) /
-							  sizeof(operations[0]),
-						  req->pid, notifier,
-						  req->id) == -1)
-					errExit("failed executing operation");
-
-				if (output)
-					write_syscall(fdout, req);
-			}
-		}
-	}
-	if (strcmp(arguments.socket, "") > 0)
-		unlink(arguments.socket);
-}
-- 
cgit v1.2.3