2002-01-03 18:46:48 +03:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2007-08-21 00:55:30 +04:00
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All rights reserved .
2002-01-03 18:46:48 +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
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2002-01-03 18:46:48 +03:00
*/
2005-05-17 17:46:38 +04:00
# include "lib.h"
# include "archiver.h"
# include "format-text.h"
# include "lvm-file.h"
# include "lvm-string.h"
# include "lvmcache.h"
# include "toolcontext.h"
2002-01-11 02:21:07 +03:00
2005-05-17 17:46:38 +04:00
# include <unistd.h>
struct archive_params {
2002-01-03 18:46:48 +03:00
int enabled ;
char * dir ;
unsigned int keep_days ;
unsigned int keep_number ;
2005-05-17 17:46:38 +04:00
} ;
2002-01-03 18:46:48 +03:00
2005-05-17 17:46:38 +04:00
struct backup_params {
2003-09-15 19:03:22 +04:00
int enabled ;
char * dir ;
2005-05-17 17:46:38 +04:00
} ;
2003-09-15 19:03:22 +04:00
2005-05-17 17:46:38 +04:00
int archive_init ( struct cmd_context * cmd , const char * dir ,
2008-12-11 06:32:56 +03:00
unsigned int keep_days , unsigned int keep_min ,
int enabled )
2002-01-03 18:46:48 +03:00
{
2005-10-17 03:03:59 +04:00
if ( ! ( cmd - > archive_params = dm_pool_zalloc ( cmd - > libmem ,
2005-05-24 21:37:39 +04:00
sizeof ( * cmd - > archive_params ) ) ) ) {
2005-05-17 17:46:38 +04:00
log_error ( " archive_params alloc failed " ) ;
return 0 ;
}
cmd - > archive_params - > dir = NULL ;
2002-01-09 16:17:14 +03:00
if ( ! * dir )
return 1 ;
2005-10-17 03:03:59 +04:00
if ( ! ( cmd - > archive_params - > dir = dm_strdup ( dir ) ) ) {
2002-01-09 16:17:14 +03:00
log_error ( " Couldn't copy archive directory name. " ) ;
2002-01-03 18:46:48 +03:00
return 0 ;
}
2005-05-17 17:46:38 +04:00
cmd - > archive_params - > keep_days = keep_days ;
cmd - > archive_params - > keep_number = keep_min ;
2008-12-11 06:32:56 +03:00
archive_enable ( cmd , enabled ) ;
2005-05-17 17:46:38 +04:00
2002-01-03 18:46:48 +03:00
return 1 ;
}
2005-05-17 17:46:38 +04:00
void archive_exit ( struct cmd_context * cmd )
2002-01-03 18:46:48 +03:00
{
2005-05-17 17:46:38 +04:00
if ( cmd - > archive_params - > dir )
2005-10-17 03:03:59 +04:00
dm_free ( cmd - > archive_params - > dir ) ;
2005-05-17 17:46:38 +04:00
memset ( cmd - > archive_params , 0 , sizeof ( * cmd - > archive_params ) ) ;
2002-01-03 18:46:48 +03:00
}
2005-05-17 17:46:38 +04:00
void archive_enable ( struct cmd_context * cmd , int flag )
2002-01-03 18:46:48 +03:00
{
2005-05-17 17:46:38 +04:00
cmd - > archive_params - > enabled = flag ;
2002-01-03 18:46:48 +03:00
}
2005-10-17 03:03:59 +04:00
static char * _build_desc ( struct dm_pool * mem , const char * line , int before )
2002-02-08 14:13:47 +03:00
{
size_t len = strlen ( line ) + 32 ;
char * buffer ;
2008-01-30 16:19:47 +03:00
if ( ! ( buffer = dm_pool_zalloc ( mem , strlen ( line ) + 32 ) ) )
return_NULL ;
2002-02-08 14:13:47 +03:00
if ( snprintf ( buffer , len ,
" Created %s executing '%s' " ,
2008-01-30 16:19:47 +03:00
before ? " *before* " : " *after* " , line ) < 0 )
return_NULL ;
2002-02-08 14:13:47 +03:00
return buffer ;
}
2002-01-03 18:46:48 +03:00
static int __archive ( struct volume_group * vg )
{
2002-02-08 14:13:47 +03:00
char * desc ;
2008-01-30 16:19:47 +03:00
if ( ! ( desc = _build_desc ( vg - > cmd - > mem , vg - > cmd - > cmd_line , 1 ) ) )
return_0 ;
2002-01-03 18:46:48 +03:00
2005-05-17 17:46:38 +04:00
return archive_vg ( vg , vg - > cmd - > archive_params - > dir , desc ,
vg - > cmd - > archive_params - > keep_days ,
vg - > cmd - > archive_params - > keep_number ) ;
2002-01-03 18:46:48 +03:00
}
int archive ( struct volume_group * vg )
{
2005-05-17 17:46:38 +04:00
if ( ! vg - > cmd - > archive_params - > enabled | | ! vg - > cmd - > archive_params - > dir )
2002-01-03 18:46:48 +03:00
return 1 ;
if ( test_mode ( ) ) {
2002-11-18 17:04:08 +03:00
log_verbose ( " Test mode: Skipping archiving of volume group. " ) ;
2002-01-03 18:46:48 +03:00
return 1 ;
}
2007-07-28 16:26:21 +04:00
if ( ! dm_create_dir ( vg - > cmd - > archive_params - > dir ) )
2005-05-03 21:31:56 +04:00
return 0 ;
2005-05-17 17:44:02 +04:00
/* Trap a read-only file system */
2008-01-30 17:00:02 +03:00
if ( ( access ( vg - > cmd - > archive_params - > dir , R_OK | W_OK | X_OK ) = = - 1 ) & &
2005-05-17 17:44:02 +04:00
( errno = = EROFS ) )
2008-01-30 17:00:02 +03:00
return 0 ;
2005-05-17 17:44:02 +04:00
log_verbose ( " Archiving volume group \" %s \" metadata (seqno %u). " , vg - > name ,
vg - > seqno ) ;
2002-01-03 18:46:48 +03:00
if ( ! __archive ( vg ) ) {
2002-01-30 18:04:48 +03:00
log_error ( " Volume group \" %s \" metadata archive failed. " ,
2002-01-09 16:17:14 +03:00
vg - > name ) ;
2002-01-03 18:46:48 +03:00
return 0 ;
}
return 1 ;
}
2002-02-11 23:50:53 +03:00
int archive_display ( struct cmd_context * cmd , const char * vg_name )
2002-02-11 14:43:17 +03:00
{
2003-09-15 19:03:22 +04:00
int r1 , r2 ;
2002-02-11 14:43:17 +03:00
2005-05-17 17:46:38 +04:00
r1 = archive_list ( cmd , cmd - > archive_params - > dir , vg_name ) ;
r2 = backup_list ( cmd , cmd - > backup_params - > dir , vg_name ) ;
2002-01-03 18:46:48 +03:00
2003-09-15 19:03:22 +04:00
return r1 & & r2 ;
}
2002-01-03 18:46:48 +03:00
2007-06-09 02:38:48 +04:00
int archive_display_file ( struct cmd_context * cmd , const char * file )
{
int r ;
r = archive_list_file ( cmd , file ) ;
return r ;
}
2008-12-11 06:33:35 +03:00
int backup_init ( struct cmd_context * cmd , const char * dir ,
int enabled )
2002-01-03 18:46:48 +03:00
{
2005-10-17 03:03:59 +04:00
if ( ! ( cmd - > backup_params = dm_pool_zalloc ( cmd - > libmem ,
2009-03-24 00:56:32 +03:00
sizeof ( * cmd - > backup_params ) ) ) ) {
log_error ( " backup_params alloc failed " ) ;
2005-05-17 17:46:38 +04:00
return 0 ;
}
cmd - > backup_params - > dir = NULL ;
2002-01-09 16:17:14 +03:00
if ( ! * dir )
return 1 ;
2005-10-17 03:03:59 +04:00
if ( ! ( cmd - > backup_params - > dir = dm_strdup ( dir ) ) ) {
2002-01-09 16:17:14 +03:00
log_error ( " Couldn't copy backup directory name. " ) ;
2002-01-03 18:46:48 +03:00
return 0 ;
}
2008-12-11 06:33:35 +03:00
backup_enable ( cmd , enabled ) ;
2002-01-03 18:46:48 +03:00
return 1 ;
}
2005-05-17 17:46:38 +04:00
void backup_exit ( struct cmd_context * cmd )
2002-01-03 18:46:48 +03:00
{
2005-05-17 17:46:38 +04:00
if ( cmd - > backup_params - > dir )
2005-10-17 03:03:59 +04:00
dm_free ( cmd - > backup_params - > dir ) ;
2005-05-17 17:46:38 +04:00
memset ( cmd - > backup_params , 0 , sizeof ( * cmd - > backup_params ) ) ;
2002-01-03 18:46:48 +03:00
}
2005-05-17 17:46:38 +04:00
void backup_enable ( struct cmd_context * cmd , int flag )
2002-01-07 12:05:31 +03:00
{
2005-05-17 17:46:38 +04:00
cmd - > backup_params - > enabled = flag ;
2002-01-07 12:05:31 +03:00
}
2002-01-03 18:46:48 +03:00
static int __backup ( struct volume_group * vg )
{
char name [ PATH_MAX ] ;
2002-02-08 14:13:47 +03:00
char * desc ;
2008-01-30 16:19:47 +03:00
if ( ! ( desc = _build_desc ( vg - > cmd - > mem , vg - > cmd - > cmd_line , 0 ) ) )
return_0 ;
2002-01-03 18:46:48 +03:00
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( name , sizeof ( name ) , " %s/%s " ,
2005-05-17 17:46:38 +04:00
vg - > cmd - > backup_params - > dir , vg - > name ) < 0 ) {
2002-01-09 16:17:14 +03:00
log_error ( " Failed to generate volume group metadata backup "
" filename. " ) ;
2002-01-03 18:46:48 +03:00
return 0 ;
}
2002-11-18 17:04:08 +03:00
return backup_to_file ( name , desc , vg ) ;
2002-01-03 18:46:48 +03:00
}
int backup ( struct volume_group * vg )
{
2005-05-17 17:46:38 +04:00
if ( ! vg - > cmd - > backup_params - > enabled | | ! vg - > cmd - > backup_params - > dir ) {
2007-06-28 21:33:44 +04:00
log_warn ( " WARNING: This metadata update is NOT backed up " ) ;
2002-01-03 18:46:48 +03:00
return 1 ;
2002-01-09 16:17:14 +03:00
}
2002-01-03 18:46:48 +03:00
if ( test_mode ( ) ) {
2002-11-18 17:04:08 +03:00
log_verbose ( " Test mode: Skipping volume group backup. " ) ;
2002-01-03 18:46:48 +03:00
return 1 ;
}
2007-07-28 16:26:21 +04:00
if ( ! dm_create_dir ( vg - > cmd - > backup_params - > dir ) )
2005-05-03 21:31:56 +04:00
return 0 ;
2005-05-17 17:44:02 +04:00
/* Trap a read-only file system */
2008-01-30 17:00:02 +03:00
if ( ( access ( vg - > cmd - > backup_params - > dir , R_OK | W_OK | X_OK ) = = - 1 ) & &
2005-05-17 17:44:02 +04:00
( errno = = EROFS ) )
2008-01-30 17:00:02 +03:00
return 0 ;
2005-05-17 17:44:02 +04:00
2002-01-03 18:46:48 +03:00
if ( ! __backup ( vg ) ) {
2002-01-09 16:17:14 +03:00
log_error ( " Backup of volume group %s metadata failed. " ,
vg - > name ) ;
2002-01-03 18:46:48 +03:00
return 0 ;
}
return 1 ;
}
2002-01-09 17:07:49 +03:00
2005-05-17 17:46:38 +04:00
int backup_remove ( struct cmd_context * cmd , const char * vg_name )
2002-01-09 17:07:49 +03:00
{
char path [ PATH_MAX ] ;
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( path , sizeof ( path ) , " %s/%s " ,
2005-05-17 17:46:38 +04:00
cmd - > backup_params - > dir , vg_name ) < 0 ) {
2002-01-09 17:07:49 +03:00
log_err ( " Failed to generate backup filename (for removal). " ) ;
return 0 ;
}
/*
* Let this fail silently .
*/
unlink ( path ) ;
return 1 ;
}
2002-11-18 17:04:08 +03:00
struct volume_group * backup_read_vg ( struct cmd_context * cmd ,
const char * vg_name , const char * file )
2002-01-10 17:27:47 +03:00
{
2002-12-20 02:25:55 +03:00
struct volume_group * vg = NULL ;
2002-01-10 17:27:47 +03:00
struct format_instance * tf ;
2002-11-18 17:04:08 +03:00
struct metadata_area * mda ;
2002-04-24 22:20:51 +04:00
void * context ;
2002-01-10 17:27:47 +03:00
2002-11-18 17:04:08 +03:00
if ( ! ( context = create_text_context ( cmd , file ,
2002-04-24 22:20:51 +04:00
cmd - > cmd_line ) ) | |
2002-11-18 17:04:08 +03:00
! ( tf = cmd - > fmt_backup - > ops - > create_instance ( cmd - > fmt_backup , NULL ,
2006-04-13 01:23:04 +04:00
NULL , context ) ) ) {
2002-01-10 17:27:47 +03:00
log_error ( " Couldn't create text format object. " ) ;
2002-02-08 14:13:47 +03:00
return NULL ;
2002-01-10 17:27:47 +03:00
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( mda , & tf - > metadata_areas ) {
2002-11-18 17:04:08 +03:00
if ( ! ( vg = mda - > ops - > vg_read ( tf , vg_name , mda ) ) )
stack ;
break ;
}
2002-01-10 17:27:47 +03:00
2002-04-24 22:20:51 +04:00
tf - > fmt - > ops - > destroy_instance ( tf ) ;
2002-01-11 02:21:07 +03:00
return vg ;
2002-01-10 17:27:47 +03:00
}
2002-11-18 17:04:08 +03:00
/* ORPHAN and VG locks held before calling this */
int backup_restore_vg ( struct cmd_context * cmd , struct volume_group * vg )
2002-01-10 17:27:47 +03:00
{
2003-10-16 00:02:46 +04:00
struct pv_list * pvl ;
2002-11-18 17:04:08 +03:00
struct physical_volume * pv ;
2003-07-05 02:34:56 +04:00
struct lvmcache_info * info ;
2002-01-10 17:27:47 +03:00
/*
2002-11-18 17:04:08 +03:00
* FIXME : Check that the PVs referenced in the backup are
* not members of other existing VGs .
2002-01-10 17:27:47 +03:00
*/
2002-11-18 17:04:08 +03:00
/* Attempt to write out using currently active format */
if ( ! ( vg - > fid = cmd - > fmt - > ops - > create_instance ( cmd - > fmt , vg - > name ,
2006-04-13 01:23:04 +04:00
NULL , NULL ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Failed to allocate format instance " ) ;
2002-01-10 17:27:47 +03:00
return 0 ;
}
2002-11-18 17:04:08 +03:00
/* Add any metadata areas on the PVs */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , & vg - > pvs ) {
2003-10-16 00:02:46 +04:00
pv = pvl - > pv ;
2008-01-30 02:45:48 +03:00
if ( ! ( info = info_from_pvid ( pv - > dev - > pvid , 0 ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " PV %s missing from cache " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pv ) ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
if ( cmd - > fmt ! = info - > fmt ) {
2005-05-17 17:44:02 +04:00
log_error ( " PV %s is a different format (seqno %s) " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pv ) , info - > fmt - > name ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
if ( ! vg - > fid - > fmt - > ops - >
2009-02-22 22:00:26 +03:00
pv_setup ( vg - > fid - > fmt , UINT64_C ( 0 ) , 0 , 0 , 0 , 0UL ,
2003-03-24 21:08:53 +03:00
UINT64_C ( 0 ) , & vg - > fid - > metadata_areas , pv , vg ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Format-specific setup for %s failed " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pv ) ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
2002-04-24 22:20:51 +04:00
}
2008-01-30 16:19:47 +03:00
if ( ! vg_write ( vg ) | | ! vg_commit ( vg ) )
return_0 ;
2002-01-10 17:27:47 +03:00
return 1 ;
}
2002-11-18 17:04:08 +03:00
/* ORPHAN and VG locks held before calling this */
int backup_restore_from_file ( struct cmd_context * cmd , const char * vg_name ,
const char * file )
{
struct volume_group * vg ;
/*
* Read in the volume group from the text file .
*/
2008-01-30 16:19:47 +03:00
if ( ! ( vg = backup_read_vg ( cmd , vg_name , file ) ) )
return_0 ;
2002-11-18 17:04:08 +03:00
2009-03-24 16:16:34 +03:00
/*
* If PV is missing , there is already message from read above
*/
if ( vg_missing_pv_count ( vg ) )
return_0 ;
2002-11-18 17:04:08 +03:00
return backup_restore_vg ( cmd , vg ) ;
}
2002-02-11 23:50:53 +03:00
int backup_restore ( struct cmd_context * cmd , const char * vg_name )
2002-01-10 17:27:47 +03:00
{
char path [ PATH_MAX ] ;
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( path , sizeof ( path ) , " %s/%s " ,
2005-05-17 17:46:38 +04:00
cmd - > backup_params - > dir , vg_name ) < 0 ) {
2002-01-10 17:27:47 +03:00
log_err ( " Failed to generate backup filename (for restore). " ) ;
return 0 ;
}
2002-02-11 23:50:53 +03:00
return backup_restore_from_file ( cmd , vg_name , path ) ;
2002-01-10 17:27:47 +03:00
}
2002-11-18 17:04:08 +03:00
int backup_to_file ( const char * file , const char * desc , struct volume_group * vg )
{
2002-12-20 02:25:55 +03:00
int r = 0 ;
2002-11-18 17:04:08 +03:00
struct format_instance * tf ;
struct metadata_area * mda ;
void * context ;
struct cmd_context * cmd ;
cmd = vg - > cmd ;
2005-05-17 17:44:02 +04:00
log_verbose ( " Creating volume group backup \" %s \" (seqno %u). " , file , vg - > seqno ) ;
2004-06-19 22:55:29 +04:00
2002-11-18 17:04:08 +03:00
if ( ! ( context = create_text_context ( cmd , file , desc ) ) | |
! ( tf = cmd - > fmt_backup - > ops - > create_instance ( cmd - > fmt_backup , NULL ,
2006-04-13 01:23:04 +04:00
NULL , context ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Couldn't create backup object. " ) ;
return 0 ;
}
/* Write and commit the metadata area */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( mda , & tf - > metadata_areas ) {
2002-11-18 17:04:08 +03:00
if ( ! ( r = mda - > ops - > vg_write ( tf , vg , mda ) ) ) {
stack ;
continue ;
}
if ( mda - > ops - > vg_commit & &
! ( r = mda - > ops - > vg_commit ( tf , vg , mda ) ) ) {
stack ;
}
}
tf - > fmt - > ops - > destroy_instance ( tf ) ;
return r ;
}
2005-05-17 17:44:02 +04:00
/*
* Update backup ( and archive ) if they ' re out - of - date or don ' t exist .
*/
void check_current_backup ( struct volume_group * vg )
{
char path [ PATH_MAX ] ;
struct volume_group * vg_backup ;
2008-09-19 10:42:00 +04:00
if ( vg - > status & EXPORTED_VG )
2005-05-17 17:44:02 +04:00
return ;
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( path , sizeof ( path ) , " %s/%s " ,
2005-05-17 17:46:38 +04:00
vg - > cmd - > backup_params - > dir , vg - > name ) < 0 ) {
2005-05-17 17:44:02 +04:00
log_debug ( " Failed to generate backup filename. " ) ;
return ;
}
log_suppress ( 1 ) ;
/* Up-to-date backup exists? */
if ( ( vg_backup = backup_read_vg ( vg - > cmd , vg - > name , path ) ) & &
( vg - > seqno = = vg_backup - > seqno ) & &
2009-03-24 01:57:27 +03:00
( id_equal ( & vg - > id , & vg_backup - > id ) ) ) {
log_suppress ( 0 ) ;
2005-05-17 17:44:02 +04:00
return ;
2009-03-24 01:57:27 +03:00
}
2005-05-17 17:44:02 +04:00
log_suppress ( 0 ) ;
if ( vg_backup )
archive ( vg_backup ) ;
archive ( vg ) ;
backup ( vg ) ;
}