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, §ors) < 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