"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/src/utils_blockdev.c" (13 Jan 2022, 7606 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "utils_blockdev.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.4.1_vs_2.4.2.

    1 /*
    2  * Linux block devices helpers
    3  *
    4  * Copyright (C) 2018-2021 Red Hat, Inc. All rights reserved.
    5  * Copyright (C) 2018-2021 Ondrej Kozina
    6  *
    7  * This program is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU General Public License
    9  * as published by the Free Software Foundation; either version 2
   10  * of the License, or (at your option) any later version.
   11  *
   12  * This program is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, write to the Free Software
   19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   20  */
   21 
   22 #include "cryptsetup.h"
   23 #include <dirent.h>
   24 #ifdef HAVE_SYS_SYSMACROS_H
   25 # include <sys/sysmacros.h>     /* for major, minor */
   26 #endif
   27 #include <uuid/uuid.h>
   28 
   29 #define UUID_LEN 37 /* 36 + \0, libuuid ... */
   30 
   31 static int dm_prepare_uuid(const char *type, const char *uuid, char *buf, size_t buflen)
   32 {
   33     char *ptr, uuid2[UUID_LEN] = {0};
   34     uuid_t uu;
   35     unsigned i = 0;
   36 
   37     /* Remove '-' chars */
   38     if (uuid) {
   39         if (uuid_parse(uuid, uu) < 0) {
   40             log_dbg("Requested UUID %s has invalid format.", uuid);
   41             return 0;
   42         }
   43 
   44         for (ptr = uuid2, i = 0; i < UUID_LEN; i++)
   45             if (uuid[i] != '-') {
   46                 *ptr = uuid[i];
   47                 ptr++;
   48             }
   49     }
   50 
   51     snprintf(buf, buflen, DM_UUID_PREFIX "%s%s%s%s",
   52         type ?: "", type ? "-" : "",
   53         uuid2[0] ? uuid2 : "", uuid2[0] ? "-" : "");
   54 
   55     return 1;
   56 }
   57 
   58 /* return number of holders in general, if matched dm_uuid prefix it's returned via dm_name */
   59 /* negative value is error */
   60 static int lookup_holder_dm_name(const char *dm_uuid, dev_t devno, char *dm_name, size_t dm_name_length)
   61 {
   62     struct dirent *entry;
   63     char dm_subpath[PATH_MAX], data_dev_dir[PATH_MAX], uuid[DM_UUID_LEN];
   64     ssize_t s;
   65     struct stat st;
   66     int dmfd, fd, len, r = 0; /* not found */
   67     DIR *dir;
   68 
   69     if (!dm_name || !dm_name_length)
   70         return -EINVAL;
   71 
   72     *dm_name = '\0';
   73 
   74     len = snprintf(data_dev_dir, PATH_MAX, "/sys/dev/block/%u:%u/holders", major(devno), minor(devno));
   75     if (len < 0 || len >= PATH_MAX)
   76         return -EINVAL;
   77 
   78     if (!(dir = opendir(data_dev_dir)))
   79         /* map ENOTDIR to ENOENT we'll handle both errors same */
   80         return errno == ENOTDIR ? -ENOENT : -errno;
   81 
   82     while (r != 1 && (entry = readdir(dir))) {
   83         if (entry->d_name[0] == '.' ||
   84             !strncmp(entry->d_name, "..", 2))
   85             continue;
   86 
   87         /* there's a holder */
   88         r++;
   89 
   90         /* we already have a dm_name, just count remaining holders */
   91         if (*dm_name != '\0')
   92             continue;
   93 
   94         len = snprintf(dm_subpath, PATH_MAX, "%s/%s", entry->d_name, "dm");
   95         if (len < 0 || len >= PATH_MAX) {
   96             r = -EINVAL;
   97             break;
   98         }
   99 
  100         /* looking for dm-X/dm directory, symlinks are fine */
  101         dmfd = openat(dirfd(dir), dm_subpath, O_DIRECTORY | O_RDONLY);
  102         if (dmfd < 0)
  103             continue;
  104 
  105         fd = openat(dmfd, "uuid", O_RDONLY);
  106         if (fd < 0) {
  107             close(dmfd);
  108             continue;
  109         }
  110 
  111         if (fstat(fd, &st) || !S_ISREG(st.st_mode)) {
  112             close(fd);
  113             close(dmfd);
  114             continue;
  115         }
  116 
  117         /* reads binary data */
  118         s = read_buffer(fd, uuid, sizeof(uuid) - 1);
  119         close(fd);
  120         uuid[s > 0 ? s : 0] = '\0';
  121         if (!strncmp(uuid, dm_uuid, strlen(dm_uuid)))
  122             log_dbg("Found candidate device %s", entry->d_name);
  123         else {
  124             close(dmfd);
  125             continue;
  126         }
  127 
  128         fd = openat(dmfd, "name", O_RDONLY);
  129         if (fd < 0) {
  130             close(dmfd);
  131             continue;
  132         }
  133 
  134         if (fstat(fd, &st) || !S_ISREG(st.st_mode)) {
  135             close(fd);
  136             close(dmfd);
  137             continue;
  138         }
  139 
  140         /* reads binary data */
  141         s = read_buffer(fd, dm_name, dm_name_length - 1);
  142         close(fd);
  143         close(dmfd);
  144         if (s > 1) {
  145             dm_name[s-1] = '\0';
  146             log_dbg("Found dm device %s", dm_name);
  147         }
  148     }
  149 
  150     closedir(dir);
  151 
  152     return r;
  153 }
  154 
  155 int tools_lookup_crypt_device(struct crypt_device *cd, const char *type,
  156         const char *data_device_path, char *name, size_t name_length)
  157 {
  158     int r;
  159     char *c;
  160     struct stat st;
  161     char dev_uuid[DM_UUID_LEN + DM_BY_ID_PREFIX_LEN] = DM_BY_ID_PREFIX;
  162 
  163     if (!dm_prepare_uuid(type, crypt_get_uuid(cd), dev_uuid + DM_BY_ID_PREFIX_LEN, DM_UUID_LEN))
  164         return -EINVAL;
  165 
  166     c = strrchr(dev_uuid, '-');
  167     if (!c)
  168         return -EINVAL;
  169 
  170     /* cut of dm name */
  171     *c = '\0';
  172 
  173     log_dbg("Looking for any dm device with prefix: %s", dev_uuid);
  174 
  175     if (stat(data_device_path, &st) < 0)
  176         return -ENODEV;
  177 
  178     if (!S_ISBLK(st.st_mode))
  179         return -ENOTBLK;
  180 
  181     r = lookup_holder_dm_name(dev_uuid + DM_BY_ID_PREFIX_LEN,
  182             st.st_rdev, name, name_length);
  183     return r;
  184 }
  185 
  186 
  187 static void report_partition(const char *value, const char *device, bool batch_mode)
  188 {
  189     if (batch_mode)
  190         log_dbg("Device %s already contains a '%s' partition signature.", device, value);
  191     else
  192         log_std(_("WARNING: Device %s already contains a '%s' partition signature.\n"), device, value);
  193 }
  194 
  195 static void report_superblock(const char *value, const char *device, bool batch_mode)
  196 {
  197     if (batch_mode)
  198         log_dbg("Device %s already contains a '%s' superblock signature.", device, value);
  199     else
  200         log_std(_("WARNING: Device %s already contains a '%s' superblock signature.\n"), device, value);
  201 }
  202 
  203 int tools_detect_signatures(const char *device, int ignore_luks, size_t *count, bool batch_mode)
  204 {
  205     int r;
  206     size_t tmp_count;
  207     struct blkid_handle *h;
  208     blk_probe_status pr;
  209 
  210     if (!count)
  211         count = &tmp_count;
  212 
  213     *count = 0;
  214 
  215     if (!blk_supported()) {
  216         log_dbg("Blkid support disabled.");
  217         return 0;
  218     }
  219 
  220     if ((r = blk_init_by_path(&h, device))) {
  221         log_err(_("Failed to initialize device signature probes."));
  222         return -EINVAL;
  223     }
  224 
  225     blk_set_chains_for_full_print(h);
  226 
  227     if (ignore_luks && blk_superblocks_filter_luks(h)) {
  228         r = -EINVAL;
  229         goto out;
  230     }
  231 
  232     while ((pr = blk_probe(h)) < PRB_EMPTY) {
  233         if (blk_is_partition(h))
  234             report_partition(blk_get_partition_type(h), device, batch_mode);
  235         else if (blk_is_superblock(h))
  236             report_superblock(blk_get_superblock_type(h), device, batch_mode);
  237         else {
  238             log_dbg("Internal tools_detect_signatures() error.");
  239             r = -EINVAL;
  240             goto out;
  241         }
  242         (*count)++;
  243     }
  244 
  245     if (pr == PRB_FAIL)
  246         r = -EINVAL;
  247 out:
  248     blk_free(h);
  249     return r;
  250 }
  251 
  252 int tools_wipe_all_signatures(const char *path)
  253 {
  254     int fd, flags, r;
  255     blk_probe_status pr;
  256     struct stat st;
  257     struct blkid_handle *h = NULL;
  258 
  259     if (!blk_supported()) {
  260         log_dbg("Blkid support disabled.");
  261         return 0;
  262     }
  263 
  264     if (stat(path, &st)) {
  265         log_err(_("Failed to stat device %s."), path);
  266         return -EINVAL;
  267     }
  268 
  269     flags = O_RDWR;
  270     if (S_ISBLK(st.st_mode))
  271         flags |= O_EXCL;
  272 
  273     /* better than opening regular file with O_EXCL (undefined) */
  274     /* coverity[toctou] */
  275     fd = open(path, flags);
  276     if (fd < 0) {
  277         if (errno == EBUSY)
  278             log_err(_("Device %s is in use. Cannot proceed with format operation."), path);
  279         else
  280             log_err(_("Failed to open file %s in read/write mode."), path);
  281         return -EINVAL;
  282     }
  283 
  284     if ((r = blk_init_by_fd(&h, fd))) {
  285         log_err(_("Failed to initialize device signature probes."));
  286         r = -EINVAL;
  287         goto out;
  288     }
  289 
  290     blk_set_chains_for_wipes(h);
  291 
  292     while ((pr = blk_probe(h)) < PRB_EMPTY) {
  293         if (blk_is_partition(h))
  294             log_verbose(_("Existing '%s' partition signature on device %s will be wiped."),
  295                     blk_get_partition_type(h), path);
  296         if (blk_is_superblock(h))
  297             log_verbose(_("Existing '%s' superblock signature on device %s will be wiped."),
  298                     blk_get_superblock_type(h), path);
  299         if (blk_do_wipe(h)) {
  300             log_err(_("Failed to wipe device signature."));
  301             r = -EINVAL;
  302             goto out;
  303         }
  304     }
  305 
  306     if (pr != PRB_EMPTY) {
  307         log_err(_("Failed to probe device %s for a signature."), path);
  308         r = -EINVAL;
  309     }
  310 out:
  311     close(fd);
  312     blk_free(h);
  313     return r;
  314 }