LCOV - code coverage report
Current view: top level - crtools - mount.c (source / functions) Hit Total Coverage
Test: crtools.info Lines: 249 289 86.2 %
Date: 2012-12-28 Functions: 25 27 92.6 %
Branches: 131 200 65.5 %

           Branch data     Line data    Source code
       1                 :            : #include <stdio.h>
       2                 :            : #include <unistd.h>
       3                 :            : #include <fcntl.h>
       4                 :            : #include <sys/mman.h>
       5                 :            : #include <sys/types.h>
       6                 :            : #include <dirent.h>
       7                 :            : #include <errno.h>
       8                 :            : #include <sys/stat.h>
       9                 :            : #include <string.h>
      10                 :            : #include <stdlib.h>
      11                 :            : #include <sys/mount.h>
      12                 :            : #include <sys/types.h>
      13                 :            : #include <sys/wait.h>
      14                 :            : 
      15                 :            : #include "crtools.h"
      16                 :            : #include "types.h"
      17                 :            : #include "util.h"
      18                 :            : #include "log.h"
      19                 :            : #include "mount.h"
      20                 :            : #include "proc_parse.h"
      21                 :            : #include "image.h"
      22                 :            : 
      23                 :            : #include "protobuf.h"
      24                 :            : #include "protobuf/mnt.pb-c.h"
      25                 :            : 
      26                 :            : static struct mount_info *mntinfo;
      27                 :            : int mntns_root = -1;
      28                 :            : 
      29                 :          4 : int open_mount(unsigned int s_dev)
      30                 :            : {
      31                 :            :         struct mount_info *i;
      32                 :            : 
      33         [ +  - ]:         42 :         for (i = mntinfo; i != NULL; i = i->next)
      34         [ +  + ]:         38 :                 if (s_dev == i->s_dev)
      35                 :          4 :                         return open(i->mountpoint, O_RDONLY);
      36                 :            : 
      37                 :            :         return -ENOENT;
      38                 :            : }
      39                 :            : 
      40                 :        214 : int collect_mount_info(void)
      41                 :            : {
      42                 :        214 :         pr_info("Collecting mountinfo\n");
      43                 :            : 
      44                 :        214 :         mntinfo = parse_mountinfo(getpid());
      45         [ -  + ]:        214 :         if (!mntinfo) {
      46                 :          0 :                 pr_err("Parsing mountinfo %d failed\n", getpid());
      47                 :        214 :                 return -1;
      48                 :            :         }
      49                 :            : 
      50                 :            :         return 0;
      51                 :            : }
      52                 :            : 
      53                 :            : static struct mount_info *mnt_find_by_id(struct mount_info *list, int id)
      54                 :            : {
      55                 :            :         struct mount_info *m;
      56                 :            : 
      57         [ +  + ]:       1824 :         for (m = list; m != NULL; m = m->next)
      58         [ +  + ]:       1605 :                 if (m->mnt_id == id)
      59                 :            :                         return m;
      60                 :            : 
      61                 :            :         return NULL;
      62                 :            : }
      63                 :            : 
      64                 :        219 : static struct mount_info *mnt_build_ids_tree(struct mount_info *list)
      65                 :            : {
      66                 :        219 :         struct mount_info *m, *root = NULL;
      67                 :            : 
      68                 :            :         /*
      69                 :            :          * Just resolve the mnt_id:parent_mnt_id relations
      70                 :            :          */
      71                 :            : 
      72                 :        219 :         pr_debug("\tBuilding plain mount tree\n");
      73         [ +  + ]:        901 :         for (m = list; m != NULL; m = m->next) {
      74                 :            :                 struct mount_info *p;
      75                 :            : 
      76                 :        682 :                 pr_debug("\t\tWorking on %d->%d\n", m->mnt_id, m->parent_mnt_id);
      77                 :       1364 :                 p = mnt_find_by_id(list, m->parent_mnt_id);
      78         [ +  + ]:        682 :                 if (!p) {
      79                 :            :                         /* This should be / */
      80 [ +  - ][ +  - ]:        219 :                         if (root == NULL && !strcmp(m->mountpoint, "/")) {
                 [ +  - ]
      81                 :        219 :                                 root = m;
      82                 :        219 :                                 continue;
      83                 :            :                         }
      84                 :            : 
      85         [ #  # ]:          0 :                         pr_err("Mountpoint %d w/o parent %d found @%s (root %s)\n",
      86                 :            :                                         m->mnt_id, m->parent_mnt_id, m->mountpoint,
      87                 :            :                                         root ? "found" : "not found");
      88                 :          0 :                         return NULL;
      89                 :            :                 }
      90                 :            : 
      91                 :        463 :                 m->parent = p;
      92                 :        463 :                 list_add_tail(&m->siblings, &p->children);
      93                 :            :         }
      94                 :            : 
      95         [ -  + ]:        219 :         if (!root) {
      96                 :          0 :                 pr_err("No root found for tree\n");
      97                 :        219 :                 return NULL;
      98                 :            :         }
      99                 :            : 
     100                 :            :         return root;
     101                 :            : }
     102                 :            : 
     103                 :            : static int mnt_depth(struct mount_info *m)
     104                 :            : {
     105                 :        701 :         int depth = 0;
     106                 :            :         char *c;
     107                 :            : 
     108 [ +  + ][ +  + ]:       5431 :         for (c = m->mountpoint; *c != '\0'; c++)
     109 [ +  + ][ +  + ]:       4730 :                 if (*c == '/')
     110                 :       1004 :                         depth++;
     111                 :            : 
     112                 :            :         return depth;
     113                 :            : }
     114                 :            : 
     115                 :        682 : static void mnt_resort_siblings(struct mount_info *tree)
     116                 :            : {
     117                 :            :         struct mount_info *m, *p;
     118                 :        682 :         LIST_HEAD(list);
     119                 :            : 
     120                 :            :         /*
     121                 :            :          * Put siblings of each node in an order they can be (u)mounted
     122                 :            :          * I.e. if we have mounts on foo/bar/, foo/bar/foobar/ and foo/
     123                 :            :          * we should put them in the foo/bar/foobar/, foo/bar/, foo/ order.
     124                 :            :          * Otherwise we will not be able to (u)mount them in a sequence.
     125                 :            :          *
     126                 :            :          * Funny, but all we need for this is to sort them in the descending
     127                 :            :          * order of the amount of /-s in a path =)
     128                 :            :          *
     129                 :            :          * Use stupid insertion sort here, we're not expecting mount trees
     130                 :            :          * to contain hundreds (or more) elements.
     131                 :            :          */
     132                 :            : 
     133                 :        682 :         pr_info("\tResorting siblings on %d\n", tree->mnt_id);
     134         [ +  + ]:       1145 :         while (!list_empty(&tree->children)) {
     135                 :            :                 int depth;
     136                 :            : 
     137                 :        463 :                 m = list_first_entry(&tree->children, struct mount_info, siblings);
     138                 :        463 :                 list_del(&m->siblings);
     139                 :            : 
     140                 :        926 :                 depth = mnt_depth(m);
     141         [ +  + ]:        464 :                 list_for_each_entry(p, &list, siblings)
     142         [ +  + ]:        238 :                         if (mnt_depth(p) <= depth)
     143                 :            :                                 break;
     144                 :            : 
     145                 :        463 :                 list_add(&m->siblings, &p->siblings);
     146                 :        463 :                 mnt_resort_siblings(m);
     147                 :            :         }
     148                 :            : 
     149                 :        682 :         list_splice(&list, &tree->children);
     150                 :        682 : }
     151                 :            : 
     152                 :        682 : static void mnt_tree_show(struct mount_info *tree, int off)
     153                 :            : {
     154                 :            :         struct mount_info *m;
     155                 :            : 
     156                 :        682 :         pr_info("%*s[%s](%d->%d)\n", off, "",
     157                 :            :                         tree->mountpoint, tree->mnt_id, tree->parent_mnt_id);
     158                 :            : 
     159         [ +  + ]:       1145 :         list_for_each_entry(m, &tree->children, siblings)
     160                 :        463 :                 mnt_tree_show(m, off + 1);
     161                 :            : 
     162                 :        682 :         pr_info("%*s<--\n", off, "");
     163                 :        682 : }
     164                 :            : 
     165                 :        219 : static struct mount_info *mnt_build_tree(struct mount_info *list)
     166                 :            : {
     167                 :            :         struct mount_info *tree;
     168                 :            : 
     169                 :            :         /*
     170                 :            :          * Organize them in a sequence in which they can be mounted/umounted.
     171                 :            :          */
     172                 :            : 
     173                 :        219 :         pr_info("Building mountpoints tree\n");
     174                 :        219 :         tree = mnt_build_ids_tree(list);
     175         [ +  - ]:        219 :         if (!tree)
     176                 :            :                 return NULL;
     177                 :            : 
     178                 :        219 :         mnt_resort_siblings(tree);
     179                 :        219 :         pr_info("Done:\n");
     180                 :        219 :         mnt_tree_show(tree, 0);
     181                 :        219 :         return tree;
     182                 :            : }
     183                 :            : 
     184                 :          2 : static DIR *open_mountpoint(struct mount_info *pm)
     185                 :            : {
     186                 :            :         int fd, ret;
     187                 :            :         char path[PATH_MAX + 1];
     188                 :            :         struct stat st;
     189                 :            :         DIR *fdir;
     190                 :            : 
     191         [ -  + ]:          2 :         if (!list_empty(&pm->children)) {
     192                 :          0 :                 pr_err("Something is mounted on top of %s\n", pm->fstype->name);
     193                 :            :                 return NULL;
     194                 :            :         }
     195                 :            : 
     196                 :          2 :         snprintf(path, sizeof(path), ".%s", pm->mountpoint);
     197                 :          2 :         fd = openat(mntns_root, path, O_RDONLY);
     198         [ -  + ]:          2 :         if (fd < 0) {
     199                 :          0 :                 pr_perror("Can't open %s", pm->mountpoint);
     200                 :            :                 return NULL;
     201                 :            :         }
     202                 :            : 
     203                 :          2 :         ret = fstat(fd, &st);
     204         [ -  + ]:          2 :         if (ret < 0) {
     205                 :          0 :                 pr_perror("fstat(%s) failed", path);
     206                 :          0 :                 close(fd);
     207                 :            :                 return NULL;
     208                 :            :         }
     209                 :            : 
     210         [ -  + ]:          2 :         if (st.st_dev != pm->s_dev) {
     211                 :          0 :                 pr_err("The file system %#x %s %s is inaccessible\n",
     212                 :            :                                 pm->s_dev, pm->fstype->name, pm->mountpoint);
     213                 :          0 :                 close(fd);
     214                 :            :                 return NULL;
     215                 :            :         }
     216                 :            : 
     217                 :          2 :         fdir = fdopendir(fd);
     218         [ -  + ]:          2 :         if (fdir == NULL) {
     219                 :          0 :                 close(fd);
     220                 :          2 :                 pr_perror("Can't open %s", pm->mountpoint);
     221                 :            :                 return NULL;
     222                 :            :         }
     223                 :            : 
     224                 :            :         return fdir;
     225                 :            : }
     226                 :            : 
     227                 :          2 : static int close_mountpoint(DIR *dfd)
     228                 :            : {
     229         [ -  + ]:          2 :         if (closedir(dfd)) {
     230                 :          0 :                 pr_perror("Unable to close directory");
     231                 :          2 :                 return -1;
     232                 :            :         }
     233                 :            :         return 0;
     234                 :            : }
     235                 :            : 
     236                 :          1 : static int tmpfs_dump(struct mount_info *pm)
     237                 :            : {
     238                 :          1 :         int ret = -1;
     239                 :            :         char tmpfs_path[PATH_MAX];
     240                 :          1 :         int fd, fd_img = -1;
     241                 :          1 :         DIR *fdir = NULL;
     242                 :            : 
     243                 :          1 :         fdir = open_mountpoint(pm);
     244         [ +  - ]:          1 :         if (fdir == NULL)
     245                 :            :                 return -1;
     246                 :            : 
     247                 :          1 :         fd = dirfd(fdir);
     248         [ -  + ]:          1 :         if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) & ~FD_CLOEXEC) == -1) {
     249                 :          0 :                 pr_perror("Can not drop FD_CLOEXEC");
     250                 :          0 :                 goto out;
     251                 :            :         }
     252                 :            : 
     253                 :          1 :         fd_img = open_image(CR_FD_TMPFS, O_DUMP, pm->mnt_id);
     254         [ +  - ]:          1 :         if (fd_img < 0)
     255                 :            :                 goto out;
     256                 :            : 
     257                 :          1 :         snprintf(tmpfs_path, sizeof(tmpfs_path),
     258                 :            :                                        "/proc/self/fd/%d", fd);
     259                 :            : 
     260                 :          1 :         ret = cr_system(-1, fd_img, -1, "tar", (char *[])
     261                 :          1 :                         { "tar", "--create",
     262                 :            :                         "--gzip",
     263                 :            :                         "--check-links",
     264                 :            :                         "--preserve-permissions",
     265                 :            :                         "--sparse",
     266                 :            :                         "--numeric-owner",
     267                 :            :                         "--directory", tmpfs_path, ".", NULL });
     268                 :            : 
     269         [ -  + ]:          1 :         if (ret)
     270                 :          0 :                 pr_err("Can't dump tmpfs content\n");
     271                 :            : 
     272                 :            : out:
     273                 :          1 :         close_safe(&fd_img);
     274                 :          1 :         close_mountpoint(fdir);
     275                 :            :         return ret;
     276                 :            : }
     277                 :            : 
     278                 :          1 : static int tmpfs_restore(struct mount_info *pm)
     279                 :            : {
     280                 :            :         int ret;
     281                 :            :         int fd_img;
     282                 :            : 
     283                 :          1 :         fd_img = open_image_ro(CR_FD_TMPFS, pm->mnt_id);
     284         [ +  - ]:          1 :         if (fd_img < 0)
     285                 :            :                 return -1;
     286                 :            : 
     287                 :          1 :         ret = cr_system(fd_img, -1, -1, "tar",
     288                 :          2 :                         (char *[]) {"tar", "--extract", "--gzip",
     289                 :          1 :                                 "--directory", pm->mountpoint, NULL});
     290                 :          1 :         close(fd_img);
     291                 :            : 
     292         [ -  + ]:          1 :         if (ret) {
     293                 :          0 :                 pr_err("Can't restore tmpfs content\n");
     294                 :          1 :                 return -1;
     295                 :            :         }
     296                 :            : 
     297                 :            :         return 0;
     298                 :            : }
     299                 :            : 
     300                 :          1 : static int binfmt_misc_dump(struct mount_info *pm)
     301                 :            : {
     302                 :          1 :         int ret = -1;
     303                 :            :         struct dirent *de;
     304                 :          1 :         DIR *fdir = NULL;
     305                 :            : 
     306                 :          1 :         fdir = open_mountpoint(pm);
     307         [ +  - ]:          1 :         if (fdir == NULL)
     308                 :            :                 return -1;
     309                 :            : 
     310         [ +  + ]:          5 :         while ((de = readdir(fdir))) {
     311         [ +  + ]:          4 :                 if (dir_dots(de))
     312                 :          2 :                         continue;
     313         [ +  + ]:          2 :                 if (!strcmp(de->d_name, "register"))
     314                 :          1 :                         continue;
     315         [ +  - ]:          1 :                 if (!strcmp(de->d_name, "status"))
     316                 :          1 :                         continue;
     317                 :            : 
     318                 :          0 :                 pr_err("binfmt_misc isn't empty: %s\n", de->d_name);
     319                 :          4 :                 goto out;
     320                 :            :         }
     321                 :            : 
     322                 :            :         ret = 0;
     323                 :            : out:
     324                 :          1 :         close_mountpoint(fdir);
     325                 :          1 :         return ret;
     326                 :            : }
     327                 :            : 
     328                 :            : static struct fstype fstypes[] = {
     329                 :            :         { "unsupported" },
     330                 :            :         { "proc" },
     331                 :            :         { "sysfs" },
     332                 :            :         { "devtmpfs" },
     333                 :            :         { "binfmt_misc", binfmt_misc_dump },
     334                 :            :         { "tmpfs", tmpfs_dump, tmpfs_restore },
     335                 :            :         { "devpts" },
     336                 :            : };
     337                 :            : 
     338                 :       5466 : struct fstype *find_fstype_by_name(char *fst)
     339                 :            : {
     340                 :            :         int i;
     341                 :            : 
     342                 :            :         /*
     343                 :            :          * This fn is required for two things.
     344                 :            :          * 1st -- to check supported filesystems (as just mounting
     345                 :            :          * anything is wrong, almost every fs has its own features)
     346                 :            :          * 2nd -- save some space in the image (since we scan all
     347                 :            :          * names anyway)
     348                 :            :          */
     349                 :            : 
     350         [ +  + ]:      39907 :         for (i = 0; i < ARRAY_SIZE(fstypes); i++)
     351         [ +  + ]:      34441 :                 if (!strcmp(fstypes[i].name, fst))
     352                 :       1869 :                         return fstypes + i;
     353                 :            : 
     354                 :            :         return &fstypes[0];
     355                 :            : }
     356                 :            : 
     357                 :            : static u32 encode_fstype(struct fstype *fst)
     358                 :            : {
     359                 :        234 :         return fst - fstypes;
     360                 :            : }
     361                 :            : 
     362                 :            : static struct fstype *decode_fstype(u32 fst)
     363                 :            : {
     364                 :            : 
     365         [ +  - ]:        657 :         if (fst >= ARRAY_SIZE(fstypes))
     366                 :            :                 return &fstypes[0];
     367                 :            : 
     368                 :        657 :         return &fstypes[fst];
     369                 :            : }
     370                 :            : 
     371                 :            : static inline int is_root(char *p)
     372                 :            : {
     373 [ -  + ][ +  - ]:        516 :         return p[0] == '/' && p[1] == '\0';
         [ -  + ][ +  - ]
     374                 :            : }
     375                 :            : 
     376                 :            : static inline int is_root_mount(struct mount_info *mi)
     377                 :            : {
     378                 :         77 :         return is_root(mi->mountpoint);
     379                 :            : }
     380                 :            : 
     381                 :        234 : static int dump_one_mountpoint(struct mount_info *pm, int fd)
     382                 :            : {
     383                 :        234 :         MntEntry me = MNT_ENTRY__INIT;
     384                 :            : 
     385                 :        234 :         pr_info("\t%d: %x:%s @ %s\n", pm->mnt_id, pm->s_dev,
     386                 :            :                         pm->root, pm->mountpoint);
     387                 :            : 
     388                 :        468 :         me.fstype               = encode_fstype(pm->fstype);
     389 [ +  - ][ +  + ]:        234 :         if (fstypes[me.fstype].dump && fstypes[me.fstype].dump(pm))
     390                 :            :                 return -1;
     391                 :            : 
     392                 :        234 :         me.mnt_id               = pm->mnt_id;
     393                 :        234 :         me.root_dev             = pm->s_dev;
     394                 :        234 :         me.parent_mnt_id        = pm->parent_mnt_id;
     395                 :        234 :         me.flags                = pm->flags;
     396                 :        234 :         me.root                 = pm->root;
     397                 :        234 :         me.mountpoint           = pm->mountpoint;
     398                 :        234 :         me.source               = pm->source;
     399                 :        234 :         me.options              = pm->options;
     400                 :            : 
     401 [ +  + ][ -  + ]:        311 :         if (!me.fstype && !is_root_mount(pm)) {
     402                 :          0 :                 pr_err("FS mnt %s dev %#x root %s unsupported\n",
     403                 :            :                                 pm->mountpoint, pm->s_dev, pm->root);
     404                 :            :                 return -1;
     405                 :            :         }
     406                 :            : 
     407         [ +  - ]:        234 :         if (pb_write_one(fd, &me, PB_MOUNTPOINTS))
     408                 :            :                 return -1;
     409                 :            : 
     410                 :            :         return 0;
     411                 :            : }
     412                 :            : 
     413                 :         77 : int dump_mnt_ns(int ns_pid, struct cr_fdset *fdset)
     414                 :            : {
     415                 :            :         struct mount_info *pm;
     416                 :            :         int img_fd;
     417                 :            : 
     418                 :         77 :         pm = parse_mountinfo(ns_pid);
     419         [ -  + ]:         77 :         if (!pm) {
     420                 :          0 :                 pr_err("Can't parse %d's mountinfo\n", ns_pid);
     421                 :         77 :                 return -1;
     422                 :            :         }
     423                 :            : 
     424                 :         77 :         pr_info("Dumping mountpoints\n");
     425                 :            : 
     426                 :         77 :         img_fd = fdset_fd(fdset, CR_FD_MOUNTPOINTS);
     427                 :            :         do {
     428                 :        234 :                 struct mount_info *n = pm->next;
     429                 :            : 
     430         [ +  - ]:        234 :                 if (dump_one_mountpoint(pm, img_fd))
     431                 :            :                         return -1;
     432                 :            : 
     433         [ +  - ]:        234 :                 xfree(pm);
     434                 :        234 :                 pm = n;
     435         [ +  + ]:        234 :         } while (pm);
     436                 :            : 
     437                 :            :         return 0;
     438                 :            : }
     439                 :            : 
     440                 :            : #define MNT_TREE_WALK(_mi, _el, _fn_f, _fn_r) do {                              \
     441                 :            :                 while (1) {                                                     \
     442                 :            :                         if (_fn_f(_mi))                                         \
     443                 :            :                                 return -1;                                      \
     444                 :            :                         if (!list_empty(&_mi->children)) {                       \
     445                 :            :                                 _mi = list_entry(_mi->children._el,          \
     446                 :            :                                                 struct mount_info, siblings);   \
     447                 :            :                                 continue;                                       \
     448                 :            :                         }                                                       \
     449                 :            :         up:                                                                     \
     450                 :            :                         if (_fn_r(_mi))                                         \
     451                 :            :                                 return -1;                                      \
     452                 :            :                         if (_mi->parent == NULL)                             \
     453                 :            :                                 return 0;                                       \
     454                 :            :                         if (_mi->siblings._el == &_mi->parent->children) { \
     455                 :            :                                 _mi = _mi->parent;                           \
     456                 :            :                                 goto up;                                        \
     457                 :            :                         }                                                       \
     458                 :            :                         _mi = list_entry(_mi->siblings._el,                  \
     459                 :            :                                         struct mount_info, siblings);           \
     460                 :            :                 }                                                               \
     461                 :            :         } while (0)
     462                 :            : 
     463                 :            : #define MNT_WALK_NONE   0 &&
     464                 :            : 
     465                 :            : 
     466                 :        657 : static int mnt_tree_for_each(struct mount_info *m,
     467                 :            :                 int (*fn)(struct mount_info *))
     468                 :            : {
     469 [ +  - ][ +  + ]:        877 :         MNT_TREE_WALK(m, next, fn, MNT_WALK_NONE);
         [ +  + ][ +  + ]
     470                 :            : }
     471                 :            : 
     472                 :         25 : static int mnt_tree_for_each_reverse(struct mount_info *m,
     473                 :            :                 int (*fn)(struct mount_info *))
     474                 :            : {
     475 [ +  + ][ +  - ]:         30 :         MNT_TREE_WALK(m, prev, MNT_WALK_NONE, fn);
         [ +  + ][ +  + ]
     476                 :            : }
     477                 :            : 
     478                 :        439 : static char *resolve_source(struct mount_info *mi)
     479                 :            : {
     480         [ +  - ]:        439 :         if (kdev_major(mi->s_dev) == 0)
     481                 :            :                 /*
     482                 :            :                  * Anonymous block device. Kernel creates them for
     483                 :            :                  * diskless mounts.
     484                 :            :                  */
     485                 :        439 :                 return mi->source;
     486                 :            : 
     487                 :          0 :         pr_err("No device for %s mount\n", mi->mountpoint);
     488                 :        439 :         return NULL;
     489                 :            : }
     490                 :            : 
     491                 :        439 : static int do_new_mount(struct mount_info *mi)
     492                 :            : {
     493                 :            :         char *src;
     494                 :        439 :         struct fstype *tp = mi->fstype;
     495                 :            : 
     496                 :        439 :         src = resolve_source(mi);
     497         [ +  - ]:        439 :         if (!src)
     498                 :            :                 return -1;
     499                 :            : 
     500         [ -  + ]:        439 :         if (mount(src, mi->mountpoint, tp->name,
     501                 :        439 :                                 mi->flags, mi->options) < 0) {
     502                 :          0 :                 pr_perror("Can't mount at %s", mi->mountpoint);
     503                 :          0 :                 return -1;
     504                 :            :         }
     505                 :            : 
     506 [ +  + ][ +  - ]:        439 :         if (tp->restore && tp->restore(mi))
     507                 :            :                 return -1;
     508                 :            : 
     509                 :            :         return 0;
     510                 :            : }
     511                 :            : 
     512                 :          0 : static int do_bind_mount(struct mount_info *mi)
     513                 :            : {
     514                 :          0 :         pr_err("No bind mounts at %s\n", mi->mountpoint);
     515                 :          0 :         return -1;
     516                 :            : }
     517                 :            : 
     518                 :            : static inline int fsroot_mounted(struct mount_info *mi)
     519                 :            : {
     520                 :        439 :         return is_root(mi->root);
     521                 :            : }
     522                 :            : 
     523                 :        657 : static int do_mount_one(struct mount_info *mi)
     524                 :            : {
     525         [ +  + ]:        657 :         if (!mi->parent)
     526                 :            :                 return 0;
     527                 :            : 
     528                 :        439 :         pr_debug("\tMounting %s @%s\n", mi->fstype->name, mi->mountpoint);
     529                 :            : 
     530         [ +  - ]:        439 :         if (fsroot_mounted(mi))
     531                 :        439 :                 return do_new_mount(mi);
     532                 :            :         else
     533                 :        657 :                 return do_bind_mount(mi);
     534                 :            : }
     535                 :            : 
     536                 :         25 : static int do_umount_one(struct mount_info *mi)
     537                 :            : {
     538         [ +  + ]:         25 :         if (!mi->parent)
     539                 :            :                 return 0;
     540                 :            : 
     541         [ -  + ]:         24 :         if (umount(mi->mountpoint)) {
     542                 :          0 :                 pr_perror("Can't umount at %s", mi->mountpoint);
     543                 :          0 :                 return -1;
     544                 :            :         }
     545                 :            : 
     546                 :         24 :         pr_info("Umounted at %s\n", mi->mountpoint);
     547                 :         25 :         return 0;
     548                 :            : }
     549                 :            : 
     550                 :          1 : static int clean_mnt_ns(void)
     551                 :            : {
     552                 :            :         int ret;
     553                 :            :         struct mount_info *pm;
     554                 :            : 
     555                 :          1 :         pr_info("Cleaning mount namespace\n");
     556                 :            : 
     557                 :            :         /*
     558                 :            :          * Mountinfos were collected at prepare stage
     559                 :            :          */
     560                 :            : 
     561                 :          1 :         pm = mnt_build_tree(mntinfo);
     562         [ +  - ]:          1 :         if (!pm)
     563                 :            :                 return -1;
     564                 :            : 
     565                 :          1 :         ret = mnt_tree_for_each_reverse(pm, do_umount_one);
     566                 :            : 
     567         [ +  + ]:         26 :         while (mntinfo) {
     568                 :         25 :                 pm = mntinfo->next;
     569         [ +  - ]:         25 :                 xfree(mntinfo);
     570                 :         25 :                 mntinfo = pm;
     571                 :            :         }
     572                 :            : 
     573                 :            :         return ret;
     574                 :            : }
     575                 :            : 
     576                 :        217 : static int cr_pivot_root()
     577                 :            : {
     578                 :        217 :         char put_root[] = "crtools-put-root.XXXXXX";
     579                 :            : 
     580                 :        217 :         pr_info("Move the root to %s", opts.root);
     581                 :            : 
     582         [ -  + ]:        217 :         if (chdir(opts.root)) {
     583                 :          0 :                 pr_perror("chdir(%s) failed", opts.root);
     584                 :            :                 return -1;
     585                 :            :         }
     586         [ -  + ]:        217 :         if (mkdtemp(put_root) == NULL) {
     587                 :          0 :                 pr_perror("Can't create a temparary directory");
     588                 :            :                 return -1;
     589                 :            :         }
     590         [ -  + ]:        217 :         if (pivot_root(".", put_root)) {
     591                 :          0 :                 pr_perror("pivot_root(., %s) failed", put_root);
     592         [ #  # ]:          0 :                 if (rmdir(put_root))
     593                 :          0 :                         pr_perror("Can't remove the directory %s", put_root);
     594                 :            :                 return -1;
     595                 :            :         }
     596         [ -  + ]:        217 :         if (umount2(put_root, MNT_DETACH)) {
     597                 :          0 :                 pr_perror("Can't umount %s", put_root);
     598                 :            :                 return -1;
     599                 :            :         }
     600         [ -  + ]:        217 :         if (rmdir(put_root)) {
     601                 :        217 :                 pr_perror("Can't remove the directory %s", put_root);
     602                 :            :                 return -1;
     603                 :            :         }
     604                 :            : 
     605                 :            :         return 0;
     606                 :            : }
     607                 :            : 
     608                 :        218 : static int populate_mnt_ns(int ns_pid)
     609                 :            : {
     610                 :        218 :         MntEntry *me = NULL;
     611                 :            :         int img, ret;
     612                 :        218 :         struct mount_info *pms = NULL;
     613                 :            : 
     614                 :        218 :         pr_info("Populating mount namespace\n");
     615                 :            : 
     616                 :        218 :         img = open_image_ro(CR_FD_MOUNTPOINTS, ns_pid);
     617         [ +  - ]:        218 :         if (img < 0)
     618                 :            :                 return -1;
     619                 :            : 
     620                 :        218 :         pr_debug("Reading mountpoint images\n");
     621                 :            : 
     622                 :            :         while (1) {
     623                 :            :                 struct mount_info *pm;
     624                 :            : 
     625                 :        875 :                 ret = pb_read_one_eof(img, &me, PB_MOUNTPOINTS);
     626         [ +  + ]:        875 :                 if (ret <= 0)
     627                 :            :                         break;
     628                 :            : 
     629                 :        657 :                 ret = -1;
     630         [ -  + ]:        657 :                 pm = xmalloc(sizeof(*pm));
     631         [ +  - ]:        657 :                 if (!pm)
     632                 :            :                         break;
     633                 :            : 
     634                 :            :                 mnt_entry_init(pm);
     635                 :            : 
     636                 :        657 :                 pm->mnt_id           = me->mnt_id;
     637                 :        657 :                 pm->parent_mnt_id    = me->parent_mnt_id;
     638                 :        657 :                 pm->s_dev            = me->root_dev;
     639                 :        657 :                 pm->flags            = me->flags;
     640                 :            : 
     641                 :            :                 /* FIXME: abort unsupported early */
     642                 :       1314 :                 pm->fstype           = decode_fstype(me->fstype);
     643                 :            : 
     644                 :        657 :                 pr_debug("\t\tGetting root for %d\n", pm->mnt_id);
     645         [ -  + ]:        657 :                 pm->root = xstrdup(me->root);
     646         [ +  - ]:        657 :                 if (!pm->root)
     647                 :            :                         goto err;
     648                 :            : 
     649                 :        657 :                 pr_debug("\t\tGetting mpt for %d\n", pm->mnt_id);
     650         [ -  + ]:        657 :                 pm->mountpoint = xstrdup(me->mountpoint);
     651         [ +  - ]:        657 :                 if (!pm->mountpoint)
     652                 :            :                         goto err;
     653                 :            : 
     654                 :        657 :                 pr_debug("\t\tGetting source for %d\n", pm->mnt_id);
     655         [ -  + ]:        657 :                 pm->source = xstrdup(me->source);
     656         [ +  - ]:        657 :                 if (!pm->source)
     657                 :            :                         goto err;
     658                 :            : 
     659                 :        657 :                 pr_debug("\t\tGetting opts for %d\n", pm->mnt_id);
     660         [ -  + ]:        657 :                 pm->options = xstrdup(me->options);
     661         [ +  - ]:        657 :                 if (!pm->options)
     662                 :            :                         goto err;
     663                 :            : 
     664                 :        657 :                 pr_debug("\tRead %d mp @ %s\n", pm->mnt_id, pm->mountpoint);
     665                 :        657 :                 pm->next = pms;
     666                 :        657 :                 pms = pm;
     667                 :        657 :         }
     668                 :            : 
     669         [ -  + ]:        218 :         if (me)
     670                 :          0 :                 mnt_entry__free_unpacked(me, NULL);
     671                 :            : 
     672                 :        218 :         close(img);
     673                 :        218 :         mntinfo = pms;
     674                 :            : 
     675                 :        218 :         pms = mnt_build_tree(pms);
     676         [ +  - ]:        218 :         if (!pms)
     677                 :            :                 return -1;
     678                 :            : 
     679                 :        218 :         return mnt_tree_for_each(pms, do_mount_one);
     680                 :            : err:
     681                 :        218 :         close_safe(&img);
     682                 :            :         return -1;
     683                 :            : }
     684                 :            : 
     685                 :        218 : int prepare_mnt_ns(int ns_pid)
     686                 :            : {
     687                 :            :         int ret;
     688                 :            : 
     689                 :        218 :         pr_info("Restoring mount namespace\n");
     690                 :            : 
     691                 :            :         /*
     692                 :            :          * The new mount namespace is filled with the mountpoint
     693                 :            :          * clones from the original one. We have to umount them
     694                 :            :          * prior to recreating new ones.
     695                 :            :          */
     696                 :            : 
     697         [ +  + ]:        218 :         if (opts.root)
     698                 :        217 :                 ret = cr_pivot_root();
     699                 :            :         else
     700                 :          1 :                 ret = clean_mnt_ns();
     701                 :            : 
     702         [ +  - ]:        218 :         if (!ret)
     703                 :        218 :                 ret = populate_mnt_ns(ns_pid);
     704                 :            : 
     705                 :        218 :         return ret;
     706                 :            : }
     707                 :            : 
     708                 :          0 : void show_mountpoints(int fd, struct cr_options *o)
     709                 :            : {
     710                 :          0 :         pb_show_plain(fd, PB_MOUNTPOINTS);
     711                 :          0 : }
     712                 :            : 
     713                 :        167 : int mntns_collect_root(pid_t pid)
     714                 :            : {
     715                 :            :         int fd, pfd;
     716                 :            :         int ret;
     717                 :            :         char path[PATH_MAX + 1];
     718                 :            : 
     719                 :            :         /*
     720                 :            :          * If /proc/pid/root links on '/', it signs that a root of the task
     721                 :            :          * and a root of mntns is the same.
     722                 :            :          */
     723                 :            : 
     724                 :        167 :         pfd = open_pid_proc(pid);
     725                 :        167 :         ret = readlinkat(pfd, "root", path, sizeof(path) - 1);
     726         [ +  - ]:        167 :         if (ret < 0)
     727                 :            :                 return ret;
     728                 :            : 
     729                 :        167 :         path[ret] = '\0';
     730                 :            : 
     731 [ +  - ][ -  + ]:        167 :         if (ret != 1 || path[0] != '/') {
     732                 :          0 :                 pr_err("The root task has another root than mntns: %s\n", path);
     733                 :          0 :                 close_pid_proc();
     734                 :            :                 return -1;
     735                 :            :         }
     736                 :            : 
     737                 :        167 :         fd = openat(pfd, "root", O_RDONLY | O_DIRECTORY, 0);
     738                 :        167 :         close_pid_proc();
     739         [ -  + ]:        167 :         if (fd < 0) {
     740                 :          0 :                 pr_perror("Can't open the task root");
     741                 :            :                 return -1;
     742                 :            :         }
     743                 :            : 
     744                 :        167 :         mntns_root = fd;
     745                 :            : 
     746                 :            :         return 0;
     747                 :       1140 : }

Generated by: LCOV version 1.9