2018-05-16 06:20:22 +00:00
|
|
|
from __future__ import print_function
|
2014-12-31 14:06:49 +02:00
|
|
|
import argparse
|
|
|
|
import sys
|
|
|
|
import json
|
2015-12-14 13:20:04 +03:00
|
|
|
import os
|
2014-12-31 14:06:49 +02:00
|
|
|
|
|
|
|
import pycriu
|
|
|
|
|
2015-01-15 19:51:18 +03:00
|
|
|
def inf(opts):
|
|
|
|
if opts['in']:
|
2018-05-16 06:20:22 +00:00
|
|
|
return open(opts['in'], 'rb')
|
2015-01-15 19:51:18 +03:00
|
|
|
else:
|
|
|
|
return sys.stdin
|
|
|
|
|
|
|
|
def outf(opts):
|
|
|
|
if opts['out']:
|
|
|
|
return open(opts['out'], 'w+')
|
|
|
|
else:
|
|
|
|
return sys.stdout
|
|
|
|
|
2015-12-14 13:19:00 +03:00
|
|
|
def dinf(opts, name):
|
|
|
|
return open(os.path.join(opts['dir'], name))
|
2015-01-14 16:32:38 +02:00
|
|
|
|
|
|
|
def decode(opts):
|
2014-12-31 14:06:49 +02:00
|
|
|
indent = None
|
2015-05-29 16:01:00 +03:00
|
|
|
|
|
|
|
try:
|
2016-05-19 13:04:00 +03:00
|
|
|
img = pycriu.images.load(inf(opts), opts['pretty'], opts['nopl'])
|
2015-05-29 16:01:00 +03:00
|
|
|
except pycriu.images.MagicException as exc:
|
2018-05-16 06:20:22 +00:00
|
|
|
print("Unknown magic %#x.\n"\
|
2015-05-29 16:01:00 +03:00
|
|
|
"Maybe you are feeding me an image with "\
|
2018-05-16 06:20:22 +00:00
|
|
|
"raw data(i.e. pages.img)?" % exc.magic, file=sys.stderr)
|
2015-05-29 16:01:00 +03:00
|
|
|
sys.exit(1)
|
2014-12-31 14:06:49 +02:00
|
|
|
|
2015-01-28 17:15:00 +03:00
|
|
|
if opts['pretty']:
|
2014-12-31 14:06:49 +02:00
|
|
|
indent = 4
|
|
|
|
|
2015-01-15 19:51:18 +03:00
|
|
|
f = outf(opts)
|
|
|
|
json.dump(img, f, indent=indent)
|
|
|
|
if f == sys.stdout:
|
|
|
|
f.write("\n")
|
2015-01-14 16:32:38 +02:00
|
|
|
|
|
|
|
def encode(opts):
|
2015-01-15 19:51:18 +03:00
|
|
|
img = json.load(inf(opts))
|
|
|
|
pycriu.images.dump(img, outf(opts))
|
2014-12-31 14:06:49 +02:00
|
|
|
|
2015-09-16 16:16:24 +03:00
|
|
|
def info(opts):
|
|
|
|
infs = pycriu.images.info(inf(opts))
|
|
|
|
json.dump(infs, sys.stdout, indent = 4)
|
2018-05-16 06:20:22 +00:00
|
|
|
print()
|
2015-09-16 16:16:24 +03:00
|
|
|
|
2017-09-05 11:19:41 +03:00
|
|
|
def get_task_id(p, val):
|
|
|
|
return p[val] if val in p else p['ns_' + val][0]
|
2015-12-14 13:19:00 +03:00
|
|
|
#
|
|
|
|
# Explorers
|
|
|
|
#
|
|
|
|
|
2015-12-14 13:20:04 +03:00
|
|
|
class ps_item:
|
|
|
|
def __init__(self, p, core):
|
2017-09-05 11:19:41 +03:00
|
|
|
self.pid = get_task_id(p, 'pid')
|
2015-12-14 13:20:04 +03:00
|
|
|
self.ppid = p['ppid']
|
|
|
|
self.p = p
|
|
|
|
self.core = core
|
|
|
|
self.kids = []
|
|
|
|
|
|
|
|
def show_ps(p, opts, depth = 0):
|
2018-05-16 06:20:22 +00:00
|
|
|
print("%7d%7d%7d %s%s" % (p.pid, get_task_id(p.p, 'pgid'), get_task_id(p.p, 'sid'),
|
|
|
|
' ' * (4 * depth), p.core['tc']['comm']))
|
2015-12-14 13:20:04 +03:00
|
|
|
for kid in p.kids:
|
|
|
|
show_ps(kid, opts, depth + 1)
|
|
|
|
|
|
|
|
def explore_ps(opts):
|
|
|
|
pss = { }
|
|
|
|
ps_img = pycriu.images.load(dinf(opts, 'pstree.img'))
|
|
|
|
for p in ps_img['entries']:
|
2017-09-05 11:19:41 +03:00
|
|
|
core = pycriu.images.load(dinf(opts, 'core-%d.img' % get_task_id(p, 'pid')))
|
2015-12-14 13:20:04 +03:00
|
|
|
ps = ps_item(p, core['entries'][0])
|
|
|
|
pss[ps.pid] = ps
|
|
|
|
|
|
|
|
# Build tree
|
|
|
|
psr = None
|
|
|
|
for pid in pss:
|
|
|
|
p = pss[pid]
|
|
|
|
if p.ppid == 0:
|
|
|
|
psr = p
|
|
|
|
continue
|
|
|
|
|
|
|
|
pp = pss[p.ppid]
|
|
|
|
pp.kids.append(p)
|
|
|
|
|
2018-05-16 06:20:22 +00:00
|
|
|
print("%7s%7s%7s %s" % ('PID', 'PGID', 'SID', 'COMM'))
|
2015-12-14 13:20:04 +03:00
|
|
|
show_ps(psr, opts)
|
|
|
|
|
2017-09-05 14:39:00 +03:00
|
|
|
files_img = None
|
|
|
|
|
|
|
|
def ftype_find_in_files(opts, ft, fid):
|
|
|
|
global files_img
|
|
|
|
|
|
|
|
if files_img is None:
|
|
|
|
try:
|
|
|
|
files_img = pycriu.images.load(dinf(opts, "files.img"))['entries']
|
|
|
|
except:
|
|
|
|
files_img = []
|
|
|
|
|
|
|
|
if len(files_img) == 0:
|
|
|
|
return None
|
|
|
|
|
|
|
|
for f in files_img:
|
|
|
|
if f['id'] == fid:
|
|
|
|
return f
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
2015-12-14 13:20:04 +03:00
|
|
|
|
2015-12-14 13:20:58 +03:00
|
|
|
def ftype_find_in_image(opts, ft, fid, img):
|
2017-09-05 14:39:00 +03:00
|
|
|
f = ftype_find_in_files(opts, ft, fid)
|
|
|
|
if f:
|
|
|
|
return f[ft['field']]
|
|
|
|
|
2015-12-14 13:20:58 +03:00
|
|
|
if ft['img'] == None:
|
|
|
|
ft['img'] = pycriu.images.load(dinf(opts, img))['entries']
|
|
|
|
for f in ft['img']:
|
|
|
|
if f['id'] == fid:
|
|
|
|
return f
|
|
|
|
return None
|
|
|
|
|
|
|
|
def ftype_reg(opts, ft, fid):
|
|
|
|
rf = ftype_find_in_image(opts, ft, fid, 'reg-files.img')
|
|
|
|
return rf and rf['name'] or 'unknown path'
|
|
|
|
|
|
|
|
def ftype_pipe(opts, ft, fid):
|
|
|
|
p = ftype_find_in_image(opts, ft, fid, 'pipes.img')
|
|
|
|
return p and 'pipe[%d]' % p['pipe_id'] or 'pipe[?]'
|
|
|
|
|
|
|
|
def ftype_unix(opts, ft, fid):
|
|
|
|
ux = ftype_find_in_image(opts, ft, fid, 'unixsk.img')
|
|
|
|
if not ux:
|
|
|
|
return 'unix[?]'
|
|
|
|
|
2017-09-05 14:39:00 +03:00
|
|
|
n = ux['name'] and ' %s' % ux['name'] or ''
|
2015-12-14 13:20:58 +03:00
|
|
|
return 'unix[%d (%d)%s]' % (ux['ino'], ux['peer'], n)
|
|
|
|
|
|
|
|
file_types = {
|
2017-09-05 14:39:00 +03:00
|
|
|
'REG': {'get': ftype_reg, 'img': None, 'field': 'reg'},
|
|
|
|
'PIPE': {'get': ftype_pipe, 'img': None, 'field': 'pipe'},
|
|
|
|
'UNIXSK': {'get': ftype_unix, 'img': None, 'field': 'usk'},
|
2015-12-14 13:20:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
def ftype_gen(opts, ft, fid):
|
|
|
|
return '%s.%d' % (ft['typ'], fid)
|
|
|
|
|
|
|
|
files_cache = { }
|
|
|
|
|
|
|
|
def get_file_str(opts, fd):
|
|
|
|
key = (fd['type'], fd['id'])
|
|
|
|
f = files_cache.get(key, None)
|
|
|
|
if not f:
|
|
|
|
ft = file_types.get(fd['type'], {'get': ftype_gen, 'typ': fd['type']})
|
|
|
|
f = ft['get'](opts, ft, fd['id'])
|
|
|
|
files_cache[key] = f
|
|
|
|
|
|
|
|
return f
|
|
|
|
|
|
|
|
def explore_fds(opts):
|
|
|
|
ps_img = pycriu.images.load(dinf(opts, 'pstree.img'))
|
|
|
|
for p in ps_img['entries']:
|
2017-09-05 11:19:41 +03:00
|
|
|
pid = get_task_id(p, 'pid')
|
2015-12-14 13:20:58 +03:00
|
|
|
idi = pycriu.images.load(dinf(opts, 'ids-%s.img' % pid))
|
|
|
|
fdt = idi['entries'][0]['files_id']
|
|
|
|
fdi = pycriu.images.load(dinf(opts, 'fdinfo-%d.img' % fdt))
|
|
|
|
|
2018-05-16 06:20:22 +00:00
|
|
|
print("%d" % pid)
|
2015-12-14 13:20:58 +03:00
|
|
|
for fd in fdi['entries']:
|
2018-05-16 06:20:22 +00:00
|
|
|
print("\t%7d: %s" % (fd['fd'], get_file_str(opts, fd)))
|
2015-12-14 13:20:58 +03:00
|
|
|
|
|
|
|
fdi = pycriu.images.load(dinf(opts, 'fs-%d.img' % pid))['entries'][0]
|
2018-05-16 06:20:22 +00:00
|
|
|
print("\t%7s: %s" % ('cwd', get_file_str(opts, {'type': 'REG', 'id': fdi['cwd_id']})))
|
|
|
|
print("\t%7s: %s" % ('root', get_file_str(opts, {'type': 'REG', 'id': fdi['root_id']})))
|
2015-12-14 13:20:58 +03:00
|
|
|
|
|
|
|
|
2015-12-14 17:14:00 +03:00
|
|
|
class vma_id:
|
|
|
|
def __init__(self):
|
|
|
|
self.__ids = {}
|
|
|
|
self.__last = 1
|
|
|
|
|
|
|
|
def get(self, iid):
|
|
|
|
ret = self.__ids.get(iid, None)
|
|
|
|
if not ret:
|
|
|
|
ret = self.__last
|
|
|
|
self.__last += 1
|
|
|
|
self.__ids[iid] = ret
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def explore_mems(opts):
|
|
|
|
ps_img = pycriu.images.load(dinf(opts, 'pstree.img'))
|
|
|
|
vids = vma_id()
|
|
|
|
for p in ps_img['entries']:
|
2017-09-05 11:19:41 +03:00
|
|
|
pid = get_task_id(p, 'pid')
|
2015-12-14 17:14:00 +03:00
|
|
|
mmi = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0]
|
|
|
|
|
2018-05-16 06:20:22 +00:00
|
|
|
print("%d" % pid)
|
|
|
|
print("\t%-36s %s" % ('exe', get_file_str(opts, {'type': 'REG', 'id': mmi['exe_file_id']})))
|
2015-12-14 17:14:00 +03:00
|
|
|
|
|
|
|
for vma in mmi['vmas']:
|
|
|
|
st = vma['status']
|
|
|
|
if st & (1 << 10):
|
|
|
|
fn = ' ' + 'ips[%lx]' % vids.get(vma['shmid'])
|
|
|
|
elif st & (1 << 8):
|
|
|
|
fn = ' ' + 'shmem[%lx]' % vids.get(vma['shmid'])
|
|
|
|
elif st & (1 << 11):
|
|
|
|
fn = ' ' + 'packet[%lx]' % vids.get(vma['shmid'])
|
|
|
|
elif st & ((1 << 6) | (1 << 7)):
|
|
|
|
fn = ' ' + get_file_str(opts, {'type': 'REG', 'id': vma['shmid']})
|
|
|
|
if vma['pgoff']:
|
|
|
|
fn += ' + %#lx' % vma['pgoff']
|
|
|
|
if st & (1 << 7):
|
|
|
|
fn += ' (s)'
|
|
|
|
elif st & (1 << 1):
|
|
|
|
fn = ' [stack]'
|
|
|
|
elif st & (1 << 2):
|
|
|
|
fn = ' [vsyscall]'
|
|
|
|
elif st & (1 << 3):
|
|
|
|
fn = ' [vdso]'
|
|
|
|
elif vma['flags'] & 0x0100: # growsdown
|
|
|
|
fn = ' [stack?]'
|
|
|
|
else:
|
|
|
|
fn = ''
|
|
|
|
|
|
|
|
if not st & (1 << 0):
|
|
|
|
fn += ' *'
|
|
|
|
|
|
|
|
prot = vma['prot'] & 0x1 and 'r' or '-'
|
|
|
|
prot += vma['prot'] & 0x2 and 'w' or '-'
|
|
|
|
prot += vma['prot'] & 0x4 and 'x' or '-'
|
|
|
|
|
|
|
|
astr = '%08lx-%08lx' % (vma['start'], vma['end'])
|
2018-05-16 06:20:22 +00:00
|
|
|
print("\t%-36s%s%s" % (astr, prot, fn))
|
2015-12-14 17:14:00 +03:00
|
|
|
|
|
|
|
|
2017-04-13 18:26:36 +03:00
|
|
|
def explore_rss(opts):
|
|
|
|
ps_img = pycriu.images.load(dinf(opts, 'pstree.img'))
|
|
|
|
for p in ps_img['entries']:
|
2017-09-05 11:19:41 +03:00
|
|
|
pid = get_task_id(p, 'pid')
|
2017-04-13 18:26:36 +03:00
|
|
|
vmas = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0]['vmas']
|
|
|
|
pms = pycriu.images.load(dinf(opts, 'pagemap-%d.img' % pid))['entries']
|
|
|
|
|
2018-05-16 06:20:22 +00:00
|
|
|
print("%d" % pid)
|
2017-04-13 18:26:36 +03:00
|
|
|
vmi = 0
|
|
|
|
pvmi = -1
|
|
|
|
for pm in pms[1:]:
|
|
|
|
pstr = '\t%lx / %-8d' % (pm['vaddr'], pm['nr_pages'])
|
|
|
|
while vmas[vmi]['end'] <= pm['vaddr']:
|
|
|
|
vmi += 1
|
|
|
|
|
|
|
|
pme = pm['vaddr'] + (pm['nr_pages'] << 12)
|
|
|
|
vstr = ''
|
|
|
|
while vmas[vmi]['start'] < pme:
|
|
|
|
vma = vmas[vmi]
|
|
|
|
if vmi == pvmi:
|
|
|
|
vstr += ' ~'
|
|
|
|
else:
|
|
|
|
vstr += ' %08lx / %-8d' % (vma['start'], (vma['end'] - vma['start'])>>12)
|
|
|
|
if vma['status'] & ((1 << 6) | (1 << 7)):
|
|
|
|
vstr += ' ' + get_file_str(opts, {'type': 'REG', 'id': vma['shmid']})
|
|
|
|
pvmi = vmi
|
|
|
|
vstr += '\n\t%23s' % ''
|
|
|
|
vmi += 1
|
|
|
|
|
|
|
|
vmi -= 1
|
|
|
|
|
2018-05-16 06:20:22 +00:00
|
|
|
print('%-24s%s' % (pstr, vstr))
|
2017-04-13 18:26:36 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
explorers = { 'ps': explore_ps, 'fds': explore_fds, 'mems': explore_mems, 'rss': explore_rss }
|
2015-12-14 13:19:00 +03:00
|
|
|
|
|
|
|
def explore(opts):
|
|
|
|
explorers[opts['what']](opts)
|
|
|
|
|
2014-12-31 14:06:49 +02:00
|
|
|
def main():
|
2015-02-09 14:08:22 +03:00
|
|
|
desc = 'CRiu Image Tool'
|
|
|
|
parser = argparse.ArgumentParser(description=desc,
|
|
|
|
formatter_class=argparse.RawTextHelpFormatter)
|
2014-12-31 14:06:49 +02:00
|
|
|
|
2015-02-09 14:08:22 +03:00
|
|
|
subparsers = parser.add_subparsers(help='Use crit CMD --help for command-specific help')
|
|
|
|
|
|
|
|
# Decode
|
|
|
|
decode_parser = subparsers.add_parser('decode',
|
2015-10-29 04:10:00 +03:00
|
|
|
help = 'convert criu image from binary type to json')
|
2015-02-09 14:08:22 +03:00
|
|
|
decode_parser.add_argument('--pretty',
|
|
|
|
help = 'Multiline with indents and some numerical fields in field-specific format',
|
|
|
|
action = 'store_true')
|
|
|
|
decode_parser.add_argument('-i',
|
|
|
|
'--in',
|
|
|
|
help = 'criu image in binary format to be decoded (stdin by default)')
|
|
|
|
decode_parser.add_argument('-o',
|
|
|
|
'--out',
|
|
|
|
help = 'where to put criu image in json format (stdout by default)')
|
2016-05-27 10:40:00 +03:00
|
|
|
decode_parser.set_defaults(func=decode, nopl=False)
|
2015-02-09 14:08:22 +03:00
|
|
|
|
|
|
|
# Encode
|
|
|
|
encode_parser = subparsers.add_parser('encode',
|
|
|
|
help = 'convert criu image from json type to binary')
|
|
|
|
encode_parser.add_argument('-i',
|
|
|
|
'--in',
|
|
|
|
help = 'criu image in json format to be encoded (stdin by default)')
|
|
|
|
encode_parser.add_argument('-o',
|
|
|
|
'--out',
|
|
|
|
help = 'where to put criu image in binary format (stdout by default)')
|
|
|
|
encode_parser.set_defaults(func=encode)
|
|
|
|
|
2015-09-16 16:16:24 +03:00
|
|
|
# Info
|
|
|
|
info_parser = subparsers.add_parser('info',
|
|
|
|
help = 'show info about image')
|
|
|
|
info_parser.add_argument("in")
|
|
|
|
info_parser.set_defaults(func=info)
|
|
|
|
|
2015-12-14 13:19:00 +03:00
|
|
|
# Explore
|
|
|
|
x_parser = subparsers.add_parser('x', help = 'explore image dir')
|
|
|
|
x_parser.add_argument('dir')
|
2017-04-13 18:26:36 +03:00
|
|
|
x_parser.add_argument('what', choices = [ 'ps', 'fds', 'mems', 'rss'])
|
2015-12-14 13:19:00 +03:00
|
|
|
x_parser.set_defaults(func=explore)
|
|
|
|
|
2015-07-23 02:51:00 +03:00
|
|
|
# Show
|
|
|
|
show_parser = subparsers.add_parser('show',
|
|
|
|
help = "convert criu image from binary to human-readable json")
|
|
|
|
show_parser.add_argument("in")
|
2016-05-19 13:04:00 +03:00
|
|
|
show_parser.add_argument('--nopl', help = 'do not show entry payload (if exists)', action = 'store_true')
|
2015-07-23 02:51:00 +03:00
|
|
|
show_parser.set_defaults(func=decode, pretty=True, out=None)
|
|
|
|
|
2015-02-09 14:08:22 +03:00
|
|
|
opts = vars(parser.parse_args())
|
2014-12-31 14:06:49 +02:00
|
|
|
|
crit: display help message when using python3
Running crit with python2 gives following minimal help message:
$ crit/crit
usage: crit [-h] {decode,encode,info,x,show} ...
crit: error: too few arguments
Using a python3 only system crit shows the following error:
$ crit/crit
Traceback (most recent call last):
File "crit/crit", line 6, in <module>
cli.main()
File "/home/criu/crit/pycriu/cli.py", line 334, in main
opts["func"](opts)
KeyError: 'func'
Using this patch the python3 output changes to:
$ crit/crit
usage: crit [-h] {decode,encode,info,x,show} ...
crit: error: too few arguments
Suggested-by: Andrei Vagin <avagin@gmail.com>
Signed-off-by: Adrian Reber <areber@redhat.com>
2019-02-18 16:15:08 +00:00
|
|
|
if not opts:
|
|
|
|
sys.stderr.write(parser.format_usage())
|
|
|
|
sys.stderr.write("crit: error: too few arguments\n")
|
|
|
|
sys.exit(1)
|
|
|
|
|
2015-02-09 14:08:22 +03:00
|
|
|
opts["func"](opts)
|
2014-12-31 14:06:49 +02:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|