2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-28 12:57:57 +00:00

py: Reformat everything into pep8 style

As discussed on the mailing list, current .py files formatting does not
conform to the world standard, so we should better reformat it. For this
the yapf tool is used. The command I used was

  yapf -i $(find -name *.py)

Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
This commit is contained in:
Andrei Vagin 2019-09-07 15:46:22 +03:00
parent 5ff4fcb753
commit 5aa72e7237
28 changed files with 5738 additions and 5167 deletions

View File

@ -54,11 +54,8 @@ status = {
"VMA_AREA_UNSUPP": 1 << 31 "VMA_AREA_UNSUPP": 1 << 31
} }
prot = { prot = {"PROT_READ": 0x1, "PROT_WRITE": 0x2, "PROT_EXEC": 0x4}
"PROT_READ" : 0x1,
"PROT_WRITE" : 0x2,
"PROT_EXEC" : 0x4
}
class elf_note: class elf_note:
nhdr = None # Elf_Nhdr; nhdr = None # Elf_Nhdr;
@ -75,6 +72,7 @@ class coredump:
phdrs = [] # Array of Phdrs; phdrs = [] # Array of Phdrs;
notes = [] # Array of elf_notes; notes = [] # Array of elf_notes;
vmas = [] # Array of BytesIO with memory content; vmas = [] # Array of BytesIO with memory content;
# FIXME keeping all vmas in memory is a bad idea; # FIXME keeping all vmas in memory is a bad idea;
def write(self, f): def write(self, f):
@ -146,7 +144,6 @@ class coredump_generator:
else: else:
return img["entries"] return img["entries"]
def __call__(self, imgs_dir): def __call__(self, imgs_dir):
""" """
Parse criu images stored in directory imgs_dir to fill core dumps. Parse criu images stored in directory imgs_dir to fill core dumps.
@ -161,7 +158,8 @@ class coredump_generator:
for tid in p['threads']: for tid in p['threads']:
self.cores[tid] = self._img_open_and_strip("core", True, tid) self.cores[tid] = self._img_open_and_strip("core", True, tid)
self.mms[pid] = self._img_open_and_strip("mm", True, pid) self.mms[pid] = self._img_open_and_strip("mm", True, pid)
self.pagemaps[pid] = self._img_open_and_strip("pagemap", False, pid) self.pagemaps[pid] = self._img_open_and_strip(
"pagemap", False, pid)
files = self._img_open_and_strip("files", False) files = self._img_open_and_strip("files", False)
self.reg_files = [x["reg"] for x in files if x["type"] == "REG"] self.reg_files = [x["reg"] for x in files if x["type"] == "REG"]
@ -171,7 +169,6 @@ class coredump_generator:
return self.coredumps return self.coredumps
def write(self, coredumps_dir, pid=None): def write(self, coredumps_dir, pid=None):
""" """
Write core dumpt to cores_dir directory. Specify pid to choose Write core dumpt to cores_dir directory. Specify pid to choose
@ -298,9 +295,11 @@ class coredump_generator:
prpsinfo.pr_state = 3 prpsinfo.pr_state = 3
# Don't even ask me why it is so, just borrowed from linux # Don't even ask me why it is so, just borrowed from linux
# source and made pr_state match. # source and made pr_state match.
prpsinfo.pr_sname = '.' if prpsinfo.pr_state > 5 else "RSDTZW"[prpsinfo.pr_state] prpsinfo.pr_sname = '.' if prpsinfo.pr_state > 5 else "RSDTZW" [
prpsinfo.pr_state]
prpsinfo.pr_zomb = 1 if prpsinfo.pr_state == 4 else 0 prpsinfo.pr_zomb = 1 if prpsinfo.pr_state == 4 else 0
prpsinfo.pr_nice = core["thread_core"]["sched_prio"] if "sched_prio" in core["thread_core"] else 0 prpsinfo.pr_nice = core["thread_core"][
"sched_prio"] if "sched_prio" in core["thread_core"] else 0
prpsinfo.pr_flag = core["tc"]["flags"] prpsinfo.pr_flag = core["tc"]["flags"]
prpsinfo.pr_uid = core["thread_core"]["creds"]["uid"] prpsinfo.pr_uid = core["thread_core"]["creds"]["uid"]
prpsinfo.pr_gid = core["thread_core"]["creds"]["gid"] prpsinfo.pr_gid = core["thread_core"]["creds"]["gid"]
@ -399,8 +398,10 @@ class coredump_generator:
fpregset.rdp = regs["rdp"] fpregset.rdp = regs["rdp"]
fpregset.mxcsr = regs["mxcsr"] fpregset.mxcsr = regs["mxcsr"]
fpregset.mxcr_mask = regs["mxcsr_mask"] fpregset.mxcr_mask = regs["mxcsr_mask"]
fpregset.st_space = (ctypes.c_uint * len(regs["st_space"]))(*regs["st_space"]) fpregset.st_space = (ctypes.c_uint * len(regs["st_space"]))(
fpregset.xmm_space = (ctypes.c_uint * len(regs["xmm_space"]))(*regs["xmm_space"]) *regs["st_space"])
fpregset.xmm_space = (ctypes.c_uint * len(regs["xmm_space"]))(
*regs["xmm_space"])
#fpregset.padding = regs["padding"] unused #fpregset.padding = regs["padding"] unused
nhdr = elf.Elf64_Nhdr() nhdr = elf.Elf64_Nhdr()
@ -433,12 +434,16 @@ class coredump_generator:
data.i387.rdp = fpregs["rdp"] data.i387.rdp = fpregs["rdp"]
data.i387.mxcsr = fpregs["mxcsr"] data.i387.mxcsr = fpregs["mxcsr"]
data.i387.mxcsr_mask = fpregs["mxcsr_mask"] data.i387.mxcsr_mask = fpregs["mxcsr_mask"]
data.i387.st_space = (ctypes.c_uint * len(fpregs["st_space"]))(*fpregs["st_space"]) data.i387.st_space = (ctypes.c_uint * len(fpregs["st_space"]))(
data.i387.xmm_space = (ctypes.c_uint * len(fpregs["xmm_space"]))(*fpregs["xmm_space"]) *fpregs["st_space"])
data.i387.xmm_space = (ctypes.c_uint * len(fpregs["xmm_space"]))(
*fpregs["xmm_space"])
if "xsave" in fpregs: if "xsave" in fpregs:
data.xsave_hdr.xstate_bv = fpregs["xsave"]["xstate_bv"] data.xsave_hdr.xstate_bv = fpregs["xsave"]["xstate_bv"]
data.ymmh.ymmh_space = (ctypes.c_uint * len(fpregs["xsave"]["ymmh_space"]))(*fpregs["xsave"]["ymmh_space"]) data.ymmh.ymmh_space = (ctypes.c_uint *
len(fpregs["xsave"]["ymmh_space"]))(
*fpregs["xsave"]["ymmh_space"])
nhdr = elf.Elf64_Nhdr() nhdr = elf.Elf64_Nhdr()
nhdr.n_namesz = 6 nhdr.n_namesz = 6
@ -551,7 +556,8 @@ class coredump_generator:
fields.append(("end" + str(i), ctypes.c_long)) fields.append(("end" + str(i), ctypes.c_long))
fields.append(("file_ofs" + str(i), ctypes.c_long)) fields.append(("file_ofs" + str(i), ctypes.c_long))
for i in range(len(infos)): for i in range(len(infos)):
fields.append(("name"+str(i), ctypes.c_char*(len(infos[i].name)+1))) fields.append(
("name" + str(i), ctypes.c_char * (len(infos[i].name) + 1)))
class elf_files(ctypes.Structure): class elf_files(ctypes.Structure):
_fields_ = fields _fields_ = fields
@ -639,7 +645,8 @@ class coredump_generator:
ppid = self.pstree[pid]["ppid"] ppid = self.pstree[pid]["ppid"]
return self._get_page(ppid, page_no) return self._get_page(ppid, page_no)
else: else:
with open(self._imgs_dir+"/"+"pages-"+str(pages_id)+".img") as f: with open(self._imgs_dir + "/" + "pages-" + str(pages_id) +
".img") as f:
f.seek(off * PAGESIZE) f.seek(off * PAGESIZE)
return f.read(PAGESIZE) return f.read(PAGESIZE)

View File

@ -16,13 +16,16 @@ EI_MAG0 = 0 # #define EI_MAG0 0 /* File identification b
ELFMAG0 = 0x7f # #define ELFMAG0 0x7f /* Magic number byte 0 */ ELFMAG0 = 0x7f # #define ELFMAG0 0x7f /* Magic number byte 0 */
EI_MAG1 = 1 # #define EI_MAG1 1 /* File identification byte 1 index */ EI_MAG1 = 1 # #define EI_MAG1 1 /* File identification byte 1 index */
ELFMAG1 = ord('E') # #define ELFMAG1 'E' /* Magic number byte 1 */ ELFMAG1 = ord(
'E') # #define ELFMAG1 'E' /* Magic number byte 1 */
EI_MAG2 = 2 # #define EI_MAG2 2 /* File identification byte 2 index */ EI_MAG2 = 2 # #define EI_MAG2 2 /* File identification byte 2 index */
ELFMAG2 = ord('L') # #define ELFMAG2 'L' /* Magic number byte 2 */ ELFMAG2 = ord(
'L') # #define ELFMAG2 'L' /* Magic number byte 2 */
EI_MAG3 = 3 # #define EI_MAG3 3 /* File identification byte 3 index */ EI_MAG3 = 3 # #define EI_MAG3 3 /* File identification byte 3 index */
ELFMAG3 = ord('F') # #define ELFMAG3 'F' /* Magic number byte 3 */ ELFMAG3 = ord(
'F') # #define ELFMAG3 'F' /* Magic number byte 3 */
EI_CLASS = 4 # #define EI_CLASS 4 /* File class byte index */ EI_CLASS = 4 # #define EI_CLASS 4 /* File class byte index */
@ -43,9 +46,11 @@ EM_X86_64 = 62 # #define EM_X86_64 62 /* AMD x86-64 architec
# Legal values for e_version (version). # Legal values for e_version (version).
EV_CURRENT = 1 # #define EV_CURRENT 1 /* Current version */ EV_CURRENT = 1 # #define EV_CURRENT 1 /* Current version */
class Elf64_Ehdr(ctypes.Structure): # typedef struct class Elf64_Ehdr(ctypes.Structure): # typedef struct
_fields_ = [ # { _fields_ = [ # {
("e_ident", ctypes.c_ubyte*EI_NIDENT), # unsigned char e_ident[EI_NIDENT]; ("e_ident",
ctypes.c_ubyte * EI_NIDENT), # unsigned char e_ident[EI_NIDENT];
("e_type", Elf64_Half), # Elf64_Half e_type; ("e_type", Elf64_Half), # Elf64_Half e_type;
("e_machine", Elf64_Half), # Elf64_Half e_machine; ("e_machine", Elf64_Half), # Elf64_Half e_machine;
("e_version", Elf64_Word), # Elf64_Word e_version; ("e_version", Elf64_Word), # Elf64_Word e_version;
@ -73,6 +78,7 @@ PF_X = 1 # #define PF_X (1 << 0) /* Segment is executable */
PF_W = 1 << 1 # #define PF_W (1 << 1) /* Segment is writable */ PF_W = 1 << 1 # #define PF_W (1 << 1) /* Segment is writable */
PF_R = 1 << 2 # #define PF_R (1 << 2) /* Segment is readable */ PF_R = 1 << 2 # #define PF_R (1 << 2) /* Segment is readable */
class Elf64_Phdr(ctypes.Structure): # typedef struct class Elf64_Phdr(ctypes.Structure): # typedef struct
_fields_ = [ # { _fields_ = [ # {
("p_type", Elf64_Word), # Elf64_Word p_type; ("p_type", Elf64_Word), # Elf64_Word p_type;
@ -88,14 +94,15 @@ class Elf64_Phdr(ctypes.Structure): # typedef struct
# Elf64_auxv_t related constants. # Elf64_auxv_t related constants.
class _Elf64_auxv_t_U(ctypes.Union): class _Elf64_auxv_t_U(ctypes.Union):
_fields_ = [ _fields_ = [("a_val", ctypes.c_uint64)]
("a_val", ctypes.c_uint64)
]
class Elf64_auxv_t(ctypes.Structure): # typedef struct class Elf64_auxv_t(ctypes.Structure): # typedef struct
_fields_ = [ # { _fields_ = [ # {
("a_type", ctypes.c_uint64), # uint64_t a_type; /* Entry type */ ("a_type",
ctypes.c_uint64), # uint64_t a_type; /* Entry type */
("a_un", _Elf64_auxv_t_U) # union ("a_un", _Elf64_auxv_t_U) # union
# { # {
# uint64_t a_val; /* Integer value */ # uint64_t a_val; /* Integer value */
@ -118,101 +125,178 @@ NT_FILE = 0x46494c45 # #define NT_FILE 0x46494c45 /* Contains info
# files */ # files */
NT_X86_XSTATE = 0x202 # #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ NT_X86_XSTATE = 0x202 # #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
class Elf64_Nhdr(ctypes.Structure): # typedef struct class Elf64_Nhdr(ctypes.Structure): # typedef struct
_fields_ = [ # { _fields_ = [ # {
("n_namesz", Elf64_Word), # Elf64_Word n_namesz; /* Length of the note's name. */ (
("n_descsz", Elf64_Word), # Elf64_Word n_descsz; /* Length of the note's descriptor. */ "n_namesz", Elf64_Word
("n_type", Elf64_Word), # Elf64_Word n_type; /* Type of the note. */ ), # Elf64_Word n_namesz; /* Length of the note's name. */
(
"n_descsz", Elf64_Word
), # Elf64_Word n_descsz; /* Length of the note's descriptor. */
("n_type", Elf64_Word
), # Elf64_Word n_type; /* Type of the note. */
] # } Elf64_Nhdr; ] # } Elf64_Nhdr;
# Elf64_Shdr related constants. # Elf64_Shdr related constants.
class Elf64_Shdr(ctypes.Structure): # typedef struct class Elf64_Shdr(ctypes.Structure): # typedef struct
_fields_ = [ # { _fields_ = [ # {
("sh_name", Elf64_Word), # Elf64_Word sh_name; /* Section name (string tbl index) */ (
("sh_type", Elf64_Word), # Elf64_Word sh_type; /* Section type */ "sh_name", Elf64_Word
("sh_flags", Elf64_Xword), # Elf64_Xword sh_flags; /* Section flags */ ), # Elf64_Word sh_name; /* Section name (string tbl index) */
("sh_addr", Elf64_Addr), # Elf64_Addr sh_addr; /* Section virtual addr at execution */ ("sh_type", Elf64_Word
("sh_offset", Elf64_Off), # Elf64_Off sh_offset; /* Section file offset */ ), # Elf64_Word sh_type; /* Section type */
("sh_size", Elf64_Xword), # Elf64_Xword sh_size; /* Section size in bytes */ ("sh_flags", Elf64_Xword
("sh_link", Elf64_Word), # Elf64_Word sh_link; /* Link to another section */ ), # Elf64_Xword sh_flags; /* Section flags */
("sh_info", Elf64_Word), # Elf64_Word sh_info; /* Additional section information */ (
("sh_addralign",Elf64_Xword), # Elf64_Xword sh_addralign; /* Section alignment */ "sh_addr", Elf64_Addr
("sh_entsize", Elf64_Xword) # Elf64_Xword sh_entsize; /* Entry size if section holds table */ ), # Elf64_Addr sh_addr; /* Section virtual addr at execution */
(
"sh_offset", Elf64_Off
), # Elf64_Off sh_offset; /* Section file offset */
(
"sh_size", Elf64_Xword
), # Elf64_Xword sh_size; /* Section size in bytes */
(
"sh_link", Elf64_Word
), # Elf64_Word sh_link; /* Link to another section */
(
"sh_info", Elf64_Word
), # Elf64_Word sh_info; /* Additional section information */
("sh_addralign", Elf64_Xword
), # Elf64_Xword sh_addralign; /* Section alignment */
(
"sh_entsize", Elf64_Xword
) # Elf64_Xword sh_entsize; /* Entry size if section holds table */
] # } Elf64_Shdr; ] # } Elf64_Shdr;
# elf_prstatus related constants. # elf_prstatus related constants.
# Signal info. # Signal info.
class elf_siginfo(ctypes.Structure): # struct elf_siginfo class elf_siginfo(ctypes.Structure): # struct elf_siginfo
_fields_ = [ # { _fields_ = [ # {
("si_signo", ctypes.c_int), # int si_signo; /* Signal number. */ ("si_signo", ctypes.c_int
("si_code", ctypes.c_int), # int si_code; /* Extra code. */ ), # int si_signo; /* Signal number. */
("si_errno", ctypes.c_int) # int si_errno; /* Errno. */ ("si_code", ctypes.c_int
), # int si_code; /* Extra code. */
("si_errno", ctypes.c_int
) # int si_errno; /* Errno. */
] # }; ] # };
# A time value that is accurate to the nearest # A time value that is accurate to the nearest
# microsecond but also has a range of years. # microsecond but also has a range of years.
class timeval(ctypes.Structure): # struct timeval class timeval(ctypes.Structure): # struct timeval
_fields_ = [ # { _fields_ = [ # {
("tv_sec", ctypes.c_long), # __time_t tv_sec; /* Seconds. */ ("tv_sec",
("tv_usec", ctypes.c_long) # __suseconds_t tv_usec; /* Microseconds. */ ctypes.c_long), # __time_t tv_sec; /* Seconds. */
("tv_usec", ctypes.c_long
) # __suseconds_t tv_usec; /* Microseconds. */
] # }; ] # };
class user_regs_struct(ctypes.Structure): # struct user_regs_struct class user_regs_struct(ctypes.Structure): # struct user_regs_struct
_fields_ = [ # { _fields_ = [ # {
("r15", ctypes.c_ulonglong), # __extension__ unsigned long long int r15; ("r15",
("r14", ctypes.c_ulonglong), # __extension__ unsigned long long int r14; ctypes.c_ulonglong), # __extension__ unsigned long long int r15;
("r13", ctypes.c_ulonglong), # __extension__ unsigned long long int r13; ("r14",
("r12", ctypes.c_ulonglong), # __extension__ unsigned long long int r12; ctypes.c_ulonglong), # __extension__ unsigned long long int r14;
("rbp", ctypes.c_ulonglong), # __extension__ unsigned long long int rbp; ("r13",
("rbx", ctypes.c_ulonglong), # __extension__ unsigned long long int rbx; ctypes.c_ulonglong), # __extension__ unsigned long long int r13;
("r11", ctypes.c_ulonglong), # __extension__ unsigned long long int r11; ("r12",
("r10", ctypes.c_ulonglong), # __extension__ unsigned long long int r10; ctypes.c_ulonglong), # __extension__ unsigned long long int r12;
("r9", ctypes.c_ulonglong), # __extension__ unsigned long long int r9; ("rbp",
("r8", ctypes.c_ulonglong), # __extension__ unsigned long long int r8; ctypes.c_ulonglong), # __extension__ unsigned long long int rbp;
("rax", ctypes.c_ulonglong), # __extension__ unsigned long long int rax; ("rbx",
("rcx", ctypes.c_ulonglong), # __extension__ unsigned long long int rcx; ctypes.c_ulonglong), # __extension__ unsigned long long int rbx;
("rdx", ctypes.c_ulonglong), # __extension__ unsigned long long int rdx; ("r11",
("rsi", ctypes.c_ulonglong), # __extension__ unsigned long long int rsi; ctypes.c_ulonglong), # __extension__ unsigned long long int r11;
("rdi", ctypes.c_ulonglong), # __extension__ unsigned long long int rdi; ("r10",
("orig_rax", ctypes.c_ulonglong), # __extension__ unsigned long long int orig_rax; ctypes.c_ulonglong), # __extension__ unsigned long long int r10;
("rip", ctypes.c_ulonglong), # __extension__ unsigned long long int rip; ("r9",
("cs", ctypes.c_ulonglong), # __extension__ unsigned long long int cs; ctypes.c_ulonglong), # __extension__ unsigned long long int r9;
("eflags", ctypes.c_ulonglong), # __extension__ unsigned long long int eflags; ("r8",
("rsp", ctypes.c_ulonglong), # __extension__ unsigned long long int rsp; ctypes.c_ulonglong), # __extension__ unsigned long long int r8;
("ss", ctypes.c_ulonglong), # __extension__ unsigned long long int ss; ("rax",
("fs_base", ctypes.c_ulonglong), # __extension__ unsigned long long int fs_base; ctypes.c_ulonglong), # __extension__ unsigned long long int rax;
("gs_base", ctypes.c_ulonglong), # __extension__ unsigned long long int gs_base; ("rcx",
("ds", ctypes.c_ulonglong), # __extension__ unsigned long long int ds; ctypes.c_ulonglong), # __extension__ unsigned long long int rcx;
("es", ctypes.c_ulonglong), # __extension__ unsigned long long int es; ("rdx",
("fs", ctypes.c_ulonglong), # __extension__ unsigned long long int fs; ctypes.c_ulonglong), # __extension__ unsigned long long int rdx;
("gs", ctypes.c_ulonglong) # __extension__ unsigned long long int gs; ("rsi",
ctypes.c_ulonglong), # __extension__ unsigned long long int rsi;
("rdi",
ctypes.c_ulonglong), # __extension__ unsigned long long int rdi;
("orig_rax", ctypes.c_ulonglong
), # __extension__ unsigned long long int orig_rax;
("rip",
ctypes.c_ulonglong), # __extension__ unsigned long long int rip;
("cs",
ctypes.c_ulonglong), # __extension__ unsigned long long int cs;
("eflags",
ctypes.c_ulonglong), # __extension__ unsigned long long int eflags;
("rsp",
ctypes.c_ulonglong), # __extension__ unsigned long long int rsp;
("ss",
ctypes.c_ulonglong), # __extension__ unsigned long long int ss;
("fs_base", ctypes.c_ulonglong
), # __extension__ unsigned long long int fs_base;
("gs_base", ctypes.c_ulonglong
), # __extension__ unsigned long long int gs_base;
("ds",
ctypes.c_ulonglong), # __extension__ unsigned long long int ds;
("es",
ctypes.c_ulonglong), # __extension__ unsigned long long int es;
("fs",
ctypes.c_ulonglong), # __extension__ unsigned long long int fs;
("gs", ctypes.c_ulonglong
) # __extension__ unsigned long long int gs;
] # }; ] # };
#elf_greg_t = ctypes.c_ulonglong #elf_greg_t = ctypes.c_ulonglong
#ELF_NGREG = ctypes.sizeof(user_regs_struct)/ctypes.sizeof(elf_greg_t) #ELF_NGREG = ctypes.sizeof(user_regs_struct)/ctypes.sizeof(elf_greg_t)
#elf_gregset_t = elf_greg_t*ELF_NGREG #elf_gregset_t = elf_greg_t*ELF_NGREG
elf_gregset_t = user_regs_struct elf_gregset_t = user_regs_struct
class elf_prstatus(ctypes.Structure): # struct elf_prstatus class elf_prstatus(ctypes.Structure): # struct elf_prstatus
_fields_ = [ # { _fields_ = [ # {
("pr_info", elf_siginfo), # struct elf_siginfo pr_info; /* Info associated with signal. */ (
("pr_cursig", ctypes.c_short), # short int pr_cursig; /* Current signal. */ "pr_info", elf_siginfo
("pr_sigpend", ctypes.c_ulong), # unsigned long int pr_sigpend; /* Set of pending signals. */ ), # struct elf_siginfo pr_info; /* Info associated with signal. */
("pr_sighold", ctypes.c_ulong), # unsigned long int pr_sighold; /* Set of held signals. */ ("pr_cursig", ctypes.c_short
), # short int pr_cursig; /* Current signal. */
(
"pr_sigpend", ctypes.c_ulong
), # unsigned long int pr_sigpend; /* Set of pending signals. */
(
"pr_sighold", ctypes.c_ulong
), # unsigned long int pr_sighold; /* Set of held signals. */
("pr_pid", ctypes.c_int), # __pid_t pr_pid; ("pr_pid", ctypes.c_int), # __pid_t pr_pid;
("pr_ppid", ctypes.c_int), # __pid_t pr_ppid; ("pr_ppid", ctypes.c_int), # __pid_t pr_ppid;
("pr_pgrp", ctypes.c_int), # __pid_t pr_pgrp; ("pr_pgrp", ctypes.c_int), # __pid_t pr_pgrp;
("pr_sid", ctypes.c_int), # __pid_t pr_sid; ("pr_sid", ctypes.c_int), # __pid_t pr_sid;
("pr_utime", timeval), # struct timeval pr_utime; /* User time. */ ("pr_utime",
("pr_stime", timeval), # struct timeval pr_stime; /* System time. */ timeval), # struct timeval pr_utime; /* User time. */
("pr_cutime", timeval), # struct timeval pr_cutime; /* Cumulative user time. */ ("pr_stime", timeval
("pr_cstime", timeval), # struct timeval pr_cstime; /* Cumulative system time. */ ), # struct timeval pr_stime; /* System time. */
("pr_reg", elf_gregset_t), # elf_gregset_t pr_reg; /* GP registers. */ (
("pr_fpvalid", ctypes.c_int) # int pr_fpvalid; /* True if math copro being used. */ "pr_cutime", timeval
), # struct timeval pr_cutime; /* Cumulative user time. */
(
"pr_cstime", timeval
), # struct timeval pr_cstime; /* Cumulative system time. */
("pr_reg", elf_gregset_t
), # elf_gregset_t pr_reg; /* GP registers. */
(
"pr_fpvalid", ctypes.c_int
) # int pr_fpvalid; /* True if math copro being used. */
] # }; ] # };
@ -220,13 +304,21 @@ class elf_prstatus(ctypes.Structure): # struct elf_prstatus
ELF_PRARGSZ = 80 # #define ELF_PRARGSZ (80) /* Number of chars for args. */ ELF_PRARGSZ = 80 # #define ELF_PRARGSZ (80) /* Number of chars for args. */
class elf_prpsinfo(ctypes.Structure): # struct elf_prpsinfo class elf_prpsinfo(ctypes.Structure): # struct elf_prpsinfo
_fields_ = [ # { _fields_ = [ # {
("pr_state", ctypes.c_byte), # char pr_state; /* Numeric process state. */ (
("pr_sname", ctypes.c_char), # char pr_sname; /* Char for pr_state. */ "pr_state", ctypes.c_byte
("pr_zomb", ctypes.c_byte), # char pr_zomb; /* Zombie. */ ), # char pr_state; /* Numeric process state. */
("pr_nice", ctypes.c_byte), # char pr_nice; /* Nice val. */ (
("pr_flag", ctypes.c_ulong), # unsigned long int pr_flag; /* Flags. */ "pr_sname", ctypes.c_char
), # char pr_sname; /* Char for pr_state. */
("pr_zomb", ctypes.c_byte
), # char pr_zomb; /* Zombie. */
("pr_nice", ctypes.c_byte
), # char pr_nice; /* Nice val. */
("pr_flag", ctypes.c_ulong
), # unsigned long int pr_flag; /* Flags. */
# #if __WORDSIZE == 32 # #if __WORDSIZE == 32
# unsigned short int pr_uid; # unsigned short int pr_uid;
# unsigned short int pr_gid; # unsigned short int pr_gid;
@ -239,8 +331,12 @@ class elf_prpsinfo(ctypes.Structure): # struct elf_prpsinfo
("pr_pgrp", ctypes.c_int), ("pr_pgrp", ctypes.c_int),
("pr_sid", ctypes.c_int), ("pr_sid", ctypes.c_int),
# /* Lots missing */ # /* Lots missing */
("pr_fname", ctypes.c_char*16), # char pr_fname[16]; /* Filename of executable. */ (
("pr_psargs", ctypes.c_char*ELF_PRARGSZ) # char pr_psargs[ELF_PRARGSZ]; /* Initial part of arg list. */ "pr_fname", ctypes.c_char * 16
), # char pr_fname[16]; /* Filename of executable. */
(
"pr_psargs", ctypes.c_char * ELF_PRARGSZ
) # char pr_psargs[ELF_PRARGSZ]; /* Initial part of arg list. */
] # }; ] # };
@ -250,33 +346,42 @@ class user_fpregs_struct(ctypes.Structure): # struct user_fpregs_struct
("swd", ctypes.c_ushort), # unsigned short int swd; ("swd", ctypes.c_ushort), # unsigned short int swd;
("ftw", ctypes.c_ushort), # unsigned short int ftw; ("ftw", ctypes.c_ushort), # unsigned short int ftw;
("fop", ctypes.c_ushort), # unsigned short int fop; ("fop", ctypes.c_ushort), # unsigned short int fop;
("rip", ctypes.c_ulonglong), # __extension__ unsigned long long int rip; ("rip",
("rdp", ctypes.c_ulonglong), # __extension__ unsigned long long int rdp; ctypes.c_ulonglong), # __extension__ unsigned long long int rip;
("rdp",
ctypes.c_ulonglong), # __extension__ unsigned long long int rdp;
("mxcsr", ctypes.c_uint), # unsigned int mxcsr; ("mxcsr", ctypes.c_uint), # unsigned int mxcsr;
("mxcr_mask", ctypes.c_uint), # unsigned int mxcr_mask; ("mxcr_mask", ctypes.c_uint), # unsigned int mxcr_mask;
("st_space", ctypes.c_uint*32), # unsigned int st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ (
("xmm_space", ctypes.c_uint*64), # unsigned int xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */ "st_space", ctypes.c_uint * 32
("padding", ctypes.c_uint*24), # unsigned int padding[24]; ), # unsigned int st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
(
"xmm_space", ctypes.c_uint * 64
), # unsigned int xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */
("padding",
ctypes.c_uint * 24), # unsigned int padding[24];
] # }; ] # };
elf_fpregset_t = user_fpregs_struct elf_fpregset_t = user_fpregs_struct
# siginfo_t related constants. # siginfo_t related constants.
_SI_MAX_SIZE = 128 _SI_MAX_SIZE = 128
_SI_PAD_SIZE = (_SI_MAX_SIZE / ctypes.sizeof(ctypes.c_int)) - 4 _SI_PAD_SIZE = (_SI_MAX_SIZE / ctypes.sizeof(ctypes.c_int)) - 4
# /* kill(). */ # /* kill(). */
class _siginfo_t_U_kill(ctypes.Structure): # struct class _siginfo_t_U_kill(ctypes.Structure): # struct
_fields_ = [ # { _fields_ = [ # {
("si_pid", ctypes.c_int), # __pid_t si_pid; /* Sending process ID. */ ("si_pid", ctypes.c_int
("si_uid", ctypes.c_uint) # __uid_t si_uid; /* Real user ID of sending process. */ ), # __pid_t si_pid; /* Sending process ID. */
(
"si_uid", ctypes.c_uint
) # __uid_t si_uid; /* Real user ID of sending process. */
] # } _kill; ] # } _kill;
# Type for data associated with a signal. # Type for data associated with a signal.
class sigval_t(ctypes.Union): # typedef union sigval class sigval_t(ctypes.Union): # typedef union sigval
_fields_ = [ # { _fields_ = [ # {
@ -284,45 +389,63 @@ class sigval_t(ctypes.Union): # typedef union sigval
("sical_ptr", ctypes.c_void_p), # void *sival_ptr; ("sical_ptr", ctypes.c_void_p), # void *sival_ptr;
] # } sigval_t; ] # } sigval_t;
# /* POSIX.1b timers. */ # /* POSIX.1b timers. */
class _siginfo_t_U_timer(ctypes.Structure): # struct class _siginfo_t_U_timer(ctypes.Structure): # struct
_fields_ = [ # { _fields_ = [ # {
("si_tid", ctypes.c_int), # int si_tid; /* Timer ID. */ ("si_tid",
("si_overrun", ctypes.c_int), # int si_overrun; /* Overrun count. */ ctypes.c_int), # int si_tid; /* Timer ID. */
("si_sigval", sigval_t) # sigval_t si_sigval; /* Signal value. */ ("si_overrun", ctypes.c_int
), # int si_overrun; /* Overrun count. */
("si_sigval", sigval_t
) # sigval_t si_sigval; /* Signal value. */
] # } _timer; ] # } _timer;
# /* POSIX.1b signals. */ # /* POSIX.1b signals. */
class _siginfo_t_U_rt(ctypes.Structure): # struct class _siginfo_t_U_rt(ctypes.Structure): # struct
_fields_ = [ # { _fields_ = [ # {
("si_pid", ctypes.c_int), # __pid_t si_pid; /* Sending process ID. */ ("si_pid", ctypes.c_int
("si_uid", ctypes.c_uint), # __uid_t si_uid; /* Real user ID of sending process. */ ), # __pid_t si_pid; /* Sending process ID. */
("si_sigval", sigval_t) # sigval_t si_sigval; /* Signal value. */ (
"si_uid", ctypes.c_uint
), # __uid_t si_uid; /* Real user ID of sending process. */
("si_sigval", sigval_t
) # sigval_t si_sigval; /* Signal value. */
] # } _rt; ] # } _rt;
# /* SIGCHLD. */ # /* SIGCHLD. */
class _siginfo_t_U_sigchld(ctypes.Structure): # struct class _siginfo_t_U_sigchld(ctypes.Structure): # struct
_fields_ = [ # { _fields_ = [ # {
("si_pid", ctypes.c_int), # __pid_t si_pid; /* Which child. */ ("si_pid",
("si_uid", ctypes.c_uint), # __uid_t si_uid; /* Real user ID of sending process. */ ctypes.c_int), # __pid_t si_pid; /* Which child. */
("si_status", ctypes.c_int), # int si_status; /* Exit value or signal. */ (
"si_uid", ctypes.c_uint
), # __uid_t si_uid; /* Real user ID of sending process. */
("si_status", ctypes.c_int
), # int si_status; /* Exit value or signal. */
("si_utime", ctypes.c_long), # __sigchld_clock_t si_utime; ("si_utime", ctypes.c_long), # __sigchld_clock_t si_utime;
("si_stime", ctypes.c_long) # __sigchld_clock_t si_stime; ("si_stime", ctypes.c_long) # __sigchld_clock_t si_stime;
] # } _sigchld; ] # } _sigchld;
# /* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */ # /* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */
class _siginfo_t_U_sigfault(ctypes.Structure): # struct class _siginfo_t_U_sigfault(ctypes.Structure): # struct
_fields_ = [ # { _fields_ = [ # {
("si_addr", ctypes.c_void_p), # void *si_addr; /* Faulting insn/memory ref. */ ("si_addr", ctypes.c_void_p
("si_addr_lsb", ctypes.c_short) # short int si_addr_lsb; /* Valid LSB of the reported address. */ ), # void *si_addr; /* Faulting insn/memory ref. */
(
"si_addr_lsb", ctypes.c_short
) # short int si_addr_lsb; /* Valid LSB of the reported address. */
] # } _sigfault; ] # } _sigfault;
# /* SIGPOLL. */ # /* SIGPOLL. */
class _siginfo_t_U_sigpoll(ctypes.Structure): # struct class _siginfo_t_U_sigpoll(ctypes.Structure): # struct
_fields_ = [ # { _fields_ = [ # {
("si_band", ctypes.c_long), # long int si_band; /* Band event for SIGPOLL. */ ("si_band", ctypes.c_long
), # long int si_band; /* Band event for SIGPOLL. */
("si_fd", ctypes.c_int) # int si_fd; ("si_fd", ctypes.c_int) # int si_fd;
] # } _sigpoll; ] # } _sigpoll;
@ -330,15 +453,20 @@ class _siginfo_t_U_sigpoll(ctypes.Structure): # struct
# /* SIGSYS. */ # /* SIGSYS. */
class _siginfo_t_U_sigsys(ctypes.Structure): # struct class _siginfo_t_U_sigsys(ctypes.Structure): # struct
_fields_ = [ # { _fields_ = [ # {
("_call_addr", ctypes.c_void_p), # void *_call_addr; /* Calling user insn. */ ("_call_addr", ctypes.c_void_p
("_syscall", ctypes.c_int), # int _syscall; /* Triggering system call number. */ ), # void *_call_addr; /* Calling user insn. */
("_arch", ctypes.c_uint) # unsigned int _arch; /* AUDIT_ARCH_* of syscall. */ (
"_syscall", ctypes.c_int
), # int _syscall; /* Triggering system call number. */
("_arch", ctypes.c_uint
) # unsigned int _arch; /* AUDIT_ARCH_* of syscall. */
] # } _sigsys; ] # } _sigsys;
class _siginfo_t_U(ctypes.Union): # union class _siginfo_t_U(ctypes.Union): # union
_fields_ = [ # { _fields_ = [ # {
("_pad", ctypes.c_int*_SI_PAD_SIZE), # int _pad[__SI_PAD_SIZE]; ("_pad",
ctypes.c_int * _SI_PAD_SIZE), # int _pad[__SI_PAD_SIZE];
# #
# /* kill(). */ # /* kill(). */
("_kill", _siginfo_t_U_kill), # struct ("_kill", _siginfo_t_U_kill), # struct
@ -396,12 +524,17 @@ class _siginfo_t_U(ctypes.Union): # union
# } _sigsys; # } _sigsys;
] # } _sifields; ] # } _sifields;
class siginfo_t(ctypes.Structure): # typedef struct class siginfo_t(ctypes.Structure): # typedef struct
_fields_ = [ # { _fields_ = [ # {
("si_signo", ctypes.c_int), # int si_signo; /* Signal number. */ ("si_signo", ctypes.c_int
("si_errno", ctypes.c_int), # int si_errno; /* If non-zero, an errno value associated with ), # int si_signo; /* Signal number. */
(
"si_errno", ctypes.c_int
), # int si_errno; /* If non-zero, an errno value associated with
# this signal, as defined in <errno.h>. */ # this signal, as defined in <errno.h>. */
("si_code", ctypes.c_int), # int si_code; /* Signal code. */ ("si_code", ctypes.c_int
), # int si_code; /* Signal code. */
# #
("_sifields", _siginfo_t_U) # union ("_sifields", _siginfo_t_U) # union
# { # {
@ -467,30 +600,46 @@ class siginfo_t(ctypes.Structure): # typedef struct
# xsave related. # xsave related.
class ymmh_struct(ctypes.Structure): # struct ymmh_struct { class ymmh_struct(ctypes.Structure): # struct ymmh_struct {
_fields_ = [ _fields_ = [("ymmh_space", 64 * ctypes.c_uint
("ymmh_space", 64*ctypes.c_uint) # u32 ymmh_space[64]; ) # u32 ymmh_space[64];
] # } __packed; ] # } __packed;
class xsave_hdr_struct(ctypes.Structure): # struct xsave_hdr_struct { class xsave_hdr_struct(ctypes.Structure): # struct xsave_hdr_struct {
_fields_ = [ _fields_ = [
("xstate_bv", ctypes.c_ulonglong), # u64 xstate_bv; ("xstate_bv", ctypes.c_ulonglong
("reserved1", ctypes.c_ulonglong*2), # u64 reserved1[2]; ), # u64 xstate_bv;
("reserved2", ctypes.c_ulonglong*5) # u64 reserved2[5]; ("reserved1", ctypes.c_ulonglong *
2), # u64 reserved1[2];
("reserved2", ctypes.c_ulonglong * 5
) # u64 reserved2[5];
] # } __packed; ] # } __packed;
class i387_fxsave_struct(ctypes.Structure): # struct i387_fxsave_struct { class i387_fxsave_struct(ctypes.Structure): # struct i387_fxsave_struct {
_fields_ = [ _fields_ = [
("cwd", ctypes.c_ushort), # u16 cwd; /* Control Word */ (
("swd", ctypes.c_ushort), # u16 swd; /* Status Word */ "cwd", ctypes.c_ushort
("twd", ctypes.c_ushort), # u16 twd; /* Tag Word */ ), # u16 cwd; /* Control Word */
("fop", ctypes.c_ushort), # u16 fop; /* Last Instruction Opcode */ (
"swd", ctypes.c_ushort
), # u16 swd; /* Status Word */
(
"twd", ctypes.c_ushort
), # u16 twd; /* Tag Word */
(
"fop", ctypes.c_ushort
), # u16 fop; /* Last Instruction Opcode */
# union { # union {
# struct { # struct {
("rip", ctypes.c_ulonglong), # u64 rip; /* Instruction Pointer */ (
("rdp", ctypes.c_ulonglong), # u64 rdp; /* Data Pointer */ "rip", ctypes.c_ulonglong
), # u64 rip; /* Instruction Pointer */
(
"rdp", ctypes.c_ulonglong
), # u64 rdp; /* Data Pointer */
# }; # };
# struct { # struct {
# u32 fip; /* FPU IP Offset */ # u32 fip; /* FPU IP Offset */
@ -499,19 +648,27 @@ class i387_fxsave_struct(ctypes.Structure): # struct i387_fxsave_struct {
# u32 fos; /* FPU Operand Selector */ # u32 fos; /* FPU Operand Selector */
# }; # };
# }; # };
("mxcsr", ctypes.c_uint), # u32 mxcsr; /* MXCSR Register State */ (
("mxcsr_mask", ctypes.c_uint), # u32 mxcsr_mask; /* MXCSR Mask */ "mxcsr", ctypes.c_uint
), # u32 mxcsr; /* MXCSR Register State */
(
"mxcsr_mask", ctypes.c_uint
), # u32 mxcsr_mask; /* MXCSR Mask */
# #
# /* 8*16 bytes for each FP-reg = 128 bytes */ # /* 8*16 bytes for each FP-reg = 128 bytes */
("st_space", ctypes.c_uint*32), # u32 st_space[32]; ("st_space", ctypes.c_uint * 32
), # u32 st_space[32];
# #
# /* 16*16 bytes for each XMM-reg = 256 bytes */ # /* 16*16 bytes for each XMM-reg = 256 bytes */
("xmm_space", ctypes.c_uint*64), # u32 xmm_space[64]; ("xmm_space", ctypes.c_uint * 64
), # u32 xmm_space[64];
# #
("padding", ctypes.c_uint*12), # u32 padding[12]; ("padding", ctypes.c_uint * 12
), # u32 padding[12];
# #
# union { # union {
("padding1", ctypes.c_uint*12) # u32 padding1[12]; ("padding1", ctypes.c_uint * 12
) # u32 padding1[12];
# u32 sw_reserved[12]; # u32 sw_reserved[12];
# }; # };
# #
@ -520,7 +677,9 @@ class i387_fxsave_struct(ctypes.Structure): # struct i387_fxsave_struct {
class elf_xsave_struct(ctypes.Structure): # struct xsave_struct { class elf_xsave_struct(ctypes.Structure): # struct xsave_struct {
_fields_ = [ _fields_ = [
("i387", i387_fxsave_struct), # struct i387_fxsave_struct i387; ("i387",
("xsave_hdr", xsave_hdr_struct), # struct xsave_hdr_struct xsave_hdr; i387_fxsave_struct), # struct i387_fxsave_struct i387;
("xsave_hdr", xsave_hdr_struct
), # struct xsave_hdr_struct xsave_hdr;
("ymmh", ymmh_struct) # struct ymmh_struct ymmh; ("ymmh", ymmh_struct) # struct ymmh_struct ymmh;
] # } __aligned(FP_MIN_ALIGN_BYTES) __packed; ] # } __aligned(FP_MIN_ALIGN_BYTES) __packed;

View File

@ -6,21 +6,25 @@ import os
import pycriu import pycriu
def inf(opts): def inf(opts):
if opts['in']: if opts['in']:
return open(opts['in'], 'rb') return open(opts['in'], 'rb')
else: else:
return sys.stdin return sys.stdin
def outf(opts): def outf(opts):
if opts['out']: if opts['out']:
return open(opts['out'], 'w+') return open(opts['out'], 'w+')
else: else:
return sys.stdout return sys.stdout
def dinf(opts, name): def dinf(opts, name):
return open(os.path.join(opts['dir'], name)) return open(os.path.join(opts['dir'], name))
def decode(opts): def decode(opts):
indent = None indent = None
@ -40,21 +44,27 @@ def decode(opts):
if f == sys.stdout: if f == sys.stdout:
f.write("\n") f.write("\n")
def encode(opts): def encode(opts):
img = json.load(inf(opts)) img = json.load(inf(opts))
pycriu.images.dump(img, outf(opts)) pycriu.images.dump(img, outf(opts))
def info(opts): def info(opts):
infs = pycriu.images.info(inf(opts)) infs = pycriu.images.info(inf(opts))
json.dump(infs, sys.stdout, indent=4) json.dump(infs, sys.stdout, indent=4)
print() print()
def get_task_id(p, val): def get_task_id(p, val):
return p[val] if val in p else p['ns_' + val][0] return p[val] if val in p else p['ns_' + val][0]
# #
# Explorers # Explorers
# #
class ps_item: class ps_item:
def __init__(self, p, core): def __init__(self, p, core):
self.pid = get_task_id(p, 'pid') self.pid = get_task_id(p, 'pid')
@ -63,17 +73,21 @@ class ps_item:
self.core = core self.core = core
self.kids = [] self.kids = []
def show_ps(p, opts, depth=0): def show_ps(p, opts, depth=0):
print("%7d%7d%7d %s%s" % (p.pid, get_task_id(p.p, 'pgid'), get_task_id(p.p, 'sid'), print("%7d%7d%7d %s%s" %
' ' * (4 * depth), p.core['tc']['comm'])) (p.pid, get_task_id(p.p, 'pgid'), get_task_id(p.p, 'sid'), ' ' *
(4 * depth), p.core['tc']['comm']))
for kid in p.kids: for kid in p.kids:
show_ps(kid, opts, depth + 1) show_ps(kid, opts, depth + 1)
def explore_ps(opts): def explore_ps(opts):
pss = {} pss = {}
ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) ps_img = pycriu.images.load(dinf(opts, 'pstree.img'))
for p in ps_img['entries']: for p in ps_img['entries']:
core = pycriu.images.load(dinf(opts, 'core-%d.img' % get_task_id(p, 'pid'))) core = pycriu.images.load(
dinf(opts, 'core-%d.img' % get_task_id(p, 'pid')))
ps = ps_item(p, core['entries'][0]) ps = ps_item(p, core['entries'][0])
pss[ps.pid] = ps pss[ps.pid] = ps
@ -91,8 +105,10 @@ def explore_ps(opts):
print("%7s%7s%7s %s" % ('PID', 'PGID', 'SID', 'COMM')) print("%7s%7s%7s %s" % ('PID', 'PGID', 'SID', 'COMM'))
show_ps(psr, opts) show_ps(psr, opts)
files_img = None files_img = None
def ftype_find_in_files(opts, ft, fid): def ftype_find_in_files(opts, ft, fid):
global files_img global files_img
@ -124,14 +140,17 @@ def ftype_find_in_image(opts, ft, fid, img):
return f return f
return None return None
def ftype_reg(opts, ft, fid): def ftype_reg(opts, ft, fid):
rf = ftype_find_in_image(opts, ft, fid, 'reg-files.img') rf = ftype_find_in_image(opts, ft, fid, 'reg-files.img')
return rf and rf['name'] or 'unknown path' return rf and rf['name'] or 'unknown path'
def ftype_pipe(opts, ft, fid): def ftype_pipe(opts, ft, fid):
p = ftype_find_in_image(opts, ft, fid, 'pipes.img') p = ftype_find_in_image(opts, ft, fid, 'pipes.img')
return p and 'pipe[%d]' % p['pipe_id'] or 'pipe[?]' return p and 'pipe[%d]' % p['pipe_id'] or 'pipe[?]'
def ftype_unix(opts, ft, fid): def ftype_unix(opts, ft, fid):
ux = ftype_find_in_image(opts, ft, fid, 'unixsk.img') ux = ftype_find_in_image(opts, ft, fid, 'unixsk.img')
if not ux: if not ux:
@ -140,17 +159,33 @@ def ftype_unix(opts, ft, fid):
n = ux['name'] and ' %s' % ux['name'] or '' n = ux['name'] and ' %s' % ux['name'] or ''
return 'unix[%d (%d)%s]' % (ux['ino'], ux['peer'], n) return 'unix[%d (%d)%s]' % (ux['ino'], ux['peer'], n)
file_types = { file_types = {
'REG': {'get': ftype_reg, 'img': None, 'field': 'reg'}, 'REG': {
'PIPE': {'get': ftype_pipe, 'img': None, 'field': 'pipe'}, 'get': ftype_reg,
'UNIXSK': {'get': ftype_unix, 'img': None, 'field': 'usk'}, 'img': None,
'field': 'reg'
},
'PIPE': {
'get': ftype_pipe,
'img': None,
'field': 'pipe'
},
'UNIXSK': {
'get': ftype_unix,
'img': None,
'field': 'usk'
},
} }
def ftype_gen(opts, ft, fid): def ftype_gen(opts, ft, fid):
return '%s.%d' % (ft['typ'], fid) return '%s.%d' % (ft['typ'], fid)
files_cache = {} files_cache = {}
def get_file_str(opts, fd): def get_file_str(opts, fd):
key = (fd['type'], fd['id']) key = (fd['type'], fd['id'])
f = files_cache.get(key, None) f = files_cache.get(key, None)
@ -161,6 +196,7 @@ def get_file_str(opts, fd):
return f return f
def explore_fds(opts): def explore_fds(opts):
ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) ps_img = pycriu.images.load(dinf(opts, 'pstree.img'))
for p in ps_img['entries']: for p in ps_img['entries']:
@ -174,8 +210,16 @@ def explore_fds(opts):
print("\t%7d: %s" % (fd['fd'], get_file_str(opts, fd))) print("\t%7d: %s" % (fd['fd'], get_file_str(opts, fd)))
fdi = pycriu.images.load(dinf(opts, 'fs-%d.img' % pid))['entries'][0] fdi = pycriu.images.load(dinf(opts, 'fs-%d.img' % pid))['entries'][0]
print("\t%7s: %s" % ('cwd', get_file_str(opts, {'type': 'REG', 'id': fdi['cwd_id']}))) print("\t%7s: %s" %
print("\t%7s: %s" % ('root', get_file_str(opts, {'type': 'REG', 'id': fdi['root_id']}))) ('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']
})))
class vma_id: class vma_id:
@ -192,6 +236,7 @@ class vma_id:
return ret return ret
def explore_mems(opts): def explore_mems(opts):
ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) ps_img = pycriu.images.load(dinf(opts, 'pstree.img'))
vids = vma_id() vids = vma_id()
@ -200,7 +245,11 @@ def explore_mems(opts):
mmi = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0] mmi = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0]
print("%d" % pid) print("%d" % pid)
print("\t%-36s %s" % ('exe', get_file_str(opts, {'type': 'REG', 'id': mmi['exe_file_id']}))) print("\t%-36s %s" % ('exe',
get_file_str(opts, {
'type': 'REG',
'id': mmi['exe_file_id']
})))
for vma in mmi['vmas']: for vma in mmi['vmas']:
st = vma['status'] st = vma['status']
@ -211,7 +260,10 @@ def explore_mems(opts):
elif st & (1 << 11): elif st & (1 << 11):
fn = ' ' + 'packet[%lx]' % vids.get(vma['shmid']) fn = ' ' + 'packet[%lx]' % vids.get(vma['shmid'])
elif st & ((1 << 6) | (1 << 7)): elif st & ((1 << 6) | (1 << 7)):
fn = ' ' + get_file_str(opts, {'type': 'REG', 'id': vma['shmid']}) fn = ' ' + get_file_str(opts, {
'type': 'REG',
'id': vma['shmid']
})
if vma['pgoff']: if vma['pgoff']:
fn += ' + %#lx' % vma['pgoff'] fn += ' + %#lx' % vma['pgoff']
if st & (1 << 7): if st & (1 << 7):
@ -242,7 +294,8 @@ def explore_rss(opts):
ps_img = pycriu.images.load(dinf(opts, 'pstree.img')) ps_img = pycriu.images.load(dinf(opts, 'pstree.img'))
for p in ps_img['entries']: for p in ps_img['entries']:
pid = get_task_id(p, 'pid') pid = get_task_id(p, 'pid')
vmas = pycriu.images.load(dinf(opts, 'mm-%d.img' % pid))['entries'][0]['vmas'] vmas = pycriu.images.load(dinf(opts, 'mm-%d.img' %
pid))['entries'][0]['vmas']
pms = pycriu.images.load(dinf(opts, 'pagemap-%d.img' % pid))['entries'] pms = pycriu.images.load(dinf(opts, 'pagemap-%d.img' % pid))['entries']
print("%d" % pid) print("%d" % pid)
@ -260,9 +313,13 @@ def explore_rss(opts):
if vmi == pvmi: if vmi == pvmi:
vstr += ' ~' vstr += ' ~'
else: else:
vstr += ' %08lx / %-8d' % (vma['start'], (vma['end'] - vma['start'])>>12) vstr += ' %08lx / %-8d' % (
vma['start'], (vma['end'] - vma['start']) >> 12)
if vma['status'] & ((1 << 6) | (1 << 7)): if vma['status'] & ((1 << 6) | (1 << 7)):
vstr += ' ' + get_file_str(opts, {'type': 'REG', 'id': vma['shmid']}) vstr += ' ' + get_file_str(opts, {
'type': 'REG',
'id': vma['shmid']
})
pvmi = vmi pvmi = vmi
vstr += '\n\t%23s' % '' vstr += '\n\t%23s' % ''
vmi += 1 vmi += 1
@ -272,47 +329,59 @@ def explore_rss(opts):
print('%-24s%s' % (pstr, vstr)) print('%-24s%s' % (pstr, vstr))
explorers = {
'ps': explore_ps,
'fds': explore_fds,
'mems': explore_mems,
'rss': explore_rss
}
explorers = { 'ps': explore_ps, 'fds': explore_fds, 'mems': explore_mems, 'rss': explore_rss }
def explore(opts): def explore(opts):
explorers[opts['what']](opts) explorers[opts['what']](opts)
def main(): def main():
desc = 'CRiu Image Tool' desc = 'CRiu Image Tool'
parser = argparse.ArgumentParser(description=desc, parser = argparse.ArgumentParser(
formatter_class=argparse.RawTextHelpFormatter) description=desc, formatter_class=argparse.RawTextHelpFormatter)
subparsers = parser.add_subparsers(help='Use crit CMD --help for command-specific help') subparsers = parser.add_subparsers(
help='Use crit CMD --help for command-specific help')
# Decode # Decode
decode_parser = subparsers.add_parser('decode', decode_parser = subparsers.add_parser(
help = 'convert criu image from binary type to json') 'decode', help='convert criu image from binary type to json')
decode_parser.add_argument('--pretty', decode_parser.add_argument(
help = 'Multiline with indents and some numerical fields in field-specific format', '--pretty',
help=
'Multiline with indents and some numerical fields in field-specific format',
action='store_true') action='store_true')
decode_parser.add_argument('-i', decode_parser.add_argument(
'-i',
'--in', '--in',
help='criu image in binary format to be decoded (stdin by default)') help='criu image in binary format to be decoded (stdin by default)')
decode_parser.add_argument('-o', decode_parser.add_argument(
'-o',
'--out', '--out',
help='where to put criu image in json format (stdout by default)') help='where to put criu image in json format (stdout by default)')
decode_parser.set_defaults(func=decode, nopl=False) decode_parser.set_defaults(func=decode, nopl=False)
# Encode # Encode
encode_parser = subparsers.add_parser('encode', encode_parser = subparsers.add_parser(
help = 'convert criu image from json type to binary') 'encode', help='convert criu image from json type to binary')
encode_parser.add_argument('-i', encode_parser.add_argument(
'-i',
'--in', '--in',
help='criu image in json format to be encoded (stdin by default)') help='criu image in json format to be encoded (stdin by default)')
encode_parser.add_argument('-o', encode_parser.add_argument(
'-o',
'--out', '--out',
help='where to put criu image in binary format (stdout by default)') help='where to put criu image in binary format (stdout by default)')
encode_parser.set_defaults(func=encode) encode_parser.set_defaults(func=encode)
# Info # Info
info_parser = subparsers.add_parser('info', info_parser = subparsers.add_parser('info', help='show info about image')
help = 'show info about image')
info_parser.add_argument("in") info_parser.add_argument("in")
info_parser.set_defaults(func=info) info_parser.set_defaults(func=info)
@ -323,10 +392,12 @@ def main():
x_parser.set_defaults(func=explore) x_parser.set_defaults(func=explore)
# Show # Show
show_parser = subparsers.add_parser('show', show_parser = subparsers.add_parser(
help = "convert criu image from binary to human-readable json") 'show', help="convert criu image from binary to human-readable json")
show_parser.add_argument("in") show_parser.add_argument("in")
show_parser.add_argument('--nopl', help = 'do not show entry payload (if exists)', action = 'store_true') 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) show_parser.set_defaults(func=decode, pretty=True, out=None)
opts = vars(parser.parse_args()) opts = vars(parser.parse_args())
@ -338,5 +409,6 @@ def main():
opts["func"](opts) opts["func"](opts)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -8,6 +8,7 @@ import struct
import pycriu.rpc_pb2 as rpc import pycriu.rpc_pb2 as rpc
class _criu_comm: class _criu_comm:
""" """
Base class for communication classes. Base class for communication classes.
@ -37,6 +38,7 @@ class _criu_comm_sk(_criu_comm):
""" """
Communication class for unix socket. Communication class for unix socket.
""" """
def __init__(self, sk_path): def __init__(self, sk_path):
self.comm_type = self.COMM_SK self.comm_type = self.COMM_SK
self.comm = sk_path self.comm = sk_path
@ -55,22 +57,26 @@ class _criu_comm_fd(_criu_comm):
""" """
Communication class for file descriptor. Communication class for file descriptor.
""" """
def __init__(self, fd): def __init__(self, fd):
self.comm_type = self.COMM_FD self.comm_type = self.COMM_FD
self.comm = fd self.comm = fd
def connect(self, daemon): def connect(self, daemon):
self.sk = socket.fromfd(self.comm, socket.AF_UNIX, socket.SOCK_SEQPACKET) self.sk = socket.fromfd(self.comm, socket.AF_UNIX,
socket.SOCK_SEQPACKET)
return self.sk return self.sk
def disconnect(self): def disconnect(self):
self.sk.close() self.sk.close()
class _criu_comm_bin(_criu_comm): class _criu_comm_bin(_criu_comm):
""" """
Communication class for binary. Communication class for binary.
""" """
def __init__(self, bin_path): def __init__(self, bin_path):
self.comm_type = self.COMM_BIN self.comm_type = self.COMM_BIN
self.comm = bin_path self.comm = bin_path
@ -90,13 +96,16 @@ class _criu_comm_bin(_criu_comm):
p = os.fork() p = os.fork()
if p == 0: if p == 0:
def exec_criu(): def exec_criu():
os.close(0) os.close(0)
os.close(1) os.close(1)
os.close(2) os.close(2)
css[0].send(struct.pack('i', os.getpid())) css[0].send(struct.pack('i', os.getpid()))
os.execv(self.comm, [self.comm, 'swrk', "%d" % css[0].fileno()]) os.execv(self.comm,
[self.comm, 'swrk',
"%d" % css[0].fileno()])
os._exit(1) os._exit(1)
if daemon: if daemon:
@ -143,9 +152,11 @@ class CRIUExceptionInternal(CRIUException):
""" """
Exception class for handling and storing internal errors. Exception class for handling and storing internal errors.
""" """
def __init__(self, typ, s): def __init__(self, typ, s):
self.typ = typ self.typ = typ
self._str = "%s failed with internal error: %s" % (rpc.criu_req_type.Name(self.typ), s) self._str = "%s failed with internal error: %s" % (
rpc.criu_req_type.Name(self.typ), s)
class CRIUExceptionExternal(CRIUException): class CRIUExceptionExternal(CRIUException):

View File

@ -57,14 +57,17 @@ sizeof_u16 = 2
sizeof_u32 = 4 sizeof_u32 = 4
sizeof_u64 = 8 sizeof_u64 = 8
# A helper for rounding # A helper for rounding
def round_up(x, y): def round_up(x, y):
return (((x - 1) | (y - 1)) + 1) return (((x - 1) | (y - 1)) + 1)
class MagicException(Exception): class MagicException(Exception):
def __init__(self, magic): def __init__(self, magic):
self.magic = magic self.magic = magic
# Generic class to handle loading/dumping criu images entries from/to bin # Generic class to handle loading/dumping criu images entries from/to bin
# format to/from dict(json). # format to/from dict(json).
class entry_handler: class entry_handler:
@ -72,6 +75,7 @@ class entry_handler:
Generic class to handle loading/dumping criu images Generic class to handle loading/dumping criu images
entries from/to bin format to/from dict(json). entries from/to bin format to/from dict(json).
""" """
def __init__(self, payload, extra_handler=None): def __init__(self, payload, extra_handler=None):
""" """
Sets payload class and extra handler class. Sets payload class and extra handler class.
@ -102,6 +106,7 @@ class entry_handler:
# Read extra # Read extra
if self.extra_handler: if self.extra_handler:
if no_payload: if no_payload:
def human_readable(num): def human_readable(num):
for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']: for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']:
if num < 1024.0: if num < 1024.0:
@ -174,6 +179,7 @@ class entry_handler:
return entries return entries
# Special handler for pagemap.img # Special handler for pagemap.img
class pagemap_handler: class pagemap_handler:
""" """
@ -181,6 +187,7 @@ class pagemap_handler:
that it has a header of pagemap_head type followed by entries that it has a header of pagemap_head type followed by entries
of pagemap_entry type. of pagemap_entry type.
""" """
def load(self, f, pretty=False, no_payload=False): def load(self, f, pretty=False, no_payload=False):
entries = [] entries = []
@ -220,6 +227,7 @@ class pagemap_handler:
def count(self, f): def count(self, f):
return entry_handler(None).count(f) - 1 return entry_handler(None).count(f) - 1
# Special handler for ghost-file.img # Special handler for ghost-file.img
class ghost_file_handler: class ghost_file_handler:
def load(self, f, pretty=False, no_payload=False): def load(self, f, pretty=False, no_payload=False):
@ -306,6 +314,7 @@ class pipes_data_extra_handler:
f.seek(pload.bytes, os.SEEK_CUR) f.seek(pload.bytes, os.SEEK_CUR)
return pload.bytes return pload.bytes
class sk_queues_extra_handler: class sk_queues_extra_handler:
def load(self, f, pload): def load(self, f, pload):
size = pload.length size = pload.length
@ -344,6 +353,7 @@ class tcp_stream_extra_handler:
f.seek(0, os.SEEK_END) f.seek(0, os.SEEK_END)
return pbuff.inq_len + pbuff.outq_len return pbuff.inq_len + pbuff.outq_len
class ipc_sem_set_handler: class ipc_sem_set_handler:
def load(self, f, pbuff): def load(self, f, pbuff):
entry = pb2dict.pb2dict(pbuff) entry = pb2dict.pb2dict(pbuff)
@ -375,6 +385,7 @@ class ipc_sem_set_handler:
f.seek(round_up(size, sizeof_u64), os.SEEK_CUR) f.seek(round_up(size, sizeof_u64), os.SEEK_CUR)
return size return size
class ipc_msg_queue_handler: class ipc_msg_queue_handler:
def load(self, f, pbuff): def load(self, f, pbuff):
entry = pb2dict.pb2dict(pbuff) entry = pb2dict.pb2dict(pbuff)
@ -423,6 +434,7 @@ class ipc_msg_queue_handler:
return pl_len return pl_len
class ipc_shm_handler: class ipc_shm_handler:
def load(self, f, pbuff): def load(self, f, pbuff):
entry = pb2dict.pb2dict(pbuff) entry = pb2dict.pb2dict(pbuff)
@ -459,7 +471,8 @@ handlers = {
'GHOST_FILE': ghost_file_handler(), 'GHOST_FILE': ghost_file_handler(),
'MM': entry_handler(pb.mm_entry), 'MM': entry_handler(pb.mm_entry),
'CGROUP': entry_handler(pb.cgroup_entry), 'CGROUP': entry_handler(pb.cgroup_entry),
'TCP_STREAM' : entry_handler(pb.tcp_stream_entry, tcp_stream_extra_handler()), 'TCP_STREAM': entry_handler(pb.tcp_stream_entry,
tcp_stream_extra_handler()),
'STATS': entry_handler(pb.stats_entry), 'STATS': entry_handler(pb.stats_entry),
'PAGEMAP': pagemap_handler(), # Special one 'PAGEMAP': pagemap_handler(), # Special one
'PSTREE': entry_handler(pb.pstree_entry), 'PSTREE': entry_handler(pb.pstree_entry),
@ -496,7 +509,8 @@ handlers = {
'ITIMERS': entry_handler(pb.itimer_entry), 'ITIMERS': entry_handler(pb.itimer_entry),
'POSIX_TIMERS': entry_handler(pb.posix_timer_entry), 'POSIX_TIMERS': entry_handler(pb.posix_timer_entry),
'NETDEV': entry_handler(pb.net_device_entry), 'NETDEV': entry_handler(pb.net_device_entry),
'PIPES_DATA' : entry_handler(pb.pipe_data_entry, pipes_data_extra_handler()), 'PIPES_DATA': entry_handler(pb.pipe_data_entry,
pipes_data_extra_handler()),
'FIFO_DATA': entry_handler(pb.pipe_data_entry, pipes_data_extra_handler()), 'FIFO_DATA': entry_handler(pb.pipe_data_entry, pipes_data_extra_handler()),
'SK_QUEUES': entry_handler(pb.sk_packet_entry, sk_queues_extra_handler()), 'SK_QUEUES': entry_handler(pb.sk_packet_entry, sk_queues_extra_handler()),
'IPCNS_SHM': entry_handler(pb.ipc_shm_entry, ipc_shm_handler()), 'IPCNS_SHM': entry_handler(pb.ipc_shm_entry, ipc_shm_handler()),
@ -510,10 +524,12 @@ handlers = {
'CPUINFO': entry_handler(pb.cpuinfo_entry), 'CPUINFO': entry_handler(pb.cpuinfo_entry),
} }
def __rhandler(f): def __rhandler(f):
# Images v1.1 NOTE: First read "first" magic. # Images v1.1 NOTE: First read "first" magic.
img_magic, = struct.unpack('i', f.read(4)) img_magic, = struct.unpack('i', f.read(4))
if img_magic in (magic.by_name['IMG_COMMON'], magic.by_name['IMG_SERVICE']): if img_magic in (magic.by_name['IMG_COMMON'],
magic.by_name['IMG_SERVICE']):
img_magic, = struct.unpack('i', f.read(4)) img_magic, = struct.unpack('i', f.read(4))
try: try:
@ -528,6 +544,7 @@ def __rhandler(f):
return m, handler return m, handler
def load(f, pretty=False, no_payload=False): def load(f, pretty=False, no_payload=False):
""" """
Convert criu image from binary format to dict(json). Convert criu image from binary format to dict(json).
@ -543,6 +560,7 @@ def load(f, pretty = False, no_payload = False):
return image return image
def info(f): def info(f):
res = {} res = {}
@ -553,6 +571,7 @@ def info(f):
return res return res
def loads(s, pretty=False): def loads(s, pretty=False):
""" """
Same as load(), but takes a string. Same as load(), but takes a string.
@ -560,6 +579,7 @@ def loads(s, pretty = False):
f = io.BytesIO(s) f = io.BytesIO(s)
return load(f, pretty) return load(f, pretty)
def dump(img, f): def dump(img, f):
""" """
Convert criu image from dict(json) format to binary. Convert criu image from dict(json) format to binary.
@ -586,6 +606,7 @@ def dump(img, f):
handler.dump(img['entries'], f) handler.dump(img['entries'], f)
def dumps(img): def dumps(img):
""" """
Same as dump(), but takes only an image and returns Same as dump(), but takes only an image and returns

View File

@ -29,47 +29,50 @@ if "encodebytes" not in dir(base64):
# enums to string value too. (i.e. "march : x86_64" is better then # enums to string value too. (i.e. "march : x86_64" is better then
# "march : 1"). # "march : 1").
_basic_cast = { _basic_cast = {
FD.TYPE_FIXED64: int, FD.TYPE_FIXED64: int,
FD.TYPE_FIXED32: int, FD.TYPE_FIXED32: int,
FD.TYPE_SFIXED64: int, FD.TYPE_SFIXED64: int,
FD.TYPE_SFIXED32: int, FD.TYPE_SFIXED32: int,
FD.TYPE_INT64: int, FD.TYPE_INT64: int,
FD.TYPE_UINT64: int, FD.TYPE_UINT64: int,
FD.TYPE_SINT64: int, FD.TYPE_SINT64: int,
FD.TYPE_INT32: int, FD.TYPE_INT32: int,
FD.TYPE_UINT32: int, FD.TYPE_UINT32: int,
FD.TYPE_SINT32: int, FD.TYPE_SINT32: int,
FD.TYPE_BOOL: bool, FD.TYPE_BOOL: bool,
FD.TYPE_STRING: str FD.TYPE_STRING: str
} }
def _marked_as_hex(field): def _marked_as_hex(field):
return field.GetOptions().Extensions[opts_pb2.criu].hex return field.GetOptions().Extensions[opts_pb2.criu].hex
def _marked_as_ip(field): def _marked_as_ip(field):
return field.GetOptions().Extensions[opts_pb2.criu].ipadd return field.GetOptions().Extensions[opts_pb2.criu].ipadd
def _marked_as_flags(field): def _marked_as_flags(field):
return field.GetOptions().Extensions[opts_pb2.criu].flags return field.GetOptions().Extensions[opts_pb2.criu].flags
def _marked_as_dev(field): def _marked_as_dev(field):
return field.GetOptions().Extensions[opts_pb2.criu].dev return field.GetOptions().Extensions[opts_pb2.criu].dev
def _marked_as_odev(field): def _marked_as_odev(field):
return field.GetOptions().Extensions[opts_pb2.criu].odev return field.GetOptions().Extensions[opts_pb2.criu].odev
def _marked_as_dict(field): def _marked_as_dict(field):
return field.GetOptions().Extensions[opts_pb2.criu].dict return field.GetOptions().Extensions[opts_pb2.criu].dict
def _custom_conv(field): def _custom_conv(field):
return field.GetOptions().Extensions[opts_pb2.criu].conv return field.GetOptions().Extensions[opts_pb2.criu].conv
mmap_prot_map = [ mmap_prot_map = [
('PROT_READ', 0x1), ('PROT_READ', 0x1),
('PROT_WRITE', 0x2), ('PROT_WRITE', 0x2),
@ -90,17 +93,14 @@ mmap_status_map = [
('VMA_AREA_VSYSCALL', 1 << 2), ('VMA_AREA_VSYSCALL', 1 << 2),
('VMA_AREA_VDSO', 1 << 3), ('VMA_AREA_VDSO', 1 << 3),
('VMA_AREA_HEAP', 1 << 5), ('VMA_AREA_HEAP', 1 << 5),
('VMA_FILE_PRIVATE', 1 << 6), ('VMA_FILE_PRIVATE', 1 << 6),
('VMA_FILE_SHARED', 1 << 7), ('VMA_FILE_SHARED', 1 << 7),
('VMA_ANON_SHARED', 1 << 8), ('VMA_ANON_SHARED', 1 << 8),
('VMA_ANON_PRIVATE', 1 << 9), ('VMA_ANON_PRIVATE', 1 << 9),
('VMA_AREA_SYSVIPC', 1 << 10), ('VMA_AREA_SYSVIPC', 1 << 10),
('VMA_AREA_SOCKET', 1 << 11), ('VMA_AREA_SOCKET', 1 << 11),
('VMA_AREA_VVAR', 1 << 12), ('VMA_AREA_VVAR', 1 << 12),
('VMA_AREA_AIORING', 1 << 13), ('VMA_AREA_AIORING', 1 << 13),
('VMA_UNSUPP', 1 << 31), ('VMA_UNSUPP', 1 << 31),
] ]
@ -127,21 +127,30 @@ flags_maps = {
} }
gen_maps = { gen_maps = {
'task_state' : { 1: 'Alive', 3: 'Zombie', 6: 'Stopped' }, 'task_state': {
1: 'Alive',
3: 'Zombie',
6: 'Stopped'
},
} }
sk_maps = { sk_maps = {
'family' : { 1: 'UNIX', 'family': {
1: 'UNIX',
2: 'INET', 2: 'INET',
10: 'INET6', 10: 'INET6',
16: 'NETLINK', 16: 'NETLINK',
17: 'PACKET' }, 17: 'PACKET'
'type' : { 1: 'STREAM', },
'type': {
1: 'STREAM',
2: 'DGRAM', 2: 'DGRAM',
3: 'RAW', 3: 'RAW',
5: 'SEQPACKET', 5: 'SEQPACKET',
10: 'PACKET' }, 10: 'PACKET'
'state' : { 1: 'ESTABLISHED', },
'state': {
1: 'ESTABLISHED',
2: 'SYN_SENT', 2: 'SYN_SENT',
3: 'SYN_RECV', 3: 'SYN_RECV',
4: 'FIN_WAIT1', 4: 'FIN_WAIT1',
@ -150,21 +159,33 @@ sk_maps = {
7: 'CLOSE', 7: 'CLOSE',
8: 'CLOSE_WAIT', 8: 'CLOSE_WAIT',
9: 'LAST_ACK', 9: 'LAST_ACK',
10: 'LISTEN' }, 10: 'LISTEN'
'proto' : { 0: 'IP', },
'proto': {
0: 'IP',
6: 'TCP', 6: 'TCP',
17: 'UDP', 17: 'UDP',
136: 'UDPLITE' }, 136: 'UDPLITE'
},
} }
gen_rmaps = { k: {v2:k2 for k2,v2 in list(v.items())} for k,v in list(gen_maps.items()) } gen_rmaps = {
sk_rmaps = { k: {v2:k2 for k2,v2 in list(v.items())} for k,v in list(sk_maps.items()) } k: {v2: k2
for k2, v2 in list(v.items())}
for k, v in list(gen_maps.items())
}
sk_rmaps = {
k: {v2: k2
for k2, v2 in list(v.items())}
for k, v in list(sk_maps.items())
}
dict_maps = { dict_maps = {
'gen': (gen_maps, gen_rmaps), 'gen': (gen_maps, gen_rmaps),
'sk': (sk_maps, sk_rmaps), 'sk': (sk_maps, sk_rmaps),
} }
def map_flags(value, flags_map): def map_flags(value, flags_map):
bs = [x[0] for x in [x for x in flags_map if value & x[1]]] bs = [x[0] for x in [x for x in flags_map if value & x[1]]]
value &= ~sum([x[1] for x in flags_map]) value &= ~sum([x[1] for x in flags_map])
@ -172,20 +193,28 @@ def map_flags(value, flags_map):
bs.append("0x%x" % value) bs.append("0x%x" % value)
return " | ".join(bs) return " | ".join(bs)
def unmap_flags(value, flags_map): def unmap_flags(value, flags_map):
if value == '': if value == '':
return 0 return 0
bd = dict(flags_map) bd = dict(flags_map)
return sum([int(str(bd.get(x, x)), 0) for x in [x.strip() for x in value.split('|')]]) return sum([
int(str(bd.get(x, x)), 0)
for x in [x.strip() for x in value.split('|')]
])
kern_minorbits = 20 # This is how kernel encodes dev_t in new format kern_minorbits = 20 # This is how kernel encodes dev_t in new format
def decode_dev(field, value): def decode_dev(field, value):
if _marked_as_odev(field): if _marked_as_odev(field):
return "%d:%d" % (os.major(value), os.minor(value)) return "%d:%d" % (os.major(value), os.minor(value))
else: else:
return "%d:%d" % (value >> kern_minorbits, value & ((1 << kern_minorbits) - 1)) return "%d:%d" % (value >> kern_minorbits,
value & ((1 << kern_minorbits) - 1))
def encode_dev(field, value): def encode_dev(field, value):
dev = [int(x) for x in value.split(':')] dev = [int(x) for x in value.split(':')]
@ -194,19 +223,27 @@ def encode_dev(field, value):
else: else:
return dev[0] << kern_minorbits | dev[1] return dev[0] << kern_minorbits | dev[1]
def encode_base64(value): def encode_base64(value):
return base64.encodebytes(value) return base64.encodebytes(value)
def decode_base64(value): def decode_base64(value):
return base64.decodebytes(value) return base64.decodebytes(value)
def encode_unix(value): def encode_unix(value):
return quopri.encodestring(value) return quopri.encodestring(value)
def decode_unix(value): def decode_unix(value):
return quopri.decodestring(value) return quopri.decodestring(value)
encode = {'unix_name': encode_unix} encode = {'unix_name': encode_unix}
decode = {'unix_name': decode_unix} decode = {'unix_name': decode_unix}
def get_bytes_enc(field): def get_bytes_enc(field):
c = _custom_conv(field) c = _custom_conv(field)
if c: if c:
@ -214,6 +251,7 @@ def get_bytes_enc(field):
else: else:
return encode_base64 return encode_base64
def get_bytes_dec(field): def get_bytes_dec(field):
c = _custom_conv(field) c = _custom_conv(field)
if c: if c:
@ -221,6 +259,7 @@ def get_bytes_dec(field):
else: else:
return decode_base64 return decode_base64
def is_string(value): def is_string(value):
# Python 3 compatibility # Python 3 compatibility
if "basestring" in __builtins__: if "basestring" in __builtins__:
@ -229,6 +268,7 @@ def is_string(value):
string_types = (str, bytes) string_types = (str, bytes)
return isinstance(value, string_types) return isinstance(value, string_types)
def _pb2dict_cast(field, value, pretty=False, is_hex=False): def _pb2dict_cast(field, value, pretty=False, is_hex=False):
if not is_hex: if not is_hex:
is_hex = _marked_as_hex(field) is_hex = _marked_as_hex(field)
@ -254,7 +294,7 @@ def _pb2dict_cast(field, value, pretty = False, is_hex = False):
if flags: if flags:
try: try:
flags_map = flags_maps[flags] flags_map = flags_maps[flags]
except: except Exception:
return "0x%x" % value # flags are better seen as hex anyway return "0x%x" % value # flags are better seen as hex anyway
else: else:
return map_flags(value, flags_map) return map_flags(value, flags_map)
@ -265,7 +305,9 @@ def _pb2dict_cast(field, value, pretty = False, is_hex = False):
return cast(value) return cast(value)
else: else:
raise Exception("Field(%s) has unsupported type %d" % (field.name, field.type)) raise Exception("Field(%s) has unsupported type %d" %
(field.name, field.type))
def pb2dict(pb, pretty=False, is_hex=False): def pb2dict(pb, pretty=False, is_hex=False):
""" """
@ -297,6 +339,7 @@ def pb2dict(pb, pretty = False, is_hex = False):
d[field.name] = d_val d[field.name] = d_val
return d return d
def _dict2pb_cast(field, value): def _dict2pb_cast(field, value):
# Not considering TYPE_MESSAGE here, as repeated # Not considering TYPE_MESSAGE here, as repeated
# and non-repeated messages need special treatment # and non-repeated messages need special treatment
@ -315,7 +358,7 @@ def _dict2pb_cast(field, value):
if flags: if flags:
try: try:
flags_map = flags_maps[flags] flags_map = flags_maps[flags]
except: except Exception:
pass # Try to use plain string cast pass # Try to use plain string cast
else: else:
return unmap_flags(value, flags_map) return unmap_flags(value, flags_map)
@ -323,7 +366,7 @@ def _dict2pb_cast(field, value):
dct = _marked_as_dict(field) dct = _marked_as_dict(field)
if dct: if dct:
ret = dict_maps[dct][1][field.name].get(value, None) ret = dict_maps[dct][1][field.name].get(value, None)
if ret == None: if ret is None:
ret = cast(value, 0) ret = cast(value, 0)
return ret return ret
@ -333,7 +376,9 @@ def _dict2pb_cast(field, value):
else: else:
return cast(value) return cast(value)
else: else:
raise Exception("Field(%s) has unsupported type %d" % (field.name, field.type)) raise Exception("Field(%s) has unsupported type %d" %
(field.name, field.type))
def dict2pb(d, pb): def dict2pb(d, pb):
""" """
@ -357,7 +402,8 @@ def dict2pb(d, pb):
pb_val.append(socket.htonl((ival >> (32 * 1)) & 0xFFFFFFFF)) pb_val.append(socket.htonl((ival >> (32 * 1)) & 0xFFFFFFFF))
pb_val.append(socket.htonl((ival >> (32 * 0)) & 0xFFFFFFFF)) pb_val.append(socket.htonl((ival >> (32 * 0)) & 0xFFFFFFFF))
else: else:
raise Exception("Unknown IP address version %d" % val.version) raise Exception("Unknown IP address version %d" %
val.version)
continue continue
for v in value: for v in value:

View File

@ -8,5 +8,4 @@ setup(name = "crit",
url="https://github.com/checkpoint-restore/criu", url="https://github.com/checkpoint-restore/criu",
package_dir={'pycriu': 'lib/py'}, package_dir={'pycriu': 'lib/py'},
packages=["pycriu", "pycriu.images"], packages=["pycriu", "pycriu.images"],
scripts = ["crit/crit"] scripts=["crit/crit"])
)

View File

@ -1,6 +1,7 @@
#!/bin/env python2 #!/bin/env python2
import sys import sys
# This program parses criu magic.h file and produces # This program parses criu magic.h file and produces
# magic.py with all *_MAGIC constants except RAW and V1. # magic.py with all *_MAGIC constants except RAW and V1.
def main(argv): def main(argv):
@ -57,5 +58,6 @@ def main(argv):
f.close() f.close()
out.close() out.close()
if __name__ == "__main__": if __name__ == "__main__":
main(sys.argv) main(sys.argv)

View File

@ -13,15 +13,15 @@ sport = os.getenv("TCP_SPORT", "12345")
dport = os.getenv("TCP_DPORT", "54321") dport = os.getenv("TCP_DPORT", "54321")
print(sys.argv[1]) print(sys.argv[1])
args = [sys.argv[1], args = [
"--addr", src, "--port", sport, "--seq", "555", sys.argv[1], "--addr", src, "--port", sport, "--seq", "555", "--next",
"--next", "--addr", dst, "--port", dport, "--seq", "666", "--reverse", "--",
"--addr", dst, "--port", dport, "--seq", "666", "./tcp-test.py"
"--reverse", "--", "./tcp-test.py"] ]
p1 = Popen(args + ["dst"], stdout=PIPE, stdin=PIPE) p1 = Popen(args + ["dst"], stdout=PIPE, stdin=PIPE)
args.remove("--reverse"); args.remove("--reverse")
p2 = Popen(args + ["src"], stdout=PIPE, stdin=PIPE) p2 = Popen(args + ["src"], stdout=PIPE, stdin=PIPE)
@ -42,7 +42,7 @@ str2 = m.hexdigest()
if str2 != eval(s): if str2 != eval(s):
print("FAIL", repr(str2), repr(s)) print("FAIL", repr(str2), repr(s))
sys.exit(5); sys.exit(5)
s = p1.stdout.read() s = p1.stdout.read()
m = hashlib.md5() m = hashlib.md5()
@ -52,7 +52,7 @@ str1 = m.hexdigest()
s = p2.stdout.read() s = p2.stdout.read()
if str1 != eval(s): if str1 != eval(s):
print("FAIL", repr(str1), s) print("FAIL", repr(str1), s)
sys.exit(5); sys.exit(5)
if p1.wait(): if p1.wait():
sys.exit(1) sys.exit(1)

View File

@ -25,7 +25,8 @@ for act in open(af):
if act[2] == 'EMPTY': if act[2] == 'EMPTY':
errors.append('Action %s misses CRTOOLS_INIT_PID' % act[0]) errors.append('Action %s misses CRTOOLS_INIT_PID' % act[0])
elif not act[2].isdigit() or int(act[2]) == 0: elif not act[2].isdigit() or int(act[2]) == 0:
errors.append('Action %s PID is not number (%s)' % (act[0], act[2])) errors.append('Action %s PID is not number (%s)' %
(act[0], act[2]))
actions -= set([act[0]]) actions -= set([act[0]])

View File

@ -6,11 +6,13 @@ import sys
import os import os
import subprocess import subprocess
find = subprocess.Popen(['find', 'test/dump/', '-size', '+0', '-name', '*.img'], find = subprocess.Popen(
['find', 'test/dump/', '-size', '+0', '-name', '*.img'],
stdout=subprocess.PIPE) stdout=subprocess.PIPE)
test_pass = True test_pass = True
def recode_and_check(imgf, o_img, pretty): def recode_and_check(imgf, o_img, pretty):
try: try:
pb = pycriu.images.loads(o_img, pretty) pb = pycriu.images.loads(o_img, pretty)

View File

@ -10,6 +10,7 @@ import subprocess
criu_bin = '../../criu/criu' criu_bin = '../../criu/criu'
def mix(nr_tasks, nr_pipes): def mix(nr_tasks, nr_pipes):
# Returned is the list of combinations. # Returned is the list of combinations.
# Each combination is the lists of pipe descriptors. # Each combination is the lists of pipe descriptors.
@ -114,6 +115,7 @@ def check_pipe(kids, fds, comb, inos):
return res + 'end(%d)' % e return res + 'end(%d)' % e
return None return None
def check_pipes(kids, pipes, comb): def check_pipes(kids, pipes, comb):
# Kids contain pids # Kids contain pids
# Pipes contain pipe FDs # Pipes contain pipe FDs
@ -198,14 +200,20 @@ def cr_test(pid):
img_dir = 'pimg_%d' % pid img_dir = 'pimg_%d' % pid
try: try:
os.mkdir(img_dir) os.mkdir(img_dir)
subprocess.check_call([criu_bin, 'dump', '-t', '%d' % pid, '-D', img_dir, '-o', 'dump.log', '-v4', '-j']) subprocess.check_call([
criu_bin, 'dump', '-t',
'%d' % pid, '-D', img_dir, '-o', 'dump.log', '-v4', '-j'
])
except: except:
print('`- dump fail') print('`- dump fail')
return False return False
try: try:
os.waitpid(pid, 0) os.waitpid(pid, 0)
subprocess.check_call([criu_bin, 'restore', '-D', img_dir, '-o', 'rst.log', '-v4', '-j', '-d', '-S']) subprocess.check_call([
criu_bin, 'restore', '-D', img_dir, '-o', 'rst.log', '-v4', '-j',
'-d', '-S'
])
except: except:
print('`- restore fail') print('`- restore fail')
return False return False

View File

@ -25,12 +25,14 @@ sk_type_s = {
# - do() method, that actually does what's required # - do() method, that actually does what's required
# - show() method to return the string description of what's done # - show() method to return the string description of what's done
def mk_socket(st, typ): def mk_socket(st, typ):
st.sk_id += 1 st.sk_id += 1
sk = sock(st.sk_id, typ) sk = sock(st.sk_id, typ)
st.add_socket(sk) st.add_socket(sk)
return sk return sk
class act_socket: class act_socket:
def __init__(self, typ): def __init__(self, typ):
self.typ = typ self.typ = typ
@ -174,12 +176,14 @@ class act_sendmsg:
sk.sendto(msgv, sock.real_name_for(self.to_id)) sk.sendto(msgv, sock.real_name_for(self.to_id))
def show(self): def show(self):
return 'send(%d, %d, $message-%d)' % (self.sk_id, self.to_id, self.msg_id) return 'send(%d, %d, $message-%d)' % (self.sk_id, self.to_id,
self.msg_id)
@staticmethod @staticmethod
def msgval(msgid, pref=''): def msgval(msgid, pref=''):
return '%sMSG%d' % (pref, msgid) return '%sMSG%d' % (pref, msgid)
# #
# Description of a socket # Description of a socket
# #
@ -425,6 +429,7 @@ def set_nonblock(sk):
flags = fcntl.fcntl(fd, fcntl.F_GETFL) flags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
CHK_FAIL_UNKNOWN = 10 CHK_FAIL_UNKNOWN = 10
CHK_FAIL_SOCKET = 11 CHK_FAIL_SOCKET = 11
CHK_FAIL_STAT = 12 CHK_FAIL_STAT = 12
@ -455,6 +460,7 @@ fail_desc = {
CHK_FAIL_RESTORE: 'Cannot restore', CHK_FAIL_RESTORE: 'Cannot restore',
} }
def chk_real_state(st): def chk_real_state(st):
# Before enything else -- check that we still have # Before enything else -- check that we still have
# all the sockets at hands # all the sockets at hands
@ -485,16 +491,16 @@ def chk_real_state(st):
rsk = st.real_sockets[sk.sk_id] rsk = st.real_sockets[sk.sk_id]
r_listen = rsk.getsockopt(socket.SOL_SOCKET, socket.SO_ACCEPTCONN) r_listen = rsk.getsockopt(socket.SOL_SOCKET, socket.SO_ACCEPTCONN)
if (sk.listen and r_listen == 0) or (not sk.listen and r_listen == 1): if (sk.listen and r_listen == 0) or (not sk.listen and r_listen == 1):
print("FAIL: Socket %d listen %d, expected %d" print("FAIL: Socket %d listen %d, expected %d" %
% (sk.sk_id, r_listen, sk.listen and 1 or 0)) (sk.sk_id, r_listen, sk.listen and 1 or 0))
return CHK_FAIL_LISTEN return CHK_FAIL_LISTEN
if sk.name: if sk.name:
r_name = rsk.getsockname() r_name = rsk.getsockname()
w_name = sock.real_name_for(sk.name) w_name = sock.real_name_for(sk.name)
if r_name != w_name: if r_name != w_name:
print('FAIL: Socket %d name mismatch [%s], want [%s]' print('FAIL: Socket %d name mismatch [%s], want [%s]' %
% (sk.sk_id, r_name, w_name)) (sk.sk_id, r_name, w_name))
return CHK_FAIL_NAME return CHK_FAIL_NAME
# Second -- check (accept) pending connections # Second -- check (accept) pending connections
@ -513,7 +519,8 @@ def chk_real_state(st):
try: try:
acc.do(st) acc.do(st)
except: except:
print('FAIL: Cannot accept pending connection for %d' % sk.sk_id) print('FAIL: Cannot accept pending connection for %d' %
sk.sk_id)
return CHK_FAIL_ACCEPT return CHK_FAIL_ACCEPT
print(' `- did %s' % acc.show()) print(' `- did %s' % acc.show())
@ -536,13 +543,13 @@ def chk_real_state(st):
w_msg = act_sendmsg.msgval(msg[1]) w_msg = act_sendmsg.msgval(msg[1])
if r_msg != w_msg: if r_msg != w_msg:
print('FAIL: Message misorder: %s want %s (from %d)' print('FAIL: Message misorder: %s want %s (from %d)' %
%(r_msg, w_msg, msg[0])) (r_msg, w_msg, msg[0]))
return CHK_FAIL_RECV_MIX return CHK_FAIL_RECV_MIX
# TODO -- check sender # TODO -- check sender
print(' `- recvd %d.%d msg %s -> %d' print(' `- recvd %d.%d msg %s -> %d' %
% (msg[0], msg[1], m_from, sk.sk_id)) (msg[0], msg[1], m_from, sk.sk_id))
# Finally, after all sockets are visible and all inqueues are # Finally, after all sockets are visible and all inqueues are
# drained -- check the sockets connectivity # drained -- check the sockets connectivity
@ -557,7 +564,8 @@ def chk_real_state(st):
rsk = st.real_sockets[sk.sk_id] rsk = st.real_sockets[sk.sk_id]
psk = st.real_sockets[sk.peer] psk = st.real_sockets[sk.peer]
set_nonblock(psk) set_nonblock(psk)
msgv = act_sendmsg.msgval(3 * sk.sk_id + 5 * sk.peer, 'C') # just random msgv = act_sendmsg.msgval(3 * sk.sk_id + 5 * sk.peer,
'C') # just random
try: try:
rsk.send(msgv) rsk.send(msgv)
@ -572,8 +580,8 @@ def chk_real_state(st):
# the hard way -- also check for the message being # the hard way -- also check for the message being
# delivered for real # delivered for real
if rmsg != msgv: if rmsg != msgv:
print('FAIL: Connectivity %d -> %d not verified' print('FAIL: Connectivity %d -> %d not verified' %
% (sk.sk_id, sk.peer)) (sk.sk_id, sk.peer))
return CHK_FAIL_CONNECT2 return CHK_FAIL_CONNECT2
print(' `- checked %d -> %d with %s' % (sk.sk_id, sk.peer, msgv)) print(' `- checked %d -> %d with %s' % (sk.sk_id, sk.peer, msgv))
@ -609,7 +617,10 @@ def chk_state(st, opts):
img_path = "sti_" + st.describe() img_path = "sti_" + st.describe()
try: try:
os.mkdir(img_path) os.mkdir(img_path)
subprocess.check_call([criu_bin, "dump", "-t", "%d" % pid, "-D", img_path, "-v4", "-o", "dump.log", "-j"]) subprocess.check_call([
criu_bin, "dump", "-t",
"%d" % pid, "-D", img_path, "-v4", "-o", "dump.log", "-j"
])
except: except:
print("Dump failed") print("Dump failed")
os.kill(pid, signal.SIGKILL) os.kill(pid, signal.SIGKILL)
@ -618,7 +629,10 @@ def chk_state(st, opts):
print("`- restore") print("`- restore")
try: try:
os.waitpid(pid, 0) os.waitpid(pid, 0)
subprocess.check_call([criu_bin, "restore", "-D", img_path, "-v4", "-o", "rst.log", "-j", "-d", "-S"]) subprocess.check_call([
criu_bin, "restore", "-D", img_path, "-v4", "-o", "rst.log", "-j",
"-d", "-S"
])
except: except:
print("Restore failed") print("Restore failed")
return CHK_FAIL_RESTORE return CHK_FAIL_RESTORE
@ -722,8 +736,12 @@ p.add_argument("--depth", help = "Depth of generated tree", default = '8')
p.add_argument("--sockets", help="Maximum number of sockets", default='1') p.add_argument("--sockets", help="Maximum number of sockets", default='1')
p.add_argument("--dgram", help="Use SOCK_DGRAM sockets", action='store_true') p.add_argument("--dgram", help="Use SOCK_DGRAM sockets", action='store_true')
p.add_argument("--stream", help="Use SOCK_STREAM sockets", action='store_true') p.add_argument("--stream", help="Use SOCK_STREAM sockets", action='store_true')
p.add_argument("--gen", help = "Only generate and show states", action = 'store_true') p.add_argument("--gen",
p.add_argument("--run", help = "Run the states, but don't C/R", action = 'store_true') help="Only generate and show states",
action='store_true')
p.add_argument("--run",
help="Run the states, but don't C/R",
action='store_true')
p.add_argument("--keep", help="Don't stop on error", action='store_true') p.add_argument("--keep", help="Don't stop on error", action='store_true')
opts = p.parse_args() opts = p.parse_args()
opts.depth = int(opts.depth) opts.depth = int(opts.depth)
@ -751,4 +769,5 @@ if len(failed) == 0:
else: else:
print('FAIL %d/%d' % (len(failed), len(seen))) print('FAIL %d/%d' % (len(failed), len(seen)))
for f in failed: for f in failed:
print("\t%-50s: %s" % (f[0], fail_desc.get(f[1], 'unknown reason %d' % f[1]))) print("\t%-50s: %s" %
(f[0], fail_desc.get(f[1], 'unknown reason %d' % f[1])))

View File

@ -4,7 +4,6 @@ import os
import pty import pty
import termios import termios
ctl = False ctl = False

View File

@ -5,13 +5,19 @@ import os, sys, time, signal, pty
master, slave = pty.openpty() master, slave = pty.openpty()
p = subprocess.Popen(["setsid", "--ctty", "sleep", "10000"], p = subprocess.Popen(["setsid", "--ctty", "sleep", "10000"],
stdin = slave, stdout = slave, stderr = slave, close_fds = True) stdin=slave,
stdout=slave,
stderr=slave,
close_fds=True)
st = os.stat("/proc/self/fd/%d" % slave) st = os.stat("/proc/self/fd/%d" % slave)
ttyid = "tty[%x:%x]" % (st.st_rdev, st.st_dev) ttyid = "tty[%x:%x]" % (st.st_rdev, st.st_dev)
os.close(slave) os.close(slave)
time.sleep(1) time.sleep(1)
ret = subprocess.Popen(["../../../criu/criu", "dump", "-t", str(p.pid), "-v4", "--external", ttyid]).wait() ret = subprocess.Popen([
"../../../criu/criu", "dump", "-t",
str(p.pid), "-v4", "--external", ttyid
]).wait()
if ret: if ret:
sys.exit(ret) sys.exit(ret)
p.wait() p.wait()
@ -21,7 +27,10 @@ os.close(master)
ttyid = "fd[%d]:tty[%x:%x]" % (slave, st.st_rdev, st.st_dev) ttyid = "fd[%d]:tty[%x:%x]" % (slave, st.st_rdev, st.st_dev)
ret = subprocess.Popen(["../../../criu/criu", "restore", "-v4", "--inherit-fd", ttyid, "--restore-sibling", "--restore-detach"]).wait() ret = subprocess.Popen([
"../../../criu/criu", "restore", "-v4", "--inherit-fd", ttyid,
"--restore-sibling", "--restore-detach"
]).wait()
if ret: if ret:
sys.exit(ret) sys.exit(ret)
os.close(slave) os.close(slave)

View File

@ -1,6 +1,7 @@
import os import os
import tempfile, random import tempfile, random
def mount(src, dst, shared, private, slave): def mount(src, dst, shared, private, slave):
cmd = "mount" cmd = "mount"
if shared: if shared:
@ -19,6 +20,7 @@ def mount(src, dst, shared, private, slave):
if ret: if ret:
print("failed") print("failed")
root = tempfile.mkdtemp(prefix="root.mount", dir="/tmp") root = tempfile.mkdtemp(prefix="root.mount", dir="/tmp")
mount(None, root, 1, 0, 0) mount(None, root, 1, 0, 0)
mounts = [root] mounts = [root]
@ -27,5 +29,8 @@ for i in range(10):
dstdir = random.choice(mounts) dstdir = random.choice(mounts)
dst = tempfile.mkdtemp(prefix="mount", dir=dstdir) dst = tempfile.mkdtemp(prefix="mount", dir=dstdir)
src = random.choice(mounts + [None]) src = random.choice(mounts + [None])
mount(src, dst, random.randint(0,100) > 50, random.randint(0,100) > 90, random.randint(0,100) > 50) mount(src, dst,
random.randint(0, 100) > 50,
random.randint(0, 100) > 90,
random.randint(0, 100) > 50)
mounts.append(dst) mounts.append(dst)

View File

@ -99,7 +99,9 @@ def test_broken_configuration_file():
def search_in_log_file(log, message): def search_in_log_file(log, message):
with open(os.path.join(args['dir'], log)) as f: with open(os.path.join(args['dir'], log)) as f:
if message not in f.read(): if message not in f.read():
print('FAIL: Missing the expected error message (%s) in the log file' % message) print(
'FAIL: Missing the expected error message (%s) in the log file'
% message)
sys.exit(-1) sys.exit(-1)
@ -175,8 +177,11 @@ def test_rpc_with_configuration_file_overwriting_rpc():
check_results(resp, log) check_results(resp, log)
parser = argparse.ArgumentParser(description="Test config files using CRIU RPC") parser = argparse.ArgumentParser(
parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed") description="Test config files using CRIU RPC")
parser.add_argument('dir',
type=str,
help="Directory where CRIU images should be placed")
args = vars(parser.parse_args()) args = vars(parser.parse_args())

View File

@ -7,10 +7,13 @@ import argparse
parser = argparse.ArgumentParser(description="Test errno reported by CRIU RPC") parser = argparse.ArgumentParser(description="Test errno reported by CRIU RPC")
parser.add_argument('socket', type=str, help="CRIU service socket") parser.add_argument('socket', type=str, help="CRIU service socket")
parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed") parser.add_argument('dir',
type=str,
help="Directory where CRIU images should be placed")
args = vars(parser.parse_args()) args = vars(parser.parse_args())
# Prepare dir for images # Prepare dir for images
class test: class test:
def __init__(self): def __init__(self):
@ -73,7 +76,9 @@ class test:
print('Success') print('Success')
def process_exists(self): def process_exists(self):
print('Try to restore process which pid is already taken by other process') print(
'Try to restore process which pid is already taken by other process'
)
# Perform self-dump # Perform self-dump
req = self.get_base_req() req = self.get_base_req()
@ -131,5 +136,6 @@ class test:
self.bad_options() self.bad_options()
self.bad_request() self.bad_request()
t = test() t = test()
t.run() t.run()

View File

@ -6,7 +6,9 @@ import argparse
parser = argparse.ArgumentParser(description="Test page-server using CRIU RPC") parser = argparse.ArgumentParser(description="Test page-server using CRIU RPC")
parser.add_argument('socket', type=str, help="CRIU service socket") parser.add_argument('socket', type=str, help="CRIU service socket")
parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed") parser.add_argument('dir',
type=str,
help="Directory where CRIU images should be placed")
args = vars(parser.parse_args()) args = vars(parser.parse_args())
@ -42,12 +44,12 @@ else:
else: else:
print('Can\'t check that process %d exists' % (resp.ps.pid)) print('Can\'t check that process %d exists' % (resp.ps.pid))
sys.exit(1) sys.exit(1)
print('Success, page-server pid %d started on port %u' %(resp.ps.pid, resp.ps.port)) print('Success, page-server pid %d started on port %u' %
(resp.ps.pid, resp.ps.port))
else: else:
print('Failed to start page-server') print('Failed to start page-server')
sys.exit(1) sys.exit(1)
# Perform self-dump # Perform self-dump
print('Dumping myself using page-server') print('Dumping myself using page-server')
req.type = rpc.DUMP req.type = rpc.DUMP

View File

@ -4,9 +4,12 @@ import socket, os, sys
import rpc_pb2 as rpc import rpc_pb2 as rpc
import argparse import argparse
parser = argparse.ArgumentParser(description="Test ability to restore a process from images using CRIU RPC") parser = argparse.ArgumentParser(
description="Test ability to restore a process from images using CRIU RPC")
parser.add_argument('socket', type=str, help="CRIU service socket") parser.add_argument('socket', type=str, help="CRIU service socket")
parser.add_argument('dir', type = str, help = "Directory where CRIU images could be found") parser.add_argument('dir',
type=str,
help="Directory where CRIU images could be found")
args = vars(parser.parse_args()) args = vars(parser.parse_args())

View File

@ -4,9 +4,12 @@ import socket, os, sys
import rpc_pb2 as rpc import rpc_pb2 as rpc
import argparse import argparse
parser = argparse.ArgumentParser(description="Test dump/restore using CRIU RPC") parser = argparse.ArgumentParser(
description="Test dump/restore using CRIU RPC")
parser.add_argument('socket', type=str, help="CRIU service socket") parser.add_argument('socket', type=str, help="CRIU service socket")
parser.add_argument('dir', type = str, help = "Directory where CRIU images should be placed") parser.add_argument('dir',
type=str,
help="Directory where CRIU images should be placed")
args = vars(parser.parse_args()) args = vars(parser.parse_args())

View File

@ -6,10 +6,12 @@ cr_bin = "../../../criu/criu"
os.chdir(os.getcwd()) os.chdir(os.getcwd())
def create_pty(): def create_pty():
(fd1, fd2) = pty.openpty() (fd1, fd2) = pty.openpty()
return (os.fdopen(fd1, "w+"), os.fdopen(fd2, "w+")) return (os.fdopen(fd1, "w+"), os.fdopen(fd2, "w+"))
if not os.access("work", os.X_OK): if not os.access("work", os.X_OK):
os.mkdir("work", 0755) os.mkdir("work", 0755)
@ -53,7 +55,8 @@ if cpid == 0:
fcntl.ioctl(m.fileno(), termios.TIOCSCTTY, 1) fcntl.ioctl(m.fileno(), termios.TIOCSCTTY, 1)
cmd = [cr_bin, "restore", "-j", "-D", "work", "-v"] cmd = [cr_bin, "restore", "-j", "-D", "work", "-v"]
print("Run: %s" % " ".join(cmd)) print("Run: %s" % " ".join(cmd))
ret = subprocess.Popen([cr_bin, "restore", "-j", "-D", "work", "-v"]).wait() ret = subprocess.Popen([cr_bin, "restore", "-j", "-D", "work",
"-v"]).wait()
if ret != 0: if ret != 0:
sys.exit(1) sys.exit(1)
sys.exit(0) sys.exit(0)

View File

@ -122,7 +122,8 @@ def check_core_files():
if not reports: if not reports:
return False return False
while subprocess.Popen(r"ps axf | grep 'abrt\.sh'", shell = True).wait() == 0: while subprocess.Popen(r"ps axf | grep 'abrt\.sh'",
shell=True).wait() == 0:
time.sleep(1) time.sleep(1)
for i in reports: for i in reports:
@ -164,7 +165,10 @@ class host_flavor:
class ns_flavor: class ns_flavor:
__root_dirs = ["/bin", "/sbin", "/etc", "/lib", "/lib64", "/dev", "/dev/pts", "/dev/net", "/tmp", "/usr", "/proc", "/run"] __root_dirs = [
"/bin", "/sbin", "/etc", "/lib", "/lib64", "/dev", "/dev/pts",
"/dev/net", "/tmp", "/usr", "/proc", "/run"
]
def __init__(self, opts): def __init__(self, opts):
self.name = "ns" self.name = "ns"
@ -183,27 +187,36 @@ class ns_flavor:
except OSError as e: except OSError as e:
if e.errno != errno.EEXIST: if e.errno != errno.EEXIST:
raise raise
dst = tempfile.mktemp(".tso", "", self.root + os.path.dirname(fname)) dst = tempfile.mktemp(".tso", "",
self.root + os.path.dirname(fname))
shutil.copy2(fname, dst) shutil.copy2(fname, dst)
os.rename(dst, tfname) os.rename(dst, tfname)
def __copy_libs(self, binary): def __copy_libs(self, binary):
ldd = subprocess.Popen(["ldd", binary], stdout=subprocess.PIPE) ldd = subprocess.Popen(["ldd", binary], stdout=subprocess.PIPE)
xl = re.compile(r'^(linux-gate.so|linux-vdso(64)?.so|not a dynamic|.*\s*ldd\s)') xl = re.compile(
r'^(linux-gate.so|linux-vdso(64)?.so|not a dynamic|.*\s*ldd\s)')
# This Mayakovsky-style code gets list of libraries a binary # This Mayakovsky-style code gets list of libraries a binary
# needs minus vdso and gate .so-s # needs minus vdso and gate .so-s
libs = map(lambda x: x[1] == '=>' and x[2] or x[0], libs = map(
map(lambda x: str(x).split(), lambda x: x[1] == '=>' and x[2] or x[0],
filter(lambda x: not xl.match(x), map(
map(lambda x: str(x).strip(), lambda x: str(x).split(),
filter(lambda x: str(x).startswith('\t'), ldd.stdout.read().decode('ascii').splitlines()))))) filter(
lambda x: not xl.match(x),
map(
lambda x: str(x).strip(),
filter(lambda x: str(x).startswith('\t'),
ldd.stdout.read().decode(
'ascii').splitlines())))))
ldd.wait() ldd.wait()
for lib in libs: for lib in libs:
if not os.access(lib, os.F_OK): if not os.access(lib, os.F_OK):
raise test_fail_exc("Can't find lib %s required by %s" % (lib, binary)) raise test_fail_exc("Can't find lib %s required by %s" %
(lib, binary))
self.__copy_one(lib) self.__copy_one(lib)
def __mknod(self, name, rdev=None): def __mknod(self, name, rdev=None):
@ -242,7 +255,8 @@ class ns_flavor:
raise test_fail_exc("Deps check %s failed" % deps) raise test_fail_exc("Deps check %s failed" % deps)
def init(self, l_bins, x_bins): def init(self, l_bins, x_bins):
subprocess.check_call(["mount", "--make-slave", "--bind", ".", self.root]) subprocess.check_call(
["mount", "--make-slave", "--bind", ".", self.root])
self.root_mounted = True self.root_mounted = True
if not os.access(self.root + "/.constructed", os.F_OK): if not os.access(self.root + "/.constructed", os.F_OK):
@ -308,8 +322,7 @@ def decode_flav(i):
def tail(path): def tail(path):
p = subprocess.Popen(['tail', '-n1', path], p = subprocess.Popen(['tail', '-n1', path], stdout=subprocess.PIPE)
stdout = subprocess.PIPE)
out = p.stdout.readline() out = p.stdout.readline()
p.wait() p.wait()
return out.decode() return out.decode()
@ -342,6 +355,7 @@ def wait_pid_die(pid, who, tmo = 30):
def test_flag(tdesc, flag): def test_flag(tdesc, flag):
return flag in tdesc.get('flags', '').split() return flag in tdesc.get('flags', '').split()
# #
# Exception thrown when something inside the test goes wrong, # Exception thrown when something inside the test goes wrong,
# e.g. test doesn't start, criu returns with non zero code or # e.g. test doesn't start, criu returns with non zero code or
@ -361,6 +375,7 @@ class test_fail_expected_exc(Exception):
def __init__(self, cr_action): def __init__(self, cr_action):
self.cr_action = cr_action self.cr_action = cr_action
# #
# A test from zdtm/ directory. # A test from zdtm/ directory.
# #
@ -384,14 +399,20 @@ class zdtm_test:
def __make_action(self, act, env=None, root=None): def __make_action(self, act, env=None, root=None):
sys.stdout.flush() # Not to let make's messages appear before ours sys.stdout.flush() # Not to let make's messages appear before ours
tpath = self.__name + '.' + act tpath = self.__name + '.' + act
s_args = ['make', '--no-print-directory', s_args = [
'-C', os.path.dirname(tpath), 'make', '--no-print-directory', '-C',
os.path.basename(tpath)] os.path.dirname(tpath),
os.path.basename(tpath)
]
if env: if env:
env = dict(os.environ, **env) env = dict(os.environ, **env)
s = subprocess.Popen(s_args, env = env, cwd = root, close_fds = True, s = subprocess.Popen(
s_args,
env=env,
cwd=root,
close_fds=True,
preexec_fn=self.__freezer and self.__freezer.attach or None) preexec_fn=self.__freezer and self.__freezer.attach or None)
if act == "pid": if act == "pid":
try_run_hook(self, ["--post-start"]) try_run_hook(self, ["--post-start"])
@ -480,8 +501,10 @@ class zdtm_test:
if self.__pid == 0: if self.__pid == 0:
self.getpid() self.getpid()
notify_fdout_path = "/proc/%s/fd/%s" % (self.__pid, env['ZDTM_NOTIFY_FDOUT']) notify_fdout_path = "/proc/%s/fd/%s" % (self.__pid,
notify_fdin_path = "/proc/%s/fd/%s" % (self.__pid, env['ZDTM_NOTIFY_FDIN']) env['ZDTM_NOTIFY_FDOUT'])
notify_fdin_path = "/proc/%s/fd/%s" % (self.__pid,
env['ZDTM_NOTIFY_FDIN'])
print("Send pre-dump notify to %s" % (self.__pid)) print("Send pre-dump notify to %s" % (self.__pid))
with open(notify_fdout_path, "rb") as fdout: with open(notify_fdout_path, "rb") as fdout:
@ -516,18 +539,25 @@ class zdtm_test:
return self.__name return self.__name
def __getcropts(self): def __getcropts(self):
opts = self.__desc.get('opts', '').split() + ["--pidfile", os.path.realpath(self.__pidfile())] opts = self.__desc.get('opts', '').split() + [
"--pidfile", os.path.realpath(self.__pidfile())
]
if self.__flavor.ns: if self.__flavor.ns:
opts += ["--root", self.__flavor.root] opts += ["--root", self.__flavor.root]
if test_flag(self.__desc, 'crlib'): if test_flag(self.__desc, 'crlib'):
opts += ["-L", os.path.dirname(os.path.realpath(self.__name)) + '/lib'] opts += [
"-L",
os.path.dirname(os.path.realpath(self.__name)) + '/lib'
]
return opts return opts
def getdopts(self): def getdopts(self):
return self.__getcropts() + self.__freezer.getdopts() + self.__desc.get('dopts', '').split() return self.__getcropts() + self.__freezer.getdopts(
) + self.__desc.get('dopts', '').split()
def getropts(self): def getropts(self):
return self.__getcropts() + self.__freezer.getropts() + self.__desc.get('ropts', '').split() return self.__getcropts() + self.__freezer.getropts(
) + self.__desc.get('ropts', '').split()
def unlink_pidfile(self): def unlink_pidfile(self):
self.__pid = 0 self.__pid = 0
@ -568,11 +598,13 @@ class zdtm_test:
subprocess.check_call(["make", "zdtm_ct"]) subprocess.check_call(["make", "zdtm_ct"])
if not os.access("zdtm/lib/libzdtmtst.a", os.F_OK): if not os.access("zdtm/lib/libzdtmtst.a", os.F_OK):
subprocess.check_call(["make", "-C", "zdtm/"]) subprocess.check_call(["make", "-C", "zdtm/"])
subprocess.check_call(["flock", "zdtm_mount_cgroups.lock", "./zdtm_mount_cgroups"]) subprocess.check_call(
["flock", "zdtm_mount_cgroups.lock", "./zdtm_mount_cgroups"])
@staticmethod @staticmethod
def cleanup(): def cleanup():
subprocess.check_call(["flock", "zdtm_mount_cgroups.lock", "./zdtm_umount_cgroups"]) subprocess.check_call(
["flock", "zdtm_mount_cgroups.lock", "./zdtm_umount_cgroups"])
def load_module_from_file(name, path): def load_module_from_file(name, path):
@ -601,7 +633,9 @@ class inhfd_test:
def __get_message(self, i): def __get_message(self, i):
m = self.__messages.get(i, None) m = self.__messages.get(i, None)
if not m: if not m:
m = b"".join([random.choice(string.ascii_letters).encode() for _ in range(10)]) + b"%06d" % i m = b"".join([
random.choice(string.ascii_letters).encode() for _ in range(10)
]) + b"%06d" % i
self.__messages[i] = m self.__messages[i] = m
return m return m
@ -631,7 +665,8 @@ class inhfd_test:
os.unlink(self.__name + ".out") os.unlink(self.__name + ".out")
except Exception as e: except Exception as e:
print(e) print(e)
fd = os.open(self.__name + ".out", os.O_WRONLY | os.O_APPEND | os.O_CREAT) fd = os.open(self.__name + ".out",
os.O_WRONLY | os.O_APPEND | os.O_CREAT)
os.dup2(fd, 1) os.dup2(fd, 1)
os.dup2(fd, 2) os.dup2(fd, 2)
os.close(fd) os.close(fd)
@ -669,7 +704,8 @@ class inhfd_test:
def stop(self): def stop(self):
fds = set(os.listdir("/proc/%s/fd" % self.__peer_pid)) fds = set(os.listdir("/proc/%s/fd" % self.__peer_pid))
if fds != self.__fds: if fds != self.__fds:
raise test_fail_exc("File descriptors mismatch: %s %s" % (fds, self.__fds)) raise test_fail_exc("File descriptors mismatch: %s %s" %
(fds, self.__fds))
i = 0 i = 0
for my_file, _ in self.__files: for my_file, _ in self.__files:
msg = self.__get_message(i) msg = self.__get_message(i)
@ -753,7 +789,8 @@ class groups_test(zdtm_test):
s_args = ['make', '--no-print-directory', '-C', tdir] s_args = ['make', '--no-print-directory', '-C', tdir]
subprocess.check_call(s_args + [tname + '.cleanout']) subprocess.check_call(s_args + [tname + '.cleanout'])
s = subprocess.Popen(s_args + ['--dry-run', tname + '.pid'], stdout = subprocess.PIPE) s = subprocess.Popen(s_args + ['--dry-run', tname + '.pid'],
stdout=subprocess.PIPE)
cmd = s.stdout.readlines().pop().strip() cmd = s.stdout.readlines().pop().strip()
s.wait() s.wait()
@ -792,15 +829,26 @@ join_ns_file = '/run/netns/zdtm_netns'
class criu_cli: class criu_cli:
@staticmethod @staticmethod
def run(action, args, criu_bin, fault = None, strace = [], preexec = None, nowait = False): def run(action,
env = dict(os.environ, ASAN_OPTIONS = "log_path=asan.log:disable_coredump=0:detect_leaks=0") args,
criu_bin,
fault=None,
strace=[],
preexec=None,
nowait=False):
env = dict(
os.environ,
ASAN_OPTIONS="log_path=asan.log:disable_coredump=0:detect_leaks=0")
if fault: if fault:
print("Forcing %s fault" % fault) print("Forcing %s fault" % fault)
env['CRIU_FAULT'] = fault env['CRIU_FAULT'] = fault
cr = subprocess.Popen(strace + [criu_bin, action, "--no-default-config"] + args, cr = subprocess.Popen(strace +
env = env, close_fds = False, preexec_fn = preexec) [criu_bin, action, "--no-default-config"] + args,
env=env,
close_fds=False,
preexec_fn=preexec)
if nowait: if nowait:
return cr return cr
return cr.wait() return cr.wait()
@ -884,7 +932,13 @@ class criu_rpc:
raise test_fail_exc('RPC for %s required' % arg) raise test_fail_exc('RPC for %s required' % arg)
@staticmethod @staticmethod
def run(action, args, criu_bin, fault = None, strace = [], preexec = None, nowait = False): def run(action,
args,
criu_bin,
fault=None,
strace=[],
preexec=None,
nowait=False):
if fault: if fault:
raise test_fail_exc('RPC and FAULT not supported') raise test_fail_exc('RPC and FAULT not supported')
if strace: if strace:
@ -905,7 +959,8 @@ class criu_rpc:
criu.pre_dump() criu.pre_dump()
elif action == 'restore': elif action == 'restore':
if 'rd' not in ctx: if 'rd' not in ctx:
raise test_fail_exc('RPC Non-detached restore is impossible') raise test_fail_exc(
'RPC Non-detached restore is impossible')
res = criu.restore() res = criu.restore()
pidf = ctx.get('pidf') pidf = ctx.get('pidf')
@ -1001,7 +1056,8 @@ class criu:
os.rename(self.__dump_path, newpath) os.rename(self.__dump_path, newpath)
break break
else: else:
raise test_fail_exc("couldn't find dump dir %s" % self.__dump_path) raise test_fail_exc("couldn't find dump dir %s" %
self.__dump_path)
os.makedirs(self.__dump_path) os.makedirs(self.__dump_path)
@ -1012,10 +1068,11 @@ class criu:
def __tls_options(self): def __tls_options(self):
pki_dir = os.path.dirname(os.path.abspath(__file__)) + "/pki" pki_dir = os.path.dirname(os.path.abspath(__file__)) + "/pki"
return ["--tls", "--tls-no-cn-verify", return [
"--tls-key", pki_dir + "/key.pem", "--tls", "--tls-no-cn-verify", "--tls-key", pki_dir + "/key.pem",
"--tls-cert", pki_dir + "/cert.pem", "--tls-cert", pki_dir + "/cert.pem", "--tls-cacert",
"--tls-cacert", pki_dir + "/cacert.pem"] pki_dir + "/cacert.pem"
]
def __ddir(self): def __ddir(self):
return os.path.join(self.__dump_path, "%d" % self.__iter) return os.path.join(self.__dump_path, "%d" % self.__iter)
@ -1043,7 +1100,10 @@ class criu:
strace = ["strace", "-o", fname, '-T'] strace = ["strace", "-o", fname, '-T']
if action == 'restore': if action == 'restore':
strace += ['-f'] strace += ['-f']
s_args += ['--action-script', os.getcwd() + '/../scripts/fake-restore.sh'] s_args += [
'--action-script',
os.getcwd() + '/../scripts/fake-restore.sh'
]
if self.__script: if self.__script:
s_args += ['--action-script', self.__script] s_args += ['--action-script', self.__script]
@ -1066,7 +1126,8 @@ class criu:
with open("/proc/sys/kernel/ns_last_pid") as ns_last_pid_fd: with open("/proc/sys/kernel/ns_last_pid") as ns_last_pid_fd:
ns_last_pid = ns_last_pid_fd.read() ns_last_pid = ns_last_pid_fd.read()
ret = self.__criu.run(action, s_args, self.__criu_bin, self.__fault, strace, preexec, nowait) ret = self.__criu.run(action, s_args, self.__criu_bin, self.__fault,
strace, preexec, nowait)
if nowait: if nowait:
os.close(status_fds[1]) os.close(status_fds[1])
@ -1075,7 +1136,8 @@ class criu:
if self.__test.blocking(): if self.__test.blocking():
raise test_fail_expected_exc(action) raise test_fail_expected_exc(action)
else: else:
raise test_fail_exc("criu %s exited with %s" % (action, ret)) raise test_fail_exc("criu %s exited with %s" %
(action, ret))
os.close(status_fds[0]) os.close(status_fds[0])
return ret return ret
@ -1090,19 +1152,23 @@ class criu:
os.chmod(__ddir, 0o777) os.chmod(__ddir, 0o777)
else: else:
# on restore we move only a log file, because we need images # on restore we move only a log file, because we need images
os.rename(os.path.join(__ddir, log), os.path.join(__ddir, log + ".fail")) os.rename(os.path.join(__ddir, log),
os.path.join(__ddir, log + ".fail"))
# restore ns_last_pid to avoid a case when criu gets # restore ns_last_pid to avoid a case when criu gets
# PID of one of restored processes. # PID of one of restored processes.
with open("/proc/sys/kernel/ns_last_pid", "w+") as fd: with open("/proc/sys/kernel/ns_last_pid", "w+") as fd:
fd.write(ns_last_pid) fd.write(ns_last_pid)
# try again without faults # try again without faults
print("Run criu " + action) print("Run criu " + action)
ret = self.__criu.run(action, s_args, self.__criu_bin, False, strace, preexec) ret = self.__criu.run(action, s_args, self.__criu_bin, False,
strace, preexec)
grep_errors(os.path.join(__ddir, log)) grep_errors(os.path.join(__ddir, log))
if ret == 0: if ret == 0:
return return
rst_succeeded = os.access(os.path.join(__ddir, "restore-succeeded"), os.F_OK) rst_succeeded = os.access(
if self.__test.blocking() or (self.__sat and action == 'restore' and rst_succeeded): os.path.join(__ddir, "restore-succeeded"), os.F_OK)
if self.__test.blocking() or (self.__sat and action == 'restore' and
rst_succeeded):
raise test_fail_expected_exc(action) raise test_fail_expected_exc(action)
else: else:
raise test_fail_exc("CRIU %s" % action) raise test_fail_exc("CRIU %s" % action)
@ -1114,7 +1180,8 @@ class criu:
if not self.__show_stats: if not self.__show_stats:
return return
subprocess.Popen([self.__crit_bin, "show", self.__stats_file(action)]).wait() subprocess.Popen([self.__crit_bin, "show",
self.__stats_file(action)]).wait()
def check_pages_counts(self): def check_pages_counts(self):
if not os.access(self.__stats_file("dump"), os.R_OK): if not os.access(self.__stats_file("dump"), os.R_OK):
@ -1124,7 +1191,8 @@ class criu:
with open(self.__stats_file("dump"), 'rb') as stfile: with open(self.__stats_file("dump"), 'rb') as stfile:
stats = crpc.images.load(stfile) stats = crpc.images.load(stfile)
stent = stats['entries'][0]['dump'] stent = stats['entries'][0]['dump']
stats_written = int(stent['shpages_written']) + int(stent['pages_written']) stats_written = int(stent['shpages_written']) + int(
stent['pages_written'])
real_written = 0 real_written = 0
for f in os.listdir(self.__ddir()): for f in os.listdir(self.__ddir()):
@ -1134,7 +1202,8 @@ class criu:
r_pages = real_written / mmap.PAGESIZE r_pages = real_written / mmap.PAGESIZE
r_off = real_written % mmap.PAGESIZE r_off = real_written % mmap.PAGESIZE
if (stats_written != r_pages) or (r_off != 0): if (stats_written != r_pages) or (r_off != 0):
print("ERROR: bad page counts, stats = %d real = %d(%d)" % (stats_written, r_pages, r_off)) print("ERROR: bad page counts, stats = %d real = %d(%d)" %
(stats_written, r_pages, r_off))
raise test_fail_exc("page counts mismatch") raise test_fail_exc("page counts mismatch")
def dump(self, action, opts=[]): def dump(self, action, opts=[]):
@ -1144,7 +1213,10 @@ class criu:
a_opts = ["-t", self.__test.getpid()] a_opts = ["-t", self.__test.getpid()]
if self.__prev_dump_iter: if self.__prev_dump_iter:
a_opts += ["--prev-images-dir", "../%d" % self.__prev_dump_iter, "--track-mem"] a_opts += [
"--prev-images-dir",
"../%d" % self.__prev_dump_iter, "--track-mem"
]
self.__prev_dump_iter = self.__iter self.__prev_dump_iter = self.__iter
if self.__page_server: if self.__page_server:
@ -1154,8 +1226,12 @@ class criu:
if self.__dedup: if self.__dedup:
ps_opts += ["--auto-dedup"] ps_opts += ["--auto-dedup"]
self.__page_server_p = self.__criu_act("page-server", opts = ps_opts, nowait = True) self.__page_server_p = self.__criu_act("page-server",
a_opts += ["--page-server", "--address", "127.0.0.1", "--port", "12345"] + self.__tls opts=ps_opts,
nowait=True)
a_opts += [
"--page-server", "--address", "127.0.0.1", "--port", "12345"
] + self.__tls
a_opts += self.__test.getdopts() a_opts += self.__test.getdopts()
@ -1178,7 +1254,9 @@ class criu:
if self.__lazy_migrate and action == "dump": if self.__lazy_migrate and action == "dump":
a_opts += ["--lazy-pages", "--port", "12345"] + self.__tls a_opts += ["--lazy-pages", "--port", "12345"] + self.__tls
nowait = True nowait = True
self.__dump_process = self.__criu_act(action, opts = a_opts + opts, nowait = nowait) self.__dump_process = self.__criu_act(action,
opts=a_opts + opts,
nowait=nowait)
if self.__mdedup and self.__iter > 1: if self.__mdedup and self.__iter > 1:
self.__criu_act("dedup", opts=[]) self.__criu_act("dedup", opts=[])
@ -1212,9 +1290,6 @@ class criu:
if self.__dedup: if self.__dedup:
r_opts += ["--auto-dedup"] r_opts += ["--auto-dedup"]
if self.__dedup:
r_opts += ["--auto-dedup"]
self.__prev_dump_iter = None self.__prev_dump_iter = None
criu_dir = os.path.dirname(os.getcwd()) criu_dir = os.path.dirname(os.getcwd())
if os.getenv("GCOV"): if os.getenv("GCOV"):
@ -1224,14 +1299,21 @@ class criu:
if self.__lazy_pages or self.__lazy_migrate: if self.__lazy_pages or self.__lazy_migrate:
lp_opts = [] lp_opts = []
if self.__remote_lazy_pages or self.__lazy_migrate: if self.__remote_lazy_pages or self.__lazy_migrate:
lp_opts += ["--page-server", "--port", "12345", lp_opts += [
"--address", "127.0.0.1"] + self.__tls "--page-server", "--port", "12345", "--address",
"127.0.0.1"
] + self.__tls
if self.__remote_lazy_pages: if self.__remote_lazy_pages:
ps_opts = ["--pidfile", "ps.pid", ps_opts = [
"--port", "12345", "--lazy-pages"] + self.__tls "--pidfile", "ps.pid", "--port", "12345", "--lazy-pages"
self.__page_server_p = self.__criu_act("page-server", opts = ps_opts, nowait = True) ] + self.__tls
self.__lazy_pages_p = self.__criu_act("lazy-pages", opts = lp_opts, nowait = True) self.__page_server_p = self.__criu_act("page-server",
opts=ps_opts,
nowait=True)
self.__lazy_pages_p = self.__criu_act("lazy-pages",
opts=lp_opts,
nowait=True)
r_opts += ["--lazy-pages"] r_opts += ["--lazy-pages"]
if self.__leave_stopped: if self.__leave_stopped:
@ -1246,8 +1328,9 @@ class criu:
@staticmethod @staticmethod
def check(feature): def check(feature):
return criu_cli.run("check", ["--no-default-config", "-v0", return criu_cli.run(
"--feature", feature], opts['criu_bin']) == 0 "check", ["--no-default-config", "-v0", "--feature", feature],
opts['criu_bin']) == 0
@staticmethod @staticmethod
def available(): def available():
@ -1258,12 +1341,14 @@ class criu:
def kill(self): def kill(self):
if self.__lazy_pages_p: if self.__lazy_pages_p:
self.__lazy_pages_p.terminate() self.__lazy_pages_p.terminate()
print("criu lazy-pages exited with %s" % self.__lazy_pages_p.wait()) print("criu lazy-pages exited with %s" %
self.__lazy_pages_p.wait())
grep_errors(os.path.join(self.__ddir(), "lazy-pages.log")) grep_errors(os.path.join(self.__ddir(), "lazy-pages.log"))
self.__lazy_pages_p = None self.__lazy_pages_p = None
if self.__page_server_p: if self.__page_server_p:
self.__page_server_p.terminate() self.__page_server_p.terminate()
print("criu page-server exited with %s" % self.__page_server_p.wait()) print("criu page-server exited with %s" %
self.__page_server_p.wait())
grep_errors(os.path.join(self.__ddir(), "page-server.log")) grep_errors(os.path.join(self.__ddir(), "page-server.log"))
self.__page_server_p = None self.__page_server_p = None
if self.__dump_process: if self.__dump_process:
@ -1354,6 +1439,7 @@ def cr(cr_api, test, opts):
# Additional checks that can be done outside of test process # Additional checks that can be done outside of test process
def get_visible_state(test): def get_visible_state(test):
maps = {} maps = {}
files = {} files = {}
@ -1364,9 +1450,11 @@ def get_visible_state(test):
return ({}, {}, {}) return ({}, {}, {})
r = re.compile('^[0-9]+$') r = re.compile('^[0-9]+$')
pids = filter(lambda p: r.match(p), os.listdir("/proc/%s/root/proc/" % test.getpid())) pids = filter(lambda p: r.match(p),
os.listdir("/proc/%s/root/proc/" % test.getpid()))
for pid in pids: for pid in pids:
files[pid] = set(os.listdir("/proc/%s/root/proc/%s/fd" % (test.getpid(), pid))) files[pid] = set(
os.listdir("/proc/%s/root/proc/%s/fd" % (test.getpid(), pid)))
cmaps = [[0, 0, ""]] cmaps = [[0, 0, ""]]
last = 0 last = 0
@ -1376,7 +1464,8 @@ def get_visible_state(test):
m.append(mp.split()[1]) m.append(mp.split()[1])
f = "/proc/%s/root/proc/%s/map_files/%s" % (test.getpid(), pid, mp.split()[0]) f = "/proc/%s/root/proc/%s/map_files/%s" % (test.getpid(), pid,
mp.split()[0])
if os.access(f, os.F_OK): if os.access(f, os.F_OK):
st = os.lstat(f) st = os.lstat(f)
m.append(oct(st.st_mode)) m.append(oct(st.st_mode))
@ -1388,12 +1477,16 @@ def get_visible_state(test):
last += 1 last += 1
mapsfd.close() mapsfd.close()
maps[pid] = set(map(lambda x: '%x-%x %s' % (x[0], x[1], " ".join(x[2:])), cmaps)) maps[pid] = set(
map(lambda x: '%x-%x %s' % (x[0], x[1], " ".join(x[2:])), cmaps))
cmounts = [] cmounts = []
try: try:
r = re.compile(r"^\S+\s\S+\s\S+\s(\S+)\s(\S+)\s(\S+)\s[^-]*?(shared)?[^-]*?(master)?[^-]*?-") r = re.compile(
with open("/proc/%s/root/proc/%s/mountinfo" % (test.getpid(), pid)) as mountinfo: r"^\S+\s\S+\s\S+\s(\S+)\s(\S+)\s(\S+)\s[^-]*?(shared)?[^-]*?(master)?[^-]*?-"
)
with open("/proc/%s/root/proc/%s/mountinfo" %
(test.getpid(), pid)) as mountinfo:
for m in mountinfo: for m in mountinfo:
cmounts.append(r.match(m).groups()) cmounts.append(r.match(m).groups())
except IOError as e: except IOError as e:
@ -1442,9 +1535,11 @@ def check_visible_state(test, state, opts):
if '--link-remap' in test.getdopts(): if '--link-remap' in test.getdopts():
import glob import glob
link_remap_list = glob.glob(os.path.dirname(test.getname()) + '/link_remap*') link_remap_list = glob.glob(
os.path.dirname(test.getname()) + '/link_remap*')
if link_remap_list: if link_remap_list:
print("%s: link-remap files left: %s" % (test.getname(), link_remap_list)) print("%s: link-remap files left: %s" %
(test.getname(), link_remap_list))
raise test_fail_exc("link remaps left") raise test_fail_exc("link remaps left")
@ -1631,7 +1726,8 @@ def do_run_test(tname, tdesc, flavs, opts):
cr_api.kill() cr_api.kill()
try_run_hook(t, ["--clean"]) try_run_hook(t, ["--clean"])
if cr_api.logs(): if cr_api.logs():
add_to_report(cr_api.logs(), tname.replace('/', '_') + "_" + f + "/images") add_to_report(cr_api.logs(),
tname.replace('/', '_') + "_" + f + "/images")
if opts['keep_img'] == 'never': if opts['keep_img'] == 'never':
cr_api.cleanup() cr_api.cleanup()
# When option --keep-going not specified this exit # When option --keep-going not specified this exit
@ -1672,9 +1768,12 @@ class Launcher:
att = 0 att = 0
reportname = os.path.join(report_dir, "criu-testreport.tap") reportname = os.path.join(report_dir, "criu-testreport.tap")
junitreport = os.path.join(report_dir, "criu-testreport.xml") junitreport = os.path.join(report_dir, "criu-testreport.xml")
while os.access(reportname, os.F_OK) or os.access(junitreport, os.F_OK): while os.access(reportname, os.F_OK) or os.access(
reportname = os.path.join(report_dir, "criu-testreport" + ".%d.tap" % att) junitreport, os.F_OK):
junitreport = os.path.join(report_dir, "criu-testreport" + ".%d.xml" % att) reportname = os.path.join(report_dir,
"criu-testreport" + ".%d.tap" % att)
junitreport = os.path.join(report_dir,
"criu-testreport" + ".%d.xml" % att)
att += 1 att += 1
self.__junit_file = open(junitreport, 'a') self.__junit_file = open(junitreport, 'a')
@ -1683,7 +1782,9 @@ class Launcher:
self.__file_report = open(reportname, 'a') self.__file_report = open(reportname, 'a')
print(u"TAP version 13", file=self.__file_report) print(u"TAP version 13", file=self.__file_report)
print(u"# Hardware architecture: " + arch, file=self.__file_report) print(u"# Hardware architecture: " + arch, file=self.__file_report)
print(u"# Timestamp: " + now.strftime("%Y-%m-%d %H:%M") + " (GMT+1)", file=self.__file_report) print(u"# Timestamp: " + now.strftime("%Y-%m-%d %H:%M") +
" (GMT+1)",
file=self.__file_report)
print(u"# ", file=self.__file_report) print(u"# ", file=self.__file_report)
print(u"1.." + str(nr_tests), file=self.__file_report) print(u"1.." + str(nr_tests), file=self.__file_report)
with open("/proc/sys/kernel/tainted") as taintfd: with open("/proc/sys/kernel/tainted") as taintfd:
@ -1695,7 +1796,8 @@ class Launcher:
def __show_progress(self, msg): def __show_progress(self, msg):
perc = int(self.__nr * 16 / self.__total) perc = int(self.__nr * 16 / self.__total)
print("=== Run %d/%d %s %s" % (self.__nr, self.__total, '=' * perc + '-' * (16 - perc), msg)) print("=== Run %d/%d %s %s" %
(self.__nr, self.__total, '=' * perc + '-' * (16 - perc), msg))
def skip(self, name, reason): def skip(self, name, reason):
print("Skipping %s (%s)" % (name, reason)) print("Skipping %s (%s)" % (name, reason))
@ -1719,7 +1821,8 @@ class Launcher:
with open("/proc/sys/kernel/tainted") as taintfd: with open("/proc/sys/kernel/tainted") as taintfd:
taint = taintfd.read() taint = taintfd.read()
if self.__taint != taint: if self.__taint != taint:
raise Exception("The kernel is tainted: %r (%r)" % (taint, self.__taint)) raise Exception("The kernel is tainted: %r (%r)" %
(taint, self.__taint))
if test_flag(desc, 'excl'): if test_flag(desc, 'excl'):
self.wait_all() self.wait_all()
@ -1727,11 +1830,12 @@ class Launcher:
self.__nr += 1 self.__nr += 1
self.__show_progress(name) self.__show_progress(name)
nd = ('nocr', 'norst', 'pre', 'iters', 'page_server', 'sibling', 'stop', 'empty_ns', nd = ('nocr', 'norst', 'pre', 'iters', 'page_server', 'sibling',
'fault', 'keep_img', 'report', 'snaps', 'sat', 'script', 'rpc', 'lazy_pages', 'stop', 'empty_ns', 'fault', 'keep_img', 'report', 'snaps',
'join_ns', 'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup', 'sat', 'script', 'rpc', 'lazy_pages', 'join_ns', 'dedup', 'sbs',
'remote_lazy_pages', 'show_stats', 'lazy_migrate', 'tls', 'freezecg', 'user', 'dry_run', 'noauto_dedup',
'criu_bin', 'crit_bin') 'remote_lazy_pages', 'show_stats', 'lazy_migrate',
'tls', 'criu_bin', 'crit_bin')
arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd})) arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd}))
if self.__use_log: if self.__use_log:
@ -1743,8 +1847,15 @@ class Launcher:
sub = subprocess.Popen(["./zdtm_ct", "zdtm.py"], sub = subprocess.Popen(["./zdtm_ct", "zdtm.py"],
env=dict(os.environ, CR_CT_TEST_INFO=arg), env=dict(os.environ, CR_CT_TEST_INFO=arg),
stdout = log, stderr = subprocess.STDOUT, close_fds = True) stdout=log,
self.__subs[sub.pid] = {'sub': sub, 'log': logf, 'name': name, "start": time.time()} stderr=subprocess.STDOUT,
close_fds=True)
self.__subs[sub.pid] = {
'sub': sub,
'log': logf,
'name': name,
"start": time.time()
}
if test_flag(desc, 'excl'): if test_flag(desc, 'excl'):
self.wait() self.wait()
@ -1771,21 +1882,26 @@ class Launcher:
sub = self.__subs.pop(pid) sub = self.__subs.pop(pid)
tc = None tc = None
if self.__junit_test_cases is not None: if self.__junit_test_cases is not None:
tc = TestCase(sub['name'], elapsed_sec=time.time() - sub['start']) tc = TestCase(sub['name'],
elapsed_sec=time.time() - sub['start'])
self.__junit_test_cases.append(tc) self.__junit_test_cases.append(tc)
if status != 0: if status != 0:
self.__fail = True self.__fail = True
failed_flavor = decode_flav(os.WEXITSTATUS(status)) failed_flavor = decode_flav(os.WEXITSTATUS(status))
self.__failed.append([sub['name'], failed_flavor]) self.__failed.append([sub['name'], failed_flavor])
if self.__file_report: if self.__file_report:
testline = u"not ok %d - %s # flavor %s" % (self.__runtest, sub['name'], failed_flavor) testline = u"not ok %d - %s # flavor %s" % (
self.__runtest, sub['name'], failed_flavor)
with open(sub['log']) as sublog: with open(sub['log']) as sublog:
output = sublog.read() output = sublog.read()
details = {'output': output} details = {'output': output}
tc.add_error_info(output=output) tc.add_error_info(output=output)
print(testline, file=self.__file_report) print(testline, file=self.__file_report)
print("%s" % yaml.safe_dump(details, explicit_start=True, print("%s" % yaml.safe_dump(details,
explicit_end=True, default_style='|'), file=self.__file_report) explicit_start=True,
explicit_end=True,
default_style='|'),
file=self.__file_report)
if sub['log']: if sub['log']:
add_to_output(sub['log']) add_to_output(sub['log'])
else: else:
@ -1795,7 +1911,8 @@ class Launcher:
if sub['log']: if sub['log']:
with open(sub['log']) as sublog: with open(sub['log']) as sublog:
print("%s" % sublog.read().encode('ascii', 'ignore').decode('utf-8')) print("%s" % sublog.read().encode(
'ascii', 'ignore').decode('utf-8'))
os.unlink(sub['log']) os.unlink(sub['log'])
return True return True
@ -1824,20 +1941,23 @@ class Launcher:
if not opts['fault'] and check_core_files(): if not opts['fault'] and check_core_files():
self.__fail = True self.__fail = True
if self.__file_report: if self.__file_report:
ts = TestSuite(opts['title'], self.__junit_test_cases, os.getenv("NODE_NAME")) ts = TestSuite(opts['title'], self.__junit_test_cases,
os.getenv("NODE_NAME"))
self.__junit_file.write(TestSuite.to_xml_string([ts])) self.__junit_file.write(TestSuite.to_xml_string([ts]))
self.__junit_file.close() self.__junit_file.close()
self.__file_report.close() self.__file_report.close()
if opts['keep_going']: if opts['keep_going']:
if self.__fail: if self.__fail:
print_sep("%d TEST(S) FAILED (TOTAL %d/SKIPPED %d)" print_sep(
% (len(self.__failed), self.__total, self.__nr_skip), "#") "%d TEST(S) FAILED (TOTAL %d/SKIPPED %d)" %
(len(self.__failed), self.__total, self.__nr_skip), "#")
for failed in self.__failed: for failed in self.__failed:
print(" * %s(%s)" % (failed[0], failed[1])) print(" * %s(%s)" % (failed[0], failed[1]))
else: else:
print_sep("ALL TEST(S) PASSED (TOTAL %d/SKIPPED %d)" print_sep(
% (self.__total, self.__nr_skip), "#") "ALL TEST(S) PASSED (TOTAL %d/SKIPPED %d)" %
(self.__total, self.__nr_skip), "#")
if self.__fail: if self.__fail:
print_sep("FAIL", "#") print_sep("FAIL", "#")
@ -1860,12 +1980,9 @@ def all_tests(opts):
continue continue
files.append(fp) files.append(fp)
excl = list(map(lambda x: os.path.join(desc['dir'], x), desc['exclude'])) excl = list(map(lambda x: os.path.join(desc['dir'], x), desc['exclude']))
tlist = filter(lambda x: tlist = filter(
not x.endswith('.checkskip') and lambda x: not x.endswith('.checkskip') and not x.endswith('.hook') and
not x.endswith('.hook') and x not in excl, map(lambda x: x.strip(), files))
x not in excl,
map(lambda x: x.strip(), files)
)
return tlist return tlist
@ -1966,7 +2083,9 @@ def run_tests(opts):
torun = list(torun) torun = list(torun)
if opts['keep_going'] and len(torun) < 2: if opts['keep_going'] and len(torun) < 2:
print("[WARNING] Option --keep-going is more useful when running multiple tests") print(
"[WARNING] Option --keep-going is more useful when running multiple tests"
)
opts['keep_going'] = False opts['keep_going'] = False
if opts['exclude']: if opts['exclude']:
@ -1983,17 +2102,23 @@ def run_tests(opts):
if opts['join_ns']: if opts['join_ns']:
if subprocess.Popen(["ip", "netns", "add", "zdtm_netns"]).wait(): if subprocess.Popen(["ip", "netns", "add", "zdtm_netns"]).wait():
raise Exception("Unable to create a network namespace") raise Exception("Unable to create a network namespace")
if subprocess.Popen(["ip", "netns", "exec", "zdtm_netns", "ip", "link", "set", "up", "dev", "lo"]).wait(): if subprocess.Popen([
"ip", "netns", "exec", "zdtm_netns", "ip", "link", "set", "up",
"dev", "lo"
]).wait():
raise Exception("ip link set up dev lo") raise Exception("ip link set up dev lo")
if opts['lazy_pages'] or opts['remote_lazy_pages'] or opts['lazy_migrate']: if opts['lazy_pages'] or opts['remote_lazy_pages'] or opts['lazy_migrate']:
uffd = criu.check("uffd") uffd = criu.check("uffd")
uffd_noncoop = criu.check("uffd-noncoop") uffd_noncoop = criu.check("uffd-noncoop")
if not uffd: if not uffd:
raise Exception("UFFD is not supported, cannot run with --lazy-pages") raise Exception(
"UFFD is not supported, cannot run with --lazy-pages")
if not uffd_noncoop: if not uffd_noncoop:
# Most tests will work with 4.3 - 4.11 # Most tests will work with 4.3 - 4.11
print("[WARNING] Non-cooperative UFFD is missing, some tests might spuriously fail") print(
"[WARNING] Non-cooperative UFFD is missing, some tests might spuriously fail"
)
launcher = Launcher(opts, len(torun)) launcher = Launcher(opts, len(torun))
try: try:
@ -2047,7 +2172,8 @@ def run_tests(opts):
launcher.skip(t, "samens test in the same namespace") launcher.skip(t, "samens test in the same namespace")
continue continue
if opts['lazy_pages'] or opts['remote_lazy_pages'] or opts['lazy_migrate']: if opts['lazy_pages'] or opts['remote_lazy_pages'] or opts[
'lazy_migrate']:
if test_flag(tdesc, 'nolazy'): if test_flag(tdesc, 'nolazy'):
launcher.skip(t, "lazy pages are not supported") launcher.skip(t, "lazy pages are not supported")
continue continue
@ -2137,8 +2263,7 @@ class group:
# which will call all tests' scripts in turn # which will call all tests' scripts in turn
def __dump_meta(self, fname, ext): def __dump_meta(self, fname, ext):
scripts = filter(lambda names: os.access(names[1], os.X_OK), scripts = filter(lambda names: os.access(names[1], os.X_OK),
map(lambda test: (test, test + ext), map(lambda test: (test, test + ext), self.__tests))
self.__tests))
if scripts: if scripts:
f = open(fname + ext, "w") f = open(fname + ext, "w")
f.write("#!/bin/sh -e\n") f.write("#!/bin/sh -e\n")
@ -2250,7 +2375,9 @@ if 'CR_CT_TEST_INFO' in os.environ:
sys.exit(status) sys.exit(status)
p = argparse.ArgumentParser("CRIU test suite") p = argparse.ArgumentParser("CRIU test suite")
p.add_argument("--debug", help = "Print what's being executed", action = 'store_true') p.add_argument("--debug",
help="Print what's being executed",
action='store_true')
p.add_argument("--set", help="Which set of tests to use", default='zdtm') p.add_argument("--set", help="Which set of tests to use", default='zdtm')
sp = p.add_subparsers(help="Use --help for list of actions") sp = p.add_subparsers(help="Use --help for list of actions")
@ -2262,53 +2389,115 @@ rp.add_argument("-t", "--test", help = "Test name", action = 'append')
rp.add_argument("-T", "--tests", help="Regexp") rp.add_argument("-T", "--tests", help="Regexp")
rp.add_argument("-F", "--from", help="From file") rp.add_argument("-F", "--from", help="From file")
rp.add_argument("-f", "--flavor", help="Flavor to run") rp.add_argument("-f", "--flavor", help="Flavor to run")
rp.add_argument("-x", "--exclude", help = "Exclude tests from --all run", action = 'append') rp.add_argument("-x",
"--exclude",
help="Exclude tests from --all run",
action='append')
rp.add_argument("--sibling", help = "Restore tests as siblings", action = 'store_true') rp.add_argument("--sibling",
rp.add_argument("--join-ns", help = "Restore tests and join existing namespace", action = 'store_true') help="Restore tests as siblings",
rp.add_argument("--empty-ns", help = "Restore tests in empty net namespace", action = 'store_true') action='store_true')
rp.add_argument("--join-ns",
help="Restore tests and join existing namespace",
action='store_true')
rp.add_argument("--empty-ns",
help="Restore tests in empty net namespace",
action='store_true')
rp.add_argument("--pre", help="Do some pre-dumps before dump (n[:pause])") rp.add_argument("--pre", help="Do some pre-dumps before dump (n[:pause])")
rp.add_argument("--snaps", help = "Instead of pre-dumps do full dumps", action = 'store_true') rp.add_argument("--snaps",
rp.add_argument("--dedup", help = "Auto-deduplicate images on iterations", action = 'store_true') help="Instead of pre-dumps do full dumps",
rp.add_argument("--noauto-dedup", help = "Manual deduplicate images on iterations", action = 'store_true') action='store_true')
rp.add_argument("--nocr", help = "Do not CR anything, just check test works", action = 'store_true') rp.add_argument("--dedup",
rp.add_argument("--norst", help = "Don't restore tasks, leave them running after dump", action = 'store_true') help="Auto-deduplicate images on iterations",
rp.add_argument("--stop", help = "Check that --leave-stopped option stops ps tree.", action = 'store_true') action='store_true')
rp.add_argument("--iters", help = "Do CR cycle several times before check (n[:pause])") rp.add_argument("--noauto-dedup",
help="Manual deduplicate images on iterations",
action='store_true')
rp.add_argument("--nocr",
help="Do not CR anything, just check test works",
action='store_true')
rp.add_argument("--norst",
help="Don't restore tasks, leave them running after dump",
action='store_true')
rp.add_argument("--stop",
help="Check that --leave-stopped option stops ps tree.",
action='store_true')
rp.add_argument("--iters",
help="Do CR cycle several times before check (n[:pause])")
rp.add_argument("--fault", help="Test fault injection") rp.add_argument("--fault", help="Test fault injection")
rp.add_argument("--sat", help = "Generate criu strace-s for sat tool (restore is fake, images are kept)", action = 'store_true') rp.add_argument(
rp.add_argument("--sbs", help = "Do step-by-step execution, asking user for keypress to continue", action = 'store_true') "--sat",
help="Generate criu strace-s for sat tool (restore is fake, images are kept)",
action='store_true')
rp.add_argument(
"--sbs",
help="Do step-by-step execution, asking user for keypress to continue",
action='store_true')
rp.add_argument("--freezecg", help="Use freeze cgroup (path:state)") rp.add_argument("--freezecg", help="Use freeze cgroup (path:state)")
rp.add_argument("--user", help="Run CRIU as regular user", action='store_true') rp.add_argument("--user", help="Run CRIU as regular user", action='store_true')
rp.add_argument("--rpc", help = "Run CRIU via RPC rather than CLI", action = 'store_true') rp.add_argument("--rpc",
help="Run CRIU via RPC rather than CLI",
action='store_true')
rp.add_argument("--page-server", help = "Use page server dump", action = 'store_true') rp.add_argument("--page-server",
help="Use page server dump",
action='store_true')
rp.add_argument("--remote",
help="Use remote option for diskless C/R",
action='store_true')
rp.add_argument("-p", "--parallel", help="Run test in parallel") rp.add_argument("-p", "--parallel", help="Run test in parallel")
rp.add_argument("--dry-run", help="Don't run tests, just pretend to", action='store_true') rp.add_argument("--dry-run",
help="Don't run tests, just pretend to",
action='store_true')
rp.add_argument("--script", help="Add script to get notified by criu") rp.add_argument("--script", help="Add script to get notified by criu")
rp.add_argument("-k", "--keep-img", help = "Whether or not to keep images after test", rp.add_argument("-k",
choices = ['always', 'never', 'failed'], default = 'failed') "--keep-img",
help="Whether or not to keep images after test",
choices=['always', 'never', 'failed'],
default='failed')
rp.add_argument("--report", help="Generate summary report in directory") rp.add_argument("--report", help="Generate summary report in directory")
rp.add_argument("--keep-going", help = "Keep running tests in spite of failures", action = 'store_true') rp.add_argument("--keep-going",
rp.add_argument("--ignore-taint", help = "Don't care about a non-zero kernel taint flag", action = 'store_true') help="Keep running tests in spite of failures",
rp.add_argument("--lazy-pages", help = "restore pages on demand", action = 'store_true') action='store_true')
rp.add_argument("--lazy-migrate", help = "restore pages on demand", action = 'store_true') rp.add_argument("--ignore-taint",
rp.add_argument("--remote-lazy-pages", help = "simulate lazy migration", action = 'store_true') help="Don't care about a non-zero kernel taint flag",
action='store_true')
rp.add_argument("--lazy-pages",
help="restore pages on demand",
action='store_true')
rp.add_argument("--lazy-migrate",
help="restore pages on demand",
action='store_true')
rp.add_argument("--remote-lazy-pages",
help="simulate lazy migration",
action='store_true')
rp.add_argument("--tls", help="use TLS for migration", action='store_true') rp.add_argument("--tls", help="use TLS for migration", action='store_true')
rp.add_argument("--title", help="A test suite title", default="criu") rp.add_argument("--title", help="A test suite title", default="criu")
rp.add_argument("--show-stats", help = "Show criu statistics", action = 'store_true') rp.add_argument("--show-stats",
rp.add_argument("--criu-bin", help = "Path to criu binary", default = '../criu/criu') help="Show criu statistics",
rp.add_argument("--crit-bin", help = "Path to crit binary", default = '../crit/crit') action='store_true')
rp.add_argument("--criu-bin",
help="Path to criu binary",
default='../criu/criu')
rp.add_argument("--crit-bin",
help="Path to crit binary",
default='../crit/crit')
lp = sp.add_parser("list", help="List tests") lp = sp.add_parser("list", help="List tests")
lp.set_defaults(action=list_tests) lp.set_defaults(action=list_tests)
lp.add_argument('-i', '--info', help = "Show more info about tests", action = 'store_true') lp.add_argument('-i',
'--info',
help="Show more info about tests",
action='store_true')
gp = sp.add_parser("group", help="Generate groups") gp = sp.add_parser("group", help="Generate groups")
gp.set_defaults(action=group_tests) gp.set_defaults(action=group_tests)
gp.add_argument("-m", "--max-size", help="Maximum number of tests in group") gp.add_argument("-m", "--max-size", help="Maximum number of tests in group")
gp.add_argument("-n", "--name", help="Common name for group tests") gp.add_argument("-n", "--name", help="Common name for group tests")
gp.add_argument("-x", "--exclude", help = "Exclude tests from --all run", action = 'append') gp.add_argument("-x",
"--exclude",
help="Exclude tests from --all run",
action='append')
cp = sp.add_parser("clean", help="Clean something") cp = sp.add_parser("clean", help="Clean something")
cp.set_defaults(action=clean_stuff) cp.set_defaults(action=clean_stuff)