busybox/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * getsize.c --- get the size of a partition.
   4 *
   5 * Copyright (C) 1995, 1995 Theodore Ts'o.
   6 *
   7 * %Begin-Header%
   8 * This file may be redistributed under the terms of the
   9 * GNU Lesser General Public License.
  10 * %End-Header%
  11 */
  12
  13/* include this before sys/queues.h! */
  14#include "blkidP.h"
  15
  16#include <stdio.h>
  17#include <unistd.h>
  18#ifdef HAVE_ERRNO_H
  19#include <errno.h>
  20#endif
  21#include <fcntl.h>
  22#ifdef HAVE_SYS_IOCTL_H
  23#include <sys/ioctl.h>
  24#endif
  25#ifdef HAVE_LINUX_FD_H
  26#include <linux/fd.h>
  27#endif
  28#ifdef HAVE_SYS_DISKLABEL_H
  29#include <sys/disklabel.h>
  30#include <sys/stat.h>
  31#endif
  32#ifdef HAVE_SYS_DISK_H
  33#ifdef HAVE_SYS_QUEUE_H
  34#include <sys/queue.h> /* for LIST_HEAD */
  35#endif
  36#include <sys/disk.h>
  37#endif
  38#ifdef __linux__
  39#include <sys/utsname.h>
  40#endif
  41
  42#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
  43#define BLKGETSIZE _IO(0x12,96) /* return device size */
  44#endif
  45
  46#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
  47#define BLKGETSIZE64 _IOR(0x12,114,size_t)      /* return device size in bytes (u64 *arg) */
  48#endif
  49
  50#ifdef APPLE_DARWIN
  51#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
  52#endif /* APPLE_DARWIN */
  53
  54static int valid_offset(int fd, blkid_loff_t offset)
  55{
  56        char ch;
  57
  58        if (blkid_llseek(fd, offset, 0) < 0)
  59                return 0;
  60        if (read(fd, &ch, 1) < 1)
  61                return 0;
  62        return 1;
  63}
  64
  65/*
  66 * Returns the number of blocks in a partition
  67 */
  68blkid_loff_t blkid_get_dev_size(int fd)
  69{
  70        int valid_blkgetsize64 = 1;
  71#ifdef __linux__
  72        struct          utsname ut;
  73#endif
  74        unsigned long long size64;
  75        unsigned long size;
  76        blkid_loff_t high, low;
  77#ifdef FDGETPRM
  78        struct floppy_struct this_floppy;
  79#endif
  80#ifdef HAVE_SYS_DISKLABEL_H
  81        int part = -1;
  82        struct disklabel lab;
  83        struct partition *pp;
  84        char ch;
  85        struct stat st;
  86#endif /* HAVE_SYS_DISKLABEL_H */
  87
  88#ifdef DKIOCGETBLOCKCOUNT       /* For Apple Darwin */
  89        if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) {
  90                if ((sizeof(blkid_loff_t) < sizeof(unsigned long long))
  91                    && (size64 << 9 > 0xFFFFFFFF))
  92                        return 0; /* EFBIG */
  93                return (blkid_loff_t) size64 << 9;
  94        }
  95#endif
  96
  97#ifdef BLKGETSIZE64
  98#ifdef __linux__
  99        if ((uname(&ut) == 0) &&
 100            ((ut.release[0] == '2') && (ut.release[1] == '.') &&
 101             (ut.release[2] < '6') && (ut.release[3] == '.')))
 102                valid_blkgetsize64 = 0;
 103#endif
 104        if (valid_blkgetsize64 &&
 105            ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
 106                if ((sizeof(blkid_loff_t) < sizeof(unsigned long long))
 107                    && ((size64) > 0xFFFFFFFF))
 108                        return 0; /* EFBIG */
 109                return size64;
 110        }
 111#endif
 112
 113#ifdef BLKGETSIZE
 114        if (ioctl(fd, BLKGETSIZE, &size) >= 0)
 115                return (blkid_loff_t)size << 9;
 116#endif
 117
 118#ifdef FDGETPRM
 119        if (ioctl(fd, FDGETPRM, &this_floppy) >= 0)
 120                return (blkid_loff_t)this_floppy.size << 9;
 121#endif
 122#ifdef HAVE_SYS_DISKLABEL_H
 123#if 0
 124        /*
 125         * This should work in theory but I haven't tested it.  Anyone
 126         * on a BSD system want to test this for me?  In the meantime,
 127         * binary search mechanism should work just fine.
 128         */
 129        if ((fstat(fd, &st) >= 0) && S_ISBLK(st.st_mode))
 130                part = st.st_rdev & 7;
 131        if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
 132                pp = &lab.d_partitions[part];
 133                if (pp->p_size)
 134                        return pp->p_size << 9;
 135        }
 136#endif
 137#endif /* HAVE_SYS_DISKLABEL_H */
 138
 139        /*
 140         * OK, we couldn't figure it out by using a specialized ioctl,
 141         * which is generally the best way.  So do binary search to
 142         * find the size of the partition.
 143         */
 144        low = 0;
 145        for (high = 1024; valid_offset(fd, high); high *= 2)
 146                low = high;
 147        while (low < high - 1)
 148        {
 149                const blkid_loff_t mid = (low + high) / 2;
 150
 151                if (valid_offset(fd, mid))
 152                        low = mid;
 153                else
 154                        high = mid;
 155        }
 156        return low + 1;
 157}
 158
 159#ifdef TEST_PROGRAM
 160int main(int argc, char **argv)
 161{
 162        blkid_loff_t bytes;
 163        int     fd;
 164
 165        if (argc < 2) {
 166                fprintf(stderr, "Usage: %s device\n"
 167                        "Determine the size of a device\n", argv[0]);
 168                return 1;
 169        }
 170
 171        if ((fd = open(argv[1], O_RDONLY)) < 0)
 172                perror(argv[0]);
 173
 174        bytes = blkid_get_dev_size(fd);
 175        printf("Device %s has %lld 1k blocks.\n", argv[1], bytes >> 10);
 176
 177        return 0;
 178}
 179#endif
 180