"Fossies" - the Fresh Open Source Software Archive

Member "dosfstools-4.2/src/device_info.c" (31 Jan 2021, 9495 Bytes) of package /linux/misc/dosfstools-4.2.tar.gz:


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 "device_info.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.1_vs_4.2.

    1 /* device_info.c - Collect device information for mkfs.fat
    2 
    3    Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
    4    Copyright (C) 2018 Pali Rohár <pali.rohar@gmail.com>
    5 
    6    This program is free software: you can redistribute it and/or modify
    7    it under the terms of the GNU General Public License as published by
    8    the Free Software Foundation, either version 3 of the License, or
    9    (at your option) any later version.
   10 
   11    This program is distributed in the hope that it will be useful,
   12    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14    GNU General Public License for more details.
   15 
   16    You should have received a copy of the GNU General Public License
   17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   18 */
   19 
   20 
   21 #include <limits.h>
   22 #include <stdint.h>
   23 #include <stdbool.h>
   24 #include <sys/types.h>
   25 #include <sys/stat.h>
   26 #include <sys/ioctl.h>
   27 #include <sys/sysmacros.h>
   28 
   29 #ifdef HAVE_LINUX_LOOP_H
   30 #include <linux/loop.h>
   31 #endif
   32 
   33 #if HAVE_DECL_GETMNTENT
   34 #include <paths.h>
   35 #include <mntent.h>
   36 #endif
   37 
   38 #if HAVE_DECL_GETMNTINFO
   39 #include <sys/param.h>
   40 #include <sys/ucred.h>
   41 #include <sys/mount.h>
   42 #endif
   43 
   44 #include <unistd.h>
   45 #include <dirent.h>
   46 #include <stdio.h>
   47 #include <string.h>
   48 #include <stdlib.h>
   49 #include <errno.h>
   50 
   51 #include "blkdev.h"
   52 #include "device_info.h"
   53 
   54 
   55 static const struct device_info device_info_clueless = {
   56     .type         = TYPE_UNKNOWN,
   57     .partition    = -1,
   58     .has_children = -1,
   59     .geom_heads   = -1,
   60     .geom_sectors = -1,
   61     .geom_start   = -1,
   62     .geom_size    = -1,
   63     .sector_size  = -1,
   64     .size         = -1,
   65 };
   66 
   67 
   68 int device_info_verbose;
   69 
   70 
   71 static void get_block_device_size(struct device_info *info, int fd)
   72 {
   73     unsigned long long bytes;
   74 
   75     if (!blkdev_get_size(fd, &bytes) && bytes != 0)
   76     info->size = bytes;
   77 }
   78 
   79 
   80 static void get_block_geometry(struct device_info *info, int fd, dev_t rdev)
   81 {
   82     unsigned int heads, sectors;
   83     unsigned long long start;
   84 
   85     if (!blkdev_get_geometry(fd, &heads, &sectors)
   86         && heads && sectors) {
   87     info->geom_heads = heads;
   88     info->geom_sectors = sectors;
   89     }
   90 
   91     if (!blkdev_get_start(fd, rdev, &start))
   92     info->geom_start = start;
   93 }
   94 
   95 
   96 static void get_sector_size(struct device_info *info, int fd)
   97 {
   98     int size;
   99 
  100     if (!blkdev_get_sector_size(fd, &size))
  101     info->sector_size = size;
  102 }
  103 
  104 
  105 #ifdef __linux__
  106 static void get_block_linux_info(struct device_info *info, int devfd, dev_t rdev)
  107 {
  108     struct stat st;
  109     char path[PATH_MAX];
  110     int fd;
  111     int blockfd;
  112     FILE *file;
  113     DIR *dir;
  114     struct dirent *d;
  115     int maj;
  116     int min;
  117     long long start;
  118     int removable;
  119 
  120 #ifdef HAVE_LINUX_LOOP_H
  121     struct loop_info64 lo;
  122 #endif
  123 
  124     maj = major(rdev);
  125     min = minor(rdev);
  126 
  127     snprintf(path, sizeof(path), "/sys/dev/block/%d:%d", maj, min);
  128     blockfd = open(path, O_RDONLY | O_DIRECTORY);
  129     if (blockfd < 0)
  130         return;
  131 
  132     /* Check if device is partition */
  133     fd = openat(blockfd, "partition", O_RDONLY);
  134     if (fd >= 0) {
  135         file = fdopen(fd, "r");
  136         if (file) {
  137             if (fscanf(file, "%d", &info->partition) != 1 || info->partition == 0)
  138                 info->partition = -1;
  139             fclose(file);
  140         } else {
  141             close(fd);
  142         }
  143         /* Read total number of sectors of the disk */
  144         fd = openat(blockfd, "../size", O_RDONLY);
  145         if (fd >= 0) {
  146             file = fdopen(fd, "r");
  147             if (file) {
  148                 if (fscanf(file, "%lld", &info->geom_size) != 1 || info->geom_size == 0)
  149                     info->geom_size = -1;
  150                 fclose(file);
  151             } else {
  152                 close(fd);
  153             }
  154         }
  155     } else if (errno == ENOENT && info->geom_start <= 0) {
  156         info->partition = 0;
  157         if (info->size > 0 && info->sector_size > 0)
  158             info->geom_size = info->size / info->sector_size;
  159     }
  160 
  161     /* Check if device has partition subdevice and therefore has children */
  162     fd = dup(blockfd);
  163     if (fd >= 0) {
  164         dir = fdopendir(fd);
  165         if (dir) {
  166             info->has_children = 0;
  167             errno = 0;
  168             while ((d = readdir(dir))) {
  169                 if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
  170                     continue;
  171                 if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN)
  172                     continue;
  173                 snprintf(path, sizeof(path), "%s/partition", d->d_name);
  174                 if (fstatat(blockfd, path, &st, 0) == 0) {
  175                     if (S_ISREG(st.st_mode)) {
  176                         start = -1;
  177                         snprintf(path, sizeof(path), "%s/start", d->d_name);
  178                         fd = openat(blockfd, path, O_RDONLY);
  179                         if (fd >= 0) {
  180                             file = fdopen(fd, "r");
  181                             if (file) {
  182                                 if (fscanf(file, "%lld", &start) != 1)
  183                                     start = -1;
  184                                 fclose(file);
  185                             } else {
  186                                 close(fd);
  187                             }
  188                         }
  189                         /* If subdevice starts at zero offset then it is whole device, so it is not a child */
  190                         if (start != 0) {
  191                             info->has_children = 1;
  192                             break;
  193                         }
  194                     }
  195                 } else if (errno != ENOENT) {
  196                     info->has_children = -1;
  197                 }
  198                 errno = 0;
  199             }
  200             if (errno != 0 && info->has_children == 0)
  201                 info->has_children = -1;
  202             closedir(dir);
  203         } else {
  204             close(fd);
  205         }
  206     }
  207 
  208     /* Check if device has holders and therefore has children */
  209     if (info->has_children <= 0) {
  210         fd = openat(blockfd, "holders", O_RDONLY | O_DIRECTORY);
  211         if (fd >= 0) {
  212             dir = fdopendir(fd);
  213             if (dir) {
  214                 while ((d = readdir(dir))) {
  215                     if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
  216                         continue;
  217                     info->has_children = 1;
  218                     break;
  219                 }
  220                 closedir(dir);
  221             } else {
  222                 close(fd);
  223             }
  224         }
  225     }
  226 
  227     /* Check if device is slave of another device and therefore is virtual */
  228     fd = openat(blockfd, "slaves", O_RDONLY | O_DIRECTORY);
  229     if (fd >= 0) {
  230         dir = fdopendir(fd);
  231         if (dir) {
  232             while ((d = readdir(dir))) {
  233                 if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
  234                     continue;
  235                 info->type = TYPE_VIRTUAL;
  236                 break;
  237             }
  238             closedir(dir);
  239         } else {
  240             close(fd);
  241         }
  242     }
  243 
  244 #ifdef HAVE_LINUX_LOOP_H
  245     /* Check if device is loop and detect if is based from regular file or is virtual */
  246     if (info->type == TYPE_UNKNOWN && info->partition == 0 && ioctl(devfd, LOOP_GET_STATUS64, &lo) == 0) {
  247         if (lo.lo_offset == 0 && lo.lo_sizelimit == 0 && lo.lo_encrypt_type == LO_CRYPT_NONE &&
  248             stat((char *)lo.lo_file_name, &st) == 0 && S_ISREG(st.st_mode) &&
  249             st.st_dev == lo.lo_device && st.st_ino == lo.lo_inode && st.st_size == info->size)
  250             info->type = TYPE_FILE;
  251         else
  252             info->type = TYPE_VIRTUAL;
  253     }
  254 #endif
  255 
  256     /* Device is neither loop nor virtual, so is either removable or fixed */
  257     if (info->type == TYPE_UNKNOWN) {
  258         removable = 0;
  259         fd = openat(blockfd, "removable", O_RDONLY);
  260         if (fd >= 0) {
  261             file = fdopen(fd, "r");
  262             if (file) {
  263                 if (fscanf(file, "%d", &removable) != 1)
  264                     removable = 0;
  265                 fclose(file);
  266             } else {
  267                 close(fd);
  268             }
  269         }
  270 
  271         if (removable)
  272             info->type = TYPE_REMOVABLE;
  273         else
  274             info->type = TYPE_FIXED;
  275     }
  276 
  277     close(blockfd);
  278 }
  279 #endif
  280 
  281 
  282 int get_device_info(int fd, struct device_info *info)
  283 {
  284     struct stat stat;
  285     int ret;
  286 
  287     *info = device_info_clueless;
  288 
  289     ret = fstat(fd, &stat);
  290     if (ret < 0) {
  291     perror("fstat on target failed");
  292     return -1;
  293     }
  294 
  295     if (S_ISREG(stat.st_mode)) {
  296     /* there is nothing more to discover for an image file */
  297     info->type = TYPE_FILE;
  298     info->partition = 0;
  299     info->size = stat.st_size;
  300     return 0;
  301     }
  302 
  303     if (!S_ISBLK(stat.st_mode)) {
  304     /* neither regular file nor block device? not usable */
  305     info->type = TYPE_BAD;
  306     return 0;
  307     }
  308 
  309     get_block_device_size(info, fd);
  310     get_block_geometry(info, fd, stat.st_rdev);
  311     get_sector_size(info, fd);
  312 
  313 #ifdef __linux__
  314     get_block_linux_info(info, fd, stat.st_rdev);
  315 #endif
  316 
  317     return 0;
  318 }
  319 
  320 
  321 int is_device_mounted(const char *path)
  322 {
  323 #if HAVE_DECL_GETMNTENT
  324     FILE *f;
  325     struct mntent *mnt;
  326 
  327     if ((f = setmntent(_PATH_MOUNTED, "r")) == NULL)
  328     return 0;
  329     while ((mnt = getmntent(f)) != NULL)
  330     if (strcmp(path, mnt->mnt_fsname) == 0)
  331         return 1;
  332     endmntent(f);
  333     return 0;
  334 #endif
  335 
  336 #if HAVE_DECL_GETMNTINFO
  337     struct statfs *stat;
  338     int count, i;
  339 
  340     count = getmntinfo(&stat, 0);
  341     for (i = 0; i < count; i++)
  342     if (!strcmp(path, stat[i].f_mntfromname))
  343         return 1;
  344     return 0;
  345 #endif
  346 
  347     (void)path; /* prevent unused parameter warning */
  348     return 0;
  349 }