tech-userlevel archive

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

Re: Issues with lseek(2) on a block device



Hello, thanks to everyone who responded with their suggestions. Using
various non-portable ioctls I can device size on most platforms, for
both block and raw devices.

This is more convoluted than a single lseek() call, but it is what it
is. If anyone wants to do something similar, then the following example
can give you a good start.

/*
* devsize.c
* gcc -DNETBSD -Wall -Wextra -pedantic -o devsize devsize.c
*/

#include <assert.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>

#if defined(NETBSD)
#include <sys/dkio.h>
#endif

#if defined(FREEBSD)
#include <sys/disk.h>
#endif

#if defined(MACOS)
#include <sys/disk.h>
#endif

#if defined(LINUX)
#include <linux/fs.h>
#endif

/*
* Use lseek() to get device size in bytes.
* This should be portable, but on some platforms returns 0 bytes,
* in which case nonportable ioctl should be used.
*/
static void print_devsize_lseek(int fd)
{
	off_t size;

	size = lseek(fd, 0, SEEK_END);
	assert(size >= 0);
	printf("lseek SEEK_END           = %ju bytes\n", (uintmax_t)size);
}

/* NetBSD, FreeBSD */
#if defined(DIOCGMEDIASIZE)
static void print_devsize_DIOCGMEDIASIZE(int fd)
{
	int   int_val;
	off_t size;

	/* This sets size to total number of bytes */
	int_val = ioctl(fd, DIOCGMEDIASIZE, &size);
	assert(int_val >= 0);
	printf("ioctl DIOCGMEDIASIZE     = %ju bytes\n", (uintmax_t)size);
}
#endif

/* MacOS */
#if defined(DKIOCGETBLOCKCOUNT) && defined(DKIOCGETBLOCKSIZE)
static void print_devsize_DKIOCGETBLOCKCOUNT(int fd)
{
	int      int_val
	uint64_t block_count;
	uint32_t block_size;

	/* Total block count */
	int_val = ioctl(fd, DKIOCGETBLOCKCOUNT, &block_count);
	assert(int_val >= 0);
	/* Block size */
	int_val = ioctl(fd, DKIOCGETBLOCKSIZE, &block_size);
	assert(int_val >= 0);
	printf("ioctl DKIOCGETBLOCKCOUNT = %ju bytes\n",
		(uintmax_t)block_count * (uintmax_t)block_size);
}
#endif

/* Linux */
#if defined(BLKGETSIZE)
static void print_devsize_BLKGETSIZE(int fd)
{
	int           int_val;
	unsigned long size;

	/* This sets size to number of 512-byte blocks */
	int_val = ioctl(fd, BLKGETSIZE, &size);
	assert(int_val >= 0);
	printf("ioctl BLKGETSIZE         = %ju bytes\n", (uintmax_t)size * 512);
}
#endif

/* Linux */
#if defined(BLKGETSIZE64)
static void print_devsize_BLKGETSIZE64(int fd)
{
	int      int_val;
	uint64_t size;

	/* This sets size to total number of bytes */
	int_val = ioctl(fd, BLKGETSIZE64, &size);
	assert(int_val >= 0);
	printf("ioctl BLKGETSIZE         = %ju bytes\n", (uintmax_t)size);
}
#endif


int main(int argc, char *argv[])
{
	int   fd;

	if (argc != 2)
	{
		fprintf(stderr, "Usage: devsize <device>\n");
		exit(EXIT_FAILURE);
	}

	/* Open device */
	fd = open(argv[1], O_RDONLY);
	assert(fd >= 0);

	print_devsize_lseek(fd);

	#if defined(DIOCGMEDIASIZE)
	print_devsize_DIOCGMEDIASIZE(fd);
	#endif

	#if defined(DKIOCGETBLOCKCOUNT) && defined(DKIOCGETBLOCKSIZE)
	print_devsize_DKIOCGETBLOCKCOUNT(fd);
	#endif

	#if defined(BLKGETSIZE)
	print_devsize_BLKGETSIZE(fd);
	#endif

	#if defined(BLKGETSIZE64)
	print_devsize_BLKGETSIZE64(fd);
	#endif
}


Home | Main Index | Thread Index | Old Index