2001-12-11 15:18:56 +03:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2017-02-24 02:50:00 +03:00
* Copyright ( C ) 2004 - 2017 Red Hat , Inc . All rights reserved .
2001-12-11 15:18:56 +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
2001-12-11 15:18:56 +03:00
*/
2018-05-14 12:30:20 +03:00
# include "lib/misc/lib.h"
# include "lib/metadata/metadata.h"
2001-12-11 15:18:56 +03:00
# include "import-export.h"
2018-05-14 12:30:20 +03:00
# include "lib/misc/lvm-string.h"
2001-12-11 15:18:56 +03:00
/*
* Bitsets held in the ' status ' flags get
* converted into arrays of strings .
*/
struct flag {
2009-11-25 01:55:55 +03:00
const uint64_t mask ;
2002-12-20 02:25:55 +03:00
const char * description ;
2008-07-10 15:30:57 +04:00
int kind ;
2001-12-11 15:18:56 +03:00
} ;
2010-01-07 17:47:57 +03:00
static const struct flag _vg_flags [ ] = {
2008-07-10 15:30:57 +04:00
{ EXPORTED_VG , " EXPORTED " , STATUS_FLAG } ,
{ RESIZEABLE_VG , " RESIZEABLE " , STATUS_FLAG } ,
{ PVMOVE , " PVMOVE " , STATUS_FLAG } ,
{ LVM_READ , " READ " , STATUS_FLAG } ,
{ LVM_WRITE , " WRITE " , STATUS_FLAG } ,
system_id: make new VGs read-only for old lvm versions
Previous versions of lvm will not obey the restrictions
imposed by the new system_id, and would allow such a VG
to be written. So, a VG with a new system_id is further
changed to force previous lvm versions to treat it as
read-only. This is done by removing the WRITE flag from
the metadata status line of these VGs, and putting a new
WRITE_LOCKED flag in the flags line of the metadata.
Versions of lvm that recognize WRITE_LOCKED, also obey the
new system_id. For these lvm versions, WRITE_LOCKED is
identical to WRITE, and the rules associated with matching
system_id's are imposed.
A new VG lock_type field is also added that causes the same
WRITE/WRITE_LOCKED transformation when set. A previous
version of lvm will also see a VG with lock_type as read-only.
Versions of lvm that recognize WRITE_LOCKED, must also obey
the lock_type setting. Until the lock_type feature is added,
lvm will fail to read any VG with lock_type set and report an
error about an unsupported lock_type. Once the lock_type
feature is added, lvm will allow VGs with lock_type to be
used according to the rules imposed by the lock_type.
When both system_id and lock_type settings are removed, a VG
is written with the old WRITE status flag, and without the
new WRITE_LOCKED flag. This allows old versions of lvm to
use the VG as before.
2015-03-04 20:30:53 +03:00
{ LVM_WRITE_LOCKED , " WRITE_LOCKED " , COMPATIBLE_FLAG } ,
2008-07-10 15:30:57 +04:00
{ CLUSTERED , " CLUSTERED " , STATUS_FLAG } ,
{ SHARED , " SHARED " , STATUS_FLAG } ,
2008-09-19 10:42:00 +04:00
{ PARTIAL_VG , NULL , 0 } ,
2008-07-10 15:30:57 +04:00
{ PRECOMMITTED , NULL , 0 } ,
2013-06-30 20:01:19 +04:00
{ ARCHIVED_VG , NULL , 0 } ,
2008-07-10 15:30:57 +04:00
{ 0 , NULL , 0 }
2001-12-11 15:18:56 +03:00
} ;
2010-01-07 17:47:57 +03:00
static const struct flag _pv_flags [ ] = {
2008-07-10 15:30:57 +04:00
{ ALLOCATABLE_PV , " ALLOCATABLE " , STATUS_FLAG } ,
{ EXPORTED_VG , " EXPORTED " , STATUS_FLAG } ,
2008-09-19 10:42:00 +04:00
{ MISSING_PV , " MISSING " , COMPATIBLE_FLAG } ,
2017-05-30 17:12:45 +03:00
{ MISSING_PV , " MISSING " , STATUS_FLAG } ,
2017-10-06 04:12:42 +03:00
{ PV_MOVED_VG , NULL , 0 } ,
2011-11-15 15:54:15 +04:00
{ UNLABELLED_PV , NULL , 0 } ,
2008-07-10 15:30:57 +04:00
{ 0 , NULL , 0 }
2001-12-11 15:18:56 +03:00
} ;
2010-01-07 17:47:57 +03:00
static const struct flag _lv_flags [ ] = {
2008-07-10 15:30:57 +04:00
{ LVM_READ , " READ " , STATUS_FLAG } ,
{ LVM_WRITE , " WRITE " , STATUS_FLAG } ,
system_id: make new VGs read-only for old lvm versions
Previous versions of lvm will not obey the restrictions
imposed by the new system_id, and would allow such a VG
to be written. So, a VG with a new system_id is further
changed to force previous lvm versions to treat it as
read-only. This is done by removing the WRITE flag from
the metadata status line of these VGs, and putting a new
WRITE_LOCKED flag in the flags line of the metadata.
Versions of lvm that recognize WRITE_LOCKED, also obey the
new system_id. For these lvm versions, WRITE_LOCKED is
identical to WRITE, and the rules associated with matching
system_id's are imposed.
A new VG lock_type field is also added that causes the same
WRITE/WRITE_LOCKED transformation when set. A previous
version of lvm will also see a VG with lock_type as read-only.
Versions of lvm that recognize WRITE_LOCKED, must also obey
the lock_type setting. Until the lock_type feature is added,
lvm will fail to read any VG with lock_type set and report an
error about an unsupported lock_type. Once the lock_type
feature is added, lvm will allow VGs with lock_type to be
used according to the rules imposed by the lock_type.
When both system_id and lock_type settings are removed, a VG
is written with the old WRITE status flag, and without the
new WRITE_LOCKED flag. This allows old versions of lvm to
use the VG as before.
2015-03-04 20:30:53 +03:00
{ LVM_WRITE_LOCKED , " WRITE_LOCKED " , COMPATIBLE_FLAG } ,
2008-07-10 15:30:57 +04:00
{ FIXED_MINOR , " FIXED_MINOR " , STATUS_FLAG } ,
{ VISIBLE_LV , " VISIBLE " , STATUS_FLAG } ,
{ PVMOVE , " PVMOVE " , STATUS_FLAG } ,
{ LOCKED , " LOCKED " , STATUS_FLAG } ,
2011-03-29 16:51:57 +04:00
{ LV_NOTSYNCED , " NOTSYNCED " , STATUS_FLAG } ,
2011-11-30 06:02:10 +04:00
{ LV_REBUILD , " REBUILD " , STATUS_FLAG } ,
2017-06-09 22:31:09 +03:00
{ LV_RESHAPE , " RESHAPE " , SEGTYPE_FLAG } ,
2017-07-14 16:52:18 +03:00
{ LV_RESHAPE_DATA_OFFSET , " RESHAPE_DATA_OFFSET " , SEGTYPE_FLAG } ,
2017-06-14 16:01:19 +03:00
{ LV_RESHAPE_DELTA_DISKS_PLUS , " RESHAPE_DELTA_DISKS_PLUS " , SEGTYPE_FLAG } ,
{ LV_RESHAPE_DELTA_DISKS_MINUS , " RESHAPE_DELTA_DISKS_MINUS " , SEGTYPE_FLAG } ,
{ LV_REMOVE_AFTER_RESHAPE , " REMOVE_AFTER_RESHAPE " , SEGTYPE_FLAG } ,
RAID: Add writemostly/writebehind support for RAID1
'lvchange' is used to alter a RAID 1 logical volume's write-mostly and
write-behind characteristics. The '--writemostly' parameter takes a
PV as an argument with an optional trailing character to specify whether
to set ('y'), unset ('n'), or toggle ('t') the value. If no trailing
character is given, it will set the flag.
Synopsis:
lvchange [--writemostly <PV>:{t|y|n}] [--writebehind <count>] vg/lv
Example:
lvchange --writemostly /dev/sdb1:y --writebehind 512 vg/raid1_lv
The last character in the 'lv_attr' field is used to show whether a device
has the WriteMostly flag set. It is signified with a 'w'. If the device
has failed, the 'p'artial flag has priority.
Example ("nosync" raid1 with mismatch_cnt and writemostly):
[~]# lvs -a --segment vg
LV VG Attr #Str Type SSize
raid1 vg Rwi---r-m 2 raid1 500.00m
[raid1_rimage_0] vg Iwi---r-- 1 linear 500.00m
[raid1_rimage_1] vg Iwi---r-w 1 linear 500.00m
[raid1_rmeta_0] vg ewi---r-- 1 linear 4.00m
[raid1_rmeta_1] vg ewi---r-- 1 linear 4.00m
Example (raid1 with mismatch_cnt, writemostly - but failed drive):
[~]# lvs -a --segment vg
LV VG Attr #Str Type SSize
raid1 vg rwi---r-p 2 raid1 500.00m
[raid1_rimage_0] vg Iwi---r-- 1 linear 500.00m
[raid1_rimage_1] vg Iwi---r-p 1 linear 500.00m
[raid1_rmeta_0] vg ewi---r-- 1 linear 4.00m
[raid1_rmeta_1] vg ewi---r-p 1 linear 4.00m
A new reportable field has been added for writebehind as well. If
write-behind has not been set or the LV is not RAID1, the field will
be blank.
Example (writebehind is set):
[~]# lvs -a -o name,attr,writebehind vg
LV Attr WBehind
lv rwi-a-r-- 512
[lv_rimage_0] iwi-aor-w
[lv_rimage_1] iwi-aor--
[lv_rmeta_0] ewi-aor--
[lv_rmeta_1] ewi-aor--
Example (writebehind is not set):
[~]# lvs -a -o name,attr,writebehind vg
LV Attr WBehind
lv rwi-a-r--
[lv_rimage_0] iwi-aor-w
[lv_rimage_1] iwi-aor--
[lv_rmeta_0] ewi-aor--
[lv_rmeta_1] ewi-aor--
2013-04-15 22:59:46 +04:00
{ LV_WRITEMOSTLY , " WRITEMOSTLY " , STATUS_FLAG } ,
2013-07-10 16:06:50 +04:00
{ LV_ACTIVATION_SKIP , " ACTIVATION_SKIP " , COMPATIBLE_FLAG } ,
2015-01-13 17:23:03 +03:00
{ LV_ERROR_WHEN_FULL , " ERROR_WHEN_FULL " , COMPATIBLE_FLAG } ,
2017-05-29 15:20:38 +03:00
{ LV_METADATA_FORMAT , " METADATA_FORMAT " , SEGTYPE_FLAG } ,
2018-08-17 23:45:52 +03:00
{ LV_CACHE_SINGLE , " CACHE_SINGLE " , STATUS_FLAG } ,
2013-10-10 15:24:32 +04:00
{ LV_NOSCAN , NULL , 0 } ,
activation: flag temporary LVs internally
Add LV_TEMPORARY flag for LVs with limited existence during command
execution. Such LVs are temporary in way that they need to be activated,
some action done and then removed immediately. Such LVs are just like
any normal LV - the only difference is that they are removed during
LVM command execution. This is also the case for LVs representing
future pool metadata spare LVs which we need to initialize by using
the usual LV before they are declared as pool metadata spare.
We can optimize some other parts like udev to do a better job if
it knows that the LV is temporary and any processing on it is just
useless.
This flag is orthogonal to LV_NOSCAN flag introduced recently
as LV_NOSCAN flag is primarily used to mark an LV for the scanning
to be avoided before the zeroing of the device happens. The LV_TEMPORARY
flag makes a difference between a full-fledged LV visible in the system
and the LV just used as a temporary overlay for some action that needs to
be done on underlying PVs.
For example: lvcreate --thinpool POOL --zero n -L 1G vg
- first, the usual LV is created to do a clean up for pool metadata
spare. The LV is activated, zeroed, deactivated.
- between "activated" and "zeroed" stage, the LV_NOSCAN flag is used
to avoid any scanning in udev
- betwen "zeroed" and "deactivated" stage, we need to avoid the WATCH
udev rule, but since the LV is just a usual LV, we can't make a
difference. The LV_TEMPORARY internal LV flag helps here. If we
create the LV with this flag, the DM_UDEV_DISABLE_DISK_RULES
and DM_UDEV_DISABLE_OTHER_RULES flag are set (just like as it is
with "invisible" and non-top-level LVs) - udev is directed to
skip WATCH rule use.
- if the LV_TEMPORARY flag was not used, there would normally be
a WATCH event generated once the LV is closed after "zeroed"
stage. This will make problems with immediated deactivation that
follows.
2013-10-23 16:06:39 +04:00
{ LV_TEMPORARY , NULL , 0 } ,
2013-07-05 19:10:47 +04:00
{ POOL_METADATA_SPARE , NULL , 0 } ,
2015-03-05 23:00:44 +03:00
{ LOCKD_SANLOCK_LV , NULL , 0 } ,
2011-08-03 02:07:20 +04:00
{ RAID , NULL , 0 } ,
{ RAID_META , NULL , 0 } ,
{ RAID_IMAGE , NULL , 0 } ,
2014-09-16 03:13:46 +04:00
{ MIRROR , NULL , 0 } ,
2008-07-10 15:30:57 +04:00
{ MIRROR_IMAGE , NULL , 0 } ,
{ MIRROR_LOG , NULL , 0 } ,
{ MIRRORED , NULL , 0 } ,
{ VIRTUAL , NULL , 0 } ,
{ SNAPSHOT , NULL , 0 } ,
2010-01-13 04:56:18 +03:00
{ MERGING , NULL , 0 } ,
2008-07-10 15:30:57 +04:00
{ CONVERTING , NULL , 0 } ,
2008-09-19 10:42:00 +04:00
{ PARTIAL_LV , NULL , 0 } ,
{ POSTORDER_FLAG , NULL , 0 } ,
2009-04-25 05:17:59 +04:00
{ VIRTUAL_ORIGIN , NULL , 0 } ,
2011-09-08 20:41:18 +04:00
{ THIN_VOLUME , NULL , 0 } ,
{ THIN_POOL , NULL , 0 } ,
{ THIN_POOL_DATA , NULL , 0 } ,
{ THIN_POOL_METADATA , NULL , 0 } ,
2014-02-04 21:57:08 +04:00
{ CACHE , NULL , 0 } ,
{ CACHE_POOL , NULL , 0 } ,
{ CACHE_POOL_DATA , NULL , 0 } ,
{ CACHE_POOL_METADATA , NULL , 0 } ,
2018-06-29 12:11:14 +03:00
{ LV_VDO , NULL , 0 } ,
{ LV_VDO_POOL , NULL , 0 } ,
{ LV_VDO_POOL_DATA , NULL , 0 } ,
2018-08-27 22:53:09 +03:00
{ WRITECACHE , NULL , 0 } ,
2014-11-11 17:13:00 +03:00
{ LV_PENDING_DELETE , NULL , 0 } , /* FIXME Display like COMPATIBLE_FLAG */
metadata: process_each_lv_in_vg: get the list of LVs to process first, then do the processing
This avoids a problem in which we're using selection on LV list - we
need to do the selection on initial state and not on any intermediary
state as we process LVs one by one - some of the relations among LVs
can be gone during this processing.
For example, processing one LV can cause the other LVs to lose the
relation to this LV and hence they're not selectable anymore with
the original selection criteria as it would be if we did selection
on inital state. A perfect example is with thin snapshots:
$ lvs -o lv_name,origin,layout,role vg
LV Origin Layout Role
lvol1 thin,sparse public,origin,thinorigin,multithinorigin
lvol2 lvol1 thin,sparse public,snapshot,thinsnapshot
lvol3 lvol1 thin,sparse public,snapshot,thinsnapshot
pool thin,pool private
$ lvremove -ff -S 'lv_name=lvol1 || origin=lvol1'
Logical volume "lvol1" successfully removed
The lvremove command above was supposed to remove lvol1 as well as
all its snapshots which have origin=lvol1. It failed to do so, because
once we removed the origin lvol1, the lvol2 and lvol3 which were
snapshots before are not snapshots anymore - the relations change
as we're processing these LVs one by one.
If we do the selection first and then execute any concrete actions on
these LVs (which is what this patch does), the behaviour is correct
then - the selection is done on the *initial state*:
$ lvremove -ff -S 'lv_name=lvol1 || origin=lvol1'
Logical volume "lvol1" successfully removed
Logical volume "lvol2" successfully removed
Logical volume "lvol3" successfully removed
Similarly for all the other situations in which relations among
LVs are being changed by processing the LVs one by one.
This patch also introduces LV_REMOVED internal LV status flag
to mark removed LVs so they're not processed further when we
iterate over collected list of LVs to be processed.
Previously, when we iterated directly over vg->lvs list to
process the LVs, we relied on the fact that once the LV is removed,
it is also removed from the vg->lvs list we're iterating over.
But that was incorrect as we shouldn't remove LVs from the list
during one iteration while we're iterating over that exact list
(dm_list_iterate_items safe can handle only one removal at
one iteration anyway, so it can't be used here).
2015-03-16 19:10:21 +03:00
{ LV_REMOVED , NULL , 0 } ,
2008-07-10 15:30:57 +04:00
{ 0 , NULL , 0 }
2001-12-11 15:18:56 +03:00
} ;
2017-05-26 16:47:17 +03:00
static const struct flag * _get_flags ( enum pv_vg_lv_e type )
2001-12-11 15:18:56 +03:00
{
2017-05-26 16:47:17 +03:00
switch ( type ) {
2001-12-11 15:18:56 +03:00
case VG_FLAGS :
return _vg_flags ;
case PV_FLAGS :
return _pv_flags ;
case LV_FLAGS :
return _lv_flags ;
}
2017-05-26 16:45:37 +03:00
log_error ( INTERNAL_ERROR " Unknown flag set requested. " ) ;
2001-12-11 15:18:56 +03:00
return NULL ;
}
/*
* Converts a bitset to an array of string values ,
* using one of the tables defined at the top of
* the file .
*/
2017-05-26 16:47:17 +03:00
int print_flags ( char * buffer , size_t size , enum pv_vg_lv_e type , int mask , uint64_t status )
2001-12-11 15:18:56 +03:00
{
2001-12-31 18:14:44 +03:00
int f , first = 1 ;
2010-01-07 17:47:57 +03:00
const struct flag * flags ;
2001-12-11 15:18:56 +03:00
2008-01-30 16:19:47 +03:00
if ( ! ( flags = _get_flags ( type ) ) )
return_0 ;
2001-12-11 15:18:56 +03:00
2003-09-18 00:35:57 +04:00
if ( ! emit_to_buffer ( & buffer , & size , " [ " ) )
2017-05-29 13:43:07 +03:00
return_0 ;
2001-12-11 15:18:56 +03:00
for ( f = 0 ; flags [ f ] . mask ; f + + ) {
if ( status & flags [ f ] . mask ) {
2004-05-05 22:15:47 +04:00
status & = ~ flags [ f ] . mask ;
2017-05-29 15:20:38 +03:00
if ( mask ! = flags [ f ] . kind )
2008-07-10 15:30:57 +04:00
continue ;
2004-05-05 22:15:47 +04:00
/* Internal-only flag? */
if ( ! flags [ f ] . description )
continue ;
2001-12-20 14:52:54 +03:00
if ( ! first ) {
2003-09-18 00:35:57 +04:00
if ( ! emit_to_buffer ( & buffer , & size , " , " ) )
2017-05-29 13:43:07 +03:00
return_0 ;
2001-12-20 14:52:54 +03:00
} else
2001-12-11 15:18:56 +03:00
first = 0 ;
2004-05-05 22:15:47 +04:00
if ( ! emit_to_buffer ( & buffer , & size , " \" %s \" " ,
2017-05-29 13:43:07 +03:00
flags [ f ] . description ) )
return_0 ;
2001-12-11 15:18:56 +03:00
}
}
2003-09-18 00:35:57 +04:00
if ( ! emit_to_buffer ( & buffer , & size , " ] " ) )
2017-05-29 13:43:07 +03:00
return_0 ;
2001-12-11 15:18:56 +03:00
if ( status )
2013-10-10 15:34:43 +04:00
log_warn ( INTERNAL_ERROR " Metadata inconsistency: "
" Not all flags successfully exported. " ) ;
2001-12-11 15:18:56 +03:00
return 1 ;
}
2017-05-26 16:47:17 +03:00
int read_flags ( uint64_t * status , enum pv_vg_lv_e type , int mask , const struct dm_config_value * cv )
2001-12-11 15:18:56 +03:00
{
2017-05-26 16:47:17 +03:00
unsigned f ;
2009-11-25 01:55:55 +03:00
uint64_t s = UINT64_C ( 0 ) ;
2010-01-07 17:47:57 +03:00
const struct flag * flags ;
2001-12-11 15:18:56 +03:00
2008-01-30 16:19:47 +03:00
if ( ! ( flags = _get_flags ( type ) ) )
return_0 ;
2001-12-11 15:18:56 +03:00
2011-08-30 18:55:15 +04:00
if ( cv - > type = = DM_CFG_EMPTY_ARRAY )
2002-11-18 17:04:08 +03:00
goto out ;
2001-12-11 15:18:56 +03:00
2002-11-18 17:04:08 +03:00
while ( cv ) {
2011-08-30 18:55:15 +04:00
if ( cv - > type ! = DM_CFG_STRING ) {
2009-07-16 00:02:46 +04:00
log_error ( " Status value is not a string. " ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
2002-08-01 16:51:48 +04:00
2002-11-18 17:04:08 +03:00
for ( f = 0 ; flags [ f ] . description ; f + + )
2017-05-26 16:47:17 +03:00
if ( ( flags [ f ] . kind & mask ) & &
! strcmp ( flags [ f ] . description , cv - > v . str ) ) {
2002-11-18 17:04:08 +03:00
s | = flags [ f ] . mask ;
break ;
2001-12-11 15:18:56 +03:00
}
2008-09-19 10:42:00 +04:00
if ( type = = VG_FLAGS & & ! strcmp ( cv - > v . str , " PARTIAL " ) ) {
/*
* Exception : We no longer write this flag out , but it
* might be encountered in old backup files , so restore
* it in that case . It is never part of live metadata
* though , so only vgcfgrestore needs to be concerned
* by this case .
*/
s | = PARTIAL_VG ;
2017-05-26 16:47:17 +03:00
} else if ( ! flags [ f ] . description & & ( mask & STATUS_FLAG ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " Unknown status flag '%s'. " , cv - > v . str ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
2001-12-11 15:18:56 +03:00
}
2002-11-18 17:04:08 +03:00
cv = cv - > next ;
2001-12-11 15:18:56 +03:00
}
2002-11-18 17:04:08 +03:00
out :
2008-07-10 15:30:57 +04:00
* status | = s ;
2001-12-11 15:18:56 +03:00
return 1 ;
}
2017-05-29 15:20:05 +03:00
/*
* Parse extra status flags from segment " type " string .
* These flags are seen as INCOMPATIBLE by any older lvm2 code .
* All flags separated by ' + ' are trimmed from passed string .
* All UNKNOWN flags will again cause the " UNKNOWN " segtype .
*
* Note : using these segtype status flags instead of actual
* status flags ensures wanted incompatiblity .
*/
int read_segtype_lvflags ( uint64_t * status , char * segtype_str )
{
unsigned i ;
const struct flag * flags = _lv_flags ;
char * delim ;
2017-05-30 16:59:42 +03:00
char * flag , * buffer , * str ;
2017-05-29 15:20:05 +03:00
2017-05-30 16:59:42 +03:00
if ( ! ( str = strchr ( segtype_str , ' + ' ) ) )
2017-05-29 15:20:05 +03:00
return 1 ; /* No flags */
2018-06-08 15:40:53 +03:00
if ( ! ( buffer = strdup ( str + 1 ) ) ) {
2017-05-30 16:59:42 +03:00
log_error ( " Cannot duplicate segment string. " ) ;
return 0 ;
}
delim = buffer ;
2017-05-29 15:20:05 +03:00
do {
2017-05-30 16:59:42 +03:00
flag = delim ;
if ( ( delim = strchr ( delim , ' + ' ) ) )
* delim + + = ' \0 ' ;
2017-05-29 15:20:05 +03:00
for ( i = 0 ; flags [ i ] . description ; i + + )
if ( ( flags [ i ] . kind & SEGTYPE_FLAG ) & &
! strcmp ( flags [ i ] . description , flag ) ) {
* status | = flags [ i ] . mask ;
break ;
}
2017-05-30 16:59:42 +03:00
} while ( delim & & flags [ i ] . description ) ; /* Till no more flags in type appear */
if ( ! flags [ i ] . description )
/* Unknown flag is incompatible - returns unmodified segtype_str */
log_warn ( " WARNING: Unrecognised flag %s in segment type %s. " ,
flag , segtype_str ) ;
else
* str = ' \0 ' ; /* Cut away 1st. '+' */
2018-06-08 15:40:53 +03:00
free ( buffer ) ;
2017-05-29 15:20:05 +03:00
return 1 ;
}
int print_segtype_lvflags ( char * buffer , size_t size , uint64_t status )
{
unsigned i ;
const struct flag * flags = _lv_flags ;
buffer [ 0 ] = 0 ;
for ( i = 0 ; flags [ i ] . mask ; i + + )
if ( ( flags [ i ] . kind & SEGTYPE_FLAG ) & &
( status & flags [ i ] . mask ) & &
! emit_to_buffer ( & buffer , & size , " +%s " ,
flags [ i ] . description ) )
return 0 ;
return 1 ;
}