LCOV - code coverage report
Current view: top level - shared - machine-image.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 1 662 0.2 %
Date: 2019-08-22 15:41:25 Functions: 2 27 7.4 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <dirent.h>
       4             : #include <errno.h>
       5             : #include <fcntl.h>
       6             : #include <stdio.h>
       7             : #include <stdlib.h>
       8             : #include <string.h>
       9             : #include <sys/file.h>
      10             : #include <sys/ioctl.h>
      11             : #include <sys/stat.h>
      12             : #include <unistd.h>
      13             : #include <linux/fs.h>
      14             : 
      15             : #include "alloc-util.h"
      16             : #include "btrfs-util.h"
      17             : #include "chattr-util.h"
      18             : #include "copy.h"
      19             : #include "dirent-util.h"
      20             : #include "dissect-image.h"
      21             : #include "env-file.h"
      22             : #include "env-util.h"
      23             : #include "fd-util.h"
      24             : #include "fs-util.h"
      25             : #include "hashmap.h"
      26             : #include "hostname-util.h"
      27             : #include "id128-util.h"
      28             : #include "lockfile-util.h"
      29             : #include "log.h"
      30             : #include "loop-util.h"
      31             : #include "machine-image.h"
      32             : #include "macro.h"
      33             : #include "mkdir.h"
      34             : #include "nulstr-util.h"
      35             : #include "os-util.h"
      36             : #include "path-util.h"
      37             : #include "rm-rf.h"
      38             : #include "string-table.h"
      39             : #include "string-util.h"
      40             : #include "strv.h"
      41             : #include "time-util.h"
      42             : #include "utf8.h"
      43             : #include "xattr-util.h"
      44             : 
      45             : static const char* const image_search_path[_IMAGE_CLASS_MAX] = {
      46             :         [IMAGE_MACHINE] =  "/etc/machines\0"              /* only place symlinks here */
      47             :                            "/run/machines\0"              /* and here too */
      48             :                            "/var/lib/machines\0"          /* the main place for images */
      49             :                            "/var/lib/container\0"         /* legacy */
      50             :                            "/usr/local/lib/machines\0"
      51             :                            "/usr/lib/machines\0",
      52             : 
      53             :         [IMAGE_PORTABLE] = "/etc/portables\0"             /* only place symlinks here */
      54             :                            "/run/portables\0"             /* and here too */
      55             :                            "/var/lib/portables\0"         /* the main place for images */
      56             :                            "/usr/local/lib/portables\0"
      57             :                            "/usr/lib/portables\0",
      58             : };
      59             : 
      60           0 : static Image *image_free(Image *i) {
      61           0 :         assert(i);
      62             : 
      63           0 :         free(i->name);
      64           0 :         free(i->path);
      65             : 
      66           0 :         free(i->hostname);
      67           0 :         strv_free(i->machine_info);
      68           0 :         strv_free(i->os_release);
      69             : 
      70           0 :         return mfree(i);
      71             : }
      72             : 
      73           0 : DEFINE_TRIVIAL_REF_UNREF_FUNC(Image, image, image_free);
      74           0 : DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(image_hash_ops, char, string_hash_func, string_compare_func,
      75             :                                       Image, image_unref);
      76             : 
      77           0 : static char **image_settings_path(Image *image) {
      78           0 :         _cleanup_strv_free_ char **l = NULL;
      79             :         const char *fn, *s;
      80           0 :         unsigned i = 0;
      81             : 
      82           0 :         assert(image);
      83             : 
      84           0 :         l = new0(char*, 4);
      85           0 :         if (!l)
      86           0 :                 return NULL;
      87             : 
      88           0 :         fn = strjoina(image->name, ".nspawn");
      89             : 
      90           0 :         FOREACH_STRING(s, "/etc/systemd/nspawn", "/run/systemd/nspawn") {
      91           0 :                 l[i] = path_join(s, fn);
      92           0 :                 if (!l[i])
      93           0 :                         return NULL;
      94             : 
      95           0 :                 i++;
      96             :         }
      97             : 
      98           0 :         l[i] = file_in_same_dir(image->path, fn);
      99           0 :         if (!l[i])
     100           0 :                 return NULL;
     101             : 
     102           0 :         return TAKE_PTR(l);
     103             : }
     104             : 
     105           0 : static char *image_roothash_path(Image *image) {
     106             :         const char *fn;
     107             : 
     108           0 :         assert(image);
     109             : 
     110           0 :         fn = strjoina(image->name, ".roothash");
     111             : 
     112           0 :         return file_in_same_dir(image->path, fn);
     113             : }
     114             : 
     115           0 : static int image_new(
     116             :                 ImageType t,
     117             :                 const char *pretty,
     118             :                 const char *path,
     119             :                 const char *filename,
     120             :                 bool read_only,
     121             :                 usec_t crtime,
     122             :                 usec_t mtime,
     123             :                 Image **ret) {
     124             : 
     125           0 :         _cleanup_(image_unrefp) Image *i = NULL;
     126             : 
     127           0 :         assert(t >= 0);
     128           0 :         assert(t < _IMAGE_TYPE_MAX);
     129           0 :         assert(pretty);
     130           0 :         assert(filename);
     131           0 :         assert(ret);
     132             : 
     133           0 :         i = new0(Image, 1);
     134           0 :         if (!i)
     135           0 :                 return -ENOMEM;
     136             : 
     137           0 :         i->n_ref = 1;
     138           0 :         i->type = t;
     139           0 :         i->read_only = read_only;
     140           0 :         i->crtime = crtime;
     141           0 :         i->mtime = mtime;
     142           0 :         i->usage = i->usage_exclusive = (uint64_t) -1;
     143           0 :         i->limit = i->limit_exclusive = (uint64_t) -1;
     144             : 
     145           0 :         i->name = strdup(pretty);
     146           0 :         if (!i->name)
     147           0 :                 return -ENOMEM;
     148             : 
     149           0 :         i->path = path_join(path, filename);
     150           0 :         if (!i->path)
     151           0 :                 return -ENOMEM;
     152             : 
     153           0 :         path_simplify(i->path, false);
     154             : 
     155           0 :         *ret = TAKE_PTR(i);
     156             : 
     157           0 :         return 0;
     158             : }
     159             : 
     160           0 : static int extract_pretty(const char *path, const char *suffix, char **ret) {
     161           0 :         _cleanup_free_ char *name = NULL;
     162             :         const char *p;
     163             :         size_t n;
     164             : 
     165           0 :         assert(path);
     166           0 :         assert(ret);
     167             : 
     168           0 :         p = last_path_component(path);
     169           0 :         n = strcspn(p, "/");
     170             : 
     171           0 :         name = strndup(p, n);
     172           0 :         if (!name)
     173           0 :                 return -ENOMEM;
     174             : 
     175           0 :         if (suffix) {
     176             :                 char *e;
     177             : 
     178           0 :                 e = endswith(name, suffix);
     179           0 :                 if (!e)
     180           0 :                         return -EINVAL;
     181             : 
     182           0 :                 *e = 0;
     183             :         }
     184             : 
     185           0 :         if (!image_name_is_valid(name))
     186           0 :                 return -EINVAL;
     187             : 
     188           0 :         *ret = TAKE_PTR(name);
     189           0 :         return 0;
     190             : }
     191             : 
     192           0 : static int image_make(
     193             :                 const char *pretty,
     194             :                 int dfd,
     195             :                 const char *path,
     196             :                 const char *filename,
     197             :                 const struct stat *st,
     198             :                 Image **ret) {
     199             : 
     200           0 :         _cleanup_free_ char *pretty_buffer = NULL, *parent = NULL;
     201             :         struct stat stbuf;
     202             :         bool read_only;
     203             :         int r;
     204             : 
     205           0 :         assert(dfd >= 0 || dfd == AT_FDCWD);
     206           0 :         assert(path || dfd == AT_FDCWD);
     207           0 :         assert(filename);
     208             : 
     209             :         /* We explicitly *do* follow symlinks here, since we want to allow symlinking trees, raw files and block
     210             :          * devices into /var/lib/machines/, and treat them normally.
     211             :          *
     212             :          * This function returns -ENOENT if we can't find the image after all, and -EMEDIUMTYPE if it's not a file we
     213             :          * recognize. */
     214             : 
     215           0 :         if (!st) {
     216           0 :                 if (fstatat(dfd, filename, &stbuf, 0) < 0)
     217           0 :                         return -errno;
     218             : 
     219           0 :                 st = &stbuf;
     220             :         }
     221             : 
     222           0 :         if (!path) {
     223           0 :                 if (dfd == AT_FDCWD)
     224           0 :                         (void) safe_getcwd(&parent);
     225             :                 else
     226           0 :                         (void) fd_get_path(dfd, &parent);
     227             :         }
     228             : 
     229           0 :         read_only =
     230           0 :                 (path && path_startswith(path, "/usr")) ||
     231           0 :                 (faccessat(dfd, filename, W_OK, AT_EACCESS) < 0 && errno == EROFS);
     232             : 
     233           0 :         if (S_ISDIR(st->st_mode)) {
     234           0 :                 _cleanup_close_ int fd = -1;
     235           0 :                 unsigned file_attr = 0;
     236             : 
     237           0 :                 if (!ret)
     238           0 :                         return 0;
     239             : 
     240           0 :                 if (!pretty) {
     241           0 :                         r = extract_pretty(filename, NULL, &pretty_buffer);
     242           0 :                         if (r < 0)
     243           0 :                                 return r;
     244             : 
     245           0 :                         pretty = pretty_buffer;
     246             :                 }
     247             : 
     248           0 :                 fd = openat(dfd, filename, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
     249           0 :                 if (fd < 0)
     250           0 :                         return -errno;
     251             : 
     252             :                 /* btrfs subvolumes have inode 256 */
     253           0 :                 if (st->st_ino == 256) {
     254             : 
     255           0 :                         r = btrfs_is_filesystem(fd);
     256           0 :                         if (r < 0)
     257           0 :                                 return r;
     258           0 :                         if (r) {
     259             :                                 BtrfsSubvolInfo info;
     260             : 
     261             :                                 /* It's a btrfs subvolume */
     262             : 
     263           0 :                                 r = btrfs_subvol_get_info_fd(fd, 0, &info);
     264           0 :                                 if (r < 0)
     265           0 :                                         return r;
     266             : 
     267           0 :                                 r = image_new(IMAGE_SUBVOLUME,
     268             :                                               pretty,
     269             :                                               path,
     270             :                                               filename,
     271           0 :                                               info.read_only || read_only,
     272             :                                               info.otime,
     273             :                                               0,
     274             :                                               ret);
     275           0 :                                 if (r < 0)
     276           0 :                                         return r;
     277             : 
     278           0 :                                 if (btrfs_quota_scan_ongoing(fd) == 0) {
     279             :                                         BtrfsQuotaInfo quota;
     280             : 
     281           0 :                                         r = btrfs_subvol_get_subtree_quota_fd(fd, 0, &quota);
     282           0 :                                         if (r >= 0) {
     283           0 :                                                 (*ret)->usage = quota.referenced;
     284           0 :                                                 (*ret)->usage_exclusive = quota.exclusive;
     285             : 
     286           0 :                                                 (*ret)->limit = quota.referenced_max;
     287           0 :                                                 (*ret)->limit_exclusive = quota.exclusive_max;
     288             :                                         }
     289             :                                 }
     290             : 
     291           0 :                                 return 0;
     292             :                         }
     293             :                 }
     294             : 
     295             :                 /* If the IMMUTABLE bit is set, we consider the
     296             :                  * directory read-only. Since the ioctl is not
     297             :                  * supported everywhere we ignore failures. */
     298           0 :                 (void) read_attr_fd(fd, &file_attr);
     299             : 
     300             :                 /* It's just a normal directory. */
     301           0 :                 r = image_new(IMAGE_DIRECTORY,
     302             :                               pretty,
     303             :                               path,
     304             :                               filename,
     305           0 :                               read_only || (file_attr & FS_IMMUTABLE_FL),
     306             :                               0,
     307             :                               0,
     308             :                               ret);
     309           0 :                 if (r < 0)
     310           0 :                         return r;
     311             : 
     312           0 :                 return 0;
     313             : 
     314           0 :         } else if (S_ISREG(st->st_mode) && endswith(filename, ".raw")) {
     315           0 :                 usec_t crtime = 0;
     316             : 
     317             :                 /* It's a RAW disk image */
     318             : 
     319           0 :                 if (!ret)
     320           0 :                         return 0;
     321             : 
     322           0 :                 (void) fd_getcrtime_at(dfd, filename, &crtime, 0);
     323             : 
     324           0 :                 if (!pretty) {
     325           0 :                         r = extract_pretty(filename, ".raw", &pretty_buffer);
     326           0 :                         if (r < 0)
     327           0 :                                 return r;
     328             : 
     329           0 :                         pretty = pretty_buffer;
     330             :                 }
     331             : 
     332           0 :                 r = image_new(IMAGE_RAW,
     333             :                               pretty,
     334             :                               path,
     335             :                               filename,
     336           0 :                               !(st->st_mode & 0222) || read_only,
     337             :                               crtime,
     338             :                               timespec_load(&st->st_mtim),
     339             :                               ret);
     340           0 :                 if (r < 0)
     341           0 :                         return r;
     342             : 
     343           0 :                 (*ret)->usage = (*ret)->usage_exclusive = st->st_blocks * 512;
     344           0 :                 (*ret)->limit = (*ret)->limit_exclusive = st->st_size;
     345             : 
     346           0 :                 return 0;
     347             : 
     348           0 :         } else if (S_ISBLK(st->st_mode)) {
     349           0 :                 _cleanup_close_ int block_fd = -1;
     350           0 :                 uint64_t size = UINT64_MAX;
     351             : 
     352             :                 /* A block device */
     353             : 
     354           0 :                 if (!ret)
     355           0 :                         return 0;
     356             : 
     357           0 :                 if (!pretty) {
     358           0 :                         r = extract_pretty(filename, NULL, &pretty_buffer);
     359           0 :                         if (r < 0)
     360           0 :                                 return r;
     361             : 
     362           0 :                         pretty = pretty_buffer;
     363             :                 }
     364             : 
     365           0 :                 block_fd = openat(dfd, filename, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
     366           0 :                 if (block_fd < 0)
     367           0 :                         log_debug_errno(errno, "Failed to open block device %s/%s, ignoring: %m", path ?: strnull(parent), filename);
     368             :                 else {
     369             :                         /* Refresh stat data after opening the node */
     370           0 :                         if (fstat(block_fd, &stbuf) < 0)
     371           0 :                                 return -errno;
     372           0 :                         st = &stbuf;
     373             : 
     374           0 :                         if (!S_ISBLK(st->st_mode)) /* Verify that what we opened is actually what we think it is */
     375           0 :                                 return -ENOTTY;
     376             : 
     377           0 :                         if (!read_only) {
     378           0 :                                 int state = 0;
     379             : 
     380           0 :                                 if (ioctl(block_fd, BLKROGET, &state) < 0)
     381           0 :                                         log_debug_errno(errno, "Failed to issue BLKROGET on device %s/%s, ignoring: %m", path ?: strnull(parent), filename);
     382           0 :                                 else if (state)
     383           0 :                                         read_only = true;
     384             :                         }
     385             : 
     386           0 :                         if (ioctl(block_fd, BLKGETSIZE64, &size) < 0)
     387           0 :                                 log_debug_errno(errno, "Failed to issue BLKGETSIZE64 on device %s/%s, ignoring: %m", path ?: strnull(parent), filename);
     388             : 
     389           0 :                         block_fd = safe_close(block_fd);
     390             :                 }
     391             : 
     392           0 :                 r = image_new(IMAGE_BLOCK,
     393             :                               pretty,
     394             :                               path,
     395             :                               filename,
     396           0 :                               !(st->st_mode & 0222) || read_only,
     397             :                               0,
     398             :                               0,
     399             :                               ret);
     400           0 :                 if (r < 0)
     401           0 :                         return r;
     402             : 
     403           0 :                 if (!IN_SET(size, 0, UINT64_MAX))
     404           0 :                         (*ret)->usage = (*ret)->usage_exclusive = (*ret)->limit = (*ret)->limit_exclusive = size;
     405             : 
     406           0 :                 return 0;
     407             :         }
     408             : 
     409           0 :         return -EMEDIUMTYPE;
     410             : }
     411             : 
     412           0 : int image_find(ImageClass class, const char *name, Image **ret) {
     413             :         const char *path;
     414             :         int r;
     415             : 
     416           0 :         assert(class >= 0);
     417           0 :         assert(class < _IMAGE_CLASS_MAX);
     418           0 :         assert(name);
     419             : 
     420             :         /* There are no images with invalid names */
     421           0 :         if (!image_name_is_valid(name))
     422           0 :                 return -ENOENT;
     423             : 
     424           0 :         NULSTR_FOREACH(path, image_search_path[class]) {
     425           0 :                 _cleanup_closedir_ DIR *d = NULL;
     426             :                 struct stat st;
     427             : 
     428           0 :                 d = opendir(path);
     429           0 :                 if (!d) {
     430           0 :                         if (errno == ENOENT)
     431           0 :                                 continue;
     432             : 
     433           0 :                         return -errno;
     434             :                 }
     435             : 
     436             :                 /* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people to
     437             :                  * symlink block devices into the search path */
     438           0 :                 if (fstatat(dirfd(d), name, &st, 0) < 0) {
     439           0 :                         _cleanup_free_ char *raw = NULL;
     440             : 
     441           0 :                         if (errno != ENOENT)
     442           0 :                                 return -errno;
     443             : 
     444           0 :                         raw = strjoin(name, ".raw");
     445           0 :                         if (!raw)
     446           0 :                                 return -ENOMEM;
     447             : 
     448           0 :                         if (fstatat(dirfd(d), raw, &st, 0) < 0) {
     449             : 
     450           0 :                                 if (errno == ENOENT)
     451           0 :                                         continue;
     452             : 
     453           0 :                                 return -errno;
     454             :                         }
     455             : 
     456           0 :                         if (!S_ISREG(st.st_mode))
     457           0 :                                 continue;
     458             : 
     459           0 :                         r = image_make(name, dirfd(d), path, raw, &st, ret);
     460             : 
     461             :                 } else {
     462           0 :                         if (!S_ISDIR(st.st_mode) && !S_ISBLK(st.st_mode))
     463           0 :                                 continue;
     464             : 
     465           0 :                         r = image_make(name, dirfd(d), path, name, &st, ret);
     466             :                 }
     467           0 :                 if (IN_SET(r, -ENOENT, -EMEDIUMTYPE))
     468           0 :                         continue;
     469           0 :                 if (r < 0)
     470           0 :                         return r;
     471             : 
     472           0 :                 if (ret)
     473           0 :                         (*ret)->discoverable = true;
     474             : 
     475           0 :                 return 1;
     476             :         }
     477             : 
     478           0 :         if (class == IMAGE_MACHINE && streq(name, ".host")) {
     479           0 :                 r = image_make(".host", AT_FDCWD, NULL, "/", NULL, ret);
     480           0 :                 if (r < 0)
     481           0 :                         return r;
     482             : 
     483           0 :                 if (ret)
     484           0 :                         (*ret)->discoverable = true;
     485             : 
     486           0 :                 return r;
     487             :         }
     488             : 
     489           0 :         return -ENOENT;
     490             : };
     491             : 
     492           0 : int image_from_path(const char *path, Image **ret) {
     493             : 
     494             :         /* Note that we don't set the 'discoverable' field of the returned object, because we don't check here whether
     495             :          * the image is in the image search path. And if it is we don't know if the path we used is actually not
     496             :          * overridden by another, different image earlier in the search path */
     497             : 
     498           0 :         if (path_equal(path, "/"))
     499           0 :                 return image_make(".host", AT_FDCWD, NULL, "/", NULL, ret);
     500             : 
     501           0 :         return image_make(NULL, AT_FDCWD, NULL, path, NULL, ret);
     502             : }
     503             : 
     504           0 : int image_find_harder(ImageClass class, const char *name_or_path, Image **ret) {
     505           0 :         if (image_name_is_valid(name_or_path))
     506           0 :                 return image_find(class, name_or_path, ret);
     507             : 
     508           0 :         return image_from_path(name_or_path, ret);
     509             : }
     510             : 
     511           0 : int image_discover(ImageClass class, Hashmap *h) {
     512             :         const char *path;
     513             :         int r;
     514             : 
     515           0 :         assert(class >= 0);
     516           0 :         assert(class < _IMAGE_CLASS_MAX);
     517           0 :         assert(h);
     518             : 
     519           0 :         NULSTR_FOREACH(path, image_search_path[class]) {
     520           0 :                 _cleanup_closedir_ DIR *d = NULL;
     521             :                 struct dirent *de;
     522             : 
     523           0 :                 d = opendir(path);
     524           0 :                 if (!d) {
     525           0 :                         if (errno == ENOENT)
     526           0 :                                 continue;
     527             : 
     528           0 :                         return -errno;
     529             :                 }
     530             : 
     531           0 :                 FOREACH_DIRENT_ALL(de, d, return -errno) {
     532           0 :                         _cleanup_(image_unrefp) Image *image = NULL;
     533           0 :                         _cleanup_free_ char *truncated = NULL;
     534             :                         const char *pretty;
     535             :                         struct stat st;
     536             : 
     537           0 :                         if (dot_or_dot_dot(de->d_name))
     538           0 :                                 continue;
     539             : 
     540             :                         /* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people
     541             :                          * to symlink block devices into the search path */
     542           0 :                         if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) {
     543           0 :                                 if (errno == ENOENT)
     544           0 :                                         continue;
     545             : 
     546           0 :                                 return -errno;
     547             :                         }
     548             : 
     549           0 :                         if (S_ISREG(st.st_mode)) {
     550             :                                 const char *e;
     551             : 
     552           0 :                                 e = endswith(de->d_name, ".raw");
     553           0 :                                 if (!e)
     554           0 :                                         continue;
     555             : 
     556           0 :                                 truncated = strndup(de->d_name, e - de->d_name);
     557           0 :                                 if (!truncated)
     558           0 :                                         return -ENOMEM;
     559             : 
     560           0 :                                 pretty = truncated;
     561           0 :                         } else if (S_ISDIR(st.st_mode) || S_ISBLK(st.st_mode))
     562           0 :                                 pretty = de->d_name;
     563             :                         else
     564           0 :                                 continue;
     565             : 
     566           0 :                         if (!image_name_is_valid(pretty))
     567           0 :                                 continue;
     568             : 
     569           0 :                         if (hashmap_contains(h, pretty))
     570           0 :                                 continue;
     571             : 
     572           0 :                         r = image_make(pretty, dirfd(d), path, de->d_name, &st, &image);
     573           0 :                         if (IN_SET(r, -ENOENT, -EMEDIUMTYPE))
     574           0 :                                 continue;
     575           0 :                         if (r < 0)
     576           0 :                                 return r;
     577             : 
     578           0 :                         image->discoverable = true;
     579             : 
     580           0 :                         r = hashmap_put(h, image->name, image);
     581           0 :                         if (r < 0)
     582           0 :                                 return r;
     583             : 
     584           0 :                         image = NULL;
     585             :                 }
     586             :         }
     587             : 
     588           0 :         if (class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) {
     589           0 :                 _cleanup_(image_unrefp) Image *image = NULL;
     590             : 
     591           0 :                 r = image_make(".host", AT_FDCWD, NULL, "/", NULL, &image);
     592           0 :                 if (r < 0)
     593           0 :                         return r;
     594             : 
     595           0 :                 image->discoverable = true;
     596             : 
     597           0 :                 r = hashmap_put(h, image->name, image);
     598           0 :                 if (r < 0)
     599           0 :                         return r;
     600             : 
     601           0 :                 image = NULL;
     602             :         }
     603             : 
     604           0 :         return 0;
     605             : }
     606             : 
     607           0 : int image_remove(Image *i) {
     608           0 :         _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
     609           0 :         _cleanup_strv_free_ char **settings = NULL;
     610           0 :         _cleanup_free_ char *roothash = NULL;
     611             :         char **j;
     612             :         int r;
     613             : 
     614           0 :         assert(i);
     615             : 
     616           0 :         if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
     617           0 :                 return -EROFS;
     618             : 
     619           0 :         settings = image_settings_path(i);
     620           0 :         if (!settings)
     621           0 :                 return -ENOMEM;
     622             : 
     623           0 :         roothash = image_roothash_path(i);
     624           0 :         if (!roothash)
     625           0 :                 return -ENOMEM;
     626             : 
     627             :         /* Make sure we don't interfere with a running nspawn */
     628           0 :         r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
     629           0 :         if (r < 0)
     630           0 :                 return r;
     631             : 
     632           0 :         switch (i->type) {
     633             : 
     634           0 :         case IMAGE_SUBVOLUME:
     635             : 
     636             :                 /* Let's unlink first, maybe it is a symlink? If that works we are happy. Otherwise, let's get out the
     637             :                  * big guns */
     638           0 :                 if (unlink(i->path) < 0) {
     639           0 :                         r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
     640           0 :                         if (r < 0)
     641           0 :                                 return r;
     642             :                 }
     643             : 
     644           0 :                 break;
     645             : 
     646           0 :         case IMAGE_DIRECTORY:
     647             :                 /* Allow deletion of read-only directories */
     648           0 :                 (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL, NULL);
     649           0 :                 r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
     650           0 :                 if (r < 0)
     651           0 :                         return r;
     652             : 
     653           0 :                 break;
     654             : 
     655           0 :         case IMAGE_BLOCK:
     656             : 
     657             :                 /* If this is inside of /dev, then it's a real block device, hence let's not touch the device node
     658             :                  * itself (but let's remove the stuff stored alongside it). If it's anywhere else, let's try to unlink
     659             :                  * the thing (it's most likely a symlink after all). */
     660             : 
     661           0 :                 if (path_startswith(i->path, "/dev"))
     662           0 :                         break;
     663             : 
     664             :                 _fallthrough_;
     665             :         case IMAGE_RAW:
     666           0 :                 if (unlink(i->path) < 0)
     667           0 :                         return -errno;
     668           0 :                 break;
     669             : 
     670           0 :         default:
     671           0 :                 return -EOPNOTSUPP;
     672             :         }
     673             : 
     674           0 :         STRV_FOREACH(j, settings) {
     675           0 :                 if (unlink(*j) < 0 && errno != ENOENT)
     676           0 :                         log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", *j);
     677             :         }
     678             : 
     679           0 :         if (unlink(roothash) < 0 && errno != ENOENT)
     680           0 :                 log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", roothash);
     681             : 
     682           0 :         return 0;
     683             : }
     684             : 
     685           0 : static int rename_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
     686           0 :         _cleanup_free_ char *rs = NULL;
     687             :         const char *fn;
     688             : 
     689           0 :         fn = strjoina(new_name, suffix);
     690             : 
     691           0 :         rs = file_in_same_dir(path, fn);
     692           0 :         if (!rs)
     693           0 :                 return -ENOMEM;
     694             : 
     695           0 :         return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
     696             : }
     697             : 
     698           0 : int image_rename(Image *i, const char *new_name) {
     699           0 :         _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
     700           0 :         _cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL;
     701           0 :         _cleanup_strv_free_ char **settings = NULL;
     702           0 :         unsigned file_attr = 0;
     703             :         char **j;
     704             :         int r;
     705             : 
     706           0 :         assert(i);
     707             : 
     708           0 :         if (!image_name_is_valid(new_name))
     709           0 :                 return -EINVAL;
     710             : 
     711           0 :         if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
     712           0 :                 return -EROFS;
     713             : 
     714           0 :         settings = image_settings_path(i);
     715           0 :         if (!settings)
     716           0 :                 return -ENOMEM;
     717             : 
     718           0 :         roothash = image_roothash_path(i);
     719           0 :         if (!roothash)
     720           0 :                 return -ENOMEM;
     721             : 
     722             :         /* Make sure we don't interfere with a running nspawn */
     723           0 :         r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
     724           0 :         if (r < 0)
     725           0 :                 return r;
     726             : 
     727             :         /* Make sure nobody takes the new name, between the time we
     728             :          * checked it is currently unused in all search paths, and the
     729             :          * time we take possession of it */
     730           0 :         r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
     731           0 :         if (r < 0)
     732           0 :                 return r;
     733             : 
     734           0 :         r = image_find(IMAGE_MACHINE, new_name, NULL);
     735           0 :         if (r >= 0)
     736           0 :                 return -EEXIST;
     737           0 :         if (r != -ENOENT)
     738           0 :                 return r;
     739             : 
     740           0 :         switch (i->type) {
     741             : 
     742           0 :         case IMAGE_DIRECTORY:
     743             :                 /* Turn of the immutable bit while we rename the image, so that we can rename it */
     744           0 :                 (void) read_attr_path(i->path, &file_attr);
     745             : 
     746           0 :                 if (file_attr & FS_IMMUTABLE_FL)
     747           0 :                         (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL, NULL);
     748             : 
     749             :                 _fallthrough_;
     750             :         case IMAGE_SUBVOLUME:
     751           0 :                 new_path = file_in_same_dir(i->path, new_name);
     752           0 :                 break;
     753             : 
     754           0 :         case IMAGE_BLOCK:
     755             : 
     756             :                 /* Refuse renaming raw block devices in /dev, the names are picked by udev after all. */
     757           0 :                 if (path_startswith(i->path, "/dev"))
     758           0 :                         return -EROFS;
     759             : 
     760           0 :                 new_path = file_in_same_dir(i->path, new_name);
     761           0 :                 break;
     762             : 
     763           0 :         case IMAGE_RAW: {
     764             :                 const char *fn;
     765             : 
     766           0 :                 fn = strjoina(new_name, ".raw");
     767           0 :                 new_path = file_in_same_dir(i->path, fn);
     768           0 :                 break;
     769             :         }
     770             : 
     771           0 :         default:
     772           0 :                 return -EOPNOTSUPP;
     773             :         }
     774             : 
     775           0 :         if (!new_path)
     776           0 :                 return -ENOMEM;
     777             : 
     778           0 :         nn = strdup(new_name);
     779           0 :         if (!nn)
     780           0 :                 return -ENOMEM;
     781             : 
     782           0 :         r = rename_noreplace(AT_FDCWD, i->path, AT_FDCWD, new_path);
     783           0 :         if (r < 0)
     784           0 :                 return r;
     785             : 
     786             :         /* Restore the immutable bit, if it was set before */
     787           0 :         if (file_attr & FS_IMMUTABLE_FL)
     788           0 :                 (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL);
     789             : 
     790           0 :         free_and_replace(i->path, new_path);
     791           0 :         free_and_replace(i->name, nn);
     792             : 
     793           0 :         STRV_FOREACH(j, settings) {
     794           0 :                 r = rename_auxiliary_file(*j, new_name, ".nspawn");
     795           0 :                 if (r < 0 && r != -ENOENT)
     796           0 :                         log_debug_errno(r, "Failed to rename settings file %s, ignoring: %m", *j);
     797             :         }
     798             : 
     799           0 :         r = rename_auxiliary_file(roothash, new_name, ".roothash");
     800           0 :         if (r < 0 && r != -ENOENT)
     801           0 :                 log_debug_errno(r, "Failed to rename roothash file %s, ignoring: %m", roothash);
     802             : 
     803           0 :         return 0;
     804             : }
     805             : 
     806           0 : static int clone_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
     807           0 :         _cleanup_free_ char *rs = NULL;
     808             :         const char *fn;
     809             : 
     810           0 :         fn = strjoina(new_name, suffix);
     811             : 
     812           0 :         rs = file_in_same_dir(path, fn);
     813           0 :         if (!rs)
     814           0 :                 return -ENOMEM;
     815             : 
     816           0 :         return copy_file_atomic(path, rs, 0664, 0, 0, COPY_REFLINK);
     817             : }
     818             : 
     819           0 : int image_clone(Image *i, const char *new_name, bool read_only) {
     820           0 :         _cleanup_(release_lock_file) LockFile name_lock = LOCK_FILE_INIT;
     821           0 :         _cleanup_strv_free_ char **settings = NULL;
     822           0 :         _cleanup_free_ char *roothash = NULL;
     823             :         const char *new_path;
     824             :         char **j;
     825             :         int r;
     826             : 
     827           0 :         assert(i);
     828             : 
     829           0 :         if (!image_name_is_valid(new_name))
     830           0 :                 return -EINVAL;
     831             : 
     832           0 :         settings = image_settings_path(i);
     833           0 :         if (!settings)
     834           0 :                 return -ENOMEM;
     835             : 
     836           0 :         roothash = image_roothash_path(i);
     837           0 :         if (!roothash)
     838           0 :                 return -ENOMEM;
     839             : 
     840             :         /* Make sure nobody takes the new name, between the time we
     841             :          * checked it is currently unused in all search paths, and the
     842             :          * time we take possession of it */
     843           0 :         r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
     844           0 :         if (r < 0)
     845           0 :                 return r;
     846             : 
     847           0 :         r = image_find(IMAGE_MACHINE, new_name, NULL);
     848           0 :         if (r >= 0)
     849           0 :                 return -EEXIST;
     850           0 :         if (r != -ENOENT)
     851           0 :                 return r;
     852             : 
     853           0 :         switch (i->type) {
     854             : 
     855           0 :         case IMAGE_SUBVOLUME:
     856             :         case IMAGE_DIRECTORY:
     857             :                 /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain
     858             :                  * directory. */
     859             : 
     860           0 :                 new_path = strjoina("/var/lib/machines/", new_name);
     861             : 
     862           0 :                 r = btrfs_subvol_snapshot(i->path, new_path,
     863             :                                           (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
     864             :                                           BTRFS_SNAPSHOT_FALLBACK_COPY |
     865             :                                           BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
     866             :                                           BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
     867             :                                           BTRFS_SNAPSHOT_RECURSIVE |
     868             :                                           BTRFS_SNAPSHOT_QUOTA);
     869           0 :                 if (r >= 0)
     870             :                         /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
     871           0 :                         (void) btrfs_subvol_auto_qgroup(new_path, 0, true);
     872             : 
     873           0 :                 break;
     874             : 
     875           0 :         case IMAGE_RAW:
     876           0 :                 new_path = strjoina("/var/lib/machines/", new_name, ".raw");
     877             : 
     878           0 :                 r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, FS_NOCOW_FL, FS_NOCOW_FL, COPY_REFLINK|COPY_CRTIME);
     879           0 :                 break;
     880             : 
     881           0 :         case IMAGE_BLOCK:
     882             :         default:
     883           0 :                 return -EOPNOTSUPP;
     884             :         }
     885             : 
     886           0 :         if (r < 0)
     887           0 :                 return r;
     888             : 
     889           0 :         STRV_FOREACH(j, settings) {
     890           0 :                 r = clone_auxiliary_file(*j, new_name, ".nspawn");
     891           0 :                 if (r < 0 && r != -ENOENT)
     892           0 :                         log_debug_errno(r, "Failed to clone settings %s, ignoring: %m", *j);
     893             :         }
     894             : 
     895           0 :         r = clone_auxiliary_file(roothash, new_name, ".roothash");
     896           0 :         if (r < 0 && r != -ENOENT)
     897           0 :                 log_debug_errno(r, "Failed to clone root hash file %s, ignoring: %m", roothash);
     898             : 
     899           0 :         return 0;
     900             : }
     901             : 
     902           0 : int image_read_only(Image *i, bool b) {
     903           0 :         _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
     904             :         int r;
     905             : 
     906           0 :         assert(i);
     907             : 
     908           0 :         if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
     909           0 :                 return -EROFS;
     910             : 
     911             :         /* Make sure we don't interfere with a running nspawn */
     912           0 :         r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
     913           0 :         if (r < 0)
     914           0 :                 return r;
     915             : 
     916           0 :         switch (i->type) {
     917             : 
     918           0 :         case IMAGE_SUBVOLUME:
     919             : 
     920             :                 /* Note that we set the flag only on the top-level
     921             :                  * subvolume of the image. */
     922             : 
     923           0 :                 r = btrfs_subvol_set_read_only(i->path, b);
     924           0 :                 if (r < 0)
     925           0 :                         return r;
     926             : 
     927           0 :                 break;
     928             : 
     929           0 :         case IMAGE_DIRECTORY:
     930             :                 /* For simple directory trees we cannot use the access
     931             :                    mode of the top-level directory, since it has an
     932             :                    effect on the container itself.  However, we can
     933             :                    use the "immutable" flag, to at least make the
     934             :                    top-level directory read-only. It's not as good as
     935             :                    a read-only subvolume, but at least something, and
     936             :                    we can read the value back. */
     937             : 
     938           0 :                 r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL, NULL);
     939           0 :                 if (r < 0)
     940           0 :                         return r;
     941             : 
     942           0 :                 break;
     943             : 
     944           0 :         case IMAGE_RAW: {
     945             :                 struct stat st;
     946             : 
     947           0 :                 if (stat(i->path, &st) < 0)
     948           0 :                         return -errno;
     949             : 
     950           0 :                 if (chmod(i->path, (st.st_mode & 0444) | (b ? 0000 : 0200)) < 0)
     951           0 :                         return -errno;
     952             : 
     953             :                 /* If the images is now read-only, it's a good time to
     954             :                  * defrag it, given that no write patterns will
     955             :                  * fragment it again. */
     956           0 :                 if (b)
     957           0 :                         (void) btrfs_defrag(i->path);
     958           0 :                 break;
     959             :         }
     960             : 
     961           0 :         case IMAGE_BLOCK: {
     962           0 :                 _cleanup_close_ int fd = -1;
     963             :                 struct stat st;
     964           0 :                 int state = b;
     965             : 
     966           0 :                 fd = open(i->path, O_CLOEXEC|O_RDONLY|O_NONBLOCK|O_NOCTTY);
     967           0 :                 if (fd < 0)
     968           0 :                         return -errno;
     969             : 
     970           0 :                 if (fstat(fd, &st) < 0)
     971           0 :                         return -errno;
     972           0 :                 if (!S_ISBLK(st.st_mode))
     973           0 :                         return -ENOTTY;
     974             : 
     975           0 :                 if (ioctl(fd, BLKROSET, &state) < 0)
     976           0 :                         return -errno;
     977             : 
     978           0 :                 break;
     979             :         }
     980             : 
     981           0 :         default:
     982           0 :                 return -EOPNOTSUPP;
     983             :         }
     984             : 
     985           0 :         return 0;
     986             : }
     987             : 
     988           0 : int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local) {
     989           0 :         _cleanup_free_ char *p = NULL;
     990           0 :         LockFile t = LOCK_FILE_INIT;
     991             :         struct stat st;
     992             :         bool exclusive;
     993             :         int r;
     994             : 
     995           0 :         assert(path);
     996           0 :         assert(global);
     997           0 :         assert(local);
     998             : 
     999             :         /* Locks an image path. This actually creates two locks: one "local" one, next to the image path
    1000             :          * itself, which might be shared via NFS. And another "global" one, in /run, that uses the
    1001             :          * device/inode number. This has the benefit that we can even lock a tree that is a mount point,
    1002             :          * correctly. */
    1003             : 
    1004           0 :         if (!path_is_absolute(path))
    1005           0 :                 return -EINVAL;
    1006             : 
    1007           0 :         switch (operation & (LOCK_SH|LOCK_EX)) {
    1008           0 :         case LOCK_SH:
    1009           0 :                 exclusive = false;
    1010           0 :                 break;
    1011           0 :         case LOCK_EX:
    1012           0 :                 exclusive = true;
    1013           0 :                 break;
    1014           0 :         default:
    1015           0 :                 return -EINVAL;
    1016             :         }
    1017             : 
    1018           0 :         if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
    1019           0 :                 *local = *global = (LockFile) LOCK_FILE_INIT;
    1020           0 :                 return 0;
    1021             :         }
    1022             : 
    1023             :         /* Prohibit taking exclusive locks on the host image. We can't allow this, since we ourselves are
    1024             :          * running off it after all, and we don't want any images to manipulate the host image. We make an
    1025             :          * exception for shared locks however: we allow those (and make them NOPs since there's no point in
    1026             :          * taking them if there can't be exclusive locks). Strictly speaking these are questionable as well,
    1027             :          * since it means changes made to the host might propagate to the container as they happen (and a
    1028             :          * shared lock kinda suggests that no changes happen at all while it is in place), but it's too
    1029             :          * useful not to allow read-only containers off the host root, hence let's support this, and trust
    1030             :          * the user to do the right thing with this. */
    1031           0 :         if (path_equal(path, "/")) {
    1032           0 :                 if (exclusive)
    1033           0 :                         return -EBUSY;
    1034             : 
    1035           0 :                 *local = *global = (LockFile) LOCK_FILE_INIT;
    1036           0 :                 return 0;
    1037             :         }
    1038             : 
    1039           0 :         if (stat(path, &st) >= 0) {
    1040           0 :                 if (S_ISBLK(st.st_mode))
    1041           0 :                         r = asprintf(&p, "/run/systemd/nspawn/locks/block-%u:%u", major(st.st_rdev), minor(st.st_rdev));
    1042           0 :                 else if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))
    1043           0 :                         r = asprintf(&p, "/run/systemd/nspawn/locks/inode-%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino);
    1044             :                 else
    1045           0 :                         return -ENOTTY;
    1046             : 
    1047           0 :                 if (r < 0)
    1048           0 :                         return -ENOMEM;
    1049             :         }
    1050             : 
    1051             :         /* For block devices we don't need the "local" lock, as the major/minor lock above should be
    1052             :          * sufficient, since block devices are host local anyway. */
    1053           0 :         if (!path_startswith(path, "/dev/")) {
    1054           0 :                 r = make_lock_file_for(path, operation, &t);
    1055           0 :                 if (r < 0) {
    1056           0 :                         if (!exclusive && r == -EROFS)
    1057           0 :                                 log_debug_errno(r, "Failed to create shared lock for '%s', ignoring: %m", path);
    1058             :                         else
    1059           0 :                                 return r;
    1060             :                 }
    1061             :         }
    1062             : 
    1063           0 :         if (p) {
    1064           0 :                 (void) mkdir_p("/run/systemd/nspawn/locks", 0700);
    1065             : 
    1066           0 :                 r = make_lock_file(p, operation, global);
    1067           0 :                 if (r < 0) {
    1068           0 :                         release_lock_file(&t);
    1069           0 :                         return r;
    1070             :                 }
    1071             :         } else
    1072           0 :                 *global = (LockFile) LOCK_FILE_INIT;
    1073             : 
    1074           0 :         *local = t;
    1075           0 :         return 0;
    1076             : }
    1077             : 
    1078           0 : int image_set_limit(Image *i, uint64_t referenced_max) {
    1079           0 :         assert(i);
    1080             : 
    1081           0 :         if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
    1082           0 :                 return -EROFS;
    1083             : 
    1084           0 :         if (i->type != IMAGE_SUBVOLUME)
    1085           0 :                 return -EOPNOTSUPP;
    1086             : 
    1087             :         /* We set the quota both for the subvolume as well as for the
    1088             :          * subtree. The latter is mostly for historical reasons, since
    1089             :          * we didn't use to have a concept of subtree quota, and hence
    1090             :          * only modified the subvolume quota. */
    1091             : 
    1092           0 :         (void) btrfs_qgroup_set_limit(i->path, 0, referenced_max);
    1093           0 :         (void) btrfs_subvol_auto_qgroup(i->path, 0, true);
    1094           0 :         return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max);
    1095             : }
    1096             : 
    1097           0 : int image_read_metadata(Image *i) {
    1098           0 :         _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
    1099             :         int r;
    1100             : 
    1101           0 :         assert(i);
    1102             : 
    1103           0 :         r = image_path_lock(i->path, LOCK_SH|LOCK_NB, &global_lock, &local_lock);
    1104           0 :         if (r < 0)
    1105           0 :                 return r;
    1106             : 
    1107           0 :         switch (i->type) {
    1108             : 
    1109           0 :         case IMAGE_SUBVOLUME:
    1110             :         case IMAGE_DIRECTORY: {
    1111           0 :                 _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;
    1112           0 :                 sd_id128_t machine_id = SD_ID128_NULL;
    1113           0 :                 _cleanup_free_ char *hostname = NULL;
    1114           0 :                 _cleanup_free_ char *path = NULL;
    1115             : 
    1116           0 :                 r = chase_symlinks("/etc/hostname", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
    1117           0 :                 if (r < 0 && r != -ENOENT)
    1118           0 :                         log_debug_errno(r, "Failed to chase /etc/hostname in image %s: %m", i->name);
    1119           0 :                 else if (r >= 0) {
    1120           0 :                         r = read_etc_hostname(path, &hostname);
    1121           0 :                         if (r < 0)
    1122           0 :                                 log_debug_errno(errno, "Failed to read /etc/hostname of image %s: %m", i->name);
    1123             :                 }
    1124             : 
    1125           0 :                 path = mfree(path);
    1126             : 
    1127           0 :                 r = chase_symlinks("/etc/machine-id", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
    1128           0 :                 if (r < 0 && r != -ENOENT)
    1129           0 :                         log_debug_errno(r, "Failed to chase /etc/machine-id in image %s: %m", i->name);
    1130           0 :                 else if (r >= 0) {
    1131           0 :                         _cleanup_close_ int fd = -1;
    1132             : 
    1133           0 :                         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
    1134           0 :                         if (fd < 0)
    1135           0 :                                 log_debug_errno(errno, "Failed to open %s: %m", path);
    1136             :                         else {
    1137           0 :                                 r = id128_read_fd(fd, ID128_PLAIN, &machine_id);
    1138           0 :                                 if (r < 0)
    1139           0 :                                         log_debug_errno(r, "Image %s contains invalid machine ID.", i->name);
    1140             :                         }
    1141             :                 }
    1142             : 
    1143           0 :                 path = mfree(path);
    1144             : 
    1145           0 :                 r = chase_symlinks("/etc/machine-info", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
    1146           0 :                 if (r < 0 && r != -ENOENT)
    1147           0 :                         log_debug_errno(r, "Failed to chase /etc/machine-info in image %s: %m", i->name);
    1148           0 :                 else if (r >= 0) {
    1149           0 :                         r = load_env_file_pairs(NULL, path, &machine_info);
    1150           0 :                         if (r < 0)
    1151           0 :                                 log_debug_errno(r, "Failed to parse machine-info data of %s: %m", i->name);
    1152             :                 }
    1153             : 
    1154           0 :                 r = load_os_release_pairs(i->path, &os_release);
    1155           0 :                 if (r < 0)
    1156           0 :                         log_debug_errno(r, "Failed to read os-release in image, ignoring: %m");
    1157             : 
    1158           0 :                 free_and_replace(i->hostname, hostname);
    1159           0 :                 i->machine_id = machine_id;
    1160           0 :                 strv_free_and_replace(i->machine_info, machine_info);
    1161           0 :                 strv_free_and_replace(i->os_release, os_release);
    1162             : 
    1163           0 :                 break;
    1164             :         }
    1165             : 
    1166           0 :         case IMAGE_RAW:
    1167             :         case IMAGE_BLOCK: {
    1168           0 :                 _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
    1169           0 :                 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
    1170             : 
    1171           0 :                 r = loop_device_make_by_path(i->path, O_RDONLY, &d);
    1172           0 :                 if (r < 0)
    1173           0 :                         return r;
    1174             : 
    1175           0 :                 r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
    1176           0 :                 if (r < 0)
    1177           0 :                         return r;
    1178             : 
    1179           0 :                 r = dissected_image_acquire_metadata(m);
    1180           0 :                 if (r < 0)
    1181           0 :                         return r;
    1182             : 
    1183           0 :                 free_and_replace(i->hostname, m->hostname);
    1184           0 :                 i->machine_id = m->machine_id;
    1185           0 :                 strv_free_and_replace(i->machine_info, m->machine_info);
    1186           0 :                 strv_free_and_replace(i->os_release, m->os_release);
    1187             : 
    1188           0 :                 break;
    1189             :         }
    1190             : 
    1191           0 :         default:
    1192           0 :                 return -EOPNOTSUPP;
    1193             :         }
    1194             : 
    1195           0 :         i->metadata_valid = true;
    1196             : 
    1197           0 :         return 0;
    1198             : }
    1199             : 
    1200           0 : int image_name_lock(const char *name, int operation, LockFile *ret) {
    1201           0 :         assert(name);
    1202           0 :         assert(ret);
    1203             : 
    1204             :         /* Locks an image name, regardless of the precise path used. */
    1205             : 
    1206           0 :         if (!image_name_is_valid(name))
    1207           0 :                 return -EINVAL;
    1208             : 
    1209           0 :         if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
    1210           0 :                 *ret = (LockFile) LOCK_FILE_INIT;
    1211           0 :                 return 0;
    1212             :         }
    1213             : 
    1214           0 :         if (streq(name, ".host"))
    1215           0 :                 return -EBUSY;
    1216             : 
    1217           0 :         const char *p = strjoina("/run/systemd/nspawn/locks/name-", name);
    1218           0 :         (void) mkdir_p("/run/systemd/nspawn/locks", 0700);
    1219           0 :         return make_lock_file(p, operation, ret);
    1220             : }
    1221             : 
    1222           0 : bool image_name_is_valid(const char *s) {
    1223           0 :         if (!filename_is_valid(s))
    1224           0 :                 return false;
    1225             : 
    1226           0 :         if (string_has_cc(s, NULL))
    1227           0 :                 return false;
    1228             : 
    1229           0 :         if (!utf8_is_valid(s))
    1230           0 :                 return false;
    1231             : 
    1232             :         /* Temporary files for atomically creating new files */
    1233           0 :         if (startswith(s, ".#"))
    1234           0 :                 return false;
    1235             : 
    1236           0 :         return true;
    1237             : }
    1238             : 
    1239           0 : bool image_in_search_path(ImageClass class, const char *image) {
    1240             :         const char *path;
    1241             : 
    1242           0 :         assert(image);
    1243             : 
    1244           0 :         NULSTR_FOREACH(path, image_search_path[class]) {
    1245             :                 const char *p;
    1246             :                 size_t k;
    1247             : 
    1248           0 :                 p = path_startswith(image, path);
    1249           0 :                 if (!p)
    1250           0 :                         continue;
    1251             : 
    1252             :                 /* Make sure there's a filename following */
    1253           0 :                 k = strcspn(p, "/");
    1254           0 :                 if (k == 0)
    1255           0 :                         continue;
    1256             : 
    1257           0 :                 p += k;
    1258             : 
    1259             :                 /* Accept trailing slashes */
    1260           0 :                 if (p[strspn(p, "/")] == 0)
    1261           0 :                         return true;
    1262             : 
    1263             :         }
    1264             : 
    1265           0 :         return false;
    1266             : }
    1267             : 
    1268             : static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
    1269             :         [IMAGE_DIRECTORY] = "directory",
    1270             :         [IMAGE_SUBVOLUME] = "subvolume",
    1271             :         [IMAGE_RAW] = "raw",
    1272             :         [IMAGE_BLOCK] = "block",
    1273             : };
    1274             : 
    1275          12 : DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType);

Generated by: LCOV version 1.14