2001-10-03 16:41:29 +04:00
/*
2002-08-14 18:58:00 +04:00
* Copyright ( C ) 2001 Sistina Software
2001-10-03 16:41:29 +04:00
*
2001-10-31 15:47:01 +03:00
* This file is released under the LGPL .
2001-10-03 16:41:29 +04:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2001-10-04 14:13:07 +04:00
# include "lvm-types.h"
2003-04-15 17:24:42 +04:00
# include "device.h"
2002-11-18 17:01:16 +03:00
# include "metadata.h"
2001-10-04 14:13:07 +04:00
2002-12-20 02:25:55 +03:00
# include <limits.h>
2001-10-04 14:13:07 +04:00
# include <sys/stat.h>
2002-07-22 12:10:54 +04:00
# include <fcntl.h>
2002-08-14 18:58:00 +04:00
# include <unistd.h>
2001-10-04 14:13:07 +04:00
# include <sys/ioctl.h>
2003-04-15 17:24:42 +04:00
# ifdef linux
# define u64 uint64_t /* Missing without __KERNEL__ */
# include <linux / fs.h> /* For block ioctl definitions */
# define BLKSIZE_SHIFT SECTOR_SHIFT
# endif
2001-11-13 21:52:52 +03:00
2002-12-20 02:25:55 +03:00
/* FIXME 64 bit offset!!!
_syscall5 ( int , _llseek , uint , fd , ulong , hi , ulong , lo , loff_t * , res , uint , wh ) ;
*/
2002-11-18 17:01:16 +03:00
int dev_get_size ( struct device * dev , uint64_t * size )
2001-10-03 16:41:29 +04:00
{
int fd ;
2001-10-25 18:04:18 +04:00
const char * name = dev_name ( dev ) ;
2001-10-03 16:41:29 +04:00
2001-10-25 18:04:18 +04:00
log_very_verbose ( " Getting size of %s " , name ) ;
if ( ( fd = open ( name , O_RDONLY ) ) < 0 ) {
log_sys_error ( " open " , name ) ;
2001-10-03 16:41:29 +04:00
return 0 ;
}
2003-04-15 17:24:42 +04:00
if ( ioctl ( fd , BLKGETSIZE64 , size ) < 0 ) {
log_sys_error ( " ioctl BLKGETSIZE64 " , name ) ;
2001-10-03 16:41:29 +04:00
close ( fd ) ;
return 0 ;
}
2003-04-30 19:21:10 +04:00
* size > > = BLKSIZE_SHIFT ; /* Convert to sectors */
2001-10-03 16:41:29 +04:00
close ( fd ) ;
return 1 ;
}
2002-11-18 17:01:16 +03:00
int dev_get_sectsize ( struct device * dev , uint32_t * size )
2001-12-11 13:18:49 +03:00
{
2002-08-14 18:58:00 +04:00
int fd ;
int s ;
const char * name = dev_name ( dev ) ;
log_very_verbose ( " Getting size of %s " , name ) ;
if ( ( fd = open ( name , O_RDONLY ) ) < 0 ) {
log_sys_error ( " open " , name ) ;
return 0 ;
}
if ( ioctl ( fd , BLKSSZGET , & s ) < 0 ) {
log_sys_error ( " ioctl BLKSSZGET " , name ) ;
close ( fd ) ;
return 0 ;
}
close ( fd ) ;
* size = ( uint32_t ) s ;
return 1 ;
}
static void _flush ( int fd )
{
2003-04-28 20:20:39 +04:00
if ( ioctl ( fd , BLKFLSBUF , 0 ) > = 0 )
return ;
if ( fsync ( fd ) > = 0 )
return ;
sync ( ) ;
2002-06-25 18:02:28 +04:00
}
2001-11-14 13:01:52 +03:00
int dev_open ( struct device * dev , int flags )
{
2002-01-23 21:55:01 +03:00
struct stat buf ;
2002-01-25 02:16:19 +03:00
const char * name = dev_name_confirmed ( dev ) ;
if ( ! name ) {
stack ;
return 0 ;
}
2001-11-14 13:01:52 +03:00
if ( dev - > fd > = 0 ) {
2001-11-14 16:52:38 +03:00
log_error ( " Device '%s' has already been opened " , name ) ;
2001-11-14 13:01:52 +03:00
return 0 ;
}
2002-01-23 21:55:01 +03:00
if ( ( stat ( name , & buf ) < 0 ) | | ( buf . st_rdev ! = dev - > dev ) ) {
log_error ( " %s: stat failed: Has device name changed? " , name ) ;
return 0 ;
}
2002-08-14 18:58:00 +04:00
if ( ( dev - > fd = open ( name , flags ) ) < 0 ) {
2001-11-14 16:52:38 +03:00
log_sys_error ( " open " , name ) ;
2001-11-14 13:01:52 +03:00
return 0 ;
}
2002-01-23 21:55:01 +03:00
if ( ( fstat ( dev - > fd , & buf ) < 0 ) | | ( buf . st_rdev ! = dev - > dev ) ) {
log_error ( " %s: fstat failed: Has device name changed? " , name ) ;
2002-01-24 16:31:18 +03:00
dev_close ( dev ) ;
2002-11-18 17:01:16 +03:00
dev - > fd = - 1 ;
2002-01-23 21:55:01 +03:00
return 0 ;
}
2002-08-14 18:58:00 +04:00
_flush ( dev - > fd ) ;
2002-04-24 22:20:51 +04:00
dev - > flags = 0 ;
2001-11-14 13:01:52 +03:00
return 1 ;
}
int dev_close ( struct device * dev )
{
if ( dev - > fd < 0 ) {
2001-11-14 16:52:38 +03:00
log_error ( " Attempt to close device '%s' "
" which is not open. " , dev_name ( dev ) ) ;
2001-11-14 13:01:52 +03:00
return 0 ;
}
2002-08-14 18:58:00 +04:00
if ( dev - > flags & DEV_ACCESSED_W )
_flush ( dev - > fd ) ;
2001-11-14 16:52:38 +03:00
if ( close ( dev - > fd ) )
log_sys_error ( " close " , dev_name ( dev ) ) ;
2001-11-14 13:01:52 +03:00
dev - > fd = - 1 ;
return 1 ;
}
2002-12-20 02:25:55 +03:00
ssize_t raw_read ( int fd , void * buf , size_t count )
2001-10-08 20:08:16 +04:00
{
2002-12-20 02:25:55 +03:00
ssize_t n = 0 , tot = 0 ;
2001-10-08 20:08:16 +04:00
2002-12-20 02:25:55 +03:00
if ( count > SSIZE_MAX )
return - 1 ;
while ( tot < ( signed ) count ) {
2001-10-23 15:16:30 +04:00
do
n = read ( fd , buf , count - tot ) ;
while ( ( n < 0 ) & & ( ( errno = = EINTR ) | | ( errno = = EAGAIN ) ) ) ;
2001-10-08 20:08:16 +04:00
if ( n < = 0 )
return tot ? tot : n ;
tot + = n ;
buf + = n ;
}
return tot ;
}
2002-12-20 02:25:55 +03:00
ssize_t dev_read ( struct device * dev , uint64_t offset , size_t len , void * buffer )
2001-10-03 16:41:29 +04:00
{
2001-10-25 18:04:18 +04:00
const char * name = dev_name ( dev ) ;
2001-11-14 13:01:52 +03:00
int fd = dev - > fd ;
2002-12-20 02:25:55 +03:00
/* loff_t pos; */
2001-10-08 20:08:16 +04:00
if ( fd < 0 ) {
2001-11-14 13:01:52 +03:00
log_err ( " Attempt to read an unopened device (%s). " , name ) ;
2001-10-08 20:08:16 +04:00
return 0 ;
}
2002-12-20 02:25:55 +03:00
/* if (_llseek((unsigned) fd, (ulong) (offset >> 32), (ulong) (offset & 0xFFFFFFFF), &pos, SEEK_SET) < 0) { */
if ( lseek ( fd , ( off_t ) offset , SEEK_SET ) < 0 ) {
2001-10-25 18:04:18 +04:00
log_sys_error ( " lseek " , name ) ;
2001-10-08 20:08:16 +04:00
return 0 ;
}
2002-11-18 17:01:16 +03:00
return raw_read ( fd , buffer , len ) ;
2001-10-03 16:41:29 +04:00
}
2002-12-20 02:25:55 +03:00
static int _write ( int fd , const void * buf , size_t count )
2001-10-10 17:03:10 +04:00
{
2002-11-18 17:01:16 +03:00
ssize_t n = 0 ;
2001-10-10 17:03:10 +04:00
int tot = 0 ;
2001-11-28 21:03:11 +03:00
/* Skip all writes */
if ( test_mode ( ) )
return count ;
2001-10-10 17:03:10 +04:00
while ( tot < count ) {
2001-10-23 15:16:30 +04:00
do
n = write ( fd , buf , count - tot ) ;
while ( ( n < 0 ) & & ( ( errno = = EINTR ) | | ( errno = = EAGAIN ) ) ) ;
2001-10-10 17:03:10 +04:00
if ( n < = 0 )
return tot ? tot : n ;
tot + = n ;
buf + = n ;
}
return tot ;
}
2002-12-20 02:25:55 +03:00
int64_t dev_write ( struct device * dev , uint64_t offset , size_t len ,
void * buffer )
2001-10-03 16:41:29 +04:00
{
2001-10-25 18:04:18 +04:00
const char * name = dev_name ( dev ) ;
2001-11-14 13:01:52 +03:00
int fd = dev - > fd ;
2001-10-10 17:03:10 +04:00
if ( fd < 0 ) {
2001-11-14 16:52:38 +03:00
log_error ( " Attempt to write to unopened device %s " , name ) ;
2001-10-10 17:03:10 +04:00
return 0 ;
}
2002-12-20 02:25:55 +03:00
if ( lseek ( fd , ( off_t ) offset , SEEK_SET ) < 0 ) {
2001-10-25 18:04:18 +04:00
log_sys_error ( " lseek " , name ) ;
2001-10-10 17:03:10 +04:00
return 0 ;
}
2002-04-24 22:20:51 +04:00
dev - > flags | = DEV_ACCESSED_W ;
2002-08-14 18:58:00 +04:00
return _write ( fd , buffer , len ) ;
2001-10-03 16:41:29 +04:00
}
2001-11-13 21:52:52 +03:00
2002-12-20 02:25:55 +03:00
int dev_zero ( struct device * dev , uint64_t offset , size_t len )
2001-11-13 21:52:52 +03:00
{
2002-12-20 02:25:55 +03:00
int64_t r ;
size_t s ;
2002-08-14 18:58:00 +04:00
char buffer [ 4096 ] ;
2002-11-18 17:01:16 +03:00
int already_open ;
2001-11-13 21:52:52 +03:00
2002-11-18 17:01:16 +03:00
already_open = dev_is_open ( dev ) ;
if ( ! already_open & & ! dev_open ( dev , O_RDWR ) ) {
stack ;
2001-11-13 21:52:52 +03:00
return 0 ;
}
2002-12-20 02:25:55 +03:00
if ( lseek ( dev - > fd , ( off_t ) offset , SEEK_SET ) < 0 ) {
2002-11-18 17:01:16 +03:00
log_sys_error ( " lseek " , dev_name ( dev ) ) ;
if ( ! already_open & & ! dev_close ( dev ) )
stack ;
2001-11-13 21:52:52 +03:00
return 0 ;
}
2002-11-18 17:01:16 +03:00
if ( ( offset % SECTOR_SIZE ) | | ( len % SECTOR_SIZE ) )
2003-01-08 19:41:22 +03:00
log_debug ( " Wiping %s at % " PRIu64 " length % " PRIsize_t ,
2002-11-18 17:01:16 +03:00
dev_name ( dev ) , offset , len ) ;
else
2003-01-08 19:41:22 +03:00
log_debug ( " Wiping %s at sector % " PRIu64 " length % " PRIsize_t
2002-11-18 17:01:16 +03:00
" sectors " , dev_name ( dev ) , offset > > SECTOR_SHIFT ,
len > > SECTOR_SHIFT ) ;
2002-08-14 18:58:00 +04:00
memset ( buffer , 0 , sizeof ( buffer ) ) ;
2001-11-13 21:52:52 +03:00
while ( 1 ) {
2002-08-14 18:58:00 +04:00
s = len > sizeof ( buffer ) ? sizeof ( buffer ) : len ;
2002-11-18 17:01:16 +03:00
r = _write ( dev - > fd , buffer , s ) ;
2001-11-13 21:52:52 +03:00
if ( r < = 0 )
break ;
len - = r ;
if ( ! len ) {
r = 1 ;
break ;
}
}
2002-04-24 22:20:51 +04:00
dev - > flags | = DEV_ACCESSED_W ;
2002-11-18 17:01:16 +03:00
if ( ! already_open & & ! dev_close ( dev ) )
stack ;
2001-11-19 18:20:50 +03:00
/* FIXME: Always display error */
2001-11-14 13:01:52 +03:00
return ( len = = 0 ) ;
2001-11-13 21:52:52 +03:00
}