[CRIU] [PATCH 2/4] tools: add criu2text

Ruslan Kuprieiev kupruser at gmail.com
Fri Sep 19 06:53:11 PDT 2014


criu2text.py handles cmdline opts, opens files and reads\writes them
properly. images.py has a dict with MAGIC:pb_entry_type to specify what
type of pb entry we should read from image with magic MAGIC.
magic-gen.py parses include/magic.h to get all MAGIC values except
RAW and V1, because criu2text can't handle them for now.

Signed-off-by: Ruslan Kuprieiev <kupruser at gmail.com>
---
 tools/criu2text/.gitignore   |   4 ++
 tools/criu2text/Makefile     |  15 +++++
 tools/criu2text/criu2text    | 156 +++++++++++++++++++++++++++++++++++++++++++
 tools/criu2text/images.py    | 112 +++++++++++++++++++++++++++++++
 tools/criu2text/magic-gen.py |  44 ++++++++++++
 5 files changed, 331 insertions(+)
 create mode 100644 tools/criu2text/.gitignore
 create mode 100644 tools/criu2text/Makefile
 create mode 100755 tools/criu2text/criu2text
 create mode 100644 tools/criu2text/images.py
 create mode 100644 tools/criu2text/magic-gen.py

diff --git a/tools/criu2text/.gitignore b/tools/criu2text/.gitignore
new file mode 100644
index 0000000..550f4b1
--- /dev/null
+++ b/tools/criu2text/.gitignore
@@ -0,0 +1,4 @@
+*.pyc
+*_pb2.py
+magic.py
+__pycache__
diff --git a/tools/criu2text/Makefile b/tools/criu2text/Makefile
new file mode 100644
index 0000000..986f426
--- /dev/null
+++ b/tools/criu2text/Makefile
@@ -0,0 +1,15 @@
+.PHONY: all clean protobuf
+
+PROTOBUF_DIR	= ../../protobuf
+MAGIC_C_HEADER	= ../../include/magic.h
+
+all: magic.py protobuf
+
+magic.py: $(MAGIC_C_HEADER) protobuf
+	python magic-gen.py $(MAGIC_C_HEADER)
+
+protobuf:
+	protoc -I=$(PROTOBUF_DIR) --python_out=./ $(PROTOBUF_DIR)/*.proto
+
+clean:
+	rm -rf *.pyc *_pb2.py __pycache__ magic.py
diff --git a/tools/criu2text/criu2text b/tools/criu2text/criu2text
new file mode 100755
index 0000000..1dfaae9
--- /dev/null
+++ b/tools/criu2text/criu2text
@@ -0,0 +1,156 @@
+#!/bin/env python
+import os, sys
+import struct
+import google
+import shutil
+import argparse
+
+import images
+
+def img2text(img_name):
+	fin = open(img_name, 'r')
+	# Read magic cookie to identify criu image
+	buf = fin.read(4)
+
+	# Convert cookie into "0x12345.." string to
+	# use it as a key in criu.magic dict
+	cookie, = struct.unpack('i', buf)
+	cookie = "0x{0:x}".format(cookie)
+
+	base = os.path.basename(img_name)
+
+	# Write cookie into file named magic
+	with open(base+'.magic', 'w+') as fout:
+		fout.write(cookie)
+
+	if cookie in images.pb.keys():
+		pb = images.pb[cookie]()
+		num = 0
+
+		while True:
+			# Read size of the following pb message
+			buf = fin.read(4)
+			if buf == '':
+				break
+
+			size, = struct.unpack('i', buf)
+
+			# Read pb message
+			pb.ParseFromString(fin.read(size))
+
+			# Write text representation of
+			# pb message into num file
+			with open(base+'.'+str(num), 'w+') as fout:
+				google.protobuf.text_format.PrintMessage(pb, fout)
+
+			num += 1
+			# pagemap.img is a special one. It starts with
+			# pagemap_head message and is followed by an
+			# array of pagemap_entry's.
+			if cookie == images.PAGEMAP_MAGIC:
+				pb = images.pagemap_entry()
+
+		fin.close()
+	else:
+		print("not criu image or unknown format")
+		fin.close()
+		exit(1)
+
+def text2img(img_name):
+	base = os.path.basename(img_name)
+
+	fout = open(base, 'w+')
+
+	# Open magic file to get magic cookie
+	with open(img_name+'.magic', 'r') as fin:
+		cookie = fin.read()
+
+	if cookie in images.pb.keys():
+		# Write magic cookie into img file
+		fout.write(struct.pack('i', int(cookie,16)))
+
+		# Corresponding function that we need to call
+		# to init pb message
+		pb_init_function = images.pb[cookie]
+
+		num = 0
+		while True:
+			if not os.path.isfile(img_name+'.'+str(num)):
+				break
+
+			pb = pb_init_function()
+
+			# Read pb message int text format from
+			# file num
+			with open(img_name+'.'+str(num), 'r') as fin:
+				pb_text = fin.read()
+
+			# Parse pb from text format and write
+			# it to img file
+			google.protobuf.text_format.Merge(pb_text, pb)
+			size = len(pb.SerializeToString())
+			fout.write(struct.pack('i', size))
+			fout.write(pb.SerializeToString())
+
+			num += 1
+			# pagemap.img is a special one. It starts with
+			# pagemap_head message and is followed by an
+			# array of pagemap_entry's.
+			if cookie == images.PAGEMAP_MAGIC:
+				pb_init_function = images.pagemap_entry
+
+		fout.close()
+	else:
+		print("unknown format")
+		fout.close()
+		exit(1)
+
+def main():
+	desc	= "Convert criu images to/from set of files in human-readable format"
+        epi	= "Examples:\n"\
+		  "1) Convert ./core-1234.img to set of text files (core-1234.img.magic,\n"\
+		  "   core-1234.img.0) and place them at text_imgs_dir.\n"\
+		  "\n"\
+		  "       $ criu2text to-text core-1234.img -o text_imgs_dir\n"\
+		  "       $ ls text_imgs_dir\n"\
+		  "       core-1234.img.magic\n"\
+		  "       core-1234.img.0\n"\
+		  "\n"\
+		  "2) Convert text_imgs_dir/core-1234.img.magic, text_imgs_dir/core-1234.img.0\n"\
+		  "   (note common base text_imgs_dir/core-1234.img, which we're specifying)\n"\
+		  "   to criu img format and place it at imgs_dir.\n"\
+		  "\n"\
+		  "       $ criu2text to-img text_imgs_dir/core-1234.img -o imgs_dir\n"\
+		  "       $ ls imgs_dir\n"\
+		  "       core-1234.img\n"\
+		  "\n"
+
+	parser = argparse.ArgumentParser(description = desc,
+					 epilog = epi,
+					 formatter_class = argparse.RawTextHelpFormatter)
+	parser.add_argument('command',
+			    choices = ['to-text', 'to-img'],
+			    help = 'to what type convert input file(s)')
+	parser.add_argument('image',
+			    help = 'path to criu image or base path to criu image files in '\
+				   'human-readable format (e.g. ./imgs/core-1234.img)')
+	parser.add_argument('-o',
+			    '--out',
+			    default = './',
+			    help = 'directory where output file(s) should be placed')
+
+	opts = vars(parser.parse_args())
+
+	opts['image']		= os.path.abspath(opts['image'])
+	opts['out']		= os.path.abspath(opts['out'])
+
+	os.chdir(opts['out'])
+
+	if opts['command'] == 'to-text':
+		img2text(opts['image'])
+
+	if opts['command'] == 'to-img':
+		text2img(opts['image'])
+
+if __name__ == "__main__":
+	main()
diff --git a/tools/criu2text/images.py b/tools/criu2text/images.py
new file mode 100644
index 0000000..99bc088
--- /dev/null
+++ b/tools/criu2text/images.py
@@ -0,0 +1,112 @@
+from stats_pb2 import *
+from timer_pb2 import *
+from ipc_sem_pb2 import *
+from core_pb2 import *
+from core_x86_pb2 import *
+from remap_file_path_pb2 import *
+from fsnotify_pb2 import *
+from inventory_pb2 import *
+from tcp_stream_pb2 import *
+from mnt_pb2 import *
+from packet_sock_pb2 import *
+from pipe_data_pb2 import *
+from ipc_var_pb2 import *
+from sa_pb2 import *
+from tun_pb2 import *
+from fown_pb2 import *
+from tty_pb2 import *
+from rlimit_pb2 import *
+from ipc_shm_pb2 import *
+from file_lock_pb2 import *
+from sk_unix_pb2 import *
+from sk_packet_pb2 import *
+from pagemap_pb2 import *
+from pipe_pb2 import *
+from pstree_pb2 import *
+from sk_opts_pb2 import *
+from siginfo_pb2 import *
+from cgroup_pb2 import *
+from fh_pb2 import *
+from ipc_msg_pb2 import *
+from mm_pb2 import *
+from netdev_pb2 import *
+from timerfd_pb2 import *
+from ns_pb2 import *
+from fs_pb2 import *
+from ext_file_pb2 import *
+from signalfd_pb2 import *
+from ipc_desc_pb2 import *
+from fdinfo_pb2 import *
+from fifo_pb2 import *
+from eventpoll_pb2 import *
+from regfile_pb2 import *
+from core_arm_pb2 import *
+from sk_netlink_pb2 import *
+from sk_inet_pb2 import *
+from utsns_pb2 import *
+from core_aarch64_pb2 import *
+from eventfd_pb2 import *
+from creds_pb2 import *
+from vma_pb2 import *
+from rpc_pb2 import *
+from ghost_file_pb2 import *
+
+from magic import *
+
+# This dict is needed to identify what type of pb messages
+# we need to read from image.
+pb = {
+	IDS_MAGIC           : task_kobj_ids_entry,
+	IRMAP_CACHE_MAGIC   : irmap_cache_entry,
+	FS_MAGIC            : fs_entry,
+	PAGEMAP_MAGIC       : pagemap_head,
+	FIFO_MAGIC          : fifo_entry,
+	EVENTFD_FILE_MAGIC  : eventfd_file_entry,
+	PIPES_DATA_MAGIC    : pipe_data_entry,
+	INETSK_MAGIC        : inet_sk_entry,
+	TTY_FILES_MAGIC     : tty_file_entry,
+	UTSNS_MAGIC         : utsns_entry,
+	FDINFO_MAGIC        : fdinfo_entry,
+	NS_FILES_MAGIC      : ns_file_entry,
+	INOTIFY_WD_MAGIC    : inotify_wd_entry,
+	EVENTPOLL_TFD_MAGIC : eventpoll_tfd_entry,
+	MNTS_MAGIC          : mnt_entry,
+	VMAS_MAGIC          : vma_entry,
+	IPCNS_SHM_MAGIC     : ipc_shm_entry,
+	CORE_MAGIC          : core_entry,
+	FILE_LOCKS_MAGIC    : file_lock_entry,
+	EVENTPOLL_FILE_MAGIC: eventpoll_file_entry,
+	REMAP_FPATH_MAGIC   : remap_file_path_entry,
+	SK_QUEUES_MAGIC     : sk_packet_entry,
+	REG_FILES_MAGIC     : reg_file_entry,
+	TUNFILE_MAGIC       : tunfile_entry,
+	IPC_VAR_MAGIC       : ipc_var_entry,
+	TTY_INFO_MAGIC      : tty_info_entry,
+	PIPES_MAGIC         : pipe_entry,
+	NETDEV_MAGIC        : net_device_entry,
+	STATS_MAGIC         : stats_entry,
+	RLIMIT_MAGIC        : rlimit_entry,
+	POSIX_TIMERS_MAGIC  : posix_timer_entry,
+	FANOTIFY_MARK_MAGIC : fanotify_mark_entry,
+	TIMERFD_MAGIC       : timerfd_entry,
+	ITIMERS_MAGIC       : itimer_entry,
+	CREDS_MAGIC         : creds_entry,
+	SIGACT_MAGIC        : sa_entry,
+	FIFO_DATA_MAGIC     : pipe_data_entry,
+	TCP_STREAM_MAGIC    : tcp_stream_entry,
+	PSTREE_MAGIC        : pstree_entry,
+	UNIXSK_MAGIC        : unix_sk_entry,
+	EXT_FILES_MAGIC     : ext_file_entry,
+	SIGNAL_MAGIC        : siginfo_entry,
+	INOTIFY_FILE_MAGIC  : inotify_file_entry,
+	IPCNS_SEM_MAGIC     : ipc_sem_entry,
+	NETLINK_SK_MAGIC    : netlink_sk_entry,
+	FANOTIFY_FILE_MAGIC : fanotify_file_entry,
+	SIGNALFD_MAGIC      : signalfd_entry,
+	MM_MAGIC            : mm_entry,
+	CGROUP_MAGIC        : cgroup_entry,
+	PACKETSK_MAGIC      : packet_sock_entry,
+	GHOST_FILE_MAGIC    : ghost_file_entry,
+	IPCNS_MSG_MAGIC     : ipc_msg_entry,
+	INVENTORY_MAGIC     : inventory_entry,
+}
diff --git a/tools/criu2text/magic-gen.py b/tools/criu2text/magic-gen.py
new file mode 100644
index 0000000..0bd9050
--- /dev/null
+++ b/tools/criu2text/magic-gen.py
@@ -0,0 +1,44 @@
+import os, sys
+import struct
+
+# This program parses criu magic.h file and produces
+# magic.py with all *_MAGIC constants except RAW and V1.
+def main(argv):
+    if len(argv) != 2:
+        print("Usage: magic-gen.py path/to/image.h")
+        exit(1)
+
+    magic_c_header = argv[1]
+    magic_py = "magic.py"
+
+    out = open(magic_py, 'w+')
+
+    magic = {}
+
+    f = open(magic_c_header, 'r')
+    for line in f:
+    	split = line.split()
+
+    	if len(split) < 3:
+            continue
+
+	if not '#define' in split[0]:
+	    continue
+
+	key = split[1]
+	value = split[2]
+
+	if value in magic:
+            value = magic[value]
+
+	magic[key] = value
+
+        if value == '0x0' or value == '1':
+            continue
+
+        out.write(key+" = "+"\'"+value+"\'\n")
+
+    out.close()
+
+if __name__ == "__main__":
+    main(sys.argv)
-- 
1.9.3



More information about the CRIU mailing list