2002-12-20 02:25:55 +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-12-20 02:25:55 +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 ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2002-12-20 02:25:55 +03:00
*/
2018-05-14 12:30:20 +03:00
# include "lib/misc/lib.h"
# include "lib/misc/lvm-string.h"
# include "lib/metadata/metadata-exported.h"
# include "lib/display/display.h"
2002-12-20 02:25:55 +03:00
2006-08-21 16:54:53 +04:00
# include <ctype.h>
2014-04-15 15:27:47 +04:00
# include <stdarg.h>
2003-09-18 00:35:57 +04:00
int emit_to_buffer ( char * * buffer , size_t * size , const char * fmt , . . . )
{
int n ;
va_list ap ;
va_start ( ap , fmt ) ;
n = vsnprintf ( * buffer , * size , fmt , ap ) ;
va_end ( ap ) ;
2010-09-20 18:25:27 +04:00
/*
* Revert to old glibc behaviour ( version < = 2.0 .6 ) where snprintf
* returned - 1 if buffer was too small . From glibc 2.1 it returns number
* of chars that would have been written had there been room .
*/
if ( n < 0 | | ( ( unsigned ) n + 1 > * size ) )
n = - 1 ;
2007-08-22 18:38:18 +04:00
if ( n < 0 | | ( ( size_t ) n = = * size ) )
2003-09-18 00:35:57 +04:00
return 0 ;
* buffer + = n ;
* size - = n ;
return 1 ;
}
2004-02-13 17:43:35 +03:00
2010-11-17 13:19:29 +03:00
/*
* A - Za - z0 - 9. _ - + / = ! : & #
*/
int validate_tag ( const char * n )
{
register char c ;
2012-02-08 16:57:15 +04:00
/* int len = 0; */
2010-11-17 13:19:29 +03:00
if ( ! n | | ! * n )
return 0 ;
2012-02-08 16:57:15 +04:00
/* FIXME: Is unlimited tag size support needed ? */
while ( ( /* len++, */ c = * n + + ) )
2010-11-17 13:19:29 +03:00
if ( ! isalnum ( c ) & & c ! = ' . ' & & c ! = ' _ ' & & c ! = ' - ' & & c ! = ' + ' & & c ! = ' / '
& & c ! = ' = ' & & c ! = ' ! ' & & c ! = ' : ' & & c ! = ' & ' & & c ! = ' # ' )
return 0 ;
return 1 ;
}
2014-05-07 15:52:01 +04:00
static name_error_t _validate_name ( const char * n )
2006-04-19 19:33:07 +04:00
{
register char c ;
register int len = 0 ;
if ( ! n | | ! * n )
2014-05-07 15:52:01 +04:00
return NAME_INVALID_EMPTY ;
2006-04-19 19:33:07 +04:00
/* Hyphen used as VG-LV separator - ambiguity if LV starts with it */
if ( * n = = ' - ' )
2015-02-23 20:09:35 +03:00
return NAME_INVALID_HYPHEN ;
2006-04-19 19:33:07 +04:00
2012-12-14 17:03:58 +04:00
if ( ( * n = = ' . ' ) & & ( ! n [ 1 ] | | ( n [ 1 ] = = ' . ' & & ! n [ 2 ] ) ) ) /* ".", ".." */
2014-05-07 15:52:01 +04:00
return NAME_INVALID_DOTS ;
2006-04-19 19:33:07 +04:00
while ( ( len + + , c = * n + + ) )
if ( ! isalnum ( c ) & & c ! = ' . ' & & c ! = ' _ ' & & c ! = ' - ' & & c ! = ' + ' )
2014-05-07 15:52:01 +04:00
return NAME_INVALID_CHARSET ;
2006-04-19 19:33:07 +04:00
if ( len > NAME_LEN )
2014-05-07 15:52:01 +04:00
return NAME_INVALID_LENGTH ;
2006-04-19 19:33:07 +04:00
2014-05-07 15:52:01 +04:00
return NAME_VALID ;
2013-09-26 20:37:40 +04:00
}
/*
* Device layer names are all of the form < vg > - < lv > - < layer > , any
* other hyphens that appear in these names are quoted with yet
* another hyphen . The top layer of any device has no layer
* name . eg , vg0 - lvol0 .
*/
int validate_name ( const char * n )
{
2014-05-07 15:52:01 +04:00
return ( _validate_name ( n ) = = NAME_VALID ) ? 1 : 0 ;
2006-04-19 19:33:07 +04:00
}
2010-04-23 18:16:32 +04:00
2014-10-24 21:29:04 +04:00
/*
2015-02-23 22:47:03 +03:00
* Copy valid systemid characters from source to destination .
2014-10-24 21:29:04 +04:00
* Invalid characters are skipped . Copying is stopped
* when NAME_LEN characters have been copied .
2015-02-23 22:47:03 +03:00
* A terminating NUL is appended .
2014-10-24 21:29:04 +04:00
*/
2015-02-23 22:47:03 +03:00
void copy_systemid_chars ( const char * src , char * dst )
2014-10-24 21:29:04 +04:00
{
const char * s = src ;
char * d = dst ;
int len = 0 ;
char c ;
if ( ! s | | ! * s )
return ;
2015-02-23 22:47:03 +03:00
/* Skip non-alphanumeric starting characters */
while ( * s & & ! isalnum ( * s ) )
2015-02-13 20:14:46 +03:00
s + + ;
2014-10-24 21:29:04 +04:00
2015-02-23 22:47:03 +03:00
while ( ( c = * s + + ) ) {
if ( ! isalnum ( c ) & & c ! = ' . ' & & c ! = ' _ ' & & c ! = ' - ' & & c ! = ' + ' )
2014-10-24 21:29:04 +04:00
continue ;
2015-02-23 22:47:03 +03:00
* d + + = c ;
2014-10-24 21:29:04 +04:00
2015-02-23 22:47:03 +03:00
if ( + + len > = NAME_LEN )
2014-10-24 21:29:04 +04:00
break ;
}
2015-02-23 22:47:03 +03:00
* d = ' \0 ' ;
2014-10-24 21:29:04 +04:00
}
2014-04-07 22:19:14 +04:00
static const char * _lvname_has_reserved_prefix ( const char * lvname )
2010-04-23 18:16:32 +04:00
{
2014-04-07 22:19:14 +04:00
static const char _prefixes [ ] [ 12 ] = {
2011-09-06 19:38:44 +04:00
" pvmove " ,
2014-04-07 22:19:14 +04:00
" snapshot "
2011-09-06 19:38:44 +04:00
} ;
2014-04-07 22:19:14 +04:00
unsigned i ;
for ( i = 0 ; i < DM_ARRAY_SIZE ( _prefixes ) ; + + i )
if ( ! strncmp ( lvname , _prefixes [ i ] , strlen ( _prefixes [ i ] ) ) )
return _prefixes [ i ] ;
2011-09-06 19:38:44 +04:00
2014-04-07 22:19:14 +04:00
return NULL ;
}
2017-12-11 20:12:47 +03:00
static const char * _lvname_has_reserved_component_string ( const char * lvname )
2014-04-07 22:19:14 +04:00
{
static const char _strings [ ] [ 12 ] = {
2017-12-11 20:12:47 +03:00
/* Suffixes for compoment LVs */
2014-04-07 23:36:59 +04:00
" _cdata " ,
" _cmeta " ,
2014-11-08 15:16:35 +03:00
" _corig " ,
2019-10-22 17:07:21 +03:00
" _cpool " ,
2019-10-07 15:58:26 +03:00
" _cvol " ,
2019-09-20 22:04:18 +03:00
" _wcorig " ,
2011-09-06 19:38:44 +04:00
" _mimage " ,
2014-04-07 22:19:14 +04:00
" _mlog " ,
2011-09-06 19:38:44 +04:00
" _rimage " ,
" _rmeta " ,
2011-11-03 18:38:36 +04:00
" _tdata " ,
2018-07-03 12:05:50 +03:00
" _tmeta " ,
2019-11-21 01:07:27 +03:00
" _vdata " ,
" _imeta " ,
" _iorig "
2017-12-11 20:12:47 +03:00
} ;
unsigned i ;
for ( i = 0 ; i < DM_ARRAY_SIZE ( _strings ) ; + + i )
if ( strstr ( lvname , _strings [ i ] ) )
return _strings [ i ] ;
return NULL ;
}
static const char * _lvname_has_reserved_string ( const char * lvname )
{
static const char _strings [ ] [ 12 ] = {
/* Additional suffixes for non-compoment LVs */
" _pmspare " ,
2014-04-07 22:19:14 +04:00
" _vorigin "
2011-09-06 19:38:44 +04:00
} ;
unsigned i ;
2017-12-11 20:12:47 +03:00
const char * cs ;
if ( ( cs = _lvname_has_reserved_component_string ( lvname ) ) )
return cs ;
2014-04-07 22:19:14 +04:00
for ( i = 0 ; i < DM_ARRAY_SIZE ( _strings ) ; + + i )
if ( strstr ( lvname , _strings [ i ] ) )
return _strings [ i ] ;
return NULL ;
}
int apply_lvname_restrictions ( const char * name )
{
2011-09-06 19:38:44 +04:00
const char * s ;
2014-04-07 22:19:14 +04:00
if ( ( s = _lvname_has_reserved_prefix ( name ) ) ) {
log_error ( " Names starting \" %s \" are reserved. "
" Please choose a different LV name. " , s ) ;
return 0 ;
2011-09-06 04:26:42 +04:00
}
2014-04-07 22:19:14 +04:00
if ( ( s = _lvname_has_reserved_string ( name ) ) ) {
log_error ( " Names including \" %s \" are reserved. "
" Please choose a different LV name. " , s ) ;
return 0 ;
2011-09-06 04:26:42 +04:00
}
2010-04-23 18:16:32 +04:00
return 1 ;
}
2013-09-26 20:37:40 +04:00
/*
* Validates name and returns an emunerated reason for name validataion failure .
*/
name_error_t validate_name_detailed ( const char * name )
{
return _validate_name ( name ) ;
}
2010-04-23 18:16:32 +04:00
int is_reserved_lvname ( const char * name )
{
2014-04-07 22:19:14 +04:00
return ( _lvname_has_reserved_prefix ( name ) | |
_lvname_has_reserved_string ( name ) ) ? 1 : 0 ;
2010-04-23 18:16:32 +04:00
}
2011-08-30 18:55:15 +04:00
2017-12-11 20:12:47 +03:00
int is_component_lvname ( const char * name )
{
return ( _lvname_has_reserved_component_string ( name ) ) ? 1 : 0 ;
}
2014-03-11 20:13:47 +04:00
char * build_dm_uuid ( struct dm_pool * mem , const struct logical_volume * lv ,
2011-08-30 18:55:15 +04:00
const char * layer )
{
2014-03-11 20:13:47 +04:00
const char * lvid = lv - > lvid . s ;
2015-11-26 23:52:05 +03:00
char * dlid ;
2014-03-11 20:13:47 +04:00
2014-06-27 02:03:31 +04:00
if ( ! layer ) {
/*
* Mark internal LVs with layer suffix
* so tools like blkid may immeditelly see it ' s
2014-06-30 16:04:25 +04:00
* an internal LV they should not scan .
* Should also make internal detection simpler .
2014-06-27 02:03:31 +04:00
*/
2014-07-31 00:55:11 +04:00
/* Suffixes used here MUST match lib/activate/dev_manager.c */
2014-11-05 01:19:34 +03:00
layer = lv_is_cache_origin ( lv ) ? " real " :
2020-02-19 22:30:02 +03:00
lv_is_writecache_origin ( lv ) ? " real " :
2014-11-10 12:56:43 +03:00
( lv_is_cache ( lv ) & & lv_is_pending_delete ( lv ) ) ? " real " :
2014-11-05 01:19:34 +03:00
lv_is_cache_pool_data ( lv ) ? " cdata " :
2014-06-27 02:03:31 +04:00
lv_is_cache_pool_metadata ( lv ) ? " cmeta " :
2019-10-07 15:58:26 +03:00
lv_is_cache_vol ( lv ) ? " cvol " :
2014-06-30 16:04:25 +04:00
// FIXME: dm-tree needs fixes for mirrors/raids
//lv_is_mirror_image(lv) ? "mimage" :
//lv_is_mirror_log(lv) ? "mlog" :
//lv_is_raid_image(lv) ? "rimage" :
//lv_is_raid_metadata(lv) ? "rmeta" :
2014-06-27 02:03:31 +04:00
lv_is_thin_pool ( lv ) ? " pool " :
lv_is_thin_pool_data ( lv ) ? " tdata " :
lv_is_thin_pool_metadata ( lv ) ? " tmeta " :
2019-09-14 02:13:33 +03:00
lv_is_vdo_pool ( lv ) ? " pool " :
2018-06-29 12:11:14 +03:00
lv_is_vdo_pool_data ( lv ) ? " vdata " :
2014-06-27 02:03:31 +04:00
NULL ;
}
2014-03-11 20:14:01 +04:00
2015-11-26 23:52:05 +03:00
if ( ! ( dlid = dm_build_dm_uuid ( mem , UUID_PREFIX , lvid , layer ) ) )
log_error ( " Failed to build LVM dlid for %s. " ,
display_lvname ( lv ) ) ;
return dlid ;
2011-08-30 18:55:15 +04:00
}
2016-07-14 16:46:38 +03:00
char * first_substring ( const char * str , . . . )
{
char * substr , * r = NULL ;
va_list ap ;
va_start ( ap , str ) ;
while ( ( substr = va_arg ( ap , char * ) ) )
if ( ( r = strstr ( str , substr ) ) )
break ;
va_end ( ap ) ;
return r ;
}
2019-10-21 10:17:57 +03:00
/* Cut suffix (if present) and write the name into NAME_LEN sized new_name buffer
* When suffix is NULL , everythin past the last ' _ ' is removed .
* Returns 1 when suffix was removed , 0 otherwise .
*/
int drop_lvname_suffix ( char * new_name , const char * name , const char * suffix )
{
char * c ;
if ( ! dm_strncpy ( new_name , name , NAME_LEN ) ) {
log_debug ( INTERNAL_ERROR " Name is too long. " ) ;
return 0 ;
}
if ( ! ( c = strrchr ( new_name , ' _ ' ) ) )
return 0 ;
if ( suffix & & strcmp ( c + 1 , suffix ) )
return 0 ;
* c = 0 ; /* remove suffix */
return 1 ;
}