LCOV - code coverage report
Current view: top level - basic - blockdev-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 93 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <sys/stat.h>
       4             : #include <sys/statfs.h>
       5             : 
       6             : #include "alloc-util.h"
       7             : #include "blockdev-util.h"
       8             : #include "btrfs-util.h"
       9             : #include "dirent-util.h"
      10             : #include "fd-util.h"
      11             : #include "fileio.h"
      12             : #include "missing.h"
      13             : #include "parse-util.h"
      14             : #include "stat-util.h"
      15             : 
      16           0 : int block_get_whole_disk(dev_t d, dev_t *ret) {
      17           0 :         char p[SYS_BLOCK_PATH_MAX("/partition")];
      18           0 :         _cleanup_free_ char *s = NULL;
      19             :         dev_t devt;
      20             :         int r;
      21             : 
      22           0 :         assert(ret);
      23             : 
      24           0 :         if (major(d) == 0)
      25           0 :                 return -ENODEV;
      26             : 
      27             :         /* If it has a queue this is good enough for us */
      28           0 :         xsprintf_sys_block_path(p, "/queue", d);
      29           0 :         if (access(p, F_OK) >= 0) {
      30           0 :                 *ret = d;
      31           0 :                 return 0;
      32             :         }
      33             : 
      34             :         /* If it is a partition find the originating device */
      35           0 :         xsprintf_sys_block_path(p, "/partition", d);
      36           0 :         if (access(p, F_OK) < 0)
      37           0 :                 return -errno;
      38             : 
      39             :         /* Get parent dev_t */
      40           0 :         xsprintf_sys_block_path(p, "/../dev", d);
      41           0 :         r = read_one_line_file(p, &s);
      42           0 :         if (r < 0)
      43           0 :                 return r;
      44             : 
      45           0 :         r = parse_dev(s, &devt);
      46           0 :         if (r < 0)
      47           0 :                 return r;
      48             : 
      49             :         /* Only return this if it is really good enough for us. */
      50           0 :         xsprintf_sys_block_path(p, "/queue", devt);
      51           0 :         if (access(p, F_OK) < 0)
      52           0 :                 return -errno;
      53             : 
      54           0 :         *ret = devt;
      55           0 :         return 1;
      56             : }
      57             : 
      58           0 : int get_block_device(const char *path, dev_t *dev) {
      59             :         struct stat st;
      60             :         struct statfs sfs;
      61             : 
      62           0 :         assert(path);
      63           0 :         assert(dev);
      64             : 
      65             :         /* Gets the block device directly backing a file system. If
      66             :          * the block device is encrypted, returns the device mapper
      67             :          * block device. */
      68             : 
      69           0 :         if (lstat(path, &st))
      70           0 :                 return -errno;
      71             : 
      72           0 :         if (major(st.st_dev) != 0) {
      73           0 :                 *dev = st.st_dev;
      74           0 :                 return 1;
      75             :         }
      76             : 
      77           0 :         if (statfs(path, &sfs) < 0)
      78           0 :                 return -errno;
      79             : 
      80           0 :         if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
      81           0 :                 return btrfs_get_block_device(path, dev);
      82             : 
      83           0 :         *dev = 0;
      84           0 :         return 0;
      85             : }
      86             : 
      87           0 : int block_get_originating(dev_t dt, dev_t *ret) {
      88           0 :         _cleanup_closedir_ DIR *d = NULL;
      89           0 :         _cleanup_free_ char *t = NULL;
      90           0 :         char p[SYS_BLOCK_PATH_MAX("/slaves")];
      91           0 :         struct dirent *de, *found = NULL;
      92             :         const char *q;
      93             :         dev_t devt;
      94             :         int r;
      95             : 
      96             :         /* For the specified block device tries to chase it through the layers, in case LUKS-style DM stacking is used,
      97             :          * trying to find the next underlying layer.  */
      98             : 
      99           0 :         xsprintf_sys_block_path(p, "/slaves", dt);
     100           0 :         d = opendir(p);
     101           0 :         if (!d)
     102           0 :                 return -errno;
     103             : 
     104           0 :         FOREACH_DIRENT_ALL(de, d, return -errno) {
     105             : 
     106           0 :                 if (dot_or_dot_dot(de->d_name))
     107           0 :                         continue;
     108             : 
     109           0 :                 if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
     110           0 :                         continue;
     111             : 
     112           0 :                 if (found) {
     113           0 :                         _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL;
     114             : 
     115             :                         /* We found a device backed by multiple other devices. We don't really support automatic
     116             :                          * discovery on such setups, with the exception of dm-verity partitions. In this case there are
     117             :                          * two backing devices: the data partition and the hash partition. We are fine with such
     118             :                          * setups, however, only if both partitions are on the same physical device. Hence, let's
     119             :                          * verify this. */
     120             : 
     121           0 :                         u = path_join(p, de->d_name, "../dev");
     122           0 :                         if (!u)
     123           0 :                                 return -ENOMEM;
     124             : 
     125           0 :                         v = path_join(p, found->d_name, "../dev");
     126           0 :                         if (!v)
     127           0 :                                 return -ENOMEM;
     128             : 
     129           0 :                         r = read_one_line_file(u, &a);
     130           0 :                         if (r < 0)
     131           0 :                                 return log_debug_errno(r, "Failed to read %s: %m", u);
     132             : 
     133           0 :                         r = read_one_line_file(v, &b);
     134           0 :                         if (r < 0)
     135           0 :                                 return log_debug_errno(r, "Failed to read %s: %m", v);
     136             : 
     137             :                         /* Check if the parent device is the same. If not, then the two backing devices are on
     138             :                          * different physical devices, and we don't support that. */
     139           0 :                         if (!streq(a, b))
     140           0 :                                 return -ENOTUNIQ;
     141             :                 }
     142             : 
     143           0 :                 found = de;
     144             :         }
     145             : 
     146           0 :         if (!found)
     147           0 :                 return -ENOENT;
     148             : 
     149           0 :         q = strjoina(p, "/", found->d_name, "/dev");
     150             : 
     151           0 :         r = read_one_line_file(q, &t);
     152           0 :         if (r < 0)
     153           0 :                 return r;
     154             : 
     155           0 :         r = parse_dev(t, &devt);
     156           0 :         if (r < 0)
     157           0 :                 return -EINVAL;
     158             : 
     159           0 :         if (major(devt) == 0)
     160           0 :                 return -ENOENT;
     161             : 
     162           0 :         *ret = devt;
     163           0 :         return 1;
     164             : }
     165             : 
     166           0 : int get_block_device_harder(const char *path, dev_t *ret) {
     167             :         int r;
     168             : 
     169           0 :         assert(path);
     170           0 :         assert(ret);
     171             : 
     172             :         /* Gets the backing block device for a file system, and handles LUKS encrypted file systems, looking for its
     173             :          * immediate parent, if there is one. */
     174             : 
     175           0 :         r = get_block_device(path, ret);
     176           0 :         if (r <= 0)
     177           0 :                 return r;
     178             : 
     179           0 :         r = block_get_originating(*ret, ret);
     180           0 :         if (r < 0)
     181           0 :                 log_debug_errno(r, "Failed to chase block device '%s', ignoring: %m", path);
     182             : 
     183           0 :         return 1;
     184             : }

Generated by: LCOV version 1.14