2001-11-09 11:48:22 +03:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 Red Hat , Inc . All rights reserved .
2001-11-09 11:48:22 +03:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2001-11-09 11:48:22 +03:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2002-02-11 23:50:53 +03:00
# include "fs.h"
# include "toolcontext.h"
2002-02-26 14:49:17 +03:00
# include "lvm-string.h"
2002-03-12 01:23:24 +03:00
# include "lvm-file.h"
2003-07-05 02:34:56 +04:00
# include "memlock.h"
2002-02-11 23:50:53 +03:00
2004-04-07 18:08:22 +04:00
# ifdef HAVE_SELINUX
# include "selinux.h"
# endif
2001-11-12 14:48:31 +03:00
# include <sys/stat.h>
# include <fcntl.h>
2001-11-09 11:48:22 +03:00
# include <unistd.h>
2001-11-12 14:48:31 +03:00
# include <limits.h>
2003-01-03 16:50:47 +03:00
# include <dirent.h>
2001-11-21 22:32:35 +03:00
# include <libdevmapper.h>
2002-01-11 02:21:07 +03:00
2003-07-05 02:34:56 +04:00
static int _mk_dir ( const char * dev_dir , const char * vg_name )
2001-11-09 11:48:22 +03:00
{
char vg_path [ PATH_MAX ] ;
2002-02-26 19:08:22 +03:00
if ( lvm_snprintf ( vg_path , sizeof ( vg_path ) , " %s%s " ,
2003-07-05 02:34:56 +04:00
dev_dir , vg_name ) = = - 1 ) {
2002-02-26 14:49:17 +03:00
log_error ( " Couldn't construct name of volume "
" group directory. " ) ;
2002-01-21 14:06:32 +03:00
return 0 ;
}
2001-12-05 02:20:27 +03:00
2002-03-12 01:23:24 +03:00
if ( dir_exists ( vg_path ) )
2002-03-11 23:43:58 +03:00
return 1 ;
2002-03-12 01:23:24 +03:00
log_very_verbose ( " Creating directory %s " , vg_path ) ;
2004-09-02 18:38:46 +04:00
if ( mkdir ( vg_path , 0777 ) ) {
2002-03-12 01:23:24 +03:00
log_sys_error ( " mkdir " , vg_path ) ;
2002-03-11 23:43:58 +03:00
return 0 ;
}
2002-03-12 01:23:24 +03:00
return 1 ;
2002-03-11 23:43:58 +03:00
}
2003-07-05 02:34:56 +04:00
static int _rm_dir ( const char * dev_dir , const char * vg_name )
2001-11-09 11:48:22 +03:00
{
char vg_path [ PATH_MAX ] ;
2002-02-26 19:08:22 +03:00
if ( lvm_snprintf ( vg_path , sizeof ( vg_path ) , " %s%s " ,
2003-07-05 02:34:56 +04:00
dev_dir , vg_name ) = = - 1 ) {
2002-02-26 14:49:17 +03:00
log_error ( " Couldn't construct name of volume "
" group directory. " ) ;
2002-01-21 14:06:32 +03:00
return 0 ;
}
2001-12-05 02:20:27 +03:00
log_very_verbose ( " Removing directory %s " , vg_path ) ;
2002-03-11 23:43:58 +03:00
2002-03-12 01:23:24 +03:00
if ( is_empty_dir ( vg_path ) )
2002-03-11 23:43:58 +03:00
rmdir ( vg_path ) ;
2002-01-21 14:06:32 +03:00
return 1 ;
2001-11-09 11:48:22 +03:00
}
2003-01-03 16:50:47 +03:00
static void _rm_blks ( const char * dir )
{
const char * name ;
char path [ PATH_MAX ] ;
struct dirent * dirent ;
struct stat buf ;
DIR * d ;
if ( ! ( d = opendir ( dir ) ) ) {
log_sys_error ( " opendir " , dir ) ;
return ;
}
while ( ( dirent = readdir ( d ) ) ) {
name = dirent - > d_name ;
if ( ! strcmp ( name , " . " ) | | ! strcmp ( name , " .. " ) )
continue ;
if ( lvm_snprintf ( path , sizeof ( path ) , " %s/%s " , dir , name ) = = - 1 ) {
log_error ( " Couldn't create path for %s " , name ) ;
continue ;
}
if ( ! lstat ( path , & buf ) ) {
if ( ! S_ISBLK ( buf . st_mode ) )
continue ;
log_very_verbose ( " Removing %s " , path ) ;
if ( unlink ( path ) < 0 )
log_sys_error ( " unlink " , path ) ;
}
}
}
2003-07-05 02:34:56 +04:00
static int _mk_link ( const char * dev_dir , const char * vg_name ,
const char * lv_name , const char * dev )
2001-11-09 11:48:22 +03:00
{
2003-01-03 16:50:47 +03:00
char lv_path [ PATH_MAX ] , link_path [ PATH_MAX ] , lvm1_group_path [ PATH_MAX ] ;
char vg_path [ PATH_MAX ] ;
2002-01-22 22:58:37 +03:00
struct stat buf ;
2001-11-09 11:48:22 +03:00
2003-01-03 16:50:47 +03:00
if ( lvm_snprintf ( vg_path , sizeof ( vg_path ) , " %s%s " ,
2003-07-05 02:34:56 +04:00
dev_dir , vg_name ) = = - 1 ) {
2003-01-03 16:50:47 +03:00
log_error ( " Couldn't create path for volume group dir %s " ,
2003-07-05 02:34:56 +04:00
vg_name ) ;
2003-01-03 16:50:47 +03:00
return 0 ;
}
if ( lvm_snprintf ( lv_path , sizeof ( lv_path ) , " %s/%s " , vg_path ,
2003-07-05 02:34:56 +04:00
lv_name ) = = - 1 ) {
2002-02-26 14:49:17 +03:00
log_error ( " Couldn't create source pathname for "
2003-07-05 02:34:56 +04:00
" logical volume link %s " , lv_name ) ;
2002-01-21 14:06:32 +03:00
return 0 ;
}
2002-02-26 14:49:17 +03:00
if ( lvm_snprintf ( link_path , sizeof ( link_path ) , " %s/%s " ,
dm_dir ( ) , dev ) = = - 1 ) {
log_error ( " Couldn't create destination pathname for "
2003-07-05 02:34:56 +04:00
" logical volume link for %s " , lv_name ) ;
2002-01-21 14:06:32 +03:00
return 0 ;
}
2001-11-12 14:42:29 +03:00
2003-01-03 16:50:47 +03:00
if ( lvm_snprintf ( lvm1_group_path , sizeof ( lvm1_group_path ) , " %s/group " ,
vg_path ) = = - 1 ) {
log_error ( " Couldn't create pathname for LVM1 group file for %s " ,
2003-07-05 02:34:56 +04:00
vg_name ) ;
2003-01-03 16:50:47 +03:00
return 0 ;
}
/* To reach this point, the VG must have been locked.
* As locking fails if the VG is active under LVM1 , it ' s
* now safe to remove any LVM1 devices we find here
* ( as well as any existing LVM2 symlink ) . */
if ( ! lstat ( lvm1_group_path , & buf ) ) {
if ( ! S_ISCHR ( buf . st_mode ) ) {
log_error ( " Non-LVM1 character device found at %s " ,
lvm1_group_path ) ;
} else {
_rm_blks ( vg_path ) ;
log_very_verbose ( " Removing %s " , lvm1_group_path ) ;
if ( unlink ( lvm1_group_path ) < 0 )
log_sys_error ( " unlink " , lvm1_group_path ) ;
}
}
2002-02-26 14:49:17 +03:00
if ( ! lstat ( lv_path , & buf ) ) {
2003-01-03 16:50:47 +03:00
if ( ! S_ISLNK ( buf . st_mode ) & & ! S_ISBLK ( buf . st_mode ) ) {
2002-01-22 22:58:37 +03:00
log_error ( " Symbolic link %s not created: file exists " ,
link_path ) ;
return 0 ;
}
2002-02-26 14:49:17 +03:00
2003-01-03 16:50:47 +03:00
log_very_verbose ( " Removing %s " , lv_path ) ;
2002-02-26 14:49:17 +03:00
if ( unlink ( lv_path ) < 0 ) {
log_sys_error ( " unlink " , lv_path ) ;
2002-01-22 22:58:37 +03:00
return 0 ;
}
}
2002-02-26 19:08:22 +03:00
log_very_verbose ( " Linking %s -> %s " , lv_path , link_path ) ;
2002-02-26 14:49:17 +03:00
if ( symlink ( link_path , lv_path ) < 0 ) {
log_sys_error ( " symlink " , lv_path ) ;
2001-11-12 14:42:29 +03:00
return 0 ;
}
2004-04-07 18:08:22 +04:00
# ifdef HAVE_SELINUX
2004-04-14 22:10:10 +04:00
if ( ! set_selinux_context ( lv_path ) ) {
2004-05-04 19:29:26 +04:00
stack ;
2004-04-07 18:08:22 +04:00
return 0 ;
}
# endif
2001-11-12 14:42:29 +03:00
return 1 ;
}
2003-07-05 02:34:56 +04:00
static int _rm_link ( const char * dev_dir , const char * vg_name ,
const char * lv_name )
2001-11-12 14:42:29 +03:00
{
2002-01-25 23:17:44 +03:00
struct stat buf ;
2002-02-26 14:49:17 +03:00
char lv_path [ PATH_MAX ] ;
2001-11-12 14:42:29 +03:00
2002-02-26 19:08:22 +03:00
if ( lvm_snprintf ( lv_path , sizeof ( lv_path ) , " %s%s/%s " ,
2003-07-05 02:34:56 +04:00
dev_dir , vg_name , lv_name ) = = - 1 ) {
2002-01-28 00:30:47 +03:00
log_error ( " Couldn't determine link pathname. " ) ;
2002-01-21 14:06:32 +03:00
return 0 ;
}
2001-11-12 14:42:29 +03:00
2002-02-26 14:49:17 +03:00
if ( lstat ( lv_path , & buf ) | | ! S_ISLNK ( buf . st_mode ) ) {
2003-11-12 22:16:48 +03:00
if ( errno ! = ENOENT )
log_error ( " %s not symbolic link - not removing " ,
lv_path ) ;
2002-02-26 14:49:17 +03:00
return 0 ;
2002-01-25 23:17:44 +03:00
}
2002-02-26 14:49:17 +03:00
2003-01-03 16:50:47 +03:00
log_very_verbose ( " Removing link %s " , lv_path ) ;
2002-02-26 14:49:17 +03:00
if ( unlink ( lv_path ) < 0 ) {
log_sys_error ( " unlink " , lv_path ) ;
2001-11-12 14:42:29 +03:00
return 0 ;
}
return 1 ;
2001-11-09 11:48:22 +03:00
}
2003-07-05 02:34:56 +04:00
typedef enum {
FS_ADD ,
FS_DEL ,
FS_RENAME
} fs_op_t ;
static int _do_fs_op ( fs_op_t type , const char * dev_dir , const char * vg_name ,
const char * lv_name , const char * dev ,
const char * old_lv_name )
2001-11-09 11:48:22 +03:00
{
2003-07-05 02:34:56 +04:00
switch ( type ) {
case FS_ADD :
if ( ! _mk_dir ( dev_dir , vg_name ) | |
! _mk_link ( dev_dir , vg_name , lv_name , dev ) ) {
stack ;
return 0 ;
}
break ;
case FS_DEL :
if ( ! _rm_link ( dev_dir , vg_name , lv_name ) | |
! _rm_dir ( dev_dir , vg_name ) ) {
stack ;
return 0 ;
}
break ;
/* FIXME Use rename() */
case FS_RENAME :
if ( old_lv_name & & ! _rm_link ( dev_dir , vg_name , old_lv_name ) )
stack ;
if ( ! _mk_link ( dev_dir , vg_name , lv_name , dev ) )
stack ;
2001-11-09 11:48:22 +03:00
}
return 1 ;
}
2003-07-05 02:34:56 +04:00
static LIST_INIT ( _fs_ops ) ;
struct fs_op_parms {
struct list list ;
fs_op_t type ;
char * dev_dir ;
char * vg_name ;
char * lv_name ;
char * dev ;
char * old_lv_name ;
char names [ 0 ] ;
} ;
static void _store_str ( char * * pos , char * * ptr , const char * str )
2001-11-09 11:48:22 +03:00
{
2003-07-05 02:34:56 +04:00
strcpy ( * pos , str ) ;
* ptr = * pos ;
* pos + = strlen ( * ptr ) + 1 ;
}
static int _stack_fs_op ( fs_op_t type , const char * dev_dir , const char * vg_name ,
const char * lv_name , const char * dev ,
const char * old_lv_name )
{
struct fs_op_parms * fsp ;
size_t len = strlen ( dev_dir ) + strlen ( vg_name ) + strlen ( lv_name ) +
strlen ( dev ) + strlen ( old_lv_name ) + 5 ;
char * pos ;
if ( ! ( fsp = dbg_malloc ( sizeof ( * fsp ) + len ) ) ) {
log_error ( " No space to stack fs operation " ) ;
2001-11-09 11:48:22 +03:00
return 0 ;
}
2003-07-05 02:34:56 +04:00
pos = fsp - > names ;
fsp - > type = type ;
_store_str ( & pos , & fsp - > dev_dir , dev_dir ) ;
_store_str ( & pos , & fsp - > vg_name , vg_name ) ;
_store_str ( & pos , & fsp - > lv_name , lv_name ) ;
_store_str ( & pos , & fsp - > dev , dev ) ;
_store_str ( & pos , & fsp - > old_lv_name , old_lv_name ) ;
list_add ( & _fs_ops , & fsp - > list ) ;
2001-11-09 11:48:22 +03:00
return 1 ;
}
2003-07-05 02:34:56 +04:00
static void _pop_fs_ops ( void )
{
struct list * fsph , * fspht ;
struct fs_op_parms * fsp ;
list_iterate_safe ( fsph , fspht , & _fs_ops ) {
fsp = list_item ( fsph , struct fs_op_parms ) ;
_do_fs_op ( fsp - > type , fsp - > dev_dir , fsp - > vg_name , fsp - > lv_name ,
fsp - > dev , fsp - > old_lv_name ) ;
list_del ( & fsp - > list ) ;
dbg_free ( fsp ) ;
}
}
static int _fs_op ( fs_op_t type , const char * dev_dir , const char * vg_name ,
const char * lv_name , const char * dev , const char * old_lv_name )
{
if ( memlock ( ) ) {
if ( ! _stack_fs_op ( type , dev_dir , vg_name , lv_name , dev ,
old_lv_name ) ) {
stack ;
return 0 ;
}
return 1 ;
}
return _do_fs_op ( type , dev_dir , vg_name , lv_name , dev , old_lv_name ) ;
}
2003-11-12 22:16:48 +03:00
int fs_add_lv ( const struct logical_volume * lv , const char * dev )
2003-07-05 02:34:56 +04:00
{
return _fs_op ( FS_ADD , lv - > vg - > cmd - > dev_dir , lv - > vg - > name , lv - > name ,
dev , " " ) ;
}
2003-11-12 22:16:48 +03:00
int fs_del_lv ( const struct logical_volume * lv )
2003-07-05 02:34:56 +04:00
{
return _fs_op ( FS_DEL , lv - > vg - > cmd - > dev_dir , lv - > vg - > name , lv - > name ,
" " , " " ) ;
}
2002-02-26 14:49:17 +03:00
int fs_rename_lv ( struct logical_volume * lv ,
const char * dev , const char * old_name )
2002-01-11 02:21:07 +03:00
{
2003-07-05 02:34:56 +04:00
return _fs_op ( FS_RENAME , lv - > vg - > cmd - > dev_dir , lv - > vg - > name , lv - > name ,
dev , old_name ) ;
}
2002-01-11 02:21:07 +03:00
2003-07-05 02:34:56 +04:00
void fs_unlock ( void )
{
if ( ! memlock ( ) ) {
dm_lib_release ( ) ;
_pop_fs_ops ( ) ;
}
2002-01-11 02:21:07 +03:00
}