"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/lib/utils_loop.c" (13 Jan 2022, 6703 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_loop.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.3.6_vs_2.4.0.

    1 /*
    2  * loopback block device utilities
    3  *
    4  * Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
    5  * Copyright (C) 2009-2021 Milan Broz
    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 <stdlib.h>
   23 #include <string.h>
   24 #include <stdio.h>
   25 #include <unistd.h>
   26 #include <fcntl.h>
   27 #include <errno.h>
   28 #include <limits.h>
   29 #include <sys/ioctl.h>
   30 #include <sys/stat.h>
   31 #ifdef HAVE_SYS_SYSMACROS_H
   32 # include <sys/sysmacros.h>     /* for major, minor */
   33 #endif
   34 #include <linux/types.h>
   35 #include <linux/loop.h>
   36 
   37 #include "utils_loop.h"
   38 #include "libcryptsetup_macros.h"
   39 
   40 #define LOOP_DEV_MAJOR 7
   41 
   42 #ifndef LO_FLAGS_AUTOCLEAR
   43 #define LO_FLAGS_AUTOCLEAR 4
   44 #endif
   45 
   46 #ifndef LOOP_CTL_GET_FREE
   47 #define LOOP_CTL_GET_FREE 0x4C82
   48 #endif
   49 
   50 #ifndef LOOP_SET_CAPACITY
   51 #define LOOP_SET_CAPACITY 0x4C07
   52 #endif
   53 
   54 #ifndef LOOP_SET_BLOCK_SIZE
   55 #define LOOP_SET_BLOCK_SIZE 0x4C09
   56 #endif
   57 
   58 #ifndef LOOP_CONFIGURE
   59 #define LOOP_CONFIGURE 0x4C0A
   60 struct loop_config {
   61   __u32 fd;
   62   __u32 block_size;
   63   struct loop_info64 info;
   64   __u64 __reserved[8];
   65 };
   66 #endif
   67 
   68 static char *crypt_loop_get_device_old(void)
   69 {
   70     char dev[20];
   71     int i, loop_fd;
   72     struct loop_info64 lo64 = {0};
   73 
   74     for (i = 0; i < 256; i++) {
   75         sprintf(dev, "/dev/loop%d", i);
   76 
   77         loop_fd = open(dev, O_RDONLY);
   78         if (loop_fd < 0)
   79             return NULL;
   80 
   81         if (ioctl(loop_fd, LOOP_GET_STATUS64, &lo64) &&
   82             errno == ENXIO) {
   83             close(loop_fd);
   84             return strdup(dev);
   85         }
   86         close(loop_fd);
   87     }
   88 
   89     return NULL;
   90 }
   91 
   92 static char *crypt_loop_get_device(void)
   93 {
   94     char dev[64];
   95     int i, loop_fd;
   96     struct stat st;
   97 
   98     loop_fd = open("/dev/loop-control", O_RDONLY);
   99     if (loop_fd < 0)
  100         return crypt_loop_get_device_old();
  101 
  102     i = ioctl(loop_fd, LOOP_CTL_GET_FREE);
  103     if (i < 0) {
  104         close(loop_fd);
  105         return NULL;
  106     }
  107     close(loop_fd);
  108 
  109     if (sprintf(dev, "/dev/loop%d", i) < 0)
  110         return NULL;
  111 
  112     if (stat(dev, &st) || !S_ISBLK(st.st_mode))
  113         return NULL;
  114 
  115     return strdup(dev);
  116 }
  117 
  118 int crypt_loop_attach(char **loop, const char *file, int offset,
  119               int autoclear, int *readonly, size_t blocksize)
  120 {
  121     struct loop_config config = {0};
  122     char *lo_file_name;
  123     int loop_fd = -1, file_fd = -1, r = 1;
  124     int fallback = 0;
  125 
  126     *loop = NULL;
  127 
  128     file_fd = open(file, (*readonly ? O_RDONLY : O_RDWR) | O_EXCL);
  129     if (file_fd < 0 && (errno == EROFS || errno == EACCES) && !*readonly) {
  130         *readonly = 1;
  131         file_fd = open(file, O_RDONLY | O_EXCL);
  132     }
  133     if (file_fd < 0)
  134         goto out;
  135 
  136     config.fd = file_fd;
  137 
  138     lo_file_name = (char*)config.info.lo_file_name;
  139     lo_file_name[LO_NAME_SIZE-1] = '\0';
  140     strncpy(lo_file_name, file, LO_NAME_SIZE-1);
  141     config.info.lo_offset = offset;
  142     if (autoclear)
  143         config.info.lo_flags |= LO_FLAGS_AUTOCLEAR;
  144     if (blocksize > SECTOR_SIZE)
  145         config.block_size = blocksize;
  146 
  147     while (loop_fd < 0) {
  148         *loop = crypt_loop_get_device();
  149         if (!*loop)
  150             goto out;
  151 
  152         loop_fd = open(*loop, *readonly ? O_RDONLY : O_RDWR);
  153         if (loop_fd < 0)
  154             goto out;
  155         if (ioctl(loop_fd, LOOP_CONFIGURE, &config) < 0) {
  156             if (errno == EINVAL || errno == ENOTTY) {
  157                 free(*loop);
  158                 *loop = NULL;
  159 
  160                 close(loop_fd);
  161                 loop_fd = -1;
  162 
  163                 /* kernel doesn't support LOOP_CONFIGURE */
  164                 fallback = 1;
  165                 break;
  166             }
  167             if (errno != EBUSY)
  168                 goto out;
  169             free(*loop);
  170             *loop = NULL;
  171 
  172             close(loop_fd);
  173             loop_fd = -1;
  174         }
  175     }
  176 
  177     if (fallback) {
  178         while (loop_fd < 0) {
  179             *loop = crypt_loop_get_device();
  180             if (!*loop)
  181                 goto out;
  182 
  183             loop_fd = open(*loop, *readonly ? O_RDONLY : O_RDWR);
  184             if (loop_fd < 0)
  185                 goto out;
  186             if (ioctl(loop_fd, LOOP_SET_FD, file_fd) < 0) {
  187                 if (errno != EBUSY)
  188                     goto out;
  189                 free(*loop);
  190                 *loop = NULL;
  191 
  192                 close(loop_fd);
  193                 loop_fd = -1;
  194             }
  195         }
  196 
  197         if (blocksize > SECTOR_SIZE)
  198             (void)ioctl(loop_fd, LOOP_SET_BLOCK_SIZE, (unsigned long)blocksize);
  199 
  200         if (ioctl(loop_fd, LOOP_SET_STATUS64, &config.info) < 0) {
  201             (void)ioctl(loop_fd, LOOP_CLR_FD, 0);
  202             goto out;
  203         }
  204     }
  205 
  206     /* Verify that autoclear is really set */
  207     if (autoclear) {
  208         memset(&config.info, 0, sizeof(config.info));
  209         if (ioctl(loop_fd, LOOP_GET_STATUS64, &config.info) < 0 ||
  210            !(config.info.lo_flags & LO_FLAGS_AUTOCLEAR)) {
  211         (void)ioctl(loop_fd, LOOP_CLR_FD, 0);
  212             goto out;
  213         }
  214     }
  215 
  216     r = 0;
  217 out:
  218     if (r && loop_fd >= 0)
  219         close(loop_fd);
  220     if (file_fd >= 0)
  221         close(file_fd);
  222     if (r && *loop) {
  223         free(*loop);
  224         *loop = NULL;
  225     }
  226     return r ? -1 : loop_fd;
  227 }
  228 
  229 int crypt_loop_detach(const char *loop)
  230 {
  231     int loop_fd = -1, r = 1;
  232 
  233     loop_fd = open(loop, O_RDONLY);
  234     if (loop_fd < 0)
  235                 return 1;
  236 
  237     if (!ioctl(loop_fd, LOOP_CLR_FD, 0))
  238         r = 0;
  239 
  240     close(loop_fd);
  241     return r;
  242 }
  243 
  244 int crypt_loop_resize(const char *loop)
  245 {
  246     int loop_fd = -1, r = 1;
  247 
  248     loop_fd = open(loop, O_RDONLY);
  249     if (loop_fd < 0)
  250                 return 1;
  251 
  252     if (!ioctl(loop_fd, LOOP_SET_CAPACITY, 0))
  253         r = 0;
  254 
  255     close(loop_fd);
  256     return r;
  257 }
  258 
  259 static char *_ioctl_backing_file(const char *loop)
  260 {
  261     struct loop_info64 lo64 = {0};
  262     int loop_fd;
  263 
  264     loop_fd = open(loop, O_RDONLY);
  265     if (loop_fd < 0)
  266         return NULL;
  267 
  268     if (ioctl(loop_fd, LOOP_GET_STATUS64, &lo64) < 0) {
  269         close(loop_fd);
  270         return NULL;
  271     }
  272 
  273     lo64.lo_file_name[LO_NAME_SIZE-2] = '*';
  274     lo64.lo_file_name[LO_NAME_SIZE-1] = 0;
  275 
  276     close(loop_fd);
  277 
  278     return strdup((char*)lo64.lo_file_name);
  279 }
  280 
  281 static char *_sysfs_backing_file(const char *loop)
  282 {
  283     struct stat st;
  284     char buf[PATH_MAX];
  285     size_t len;
  286     int fd;
  287 
  288     if (stat(loop, &st) || !S_ISBLK(st.st_mode))
  289         return NULL;
  290 
  291     if (snprintf(buf, sizeof(buf), "/sys/dev/block/%d:%d/loop/backing_file",
  292              major(st.st_rdev), minor(st.st_rdev)) < 0)
  293         return NULL;
  294 
  295     fd = open(buf, O_RDONLY);
  296     if (fd < 0)
  297         return NULL;
  298 
  299     len = read(fd, buf, PATH_MAX);
  300     close(fd);
  301     if (len < 2)
  302         return NULL;
  303 
  304     buf[len - 1] = '\0';
  305     return strdup(buf);
  306 }
  307 
  308 char *crypt_loop_backing_file(const char *loop)
  309 {
  310     char *bf;
  311 
  312     if (!crypt_loop_device(loop))
  313         return NULL;
  314 
  315     bf = _sysfs_backing_file(loop);
  316     return bf ?: _ioctl_backing_file(loop);
  317 }
  318 
  319 int crypt_loop_device(const char *loop)
  320 {
  321     struct stat st;
  322 
  323     if (!loop)
  324         return 0;
  325 
  326     if (stat(loop, &st) || !S_ISBLK(st.st_mode) ||
  327         major(st.st_rdev) != LOOP_DEV_MAJOR)
  328         return 0;
  329 
  330     return 1;
  331 }