"Fossies" - the Fresh Open Source Software Archive

Member "dosfstools-4.2/src/blkdev/blkdev.c" (31 Jan 2021, 7578 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 "blkdev.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 /*
    2  * No copyright is claimed.  This code is in the public domain; do with
    3  * it what you wish.
    4  *
    5  * Written by Karel Zak <kzak@redhat.com>
    6  */
    7 #include <sys/types.h>
    8 #include <sys/stat.h>
    9 #include <sys/ioctl.h>
   10 #include <sys/sysmacros.h>
   11 #include <unistd.h>
   12 #include <stdint.h>
   13 #include <stdio.h>
   14 #include <limits.h>
   15 
   16 #ifdef HAVE_LINUX_HDREG_H
   17 #include <linux/hdreg.h>
   18 #endif
   19 
   20 #ifdef HAVE_LINUX_FD_H
   21 #include <linux/fd.h>
   22 #endif
   23 
   24 #ifdef HAVE_SYS_DISKLABEL_H
   25 #include <sys/disklabel.h>
   26 #endif
   27 
   28 #ifdef HAVE_SYS_DISK_H
   29 # ifdef HAVE_SYS_QUEUE_H
   30 #  include <sys/queue.h>    /* for LIST_HEAD */
   31 # endif
   32 # include <sys/disk.h>
   33 #endif
   34 
   35 #include "blkdev.h"
   36 #include "linux_version.h"
   37 
   38 static long
   39 blkdev_valid_offset (int fd, off_t offset) {
   40     char ch;
   41 
   42     if (lseek (fd, offset, 0) < 0)
   43         return 0;
   44     if (read (fd, &ch, 1) < 1)
   45         return 0;
   46     return 1;
   47 }
   48 
   49 int is_blkdev(int fd)
   50 {
   51     struct stat st;
   52     return (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode));
   53 }
   54 
   55 off_t
   56 blkdev_find_size (int fd) {
   57     uintmax_t high, low = 0;
   58 
   59     for (high = 1024; blkdev_valid_offset (fd, high); ) {
   60         if (high == UINTMAX_MAX)
   61             return -1;
   62 
   63         low = high;
   64 
   65         if (high >= UINTMAX_MAX/2)
   66             high = UINTMAX_MAX;
   67         else
   68             high *= 2;
   69     }
   70 
   71     while (low < high - 1)
   72     {
   73         uintmax_t mid = (low + high) / 2;
   74 
   75         if (blkdev_valid_offset (fd, mid))
   76             low = mid;
   77         else
   78             high = mid;
   79     }
   80     blkdev_valid_offset (fd, 0);
   81     return (low + 1);
   82 }
   83 
   84 /* get size in bytes */
   85 int
   86 blkdev_get_size(int fd, unsigned long long *bytes)
   87 {
   88 #ifdef DKIOCGETBLOCKCOUNT
   89     /* Apple Darwin */
   90     if (ioctl(fd, DKIOCGETBLOCKCOUNT, bytes) >= 0) {
   91         *bytes <<= 9;
   92         return 0;
   93     }
   94 #endif
   95 
   96 #ifdef BLKGETSIZE64
   97     {
   98 #ifdef __linux__
   99         int ver = get_linux_version();
  100 
  101         /* kernels 2.4.15-2.4.17, had a broken BLKGETSIZE64 */
  102         if (ver >= KERNEL_VERSION (2,6,0) ||
  103            (ver >= KERNEL_VERSION (2,4,18) && ver < KERNEL_VERSION (2,5,0)))
  104 #endif
  105             if (ioctl(fd, BLKGETSIZE64, bytes) >= 0)
  106                 return 0;
  107     }
  108 #endif /* BLKGETSIZE64 */
  109 
  110 #ifdef BLKGETSIZE
  111     {
  112         unsigned long size;
  113 
  114         if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
  115             *bytes = ((unsigned long long)size << 9);
  116             return 0;
  117         }
  118     }
  119 
  120 #endif /* BLKGETSIZE */
  121 
  122 #ifdef DIOCGMEDIASIZE
  123     /* FreeBSD */
  124     if (ioctl(fd, DIOCGMEDIASIZE, bytes) >= 0)
  125         return 0;
  126 #endif
  127 
  128 #ifdef FDGETPRM
  129     {
  130         struct floppy_struct this_floppy;
  131 
  132         if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
  133             *bytes = ((unsigned long long) this_floppy.size) << 9;
  134             return 0;
  135         }
  136     }
  137 #endif /* FDGETPRM */
  138 
  139 #ifdef HAVE_SYS_DISKLABEL_H
  140     {
  141         /*
  142          * This code works for FreeBSD 4.11 i386, except for the full device
  143          * (such as /dev/ad0). It doesn't work properly for newer FreeBSD
  144          * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE
  145          * above however.
  146          *
  147          * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw,
  148          * character) devices, so we need to check for S_ISCHR, too.
  149          */
  150         int part = -1;
  151         struct disklabel lab;
  152         struct partition *pp;
  153         struct stat st;
  154 
  155         if ((fstat(fd, &st) >= 0) &&
  156             (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)))
  157             part = st.st_rdev & 7;
  158 
  159         if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
  160             pp = &lab.d_partitions[part];
  161             if (pp->p_size) {
  162                  *bytes = pp->p_size << 9;
  163                  return 0;
  164             }
  165         }
  166     }
  167 #endif /* HAVE_SYS_DISKLABEL_H */
  168 
  169     {
  170         struct stat st;
  171 
  172         if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
  173             *bytes = st.st_size;
  174             return 0;
  175         }
  176         if (!S_ISBLK(st.st_mode))
  177             return -1;
  178     }
  179 
  180     *bytes = blkdev_find_size(fd);
  181     return 0;
  182 }
  183 
  184 /* get 512-byte sector count */
  185 int
  186 blkdev_get_sectors(int fd, unsigned long long *sectors)
  187 {
  188     unsigned long long bytes;
  189 
  190     if (blkdev_get_size(fd, &bytes) == 0) {
  191         *sectors = (bytes >> 9);
  192         return 0;
  193     }
  194 
  195     return -1;
  196 }
  197 
  198 /*
  199  * Get logical sector size.
  200  *
  201  * This is the smallest unit the storage device can
  202  * address. It is typically 512 bytes.
  203  */
  204 int blkdev_get_sector_size(int fd, int *sector_size)
  205 {
  206 #ifdef BLKSSZGET
  207     if (ioctl(fd, BLKSSZGET, sector_size) >= 0)
  208         return 0;
  209     return -1;
  210 #else
  211     (void)fd; /* prevent unused parameter warning */
  212     *sector_size = DEFAULT_SECTOR_SIZE;
  213     return 0;
  214 #endif
  215 }
  216 
  217 /*
  218  * Get physical block device size. The BLKPBSZGET is supported since Linux
  219  * 2.6.32. For old kernels is probably the best to assume that physical sector
  220  * size is the same as logical sector size.
  221  *
  222  * Example:
  223  *
  224  * rc = blkdev_get_physector_size(fd, &physec);
  225  * if (rc || physec == 0) {
  226  *  rc = blkdev_get_sector_size(fd, &physec);
  227  *  if (rc)
  228  *      physec = DEFAULT_SECTOR_SIZE;
  229  * }
  230  */
  231 int blkdev_get_physector_size(int fd, int *sector_size)
  232 {
  233 #ifdef BLKPBSZGET
  234     if (ioctl(fd, BLKPBSZGET, &sector_size) >= 0)
  235         return 0;
  236     return -1;
  237 #else
  238     (void)fd; /* prevent unused parameter warning */
  239     *sector_size = DEFAULT_SECTOR_SIZE;
  240     return 0;
  241 #endif
  242 }
  243 
  244 /*
  245  * Return the alignment status of a device
  246  */
  247 int blkdev_is_misaligned(int fd)
  248 {
  249 #ifdef BLKALIGNOFF
  250     int aligned;
  251 
  252     if (ioctl(fd, BLKALIGNOFF, &aligned) < 0)
  253         return 0;           /* probably kernel < 2.6.32 */
  254     /*
  255      * Note that kernel returns -1 as alignement offset if no compatible
  256      * sizes and alignments exist for stacked devices
  257      */
  258     return aligned != 0 ? 1 : 0;
  259 #else
  260     (void)fd; /* prevent unused parameter warning */
  261     return 0;
  262 #endif
  263 }
  264 
  265 int blkdev_is_cdrom(int fd)
  266 {
  267 #ifdef CDROM_GET_CAPABILITY
  268     int ret;
  269 
  270     if ((ret = ioctl(fd, CDROM_GET_CAPABILITY, NULL)) < 0)
  271         return 0;
  272     else
  273         return ret;
  274 #else
  275     (void)fd; /* prevent unused parameter warning */
  276     return 0;
  277 #endif
  278 }
  279 
  280 /*
  281  * Get kernel's interpretation of the device's geometry.
  282  *
  283  * Returns the heads and sectors - but not cylinders
  284  * as it's truncated for disks with more than 65535 tracks.
  285  *
  286  * Note that this is deprecated in favor of LBA addressing.
  287  */
  288 int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s)
  289 {
  290 #ifdef HDIO_GETGEO
  291     {
  292         struct hd_geometry geometry;
  293 
  294         if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) {
  295             *h = geometry.heads;
  296             *s = geometry.sectors;
  297             return 0;
  298         }
  299     }
  300 #endif
  301 
  302 #ifdef FDGETPRM
  303     {
  304         struct floppy_struct fdparam;
  305 
  306         if (ioctl(fd, FDGETPRM, &fdparam) == 0) {
  307             *h = fdparam.head;
  308             *s = fdparam.sect;
  309             return 0;
  310         }
  311     }
  312 #endif
  313 
  314     (void)fd; /* prevent unused parameter warning */
  315     *h = 0;
  316     *s = 0;
  317     return -1;
  318 }
  319 
  320 /*
  321  * Get start offset of partition
  322  */
  323 int blkdev_get_start(int fd, dev_t rdev, unsigned long long *s)
  324 {
  325 #ifdef __linux__
  326     {
  327         char path[PATH_MAX];
  328         FILE *file;
  329         int ret;
  330 
  331         snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/start", major(rdev), minor(rdev));
  332         file = fopen(path, "r");
  333         if (file) {
  334             ret = fscanf(file, "%llu", s);
  335             fclose(file);
  336             if (ret == 1)
  337                 return 0;
  338         }
  339     }
  340 #endif
  341 
  342 #ifdef HDIO_GETGEO
  343     {
  344     struct hd_geometry geometry;
  345 
  346     if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) {
  347         *s = geometry.start;
  348         return 0;
  349     }
  350     }
  351 #endif
  352 
  353     (void)rdev; /* prevent unused parameter warning */
  354     (void)fd; /* prevent unused parameter warning */
  355     *s = 0;
  356     return -1;
  357 }
  358 
  359 /*
  360  * Convert scsi type to human readable string.
  361  */
  362 const char *blkdev_scsi_type_to_name(int type)
  363 {
  364     switch (type) {
  365     case SCSI_TYPE_DISK:
  366         return "disk";
  367     case SCSI_TYPE_TAPE:
  368         return "tape";
  369     case SCSI_TYPE_PRINTER:
  370         return "printer";
  371     case SCSI_TYPE_PROCESSOR:
  372         return "processor";
  373     case SCSI_TYPE_WORM:
  374         return "worm";
  375     case SCSI_TYPE_ROM:
  376         return "rom";
  377     case SCSI_TYPE_SCANNER:
  378         return "scanner";
  379     case SCSI_TYPE_MOD:
  380         return "mo-disk";
  381     case SCSI_TYPE_MEDIUM_CHANGER:
  382         return "changer";
  383     case SCSI_TYPE_COMM:
  384         return "comm";
  385     case SCSI_TYPE_RAID:
  386         return "raid";
  387     case SCSI_TYPE_ENCLOSURE:
  388         return "enclosure";
  389     case SCSI_TYPE_RBC:
  390         return "rbc";
  391     case SCSI_TYPE_OSD:
  392         return "osd";
  393     case SCSI_TYPE_NO_LUN:
  394         return "no-lun";
  395     default:
  396         break;
  397     }
  398     return NULL;
  399 }