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
*/
2001-10-04 14:13:07 +04:00
# include "device.h"
# include "lvm-types.h"
# include "log.h"
# include <sys/types.h>
# 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>
2002-08-14 18:58:00 +04:00
# include <linux/fs.h> // UGH!!! for BLKSSZGET
2001-11-13 21:52:52 +03:00
2002-04-24 22:20:51 +04:00
int dev_get_size ( struct device * dev , uint64_t * size )
2001-10-03 16:41:29 +04:00
{
int fd ;
long s ;
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 ;
}
/* FIXME: add 64 bit ioctl */
if ( ioctl ( fd , BLKGETSIZE , & s ) < 0 ) {
2001-10-25 18:04:18 +04:00
log_sys_error ( " ioctl BLKGETSIZE " , name ) ;
2001-10-03 16:41:29 +04:00
close ( fd ) ;
return 0 ;
}
close ( fd ) ;
* size = ( uint64_t ) s ;
return 1 ;
}
2002-04-24 22:20:51 +04: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 )
{
ioctl ( fd , BLKFLSBUF , 0 ) ;
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-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 ;
}
2001-10-10 17:03:10 +04:00
/*
* FIXME : factor common code out .
*/
2001-10-08 20:08:16 +04:00
int _read ( int fd , void * buf , size_t count )
{
size_t n = 0 ;
int tot = 0 ;
while ( tot < 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-04-24 22:20:51 +04:00
int64_t dev_read ( struct device * dev , uint64_t offset ,
2001-10-03 16:41:29 +04:00
int64_t len , void * buffer )
{
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-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-08-14 18:58:00 +04:00
if ( lseek ( fd , 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-08-14 18:58:00 +04:00
return _read ( fd , buffer , len ) ;
2001-10-03 16:41:29 +04:00
}
2001-10-10 17:03:10 +04:00
int _write ( int fd , const void * buf , size_t count )
{
size_t n = 0 ;
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-04-24 22:20:51 +04:00
int64_t dev_write ( struct device * dev , uint64_t offset ,
2001-10-03 16:41:29 +04:00
int64_t len , void * buffer )
{
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-08-14 18:58:00 +04:00
if ( lseek ( fd , 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
int dev_zero ( struct device * dev , uint64_t offset , int64_t len )
{
int64_t r , s ;
2002-08-14 18:58:00 +04:00
char buffer [ 4096 ] ;
2001-11-13 21:52:52 +03:00
const char * name = dev_name ( dev ) ;
2001-11-14 13:01:52 +03:00
int fd = dev - > fd ;
2001-11-13 21:52:52 +03:00
if ( fd < 0 ) {
2001-12-11 13:18:49 +03:00
log_error ( " Attempt to zero part of an unopened device %s " ,
2001-11-14 16:52:38 +03:00
name ) ;
2001-11-13 21:52:52 +03:00
return 0 ;
}
if ( lseek ( fd , offset , SEEK_SET ) < 0 ) {
log_sys_error ( " lseek " , name ) ;
return 0 ;
}
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 ;
r = _write ( 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 ;
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
}