[PATCH] lib: create blkdevsize.c and blkdevsize.h

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Karel Zak <kzak@xxxxxxxxxx> 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux