LCOV - code coverage report
Current view: top level - volatile-root - volatile-root.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 112 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 4 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 132 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <sys/mount.h>
       4                 :            : 
       5                 :            : #include "alloc-util.h"
       6                 :            : #include "blockdev-util.h"
       7                 :            : #include "escape.h"
       8                 :            : #include "fs-util.h"
       9                 :            : #include "main-func.h"
      10                 :            : #include "mkdir.h"
      11                 :            : #include "mount-util.h"
      12                 :            : #include "mountpoint-util.h"
      13                 :            : #include "path-util.h"
      14                 :            : #include "stat-util.h"
      15                 :            : #include "string-util.h"
      16                 :            : #include "volatile-util.h"
      17                 :            : 
      18                 :          0 : static int make_volatile(const char *path) {
      19                 :          0 :         _cleanup_free_ char *old_usr = NULL;
      20                 :            :         int r;
      21                 :            : 
      22         [ #  # ]:          0 :         assert(path);
      23                 :            : 
      24                 :          0 :         r = chase_symlinks("/usr", path, CHASE_PREFIX_ROOT, &old_usr);
      25         [ #  # ]:          0 :         if (r < 0)
      26         [ #  # ]:          0 :                 return log_error_errno(r, "/usr not available in old root: %m");
      27                 :            : 
      28                 :          0 :         r = mkdir_p("/run/systemd/volatile-sysroot", 0700);
      29         [ #  # ]:          0 :         if (r < 0)
      30         [ #  # ]:          0 :                 return log_error_errno(r, "Couldn't generate volatile sysroot directory: %m");
      31                 :            : 
      32                 :          0 :         r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/volatile-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
      33         [ #  # ]:          0 :         if (r < 0)
      34                 :          0 :                 goto finish_rmdir;
      35                 :            : 
      36         [ #  # ]:          0 :         if (mkdir("/run/systemd/volatile-sysroot/usr", 0755) < 0) {
      37         [ #  # ]:          0 :                 r = log_error_errno(errno, "Failed to create /usr directory: %m");
      38                 :          0 :                 goto finish_umount;
      39                 :            :         }
      40                 :            : 
      41                 :          0 :         r = mount_verbose(LOG_ERR, old_usr, "/run/systemd/volatile-sysroot/usr", NULL, MS_BIND|MS_REC, NULL);
      42         [ #  # ]:          0 :         if (r < 0)
      43                 :          0 :                 goto finish_umount;
      44                 :            : 
      45                 :          0 :         r = bind_remount_recursive("/run/systemd/volatile-sysroot/usr", MS_RDONLY, MS_RDONLY, NULL);
      46         [ #  # ]:          0 :         if (r < 0) {
      47         [ #  # ]:          0 :                 log_error_errno(r, "Failed to remount /usr read-only: %m");
      48                 :          0 :                 goto finish_umount;
      49                 :            :         }
      50                 :            : 
      51                 :          0 :         r = umount_recursive(path, 0);
      52         [ #  # ]:          0 :         if (r < 0) {
      53         [ #  # ]:          0 :                 log_error_errno(r, "Failed to unmount %s: %m", path);
      54                 :          0 :                 goto finish_umount;
      55                 :            :         }
      56                 :            : 
      57         [ #  # ]:          0 :         if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
      58         [ #  # ]:          0 :                 log_warning_errno(errno, "Failed to remount %s MS_SLAVE|MS_REC, ignoring: %m", path);
      59                 :            : 
      60                 :          0 :         r = mount_verbose(LOG_ERR, "/run/systemd/volatile-sysroot", path, NULL, MS_MOVE, NULL);
      61                 :            : 
      62                 :          0 : finish_umount:
      63                 :          0 :         (void) umount_recursive("/run/systemd/volatile-sysroot", 0);
      64                 :            : 
      65                 :          0 : finish_rmdir:
      66                 :          0 :         (void) rmdir("/run/systemd/volatile-sysroot");
      67                 :            : 
      68                 :          0 :         return r;
      69                 :            : }
      70                 :            : 
      71                 :          0 : static int make_overlay(const char *path) {
      72                 :          0 :         _cleanup_free_ char *escaped_path = NULL;
      73                 :          0 :         bool tmpfs_mounted = false;
      74                 :          0 :         const char *options = NULL;
      75                 :            :         int r;
      76                 :            : 
      77         [ #  # ]:          0 :         assert(path);
      78                 :            : 
      79                 :          0 :         r = mkdir_p("/run/systemd/overlay-sysroot", 0700);
      80         [ #  # ]:          0 :         if (r < 0)
      81         [ #  # ]:          0 :                 return log_error_errno(r, "Couldn't create overlay sysroot directory: %m");
      82                 :            : 
      83                 :          0 :         r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/overlay-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
      84         [ #  # ]:          0 :         if (r < 0)
      85                 :          0 :                 goto finish;
      86                 :            : 
      87                 :          0 :         tmpfs_mounted = true;
      88                 :            : 
      89         [ #  # ]:          0 :         if (mkdir("/run/systemd/overlay-sysroot/upper", 0755) < 0) {
      90         [ #  # ]:          0 :                 r = log_error_errno(errno, "Failed to create /run/systemd/overlay-sysroot/upper: %m");
      91                 :          0 :                 goto finish;
      92                 :            :         }
      93                 :            : 
      94         [ #  # ]:          0 :         if (mkdir("/run/systemd/overlay-sysroot/work", 0755) < 0) {
      95         [ #  # ]:          0 :                 r = log_error_errno(errno, "Failed to create /run/systemd/overlay-sysroot/work: %m");
      96                 :          0 :                 goto finish;
      97                 :            :         }
      98                 :            : 
      99                 :          0 :         escaped_path = shell_escape(path, ",:");
     100         [ #  # ]:          0 :         if (!escaped_path) {
     101                 :          0 :                 r = log_oom();
     102                 :          0 :                 goto finish;
     103                 :            :         }
     104                 :            : 
     105   [ #  #  #  #  :          0 :         options = strjoina("lowerdir=", escaped_path, ",upperdir=/run/systemd/overlay-sysroot/upper,workdir=/run/systemd/overlay-sysroot/work");
          #  #  #  #  #  
                #  #  # ]
     106                 :          0 :         r = mount_verbose(LOG_ERR, "overlay", path, "overlay", 0, options);
     107                 :            : 
     108                 :          0 : finish:
     109         [ #  # ]:          0 :         if (tmpfs_mounted)
     110                 :          0 :                 (void) umount_verbose("/run/systemd/overlay-sysroot");
     111                 :            : 
     112                 :          0 :         (void) rmdir("/run/systemd/overlay-sysroot");
     113                 :          0 :         return r;
     114                 :            : }
     115                 :            : 
     116                 :          0 : static int run(int argc, char *argv[]) {
     117                 :          0 :         VolatileMode m = _VOLATILE_MODE_INVALID;
     118                 :            :         const char *path;
     119                 :            :         dev_t devt;
     120                 :            :         int r;
     121                 :            : 
     122                 :          0 :         log_setup_service();
     123                 :            : 
     124         [ #  # ]:          0 :         if (argc > 3)
     125         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     126                 :            :                                        "Too many arguments. Expected directory and mode.");
     127                 :            : 
     128                 :          0 :         r = query_volatile_mode(&m);
     129         [ #  # ]:          0 :         if (r < 0)
     130         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to determine volatile mode from kernel command line.");
     131   [ #  #  #  # ]:          0 :         if (r == 0 && argc >= 2) {
     132                 :            :                 /* The kernel command line always wins. However if nothing was set there, the argument passed here wins instead. */
     133                 :          0 :                 m = volatile_mode_from_string(argv[1]);
     134         [ #  # ]:          0 :                 if (m < 0)
     135         [ #  # ]:          0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Couldn't parse volatile mode: %s", argv[1]);
     136                 :            :         }
     137                 :            : 
     138         [ #  # ]:          0 :         if (argc < 3)
     139                 :          0 :                 path = "/sysroot";
     140                 :            :         else {
     141                 :          0 :                 path = argv[2];
     142                 :            : 
     143         [ #  # ]:          0 :                 if (isempty(path))
     144         [ #  # ]:          0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     145                 :            :                                                "Directory name cannot be empty.");
     146         [ #  # ]:          0 :                 if (!path_is_absolute(path))
     147         [ #  # ]:          0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     148                 :            :                                                "Directory must be specified as absolute path.");
     149         [ #  # ]:          0 :                 if (path_equal(path, "/"))
     150         [ #  # ]:          0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     151                 :            :                                                "Directory cannot be the root directory.");
     152                 :            :         }
     153                 :            : 
     154   [ #  #  #  # ]:          0 :         if (!IN_SET(m, VOLATILE_YES, VOLATILE_OVERLAY))
     155                 :          0 :                 return 0;
     156                 :            : 
     157                 :          0 :         r = path_is_mount_point(path, NULL, AT_SYMLINK_FOLLOW);
     158         [ #  # ]:          0 :         if (r < 0)
     159         [ #  # ]:          0 :                 return log_error_errno(r, "Couldn't determine whether %s is a mount point: %m", path);
     160         [ #  # ]:          0 :         if (r == 0)
     161         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s is not a mount point.", path);
     162                 :            : 
     163                 :          0 :         r = path_is_temporary_fs(path);
     164         [ #  # ]:          0 :         if (r < 0)
     165         [ #  # ]:          0 :                 return log_error_errno(r, "Couldn't determine whether %s is a temporary file system: %m", path);
     166         [ #  # ]:          0 :         if (r > 0) {
     167         [ #  # ]:          0 :                 log_info("%s already is a temporary file system.", path);
     168                 :          0 :                 return 0;
     169                 :            :         }
     170                 :            : 
     171                 :            :         /* We are about to replace the root directory with something else. Later code might want to know what we
     172                 :            :          * replaced here, hence let's save that information as a symlink we can later use. (This is particularly
     173                 :            :          * relevant for the overlayfs case where we'll fully obstruct the view onto the underlying device, hence
     174                 :            :          * querying the backing device node from the file system directly is no longer possible. */
     175                 :          0 :         r = get_block_device_harder(path, &devt);
     176         [ #  # ]:          0 :         if (r < 0)
     177         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to determine device major/minor of %s: %m", path);
     178         [ #  # ]:          0 :         else if (r > 0) {
     179         [ #  # ]:          0 :                 _cleanup_free_ char *dn = NULL;
     180                 :            : 
     181                 :          0 :                 r = device_path_make_major_minor(S_IFBLK, devt, &dn);
     182         [ #  # ]:          0 :                 if (r < 0)
     183         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to format device node path: %m");
     184                 :            : 
     185         [ #  # ]:          0 :                 if (symlink(dn, "/run/systemd/volatile-root") < 0)
     186         [ #  # ]:          0 :                         log_warning_errno(errno, "Failed to create symlink /run/systemd/volatile-root: %m");
     187                 :            :         }
     188                 :            : 
     189         [ #  # ]:          0 :         if (m == VOLATILE_YES)
     190                 :          0 :                 return make_volatile(path);
     191                 :            :         else {
     192         [ #  # ]:          0 :                 assert(m == VOLATILE_OVERLAY);
     193                 :          0 :                 return make_overlay(path);
     194                 :            :         }
     195                 :            : }
     196                 :            : 
     197                 :          0 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14