Karel Zak <[EMAIL PROTECTED]> wrote:
> > It would be great to have an implementation that is guaranteed to work
> > with older kernels. The getsize() of e2fsprogs for example doesn't trust
> > BLKGETSIZE64 for kernels < 2.6.
> 
>  OK, send patch :-)

In the meantime I found that both implementations guard against broken
kernels 2.4.15-2.4.17:


http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=236528


util-linux-2.12a had a _very_ helpful comment, which got lost:

        /*
         * If BLKGETSIZE64 was unknown or broken, use longsectors.
         * (Kernels 2.4.15-2.4.17 had a broken BLKGETSIZE64
         * that returns sectors instead of bytes.)
         */



I find the e2fsprogs version more straightforward. This is a highly modified
version of getsize() in e2fsprogs. The original is GPL (copyright T. Ts'o).


=======================================================================

diff --git a/lib/blkdevsize.c b/lib/blkdevsize.c
new file mode 100644
index 0000000..8e1dabf
--- /dev/null
+++ b/lib/blkdevsize.c
@@ -0,0 +1,97 @@
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+#include "blkdevsize.h"
+
+/*
+ * maybe FIXME: a lot of implementations use this idiom:
+ *
+ *   #if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
+ */ 
+
+#define BLKGETSIZE _IO(0x12,96)    /* size in 512 byte sectors (ulong *arg) */
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)     /* size in bytes (u64 *arg) */
+
+
+static int kernel_ge_2_6(void)
+{
+       struct utsname ut;
+
+       if (uname(&ut) < 0)
+               return 0;
+
+       if ((ut.release[0] == '2') && (ut.release[1] == '.') &&
+           (ut.release[2] < '6') && (ut.release[3] == '.'))
+               return 0;
+
+       return 1;
+}
+
+/* get size in bytes */
+int blkdev_get_size(int fd, unsigned long long *bytes)
+{
+       unsigned long size;
+
+       /* kernels 2.4.15-2.4.17 had a broken BLKGETSIZE64 */
+       if (kernel_ge_2_6())
+               if (ioctl(fd, BLKGETSIZE64, bytes) >= 0)
+                       return 0;
+
+       if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
+               *bytes = ((unsigned long long)size << 9);
+               return 0;
+       }
+
+       return -1;
+}
+
+/* get sector count */
+int blkdev_get_sectors(int fd, unsigned long long *sectors)
+{
+       unsigned long long bytes;
+
+       if (blkdev_get_size(fd, &bytes) == 0) {
+               *sectors = (bytes >> 9);
+               return 0;
+       }
+
+       return -1;
+}
+
+
+#ifdef TEST_PROGRAM
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+int main(int argc, char **argv)
+{
+       unsigned long long bytes;
+       unsigned long long sectors;
+       int fd;
+
+
+       if (argc < 2) {
+               fprintf(stderr, "usage: %s device\n", argv[0]);
+               exit(1);
+       }
+
+       if ((fd = open(argv[1], O_RDONLY)) < 0) {
+               perror(argv[0]);
+               exit(1);
+       }
+
+       if (blkdev_get_size(fd, &bytes) < 0) {
+               perror(argv[0]);
+               exit(1);
+       }
+       if (blkdev_get_sectors(fd, &sectors) < 0) {
+               perror(argv[0]);
+               exit(1);
+       }
+
+       printf("bytes: %llu     sectors: %llu\n", bytes, sectors);
+
+       return 0;
+}
+#endif /* TEST_PROGRAM */
+


=======================================================================

diff --git a/lib/blkdevsize.h b/lib/blkdevsize.h
new file mode 100644
index 0000000..3199a03
--- /dev/null
+++ b/lib/blkdevsize.h
@@ -0,0 +1,11 @@
+#ifndef BLKDEVSIZE_H
+#define BLKDEVSIZE_H
+
+
+/* get size in bytes */
+int blkdev_get_size(int fd, unsigned long long *bytes);
+/* get sector count */
+int blkdev_get_sectors(int fd, unsigned long long *sectors);
+
+
+#endif /* BLKDEVSIZE_H */


-
To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to