2001-12-05 19:41:52 +03:00
/*
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
*
* This file is released under the LGPL .
*/
2002-11-14 17:44:42 +03:00
# include "libdm-targets.h"
# include "libdm-common.h"
2001-12-05 19:41:52 +03:00
# include <stdio.h>
# include <stdlib.h>
# include <stdarg.h>
# include <string.h>
# include <sys/param.h>
# include <sys/stat.h>
2003-01-22 00:25:11 +03:00
# include <unistd.h>
2001-12-05 19:41:52 +03:00
# include <errno.h>
2002-11-14 17:44:42 +03:00
# include <linux/dm-ioctl.h>
2003-01-22 00:25:11 +03:00
# include <linux/kdev_t.h>
2001-12-05 19:41:52 +03:00
# define DEV_DIR " / dev / "
static char _dm_dir [ PATH_MAX ] = DEV_DIR DM_DIR ;
2003-01-22 00:25:11 +03:00
static int _verbose = 0 ;
2002-01-03 13:39:21 +03:00
/*
2001-12-05 19:41:52 +03:00
* Library users can provide their own logging
* function .
*/
2002-11-14 22:26:28 +03:00
static void _default_log ( int level , const char * file , int line ,
const char * f , . . . )
2001-12-05 19:41:52 +03:00
{
2002-03-19 02:39:42 +03:00
va_list ap ;
2001-12-05 19:41:52 +03:00
2003-01-22 00:25:11 +03:00
if ( level > _LOG_WARN & & ! _verbose )
2002-03-14 16:39:33 +03:00
return ;
2002-03-19 02:39:42 +03:00
va_start ( ap , f ) ;
2002-03-14 16:39:33 +03:00
2003-01-22 00:25:11 +03:00
if ( level < _LOG_WARN )
2002-03-19 02:39:42 +03:00
vfprintf ( stderr , f , ap ) ;
2003-01-22 00:25:11 +03:00
else
vprintf ( f , ap ) ;
2002-03-14 16:39:33 +03:00
2002-03-19 02:39:42 +03:00
va_end ( ap ) ;
2001-12-05 19:41:52 +03:00
2003-01-22 00:25:11 +03:00
if ( level < _LOG_WARN )
fprintf ( stderr , " \n " ) ;
else
printf ( " \n " ) ;
2001-12-05 19:41:52 +03:00
}
dm_log_fn _log = _default_log ;
void dm_log_init ( dm_log_fn fn )
{
2002-03-19 02:39:42 +03:00
_log = fn ;
2001-12-05 19:41:52 +03:00
}
2003-01-22 00:25:11 +03:00
void dm_log_init_verbose ( int level )
{
_verbose = level ;
}
2002-11-14 22:26:28 +03:00
static void _build_dev_path ( char * buffer , size_t len , const char * dev_name )
2001-12-14 16:30:04 +03:00
{
/* If there's a /, assume caller knows what they're doing */
if ( strchr ( dev_name , ' / ' ) )
snprintf ( buffer , len , " %s " , dev_name ) ;
else
2002-03-19 02:39:42 +03:00
snprintf ( buffer , len , " %s/%s " , _dm_dir , dev_name ) ;
2001-12-14 16:30:04 +03:00
}
2002-01-17 17:13:25 +03:00
int dm_get_library_version ( char * version , size_t size )
{
strncpy ( version , DM_LIB_VERSION , size ) ;
return 1 ;
}
2001-12-05 19:41:52 +03:00
struct dm_task * dm_task_create ( int type )
{
2002-03-19 02:39:42 +03:00
struct dm_task * dmt = malloc ( sizeof ( * dmt ) ) ;
2001-12-05 19:41:52 +03:00
2003-01-22 00:25:11 +03:00
if ( ! dm_check_version ( ) )
return NULL ;
2002-03-19 02:39:42 +03:00
if ( ! dmt ) {
log_error ( " dm_task_create: malloc(%d) failed " , sizeof ( * dmt ) ) ;
return NULL ;
}
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
memset ( dmt , 0 , sizeof ( * dmt ) ) ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
dmt - > type = type ;
2002-01-11 15:12:46 +03:00
dmt - > minor = - 1 ;
2003-04-02 23:03:00 +04:00
dmt - > major = - 1 ;
2003-01-22 00:25:11 +03:00
2002-03-19 02:39:42 +03:00
return dmt ;
2001-12-05 19:41:52 +03:00
}
int dm_task_set_name ( struct dm_task * dmt , const char * name )
{
2001-12-14 16:30:04 +03:00
char * pos ;
char path [ PATH_MAX ] ;
struct stat st1 , st2 ;
2002-03-19 02:39:42 +03:00
if ( dmt - > dev_name ) {
free ( dmt - > dev_name ) ;
2002-03-12 01:44:36 +03:00
dmt - > dev_name = NULL ;
}
2001-12-05 19:41:52 +03:00
2001-12-14 16:30:04 +03:00
/* If path was supplied, remove it if it points to the same device
* as its last component .
*/
if ( ( pos = strrchr ( name , ' / ' ) ) ) {
2002-01-17 16:19:55 +03:00
snprintf ( path , sizeof ( path ) , " %s/%s " , _dm_dir , pos + 1 ) ;
2001-12-14 16:30:04 +03:00
if ( stat ( name , & st1 ) | | stat ( path , & st2 ) | |
! ( st1 . st_dev = = st2 . st_dev ) ) {
2002-03-19 02:39:42 +03:00
log_error ( " dm_task_set_name: Device %s not found " ,
name ) ;
2001-12-14 16:30:04 +03:00
return 0 ;
}
name = pos + 1 ;
}
2002-03-19 02:39:42 +03:00
if ( ! ( dmt - > dev_name = strdup ( name ) ) ) {
2002-01-18 22:37:26 +03:00
log_error ( " dm_task_set_name: strdup(%s) failed " , name ) ;
2001-12-14 16:30:04 +03:00
return 0 ;
}
2002-03-19 02:39:42 +03:00
return 1 ;
2001-12-05 19:41:52 +03:00
}
2002-03-12 01:44:36 +03:00
int dm_task_set_uuid ( struct dm_task * dmt , const char * uuid )
{
if ( dmt - > uuid ) {
free ( dmt - > uuid ) ;
dmt - > uuid = NULL ;
}
if ( ! ( dmt - > uuid = strdup ( uuid ) ) ) {
log_error ( " dm_task_set_uuid: strdup(%s) failed " , uuid ) ;
return 0 ;
}
return 1 ;
}
2003-04-02 23:03:00 +04:00
int dm_task_set_major ( struct dm_task * dmt , int major )
{
dmt - > major = major ;
log_debug ( " Setting major: %d " , dmt - > major ) ;
return 1 ;
}
2002-01-11 15:12:46 +03:00
int dm_task_set_minor ( struct dm_task * dmt , int minor )
{
2002-03-19 02:39:42 +03:00
dmt - > minor = minor ;
log_debug ( " Setting minor: %d " , dmt - > minor ) ;
2002-01-11 15:12:46 +03:00
2002-03-19 02:39:42 +03:00
return 1 ;
}
2002-01-11 15:12:46 +03:00
2002-03-19 02:39:42 +03:00
int dm_task_add_target ( struct dm_task * dmt , uint64_t start , uint64_t size ,
const char * ttype , const char * params )
2001-12-05 19:41:52 +03:00
{
2002-03-19 02:39:42 +03:00
struct target * t = create_target ( start , size , ttype , params ) ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( ! t )
return 0 ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( ! dmt - > head )
dmt - > head = dmt - > tail = t ;
else {
dmt - > tail - > next = t ;
dmt - > tail = t ;
}
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
return 1 ;
2001-12-05 19:41:52 +03:00
}
2003-01-22 00:25:11 +03:00
int add_dev_node ( const char * dev_name , uint32_t major , uint32_t minor )
2001-12-05 19:41:52 +03:00
{
2002-03-19 02:39:42 +03:00
char path [ PATH_MAX ] ;
struct stat info ;
2003-01-22 00:25:11 +03:00
dev_t dev = MKDEV ( major , minor ) ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
_build_dev_path ( path , sizeof ( path ) , dev_name ) ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( stat ( path , & info ) > = 0 ) {
if ( ! S_ISBLK ( info . st_mode ) ) {
log_error ( " A non-block device file at '%s' "
" is already present " , path ) ;
return 0 ;
}
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( info . st_rdev = = dev )
return 1 ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( unlink ( path ) < 0 ) {
log_error ( " Unable to unlink device node for '%s' " ,
dev_name ) ;
return 0 ;
}
}
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( mknod ( path , S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP , dev ) < 0 ) {
log_error ( " Unable to make device node for '%s' " , dev_name ) ;
return 0 ;
}
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
return 1 ;
2001-12-05 19:41:52 +03:00
}
2002-04-11 16:45:18 +04:00
int rename_dev_node ( const char * old_name , const char * new_name )
{
char oldpath [ PATH_MAX ] ;
char newpath [ PATH_MAX ] ;
struct stat info ;
_build_dev_path ( oldpath , sizeof ( oldpath ) , old_name ) ;
_build_dev_path ( newpath , sizeof ( newpath ) , new_name ) ;
2002-04-24 01:47:50 +04:00
if ( stat ( newpath , & info ) = = 0 ) {
2002-04-11 16:45:18 +04:00
if ( ! S_ISBLK ( info . st_mode ) ) {
log_error ( " A non-block device file at '%s' "
" is already present " , newpath ) ;
return 0 ;
}
if ( unlink ( newpath ) < 0 ) {
2003-01-22 00:25:11 +03:00
if ( errno = = EPERM ) {
2002-04-24 01:47:50 +04:00
/* devfs, entry has already been renamed */
return 1 ;
2002-04-11 16:45:18 +04:00
}
log_error ( " Unable to unlink device node for '%s' " ,
new_name ) ;
return 0 ;
}
}
if ( rename ( oldpath , newpath ) < 0 ) {
2002-04-24 01:47:50 +04:00
log_error ( " Unable to rename device node from '%s' to '%s' " ,
old_name , new_name ) ;
2002-04-11 16:45:18 +04:00
return 0 ;
}
return 1 ;
}
2001-12-05 19:41:52 +03:00
int rm_dev_node ( const char * dev_name )
{
2002-03-19 02:39:42 +03:00
char path [ PATH_MAX ] ;
struct stat info ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
_build_dev_path ( path , sizeof ( path ) , dev_name ) ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( stat ( path , & info ) < 0 )
return 1 ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( unlink ( path ) < 0 ) {
log_error ( " Unable to unlink device node for '%s' " , dev_name ) ;
return 0 ;
}
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
return 1 ;
2001-12-05 19:41:52 +03:00
}
int dm_set_dev_dir ( const char * dir )
{
2002-03-19 02:39:42 +03:00
snprintf ( _dm_dir , sizeof ( _dm_dir ) , " %s%s " , dir , DM_DIR ) ;
return 1 ;
2001-12-05 19:41:52 +03:00
}
const char * dm_dir ( void )
{
2002-03-19 02:39:42 +03:00
return _dm_dir ;
2001-12-05 19:41:52 +03:00
}