static int collect_children(struct pstree_item *item) { pid_t *ch; int ret, i, nr_children, nr_inprogress; ret = parse_children(item->pid.real, &ch, &nr_children); if (ret < 0) return ret; nr_inprogress = 0; for (i = 0; i < nr_children; i++) { struct pstree_item *c; pid_t pid = ch[i]; /* Is it already frozen? */ if (child_collected(item, pid)) continue; nr_inprogress++; pr_info("Seized task %d, state %d\n", pid, ret); c = alloc_pstree_item(); if (c == NULL) { ret = -1; goto free; } if (!opts.freeze_cgroup) /* fails when meets a zombie */ seize_catch_task(pid); ret = seize_wait_task(pid, item->pid.real, &dmpi(c)->pi_creds); if (ret < 0) { /* * Here is a race window between parse_children() and seize(), * so the task could die for these time. * Don't worry, will try again on the next attempt. The number * of attempts is restricted, so it will exit if something * really wrong. */ ret = 0; xfree(c); continue; } c->pid.real = pid; c->parent = item; c->state = ret; list_add_tail(&c->sibling, &item->children); /* Here is a recursive call (Depth-first search) */ ret = collect_task(c); if (ret < 0) goto free; } free: xfree(ch); return ret < 0 ? ret : nr_inprogress; }
int collect_pstree(pid_t pid) { int ret; timing_start(TIME_FREEZING); if (opts.freeze_cgroup && freeze_processes()) return -1; root_item = alloc_pstree_item(); if (root_item == NULL) return -1; root_item->pid.real = pid; if (!opts.freeze_cgroup && seize_catch_task(pid)) { set_cr_errno(ESRCH); goto err; } ret = seize_wait_task(pid, -1, &dmpi(root_item)->pi_creds); if (ret < 0) goto err; pr_info("Seized task %d, state %d\n", pid, ret); root_item->state = ret; ret = collect_task(root_item); if (ret < 0) goto err; timing_stop(TIME_FREEZING); timing_start(TIME_FROZEN); return 0; err: pstree_switch_state(root_item, TASK_ALIVE); return -1; }
int cr_check(void) { struct ns_id ns = { .type = NS_CRIU, .ns_pid = PROC_SELF, .nd = &mnt_ns_desc }; int ret = 0; if (!is_root_user()) return -1; root_item = alloc_pstree_item(); if (root_item == NULL) return -1; root_item->pid.real = getpid(); if (collect_pstree_ids()) return -1; ns.id = root_item->ids->mnt_ns_id; mntinfo = collect_mntinfo(&ns, false); if (mntinfo == NULL) return -1; if (chk_feature) { ret = chk_feature(); goto out; } ret |= check_map_files(); ret |= check_sock_diag(); ret |= check_ns_last_pid(); ret |= check_sock_peek_off(); ret |= check_kcmp(); ret |= check_prctl(); ret |= check_fcntl(); ret |= check_proc_stat(); ret |= check_tcp(); ret |= check_fdinfo_ext(); ret |= check_unaligned_vmsplice(); ret |= check_tty(); ret |= check_so_gets(); ret |= check_ipc(); ret |= check_sigqueuinfo(); ret |= check_ptrace_peeksiginfo(); ret |= check_ptrace_suspend_seccomp(); ret |= check_ptrace_dump_seccomp_filters(); ret |= check_mem_dirty_track(); ret |= check_posix_timers(); ret |= check_tun_cr(0); ret |= check_timerfd(); ret |= check_mnt_id(); ret |= check_aio_remap(); ret |= check_fdinfo_lock(); ret |= check_clone_parent_vs_pid(); out: if (!ret) print_on_level(DEFAULT_LOGLEVEL, "Looks good.\n"); return ret; }