[CRIU] [PATCH] crit: Show no payload for image objects

Pavel Emelyanov xemul at virtuozzo.com
Thu May 19 03:04:49 PDT 2016


In some images there can be quite a long "payload" -- some
raw data that is represented by base64 encoding. If we want
to explore huge images reading tons of base64 symbols can 
be quite time consuming :) E.g. I a 1.5 gigs image with sysv 
shmem was sent to me some time ago for investigation %)

So here is the --nopl argument for show action (decode should
produce encode-able image, so payload there is needed) that
just shows the amount of bytes in payload (if any).

Signed-off-by: Pavel Emelyanov <xemul at virtuozzo.com>
---
 crit/crit               |  3 ++-
 lib/py/images/images.py | 71 +++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 68 insertions(+), 6 deletions(-)

diff --git a/crit/crit b/crit/crit
index 93cbc98..09c59ab 100755
--- a/crit/crit
+++ b/crit/crit
@@ -25,7 +25,7 @@ def decode(opts):
 	indent = None
 
 	try:
-		img = pycriu.images.load(inf(opts), opts['pretty'])
+		img = pycriu.images.load(inf(opts), opts['pretty'], opts['nopl'])
 	except pycriu.images.MagicException as exc:
 		print >>sys.stderr, "Unknown magic %#x.\n"\
 				"Maybe you are feeding me an image with "\
@@ -265,6 +265,7 @@ def main():
 	show_parser = subparsers.add_parser('show',
 			help = "convert criu image from binary to human-readable json")
 	show_parser.add_argument("in")
+	show_parser.add_argument('--nopl', help = 'do not show entry payload (if exists)', action = 'store_true')
 	show_parser.set_defaults(func=decode, pretty=True, out=None)
 
 	opts = vars(parser.parse_args())
diff --git a/lib/py/images/images.py b/lib/py/images/images.py
index 0bc0a1f..789bba5 100644
--- a/lib/py/images/images.py
+++ b/lib/py/images/images.py
@@ -79,7 +79,7 @@ class entry_handler:
 		self.payload		= payload
 		self.extra_handler	= extra_handler
 
-	def load(self, f, pretty = False):
+	def load(self, f, pretty = False, no_payload = False):
 		"""
 		Convert criu image entries from binary format to dict(json).
 		Takes a file-like object and returnes a list with entries in
@@ -101,7 +101,21 @@ class entry_handler:
 
 			# Read extra
 			if self.extra_handler:
-				entry['extra'] = self.extra_handler.load(f, pb)
+				if no_payload:
+					def human_readable(num):
+						for unit in ['','K','M','G','T','P','E','Z']:
+							if num < 1024.0:
+								if int(num) == num:
+									return "%d%sB" % (num, unit)
+								else:
+									return "%.1f%sB" % (num, unit)
+							num /= 1024.0
+						return "%.1fYB" % num
+
+					pl_size = self.extra_handler.skip(f, pb)
+					entry['extra'] = '... <%s>' % human_readable(pl_size)
+				else:
+					entry['extra'] = self.extra_handler.load(f, pb)
 
 			entries.append(entry)
 
@@ -167,7 +181,7 @@ class pagemap_handler:
 	that it has a header of pagemap_head type followed by entries
 	of pagemap_entry type.
 	"""
-	def load(self, f, pretty = False):
+	def load(self, f, pretty = False, no_payload = False):
 		entries = []
 
 		pb = pagemap_head()
@@ -223,6 +237,10 @@ class pipes_data_extra_handler:
 		data = extra.decode('base64')
 		f.write(data)
 
+	def skip(self, f, pload):
+		f.seek(pload.bytes, os.SEEK_CUR)
+		return pload.bytes
+
 class sk_queues_extra_handler:
 	def load(self, f, pload):
 		size = pload.length
@@ -233,6 +251,10 @@ class sk_queues_extra_handler:
 		data = extra.decode('base64')
 		f.write(data)
 
+	def skip(self, f, pload):
+		f.seek(pload.length, os.SEEK_CUR)
+		return pload.length
+
 class ghost_file_extra_handler:
 	def load(self, f, pb):
 		data = f.read()
@@ -242,6 +264,11 @@ class ghost_file_extra_handler:
 		data = extra.decode('base64')
 		f.write(data)
 
+	def skip(self, f, pb):
+		p = f.tell()
+		f.seek(0, os.SEEK_END)
+		return f.tell() - p
+
 class tcp_stream_extra_handler:
 	def load(self, f, pb):
 		d = {}
@@ -261,6 +288,10 @@ class tcp_stream_extra_handler:
 		f.write(inq)
 		f.write(outq)
 
+	def skip(self, f, pb):
+		f.seek(0, os.SEEK_END)
+		return pb.inq_len + pb.outq_len
+
 class ipc_sem_set_handler:
 	def load(self, f, pb):
 		entry = pb2dict.pb2dict(pb)
@@ -286,6 +317,12 @@ class ipc_sem_set_handler:
 		f.write(s.tostring())
 		f.write('\0' * (rounded - size))
 
+	def skip(self, f, pb):
+		entry = pb2dict.pb2dict(pb)
+		size = sizeof_u16 * entry['nsems']
+		f.seek(round_up(size, sizeof_u64), os.SEEK_CUR)
+		return size
+
 class ipc_msg_queue_handler:
 	def load(self, f, pb):
 		entry = pb2dict.pb2dict(pb)
@@ -318,6 +355,22 @@ class ipc_msg_queue_handler:
 			f.write(data[:msg.msize])
 			f.write('\0' * (rounded - msg.msize))
 
+	def skip(self, f, pb):
+		entry = pb2dict.pb2dict(pb)
+		pl_len = 0
+		for x in range (0, entry['qnum']):
+			buf = f.read(4)
+			if buf == '':
+				break
+			size, = struct.unpack('i', buf)
+			msg = ipc_msg()
+			msg.ParseFromString(f.read(size))
+			rounded = round_up(msg.msize, sizeof_u64)
+			f.seek(rounded, os.SEEK_CUR)
+			pl_len += size + msg.msize
+
+		return pl_len
+
 class ipc_shm_handler:
 	def load(self, f, pb):
 		entry = pb2dict.pb2dict(pb)
@@ -335,6 +388,14 @@ class ipc_shm_handler:
 		f.write(data[:size])
 		f.write('\0' * (rounded - size))
 
+	def skip(self, f, pb):
+		entry = pb2dict.pb2dict(pb)
+		size = entry['size']
+		rounded = round_up(size, sizeof_u32)
+		f.seek(rounded, os.SEEK_CUR)
+		return size
+
+
 handlers = {
 	'INVENTORY'		: entry_handler(inventory_entry),
 	'CORE'			: entry_handler(core_entry),
@@ -412,7 +473,7 @@ def __rhandler(f):
 
 	return m, handler
 
-def load(f, pretty = False):
+def load(f, pretty = False, no_payload = False):
 	"""
 	Convert criu image from binary format to dict(json).
 	Takes a file-like object to read criu image from.
@@ -423,7 +484,7 @@ def load(f, pretty = False):
 	m, handler = __rhandler(f)
 
 	image['magic'] = m
-	image['entries'] = handler.load(f, pretty)
+	image['entries'] = handler.load(f, pretty, no_payload)
 
 	return image
 
-- 
2.5.0


More information about the CRIU mailing list