LCOV - code coverage report
Current view: top level - home/snorch/criu - pstree.c (source / functions) Hit Total Coverage
Test: coverage3.info Lines: 281 322 87.3 %
Date: 2014-04-22 Functions: 16 16 100.0 %
Branches: 201 288 69.8 %

           Branch data     Line data    Source code
       1                 :            : #include <sys/mman.h>
       2                 :            : #include <unistd.h>
       3                 :            : #include <stdlib.h>
       4                 :            : 
       5                 :            : #include "cr_options.h"
       6                 :            : #include "pstree.h"
       7                 :            : #include "util.h"
       8                 :            : #include "lock.h"
       9                 :            : #include "namespaces.h"
      10                 :            : #include "files.h"
      11                 :            : #include "tty.h"
      12                 :            : #include "mount.h"
      13                 :            : #include "asm/dump.h"
      14                 :            : 
      15                 :            : #include "protobuf.h"
      16                 :            : #include "protobuf/pstree.pb-c.h"
      17                 :            : 
      18                 :            : struct pstree_item *root_item;
      19                 :            : 
      20                 :       1903 : void core_entry_free(CoreEntry *core)
      21                 :            : {
      22 [ +  + ][ -  + ]:       1903 :         if (core->tc && core->tc->timers)
      23         [ #  # ]:          0 :                 xfree(core->tc->timers->posix);
      24                 :       1903 :         arch_free_thread_info(core);
      25         [ +  - ]:       1903 :         xfree(core);
      26                 :       1903 : }
      27                 :            : 
      28                 :            : #ifndef RLIM_NLIMITS
      29                 :            : # define RLIM_NLIMITS 16
      30                 :            : #endif
      31                 :            : 
      32                 :       5567 : CoreEntry *core_entry_alloc(int th, int tsk)
      33                 :            : {
      34                 :            :         size_t sz;
      35                 :            :         CoreEntry *core = NULL;
      36                 :            :         void *m;
      37                 :            : 
      38                 :            :         sz = sizeof(CoreEntry);
      39         [ +  + ]:       5567 :         if (tsk) {
      40                 :            :                 sz += sizeof(TaskCoreEntry) + TASK_COMM_LEN;
      41         [ +  + ]:       3685 :                 if (th) {
      42                 :            :                         sz += sizeof(TaskRlimitsEntry);
      43                 :            :                         sz += RLIM_NLIMITS * sizeof(RlimitEntry *);
      44                 :            :                         sz += RLIM_NLIMITS * sizeof(RlimitEntry);
      45                 :            :                         sz += sizeof(TaskTimersEntry);
      46                 :            :                         sz += 3 * sizeof(ItimerEntry); /* 3 for real, virt and prof */
      47                 :            :                 }
      48                 :            :         }
      49         [ +  + ]:       5567 :         if (th)
      50                 :       5546 :                 sz += sizeof(ThreadCoreEntry) + sizeof(ThreadSasEntry);
      51                 :            : 
      52         [ -  + ]:       5567 :         m = xmalloc(sz);
      53         [ +  - ]:       5567 :         if (m) {
      54                 :            :                 core = xptr_pull(&m, CoreEntry);
      55                 :       5567 :                 core_entry__init(core);
      56                 :       5567 :                 core->mtype = CORE_ENTRY__MARCH;
      57                 :            : 
      58         [ +  + ]:       5567 :                 if (tsk) {
      59                 :       3685 :                         core->tc = xptr_pull(&m, TaskCoreEntry);
      60                 :       3685 :                         task_core_entry__init(core->tc);
      61                 :       7370 :                         core->tc->comm = xptr_pull_s(&m, TASK_COMM_LEN);
      62                 :       3685 :                         memzero(core->tc->comm, TASK_COMM_LEN);
      63                 :            : 
      64         [ +  + ]:       3685 :                         if (th) {
      65                 :            :                                 TaskRlimitsEntry *rls;
      66                 :            :                                 TaskTimersEntry *tte;
      67                 :            :                                 int i;
      68                 :            : 
      69                 :       3664 :                                 rls = core->tc->rlimits = xptr_pull(&m, TaskRlimitsEntry);
      70                 :       3664 :                                 task_rlimits_entry__init(rls);
      71                 :            : 
      72                 :       3664 :                                 rls->n_rlimits = RLIM_NLIMITS;
      73                 :       3664 :                                 rls->rlimits = xptr_pull_s(&m, sizeof(RlimitEntry *) * RLIM_NLIMITS);
      74                 :            : 
      75         [ +  + ]:      62288 :                                 for (i = 0; i < RLIM_NLIMITS; i++) {
      76                 :     117248 :                                         rls->rlimits[i] = xptr_pull(&m, RlimitEntry);
      77                 :      58624 :                                         rlimit_entry__init(rls->rlimits[i]);
      78                 :            :                                 }
      79                 :            : 
      80                 :       3664 :                                 tte = core->tc->timers = xptr_pull(&m, TaskTimersEntry);
      81                 :       3664 :                                 task_timers_entry__init(tte);
      82                 :       3664 :                                 tte->real = xptr_pull(&m, ItimerEntry);
      83                 :       3664 :                                 itimer_entry__init(tte->real);
      84                 :       3664 :                                 tte->virt = xptr_pull(&m, ItimerEntry);
      85                 :       3664 :                                 itimer_entry__init(tte->virt);
      86                 :       3664 :                                 tte->prof = xptr_pull(&m, ItimerEntry);
      87                 :       3664 :                                 itimer_entry__init(tte->prof);
      88                 :            :                         }
      89                 :            :                 }
      90                 :            : 
      91         [ +  + ]:       5567 :                 if (th) {
      92                 :       5546 :                         core->thread_core = xptr_pull(&m, ThreadCoreEntry);
      93                 :       5546 :                         thread_core_entry__init(core->thread_core);
      94                 :       5546 :                         core->thread_core->sas = xptr_pull(&m, ThreadSasEntry);
      95                 :       5546 :                         thread_sas_entry__init(core->thread_core->sas);
      96                 :            : 
      97         [ -  + ]:       5546 :                         if (arch_alloc_thread_info(core)) {
      98         [ #  # ]:          0 :                                 xfree(core);
      99                 :            :                                 core = NULL;
     100                 :            :                         }
     101                 :            :                 }
     102                 :            :         }
     103                 :            : 
     104                 :       5567 :         return core;
     105                 :            : }
     106                 :            : 
     107                 :       3664 : int pstree_alloc_cores(struct pstree_item *item)
     108                 :            : {
     109                 :            :         unsigned int i;
     110                 :            : 
     111         [ -  + ]:       3664 :         item->core = xzalloc(sizeof(*item->core) * item->nr_threads);
     112         [ +  - ]:       3664 :         if (!item->core)
     113                 :            :                 return -1;
     114                 :            : 
     115         [ +  + ]:       9210 :         for (i = 0; i < item->nr_threads; i++) {
     116         [ +  + ]:       5546 :                 if (item->threads[i].real == item->pid.real)
     117                 :       3664 :                         item->core[i] = core_entry_alloc(1, 1);
     118                 :            :                 else
     119                 :       1882 :                         item->core[i] = core_entry_alloc(1, 0);
     120                 :            : 
     121         [ +  - ]:       5546 :                 if (!item->core[i])
     122                 :            :                         goto err;
     123                 :            :         }
     124                 :            : 
     125                 :            :         return 0;
     126                 :            : err:
     127                 :          0 :         pstree_free_cores(item);
     128                 :          0 :         return -1;
     129                 :            : }
     130                 :            : 
     131                 :       3764 : void pstree_free_cores(struct pstree_item *item)
     132                 :            : {
     133                 :            :         unsigned int i;
     134                 :            : 
     135         [ +  + ]:       3764 :         if (item->core) {
     136         [ +  + ]:       5546 :                 for (i = 1; i < item->nr_threads; i++)
     137                 :       1882 :                         core_entry_free(item->core[i]);
     138         [ +  - ]:       3664 :                 xfree(item->core);
     139                 :       3664 :                 item->core = NULL;
     140                 :            :         }
     141                 :       3764 : }
     142                 :            : 
     143                 :       1792 : void free_pstree(struct pstree_item *root_item)
     144                 :            : {
     145                 :            :         struct pstree_item *item = root_item, *parent;
     146                 :            : 
     147         [ +  + ]:       7528 :         while (item) {
     148         [ +  + ]:       5736 :                 if (!list_empty(&item->children)) {
     149                 :       1972 :                         item = list_first_entry(&item->children, struct pstree_item, sibling);
     150                 :       1972 :                         continue;
     151                 :            :                 }
     152                 :            : 
     153                 :       3764 :                 parent = item->parent;
     154                 :            :                 list_del(&item->sibling);
     155                 :       3764 :                 pstree_free_cores(item);
     156         [ +  - ]:       3764 :                 xfree(item->threads);
     157         [ +  - ]:       5736 :                 xfree(item);
     158                 :            :                 item = parent;
     159                 :            :         }
     160                 :       1792 : }
     161                 :            : 
     162                 :       6313 : struct pstree_item *__alloc_pstree_item(bool rst)
     163                 :            : {
     164                 :            :         struct pstree_item *item;
     165                 :            : 
     166         [ +  + ]:       6313 :         if (!rst) {
     167         [ -  + ]:       3766 :                 item = xzalloc(sizeof(*item));
     168         [ +  - ]:       3766 :                 if (!item)
     169                 :            :                         return NULL;
     170                 :            :         } else {
     171                 :       2547 :                 item = shmalloc(sizeof(*item) + sizeof(item->rst[0]));
     172         [ +  - ]:       2547 :                 if (!item)
     173                 :            :                         return NULL;
     174                 :            :                 memset(item, 0, sizeof(*item) + sizeof(item->rst[0]));
     175                 :            :                 vm_area_list_init(&item->rst[0].vmas);
     176                 :            :         }
     177                 :            : 
     178                 :       6313 :         INIT_LIST_HEAD(&item->children);
     179                 :       6313 :         INIT_LIST_HEAD(&item->sibling);
     180                 :            : 
     181                 :       6313 :         item->pid.virt = -1;
     182                 :       6313 :         item->pid.real = -1;
     183                 :       6313 :         item->born_sid = -1;
     184                 :            : 
     185                 :       6313 :         return item;
     186                 :            : }
     187                 :            : 
     188                 :            : /* Deep first search on children */
     189                 :      12341 : struct pstree_item *pstree_item_next(struct pstree_item *item)
     190                 :            : {
     191 [ +  + ][ +  + ]:      58434 :         if (!list_empty(&item->children))
         [ +  + ][ +  + ]
         [ +  + ][ #  # ]
         [ #  # ][ +  + ]
                 [ +  + ]
     192                 :      22165 :                 return list_first_entry(&item->children, struct pstree_item, sibling);
     193                 :            : 
     194 [ +  + ][ +  + ]:      83020 :         while (item->parent) {
         [ +  + ][ +  + ]
         [ +  + ][ #  # ]
         [ #  # ][ +  + ]
                 [ +  + ]
     195 [ +  + ][ +  + ]:      31194 :                 if (item->sibling.next != &item->parent->children)
         [ +  + ][ +  + ]
         [ +  + ][ #  # ]
         [ #  # ][ +  + ]
                 [ +  + ]
     196                 :      42431 :                         return list_entry(item->sibling.next, struct pstree_item, sibling);
     197                 :            :                 item = item->parent;
     198                 :            :         }
     199                 :            : 
     200                 :            :         return NULL;
     201                 :            : }
     202                 :            : 
     203                 :        448 : int dump_pstree(struct pstree_item *root_item)
     204                 :            : {
     205                 :            :         struct pstree_item *item = root_item;
     206                 :        448 :         PstreeEntry e = PSTREE_ENTRY__INIT;
     207                 :            :         int ret = -1, i;
     208                 :            :         int pstree_fd;
     209                 :            : 
     210                 :        448 :         pr_info("\n");
     211                 :        448 :         pr_info("Dumping pstree (pid: %d)\n", root_item->pid.real);
     212                 :        448 :         pr_info("----------------------------------------\n");
     213                 :            : 
     214                 :            :         /*
     215                 :            :          * Make sure we're dumping session leader, if not an
     216                 :            :          * appropriate option must be passed.
     217                 :            :          *
     218                 :            :          * Also note that if we're not a session leader we
     219                 :            :          * can't get the situation where the leader sits somewhere
     220                 :            :          * deeper in process tree, thus top-level checking for
     221                 :            :          * leader is enough.
     222                 :            :          */
     223         [ -  + ]:        448 :         if (root_item->pid.virt != root_item->sid) {
     224         [ #  # ]:          0 :                 if (!opts.shell_job) {
     225                 :          0 :                         pr_err("The root process %d is not a session leader. "
     226                 :            :                                "Consider using --" OPT_SHELL_JOB " option\n", item->pid.virt);
     227                 :          0 :                         return -1;
     228                 :            :                 }
     229                 :            :         }
     230                 :            : 
     231                 :        448 :         pstree_fd = open_image(CR_FD_PSTREE, O_DUMP);
     232         [ +  - ]:        448 :         if (pstree_fd < 0)
     233                 :            :                 return -1;
     234                 :            : 
     235         [ +  + ]:       1388 :         for_each_pstree_item(item) {
     236                 :        940 :                 pr_info("Process: %d(%d)\n", item->pid.virt, item->pid.real);
     237                 :            : 
     238                 :        940 :                 e.pid           = item->pid.virt;
     239         [ +  + ]:        940 :                 e.ppid          = item->parent ? item->parent->pid.virt : 0;
     240                 :        940 :                 e.pgid          = item->pgid;
     241                 :        940 :                 e.sid           = item->sid;
     242                 :        940 :                 e.n_threads     = item->nr_threads;
     243                 :            : 
     244         [ -  + ]:        940 :                 e.threads = xmalloc(sizeof(e.threads[0]) * e.n_threads);
     245         [ +  - ]:        940 :                 if (!e.threads)
     246                 :            :                         goto err;
     247                 :            : 
     248         [ +  + ]:       2350 :                 for (i = 0; i < item->nr_threads; i++)
     249                 :       1410 :                         e.threads[i] = item->threads[i].virt;
     250                 :            : 
     251                 :        940 :                 ret = pb_write_one(pstree_fd, &e, PB_PSTREE);
     252         [ +  - ]:        940 :                 xfree(e.threads);
     253                 :            : 
     254         [ +  - ]:        940 :                 if (ret)
     255                 :            :                         goto err;
     256                 :            :         }
     257                 :            :         ret = 0;
     258                 :            : 
     259                 :            : err:
     260                 :        448 :         pr_info("----------------------------------------\n");
     261                 :        448 :         close(pstree_fd);
     262                 :        448 :         return ret;
     263                 :            : }
     264                 :            : 
     265                 :            : static int max_pid = 0;
     266                 :            : 
     267                 :       1013 : static int prepare_pstree_for_shell_job(void)
     268                 :            : {
     269                 :       1013 :         pid_t current_sid = getsid(getpid());
     270                 :       1013 :         pid_t current_gid = getpgid(getpid());
     271                 :            : 
     272                 :            :         struct pstree_item *pi;
     273                 :            : 
     274                 :            :         pid_t old_sid;
     275                 :            :         pid_t old_gid;
     276                 :            : 
     277         [ -  + ]:       1013 :         if (!opts.shell_job)
     278                 :            :                 return 0;
     279                 :            : 
     280         [ #  # ]:          0 :         if (root_item->sid == root_item->pid.virt)
     281                 :            :                 return 0;
     282                 :            : 
     283                 :            :         /*
     284                 :            :          * Migration of a root task group leader is a bit tricky.
     285                 :            :          * When a task yields SIGSTOP, the kernel notifies the parent
     286                 :            :          * with SIGCHLD. This means when task is running in a
     287                 :            :          * shell, the shell obtains SIGCHLD and sends a task to
     288                 :            :          * the background.
     289                 :            :          *
     290                 :            :          * The situation gets changed once we restore the
     291                 :            :          * program -- our tool become an additional stub between
     292                 :            :          * the restored program and the shell. So to be able to
     293                 :            :          * notify the shell with SIGCHLD from our restored
     294                 :            :          * program -- we make the root task to inherit the
     295                 :            :          * process group from us.
     296                 :            :          *
     297                 :            :          * Not that clever solution but at least it works.
     298                 :            :          */
     299                 :            : 
     300                 :            :         old_sid = root_item->sid;
     301                 :          0 :         old_gid = root_item->pgid;
     302                 :            : 
     303                 :          0 :         pr_info("Migrating process tree (GID %d->%d SID %d->%d)\n",
     304                 :            :                 old_gid, current_gid, old_sid, current_sid);
     305                 :            : 
     306         [ #  # ]:          0 :         for_each_pstree_item(pi) {
     307         [ #  # ]:          0 :                 if (pi->pgid == old_gid)
     308                 :          0 :                         pi->pgid = current_gid;
     309         [ #  # ]:          0 :                 if (pi->sid == old_sid)
     310                 :          0 :                         pi->sid = current_sid;
     311                 :            :         }
     312                 :            : 
     313                 :          0 :         max_pid = max((int)current_sid, max_pid);
     314                 :          0 :         max_pid = max((int)current_gid, max_pid);
     315                 :            : 
     316                 :          0 :         return 0;
     317                 :            : }
     318                 :            : 
     319                 :       1013 : static int read_pstree_image(void)
     320                 :            : {
     321                 :            :         int ret = 0, i, ps_fd, fd;
     322                 :            :         struct pstree_item *pi, *parent = NULL;
     323                 :            : 
     324                 :       1013 :         pr_info("Reading image tree\n");
     325                 :            : 
     326                 :       1013 :         ps_fd = open_image(CR_FD_PSTREE, O_RSTR);
     327         [ +  - ]:       3540 :         if (ps_fd < 0)
     328                 :            :                 return ps_fd;
     329                 :            : 
     330                 :            :         while (1) {
     331                 :            :                 PstreeEntry *e;
     332                 :            : 
     333                 :       3540 :                 ret = pb_read_one_eof(ps_fd, &e, PB_PSTREE);
     334         [ +  + ]:       3540 :                 if (ret <= 0)
     335                 :            :                         break;
     336                 :            : 
     337                 :            :                 ret = -1;
     338                 :       2527 :                 pi = alloc_pstree_item_with_rst();
     339         [ +  - ]:       2527 :                 if (pi == NULL)
     340                 :            :                         break;
     341                 :            : 
     342                 :       2527 :                 pi->pid.virt = e->pid;
     343                 :       2527 :                 max_pid = max((int)e->pid, max_pid);
     344                 :            : 
     345                 :       2527 :                 pi->pgid = e->pgid;
     346                 :       2527 :                 max_pid = max((int)e->pgid, max_pid);
     347                 :            : 
     348                 :       2527 :                 pi->sid = e->sid;
     349                 :       2527 :                 max_pid = max((int)e->sid, max_pid);
     350                 :            : 
     351         [ +  + ]:       2527 :                 if (e->ppid == 0) {
     352         [ -  + ]:       1013 :                         if (root_item) {
     353                 :          0 :                                 pr_err("Parent missed on non-root task "
     354                 :            :                                        "with pid %d, image corruption!\n", e->pid);
     355                 :          0 :                                 goto err;
     356                 :            :                         }
     357                 :       1013 :                         root_item = pi;
     358                 :       1013 :                         pi->parent = NULL;
     359                 :            :                 } else {
     360                 :            :                         /*
     361                 :            :                          * Fast path -- if the pstree image is not edited, the
     362                 :            :                          * parent of any item should have already being restored
     363                 :            :                          * and sit among the last item's ancestors.
     364                 :            :                          */
     365         [ +  - ]:       2197 :                         while (parent) {
     366         [ +  + ]:       2197 :                                 if (parent->pid.virt == e->ppid)
     367                 :            :                                         break;
     368                 :        683 :                                 parent = parent->parent;
     369                 :            :                         }
     370                 :            : 
     371         [ -  + ]:       1514 :                         if (parent == NULL) {
     372         [ #  # ]:          0 :                                 for_each_pstree_item(parent) {
     373         [ #  # ]:          0 :                                         if (parent->pid.virt == e->ppid)
     374                 :            :                                                 break;
     375                 :            :                                 }
     376                 :            : 
     377         [ #  # ]:          0 :                                 if (parent == NULL) {
     378                 :          0 :                                         pr_err("Can't find a parent for %d\n", pi->pid.virt);
     379                 :          0 :                                         pstree_entry__free_unpacked(e, NULL);
     380         [ #  # ]:          0 :                                         xfree(pi);
     381                 :            :                                         goto err;
     382                 :            :                                 }
     383                 :            :                         }
     384                 :            : 
     385                 :       1514 :                         pi->parent = parent;
     386                 :       1514 :                         list_add(&pi->sibling, &parent->children);
     387                 :            :                 }
     388                 :            : 
     389                 :            :                 parent = pi;
     390                 :            : 
     391                 :       2527 :                 pi->nr_threads = e->n_threads;
     392         [ -  + ]:       2527 :                 pi->threads = xmalloc(e->n_threads * sizeof(struct pid));
     393         [ +  - ]:       2527 :                 if (!pi->threads)
     394                 :            :                         break;
     395                 :            : 
     396         [ +  + ]:       6014 :                 for (i = 0; i < e->n_threads; i++) {
     397                 :       3487 :                         pi->threads[i].real = -1;
     398                 :       3487 :                         pi->threads[i].virt = e->threads[i];
     399                 :            :                 }
     400                 :            : 
     401                 :       2527 :                 task_entries->nr_threads += e->n_threads;
     402                 :       2527 :                 task_entries->nr_tasks++;
     403                 :            : 
     404                 :       2527 :                 pstree_entry__free_unpacked(e, NULL);
     405                 :            : 
     406                 :       2527 :                 fd = open_image(CR_FD_IDS, O_RSTR, pi->pid.virt);
     407         [ +  + ]:       2527 :                 if (fd < 0) {
     408         [ +  - ]:         61 :                         if (errno == ENOENT)
     409                 :         61 :                                 continue;
     410                 :            :                         goto err;
     411                 :            :                 }
     412                 :       2466 :                 ret = pb_read_one(fd, &pi->ids, PB_IDS);
     413                 :       2466 :                 close(fd);
     414         [ +  - ]:       2466 :                 if (ret != 1)
     415                 :            :                         goto err;
     416                 :            : 
     417         [ +  - ]:       2466 :                 if (pi->ids->has_mnt_ns_id) {
     418         [ +  - ]:       3479 :                         if (rst_add_ns_id(pi->ids->mnt_ns_id, pi->pid.virt, &mnt_ns_desc))
     419                 :            :                                 goto err;
     420                 :            :                 }
     421                 :            :         }
     422                 :            : err:
     423                 :       1013 :         close(ps_fd);
     424                 :       1013 :         return ret;
     425                 :            : }
     426                 :            : 
     427                 :       1013 : static int prepare_pstree_ids(void)
     428                 :            : {
     429                 :            :         struct pstree_item *item, *child, *helper, *tmp;
     430                 :       1013 :         LIST_HEAD(helpers);
     431                 :            : 
     432                 :       1013 :         pid_t current_pgid = getpgid(getpid());
     433                 :            : 
     434                 :            :         /*
     435                 :            :          * Some task can be reparented to init. A helper task should be added
     436                 :            :          * for restoring sid of such tasks. The helper tasks will be exited
     437                 :            :          * immediately after forking children and all children will be
     438                 :            :          * reparented to init.
     439                 :            :          */
     440         [ +  + ]:       2191 :         list_for_each_entry(item, &root_item->children, sibling) {
     441                 :            : 
     442                 :            :                 /*
     443                 :            :                  * If a child belongs to the root task's session or it's
     444                 :            :                  * a session leader himself -- this is a simple case, we
     445                 :            :                  * just proceed in a normal way.
     446                 :            :                  */
     447 [ +  + ][ +  + ]:       1178 :                 if (item->sid == root_item->sid || item->sid == item->pid.virt)
     448                 :       1162 :                         continue;
     449                 :            : 
     450                 :         16 :                 helper = alloc_pstree_item_with_rst();
     451         [ +  - ]:         16 :                 if (helper == NULL)
     452                 :            :                         return -1;
     453                 :         16 :                 helper->sid = item->sid;
     454                 :         16 :                 helper->pgid = item->sid;
     455                 :         16 :                 helper->pid.virt = item->sid;
     456                 :         16 :                 helper->state = TASK_HELPER;
     457                 :         16 :                 helper->parent = root_item;
     458                 :         16 :                 list_add_tail(&helper->sibling, &helpers);
     459                 :         16 :                 task_entries->nr_helpers++;
     460                 :            : 
     461                 :         16 :                 pr_info("Add a helper %d for restoring SID %d\n",
     462                 :            :                                 helper->pid.virt, helper->sid);
     463                 :            : 
     464                 :         16 :                 child = list_entry(item->sibling.prev, struct pstree_item, sibling);
     465                 :            :                 item = child;
     466                 :            : 
     467                 :            :                 /*
     468                 :            :                  * Stack on helper task all children with target sid.
     469                 :            :                  */
     470         [ +  + ]:         40 :                 list_for_each_entry_safe_continue(child, tmp, &root_item->children, sibling) {
     471         [ +  + ]:         24 :                         if (child->sid != helper->sid)
     472                 :          8 :                                 continue;
     473         [ -  + ]:         16 :                         if (child->sid == child->pid.virt)
     474                 :          0 :                                 continue;
     475                 :            : 
     476                 :         16 :                         pr_info("Attach %d to the temporary task %d\n",
     477                 :            :                                         child->pid.virt, helper->pid.virt);
     478                 :            : 
     479                 :         16 :                         child->parent = helper;
     480                 :         16 :                         list_move(&child->sibling, &helper->children);
     481                 :            :                 }
     482                 :            :         }
     483                 :            : 
     484                 :            :         /* Try to connect helpers to session leaders */
     485         [ +  + ]:       3540 :         for_each_pstree_item(item) {
     486         [ +  + ]:       2527 :                 if (!item->parent) /* skip the root task */
     487                 :       1013 :                         continue;
     488                 :            : 
     489         [ +  + ]:       1514 :                 if (item->state == TASK_HELPER)
     490                 :          8 :                         continue;
     491                 :            : 
     492         [ +  + ]:       1506 :                 if (item->sid != item->pid.virt) {
     493                 :            :                         struct pstree_item *parent;
     494                 :            : 
     495         [ +  + ]:       1002 :                         if (item->parent->sid == item->sid)
     496                 :        986 :                                 continue;
     497                 :            : 
     498                 :            :                         /* the task could fork a child before and after setsid() */
     499                 :            :                         parent = item->parent;
     500 [ +  - ][ +  + ]:         40 :                         while (parent && parent->pid.virt != item->sid) {
     501 [ -  + ][ #  # ]:         24 :                                 if (parent->born_sid != -1 && parent->born_sid != item->sid) {
     502                 :          0 :                                         pr_err("Can't determinate with which sid (%d or %d)"
     503                 :            :                                                 "the process %d was born\n",
     504                 :            :                                                 parent->born_sid, item->sid, parent->pid.virt);
     505                 :          0 :                                         return -1;
     506                 :            :                                 }
     507                 :         24 :                                 parent->born_sid = item->sid;
     508                 :         24 :                                 pr_info("%d was born with sid %d\n", parent->pid.virt, item->sid);
     509                 :         24 :                                 parent = parent->parent;
     510                 :            :                         }
     511                 :            : 
     512         [ -  + ]:         16 :                         if (parent == NULL) {
     513                 :          0 :                                 pr_err("Can't find a session leader for %d\n", item->sid);
     514                 :          0 :                                 return -1;
     515                 :            :                         }
     516                 :            : 
     517                 :         16 :                         continue;
     518                 :            :                 }
     519                 :            : 
     520                 :        504 :                 pr_info("Session leader %d\n", item->sid);
     521                 :            : 
     522                 :            :                 /* Try to find helpers, who should be connected to the leader */
     523         [ +  + ]:        544 :                 list_for_each_entry(child, &helpers, sibling) {
     524         [ -  + ]:         48 :                         if (child->state != TASK_HELPER)
     525                 :          0 :                                 continue;
     526                 :            : 
     527         [ +  + ]:         48 :                         if (child->sid != item->sid)
     528                 :         40 :                                 continue;
     529                 :            : 
     530                 :          8 :                         child->pgid = item->pgid;
     531                 :          8 :                         child->pid.virt = ++max_pid;
     532                 :          8 :                         child->parent = item;
     533                 :          8 :                         list_move(&child->sibling, &item->children);
     534                 :            : 
     535                 :          8 :                         pr_info("Attach %d to the task %d\n",
     536                 :            :                                         child->pid.virt, item->pid.virt);
     537                 :            : 
     538                 :          8 :                         break;
     539                 :            :                 }
     540                 :            :         }
     541                 :            : 
     542                 :            :         /* All other helpers are session leaders for own sessions */
     543                 :       1013 :         list_splice(&helpers, &root_item->children);
     544                 :            : 
     545                 :            :         /* Add a process group leader if it is absent  */
     546         [ +  + ]:       3560 :         for_each_pstree_item(item) {
     547                 :            :                 struct pstree_item *gleader;
     548                 :            : 
     549 [ +  - ][ +  + ]:       2547 :                 if (!item->pgid || item->pid.virt == item->pgid)
     550                 :       1547 :                         continue;
     551                 :            : 
     552         [ +  + ]:       1464 :                 for_each_pstree_item(gleader) {
     553         [ +  + ]:       1460 :                         if (gleader->pid.virt == item->pgid)
     554                 :            :                                 break;
     555                 :            :                 }
     556                 :            : 
     557         [ +  + ]:       1000 :                 if (gleader) {
     558                 :        996 :                         item->rst->pgrp_leader = gleader;
     559                 :        996 :                         continue;
     560                 :            :                 }
     561                 :            : 
     562                 :            :                 /*
     563                 :            :                  * If the PGID is eq to current one -- this
     564                 :            :                  * means we're inheriting group from the current
     565                 :            :                  * task so we need to escape creating a helper here.
     566                 :            :                  */
     567         [ -  + ]:          4 :                 if (current_pgid == item->pgid)
     568                 :          0 :                         continue;
     569                 :            : 
     570                 :          4 :                 helper = alloc_pstree_item_with_rst();
     571         [ +  - ]:          4 :                 if (helper == NULL)
     572                 :            :                         return -1;
     573                 :          4 :                 helper->sid = item->sid;
     574                 :          4 :                 helper->pgid = item->pgid;
     575                 :          4 :                 helper->pid.virt = item->pgid;
     576                 :          4 :                 helper->state = TASK_HELPER;
     577                 :          4 :                 helper->parent = item;
     578                 :          4 :                 list_add(&helper->sibling, &item->children);
     579                 :          4 :                 task_entries->nr_helpers++;
     580                 :          4 :                 item->rst->pgrp_leader = helper;
     581                 :            : 
     582                 :          4 :                 pr_info("Add a helper %d for restoring PGID %d\n",
     583                 :            :                                 helper->pid.virt, helper->pgid);
     584                 :            :         }
     585                 :            : 
     586                 :            :         return 0;
     587                 :            : }
     588                 :            : 
     589                 :       2466 : static unsigned long get_clone_mask(TaskKobjIdsEntry *i,
     590                 :            :                 TaskKobjIdsEntry *p)
     591                 :            : {
     592                 :            :         unsigned long mask = 0;
     593                 :            : 
     594         [ +  + ]:       2466 :         if (i->files_id == p->files_id)
     595                 :            :                 mask |= CLONE_FILES;
     596         [ +  + ]:       2466 :         if (i->pid_ns_id != p->pid_ns_id)
     597                 :        420 :                 mask |= CLONE_NEWPID;
     598         [ +  + ]:       2466 :         if (i->net_ns_id != p->net_ns_id)
     599                 :        428 :                 mask |= CLONE_NEWNET;
     600         [ +  + ]:       2466 :         if (i->ipc_ns_id != p->ipc_ns_id)
     601                 :        446 :                 mask |= CLONE_NEWIPC;
     602         [ +  + ]:       2466 :         if (i->uts_ns_id != p->uts_ns_id)
     603                 :        424 :                 mask |= CLONE_NEWUTS;
     604         [ +  + ]:       2466 :         if (i->mnt_ns_id != p->mnt_ns_id)
     605                 :        420 :                 mask |= CLONE_NEWNS;
     606                 :            : 
     607                 :       2466 :         return mask;
     608                 :            : }
     609                 :            : 
     610                 :       1013 : static int prepare_pstree_kobj_ids(void)
     611                 :            : {
     612                 :            :         struct pstree_item *item;
     613                 :            : 
     614                 :            :         /* Find a process with minimal pid for shared fd tables */
     615         [ +  + ]:       3540 :         for_each_pstree_item(item) {
     616                 :       2527 :                 struct pstree_item *parent = item->parent;
     617                 :            :                 TaskKobjIdsEntry *ids;
     618                 :            :                 unsigned long cflags;
     619                 :            : 
     620         [ +  + ]:       2527 :                 if (!item->ids) {
     621         [ -  + ]:         61 :                         if (item == root_item) {
     622                 :          0 :                                 cflags = opts.rst_namespaces_flags;
     623                 :          0 :                                 goto set_mask;
     624                 :            :                         }
     625                 :            : 
     626                 :         61 :                         continue;
     627                 :            :                 }
     628                 :            : 
     629         [ +  + ]:       2466 :                 if (parent)
     630                 :       1453 :                         ids = parent->ids;
     631                 :            :                 else
     632                 :       1013 :                         ids = root_ids;
     633                 :            : 
     634                 :            :                 /*
     635                 :            :                  * Add some sanity check on image data.
     636                 :            :                  */
     637         [ -  + ]:       2466 :                 if (unlikely(!ids)) {
     638                 :          0 :                         pr_err("No kIDs provided, image corruption\n");
     639                 :          0 :                         return -1;
     640                 :            :                 }
     641                 :            : 
     642                 :       2466 :                 cflags = get_clone_mask(item->ids, ids);
     643                 :            : 
     644         [ +  + ]:       2466 :                 if (cflags & CLONE_FILES) {
     645                 :            :                         int ret;
     646                 :            : 
     647                 :            :                         /*
     648                 :            :                          * There might be a case when kIDs for
     649                 :            :                          * root task are the same as in root_ids,
     650                 :            :                          * thus it's image corruption and we should
     651                 :            :                          * exit out.
     652                 :            :                          */
     653         [ -  + ]:         45 :                         if (unlikely(!item->parent)) {
     654                 :          0 :                                 pr_err("Image corruption on kIDs data\n");
     655                 :          0 :                                 return -1;
     656                 :            :                         }
     657                 :            : 
     658                 :         45 :                         ret = shared_fdt_prepare(item);
     659         [ +  - ]:         45 :                         if (ret)
     660                 :            :                                 return ret;
     661                 :            :                 }
     662                 :            : 
     663                 :            : set_mask:
     664                 :       2466 :                 item->rst->clone_flags = cflags;
     665                 :            : 
     666                 :       2466 :                 cflags &= CLONE_ALLNS;
     667                 :            : 
     668         [ +  + ]:       2466 :                 if (item == root_item) {
     669                 :       1013 :                         pr_info("Will restore in %lx namespaces\n", cflags);
     670                 :       1013 :                         root_ns_mask = cflags;
     671         [ -  + ]:       1453 :                 } else if (cflags & ~(root_ns_mask & CLONE_SUBNS)) {
     672                 :            :                         /*
     673                 :            :                          * Namespaces from CLONE_SUBNS can be nested, but in
     674                 :            :                          * this case nobody can't share external namespaces of
     675                 :            :                          * these types.
     676                 :            :                          *
     677                 :            :                          * Workaround for all other namespaces --
     678                 :            :                          * all tasks should be in one namespace. And
     679                 :            :                          * this namespace is either inherited from the
     680                 :            :                          * criu or is created for the init task (only)
     681                 :            :                          */
     682                 :          0 :                         pr_err("Can't restore sub-task in NS\n");
     683                 :          0 :                         return -1;
     684                 :            :                 }
     685                 :            :         }
     686                 :            : 
     687                 :       1013 :         pr_debug("NS mask to use %lx\n", root_ns_mask);
     688                 :       1013 :         return 0;
     689                 :            : }
     690                 :            : 
     691                 :       1013 : int prepare_pstree(void)
     692                 :            : {
     693                 :            :         int ret;
     694                 :            : 
     695                 :       1013 :         ret = read_pstree_image();
     696         [ +  - ]:       1013 :         if (!ret)
     697                 :            :                 /*
     698                 :            :                  * Shell job may inherit sid/pgid from the current
     699                 :            :                  * shell, not from image. Set things up for this.
     700                 :            :                  */
     701                 :       1013 :                 ret = prepare_pstree_for_shell_job();
     702         [ +  - ]:       1013 :         if (!ret)
     703                 :            :                 /*
     704                 :            :                  * Walk the collected tree and prepare for restoring
     705                 :            :                  * of shared objects at clone time
     706                 :            :                  */
     707                 :       1013 :                 ret = prepare_pstree_kobj_ids();
     708         [ +  - ]:       1013 :         if (!ret)
     709                 :            :                 /*
     710                 :            :                  * Session/Group leaders might be dead. Need to fix
     711                 :            :                  * pstree with properly injected helper tasks.
     712                 :            :                  */
     713                 :       1013 :                 ret = prepare_pstree_ids();
     714                 :            : 
     715                 :       1013 :         return ret;
     716                 :            : }
     717                 :            : 
     718                 :       1092 : bool restore_before_setsid(struct pstree_item *child)
     719                 :            : {
     720         [ +  - ]:       1092 :         int csid = child->born_sid == -1 ? child->sid : child->born_sid;
     721                 :            : 
     722         [ +  - ]:       1092 :         if (child->parent->born_sid == csid)
     723                 :            :                 return true;
     724                 :            : 
     725                 :       1092 :         return false;
     726                 :            : }
     727                 :            : 
     728                 :      17738 : bool pid_in_pstree(pid_t pid)
     729                 :            : {
     730                 :            :         struct pstree_item *item;
     731                 :            : 
     732         [ +  + ]:      54826 :         for_each_pstree_item(item) {
     733         [ +  + ]:      37108 :                 if (item->pid.real == pid)
     734                 :            :                         return true;
     735                 :            :         }
     736                 :            : 
     737                 :            :         return false;
     738                 :            : }

Generated by: LCOV version 1.9