609 lines
20 KiB
C++
609 lines
20 KiB
C++
/* Copyright (C) 2009, 2010, 2011 Curtis Gedak
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "DMRaid.h"
|
|
#include "BlockSpecial.h"
|
|
#include "Partition.h"
|
|
#include "Utils.h"
|
|
|
|
#include <limits.h>
|
|
#include <stdlib.h> //atoi function
|
|
#include <glibmm/miscutils.h>
|
|
#include <glibmm/fileutils.h>
|
|
#include <glibmm/shell.h>
|
|
#include <glibmm/ustring.h>
|
|
|
|
|
|
namespace GParted
|
|
{
|
|
|
|
// Data model:
|
|
// dmraid_cache_initialized - Has the cache been loaded?
|
|
// dmraid_found - Is the "dmraid" command available?
|
|
// dmsetup_found - Is the "dmsetup" command available?
|
|
// udevadm_found - Is the "udevadm" command available?
|
|
// dmraid_devices - Vector of active array names.
|
|
// E.g.
|
|
// ["isw_ecccdhhiga_MyArray"]
|
|
// dmraid_member_cache - Vector of members of active DMRaid arrays.
|
|
// E.g.
|
|
// //member , array
|
|
// [{BlockSpecial("/dev/sdc"), "/dev/mapper/isw_ecccdhhiga_MyArray"},
|
|
// {BlockSpecial("/dev/sdd"), "/dev/mapper/isw_ecccdhhiga_MyArray"}
|
|
// ]
|
|
|
|
//Initialize static data elements
|
|
bool DMRaid::dmraid_cache_initialized = false ;
|
|
bool DMRaid::dmraid_found = false ;
|
|
bool DMRaid::dmsetup_found = false ;
|
|
bool DMRaid::udevadm_found = false ;
|
|
std::vector<Glib::ustring> DMRaid::dmraid_devices ;
|
|
std::vector<DMRaid_Member> DMRaid::dmraid_member_cache;
|
|
|
|
|
|
DMRaid::DMRaid()
|
|
{
|
|
//Ensure that cache has been loaded at least once
|
|
if ( ! dmraid_cache_initialized )
|
|
{
|
|
dmraid_cache_initialized = true ;
|
|
set_commands_found() ;
|
|
load_dmraid_cache() ;
|
|
}
|
|
}
|
|
|
|
DMRaid::DMRaid( const bool & do_refresh )
|
|
{
|
|
//Ensure that cache has been loaded at least once
|
|
if ( ! dmraid_cache_initialized )
|
|
{
|
|
dmraid_cache_initialized = true ;
|
|
set_commands_found() ;
|
|
if ( do_refresh == false )
|
|
load_dmraid_cache() ;
|
|
}
|
|
|
|
if ( do_refresh )
|
|
load_dmraid_cache() ;
|
|
}
|
|
|
|
DMRaid::~DMRaid()
|
|
{
|
|
}
|
|
|
|
void DMRaid::load_dmraid_cache()
|
|
{
|
|
Glib::ustring output, error ;
|
|
dmraid_devices .clear() ;
|
|
dmraid_member_cache.clear();
|
|
|
|
// Load active DMRaid array names.
|
|
if ( dmraid_found )
|
|
{
|
|
if ( ! Utils::execute_command( "dmraid -sa -c", output, error, true ) )
|
|
{
|
|
if (output.substr(0, 13).lowercase() != "no raid disks")
|
|
Utils::tokenize( output, dmraid_devices, "\n" ) ;
|
|
}
|
|
}
|
|
|
|
// Load members of active DMRaid arrays.
|
|
for (unsigned int i = 0; i < dmraid_devices.size(); i++)
|
|
{
|
|
std::vector<Glib::ustring> members = lookup_dmraid_members(DEV_MAPPER_PATH + dmraid_devices[i]);
|
|
for (unsigned int j = 0; j < members.size(); j++)
|
|
{
|
|
DMRaid_Member memb;
|
|
memb.member = BlockSpecial(members[j]);
|
|
memb.array = DEV_MAPPER_PATH + dmraid_devices[i];
|
|
dmraid_member_cache.push_back(memb);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void DMRaid::set_commands_found()
|
|
{
|
|
//Set status of commands found
|
|
dmraid_found = (! Glib::find_program_in_path( "dmraid" ) .empty() ) ;
|
|
dmsetup_found = (! Glib::find_program_in_path( "dmsetup" ) .empty() ) ;
|
|
udevadm_found = (! Glib::find_program_in_path( "udevadm" ) .empty() ) ;
|
|
}
|
|
|
|
bool DMRaid::is_dmraid_supported()
|
|
{
|
|
//Determine if dmraid is supported on this computer
|
|
return ( dmraid_found && dmsetup_found ) ;
|
|
}
|
|
|
|
bool DMRaid::is_dmraid_device( const Glib::ustring & dev_path )
|
|
{
|
|
//Determine if the device is a dmraid device
|
|
bool device_found = false ; //assume not found
|
|
|
|
if ( is_dmraid_supported() )
|
|
{
|
|
for ( unsigned int k=0; k < dmraid_devices .size(); k++ )
|
|
if ( dev_path .find( dmraid_devices[k] ) != Glib::ustring::npos )
|
|
device_found = true ;
|
|
}
|
|
|
|
//Some distros appear to default to /dev/dm-# for device names, so
|
|
// also check with udev to see if they are in fact dmraid devices
|
|
if ( ! device_found && ( dev_path .find( "/dev/dm" ) != Glib::ustring::npos ) )
|
|
{
|
|
//Ensure we use the base device name if dev_path in form /dev/dm-#p#
|
|
Glib::ustring regexp = "(/dev/dm-[0-9]+)p[0-9]+" ;
|
|
Glib::ustring dev_path_only = Utils::regexp_label( dev_path, regexp ) ;
|
|
if ( dev_path_only .empty() )
|
|
dev_path_only = dev_path ;
|
|
|
|
Glib::ustring udev_name = get_udev_dm_name( dev_path_only ) ;
|
|
if ( ! udev_name .empty() )
|
|
{
|
|
for ( unsigned int k=0; k < dmraid_devices .size(); k++ )
|
|
if ( udev_name .find( dmraid_devices[k] ) != Glib::ustring::npos )
|
|
device_found = true ;
|
|
}
|
|
|
|
//Also check for a symbolic link if device not yet found
|
|
if ( ! device_found && file_test( dev_path, Glib::FILE_TEST_IS_SYMLINK ) )
|
|
{
|
|
//Path is a symbolic link so find real path
|
|
char* rpath = realpath(dev_path.c_str(), nullptr);
|
|
if (rpath != nullptr)
|
|
{
|
|
Glib::ustring tmp_path = rpath;
|
|
free( rpath );
|
|
if ( tmp_path .length() > 0 )
|
|
for ( unsigned int k=0; k < dmraid_devices .size(); k++ )
|
|
if ( tmp_path .find( dmraid_devices[k] ) != Glib::ustring::npos )
|
|
device_found = true ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return device_found ;
|
|
}
|
|
|
|
//FIXME: Copy of code from FileSystem.cc.
|
|
// This should be replaced when a general execute_command with asynchronous updates is built.
|
|
int DMRaid::execute_command( const Glib::ustring & command, OperationDetail & operationdetail )
|
|
{
|
|
Glib::ustring output, error ;
|
|
|
|
operationdetail .add_child( OperationDetail( command, STATUS_NONE, FONT_BOLD_ITALIC ) ) ;
|
|
|
|
int exit_status = Utils::execute_command( command, output, error );
|
|
|
|
if ( ! output .empty() )
|
|
operationdetail .get_last_child() .add_child( OperationDetail( output, STATUS_NONE, FONT_ITALIC ) ) ;
|
|
|
|
if ( ! error .empty() )
|
|
operationdetail .get_last_child() .add_child( OperationDetail( error, STATUS_NONE, FONT_ITALIC ) ) ;
|
|
|
|
return exit_status ;
|
|
}
|
|
|
|
void DMRaid::get_devices( std::vector<Glib::ustring> & device_list )
|
|
{
|
|
//Retrieve list of dmraid devices
|
|
device_list .clear() ;
|
|
|
|
for ( unsigned int k=0; k < dmraid_devices .size(); k++ )
|
|
device_list.push_back( DEV_MAPPER_PATH + dmraid_devices[k] );
|
|
}
|
|
|
|
Glib::ustring DMRaid::get_dmraid_name( const Glib::ustring & dev_path )
|
|
{
|
|
//Retrieve name of dmraid device
|
|
Glib::ustring dmraid_name = "" ;
|
|
Glib::ustring regexp = "" ;
|
|
|
|
for ( unsigned int k=0; k < dmraid_devices .size(); k++ )
|
|
{
|
|
regexp = ".*(" + dmraid_devices[k] + ").*" ;
|
|
if ( Utils::regexp_label( dev_path, regexp ) == dmraid_devices[k] )
|
|
dmraid_name = dmraid_devices[k] ;
|
|
}
|
|
|
|
//Some distros appear to default to /dev/dm-# for device names, so
|
|
// also check with udev for dmraid name
|
|
if ( dmraid_name .empty() && ( dev_path .find( "/dev/dm" ) != Glib::ustring::npos ) )
|
|
{
|
|
Glib::ustring udev_name = get_udev_dm_name( dev_path ) ;
|
|
for ( unsigned int k=0; k < dmraid_devices .size(); k++ )
|
|
if ( udev_name .find( dmraid_devices[k] ) != Glib::ustring::npos )
|
|
dmraid_name = dmraid_devices[k] ;
|
|
|
|
//Also check for a symbolic link if dmraid_name not yet found
|
|
if ( dmraid_name .empty() && file_test( dev_path, Glib::FILE_TEST_IS_SYMLINK ) )
|
|
{
|
|
//Path is a symbolic link so find real path
|
|
char* rpath = realpath(dev_path.c_str(), nullptr);
|
|
if (rpath != nullptr)
|
|
{
|
|
Glib::ustring tmp_path = rpath;
|
|
free( rpath );
|
|
if ( tmp_path .length() > 0 )
|
|
for ( unsigned int k=0; k < dmraid_devices .size(); k++ )
|
|
if ( tmp_path .find( dmraid_devices[k] ) != Glib::ustring::npos )
|
|
dmraid_name = dmraid_devices[k] ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return dmraid_name ;
|
|
}
|
|
|
|
void DMRaid::get_dmraid_dir_entries( const Glib::ustring & dev_path, std::vector<Glib::ustring> & dir_list )
|
|
{
|
|
//Build list of all device entries matching device path
|
|
|
|
Glib::ustring dmraid_name = get_dmraid_name( dev_path ) ;
|
|
|
|
//Loop through the entries in the directory
|
|
Glib::ustring filename = "" ;
|
|
Glib::Dir dir( DEV_MAPPER_PATH );
|
|
while ( ( filename = dir .read_name() ) != "" )
|
|
{
|
|
if ( filename == "control" )
|
|
continue ;
|
|
|
|
if ( Utils::regexp_label( filename, "^(" + dmraid_name + ")" ) == dmraid_name )
|
|
dir_list .push_back( filename ) ;
|
|
}
|
|
}
|
|
|
|
int DMRaid::get_partition_number( const Glib::ustring & partition_name )
|
|
{
|
|
Glib::ustring dmraid_name = get_dmraid_name( partition_name ) ;
|
|
return std::atoi( Utils::regexp_label( partition_name, dmraid_name + "p?([0-9]+)" ) .c_str() ) ;
|
|
}
|
|
|
|
Glib::ustring DMRaid::get_udev_dm_name( const Glib::ustring & dev_path )
|
|
{
|
|
//Retrieve DM_NAME of device using udev information
|
|
Glib::ustring output = "" ;
|
|
Glib::ustring error = "" ;
|
|
Glib::ustring dm_name = "" ;
|
|
|
|
if (udevadm_found)
|
|
Utils::execute_command( "udevadm info --query=all --name=" + Glib::shell_quote( dev_path ),
|
|
output, error, true );
|
|
|
|
if ( ! output .empty() )
|
|
{
|
|
Glib::ustring regexp = "^E: DM_NAME=([^\n]*)$" ;
|
|
dm_name = Utils::regexp_label( output, regexp ) ;
|
|
}
|
|
|
|
return dm_name ;
|
|
}
|
|
|
|
Glib::ustring DMRaid::make_path_dmraid_compatible( Glib::ustring partition_path )
|
|
{
|
|
//The purpose of this method is to ensure that the partition name matches
|
|
// the name that the dmraid command would create.
|
|
//
|
|
//From my experience, the general rule of thumb naming convention for creating
|
|
// partition names is as follows:
|
|
//
|
|
// A) If the device name ends in a number, then append the letter "p" and
|
|
// the partition number to create the partition name.
|
|
// For Example:
|
|
// Device Name : /dev/mapper/isw_cjbdddajhi_Disk0
|
|
// Partition Name: /dev/mapper/isw_cjbdddajhi_Disk0p1
|
|
//
|
|
// B) If the device name does not end in a number, then append the
|
|
// partition number only to create the partition name.
|
|
// For Example:
|
|
// Device Name : /dev/mapper/isw_cjbdddajhi_Volume
|
|
// Partition Name: /dev/mapper/isw_cjbdddajhi_Volume1
|
|
//
|
|
//The dmraid command appears to never add the "p" into the partition name.
|
|
// Instead in all cases dmraid simply appends the partition number to the
|
|
// device name to create a partition name.
|
|
//
|
|
Glib::ustring reg_exp ;
|
|
Glib::ustring partition_number ;
|
|
|
|
for ( unsigned int k=0; k < dmraid_devices .size(); k++ )
|
|
{
|
|
reg_exp = DEV_MAPPER_PATH + dmraid_devices[k] + "p([0-9]+)";
|
|
partition_number = Utils::regexp_label( partition_path, reg_exp ) ;
|
|
if ( ! partition_number .empty() )
|
|
{
|
|
partition_path = DEV_MAPPER_PATH + dmraid_devices[k] + partition_number;
|
|
return partition_path ;
|
|
}
|
|
}
|
|
|
|
//If parted is configured with --disable-device-mapper then the partition path
|
|
// could default to something like /dev/dm-#p# on some distros, so we need to
|
|
// convert these names back into /dev/mapper entries
|
|
reg_exp = "/dev/dm-[0-9]+p([0-9]+)" ;
|
|
partition_number = Utils::regexp_label( partition_path, reg_exp ) ;
|
|
if ( ! partition_number .empty() )
|
|
{
|
|
reg_exp = "(/dev/dm-[0-9]+)p[0-9]+" ;
|
|
Glib::ustring device_path = Utils::regexp_label( partition_path, reg_exp ) ;
|
|
if ( ! device_path .empty() )
|
|
{
|
|
device_path = get_udev_dm_name( device_path ) ;
|
|
partition_path = DEV_MAPPER_PATH + device_path + partition_number;
|
|
}
|
|
}
|
|
|
|
return partition_path ;
|
|
}
|
|
|
|
bool DMRaid::create_dev_map_entries( const Partition & partition, OperationDetail & operationdetail )
|
|
{
|
|
//Create all missing dev mapper entries for a specified device.
|
|
|
|
bool exit_status = true ;
|
|
|
|
/*TO TRANSLATORS: looks like create missing /dev/mapper entries */
|
|
Glib::ustring tmp = Glib::ustring::compose( _("create missing %1 entries"), DEV_MAPPER_PATH );
|
|
operationdetail .add_child( OperationDetail( tmp ) );
|
|
|
|
//Newer dmraid defaults to always inserting the letter 'p' between the device name
|
|
// and the partition number.
|
|
if ( execute_command( "dmraid -ay -P \"\" -v", operationdetail.get_last_child() ) )
|
|
exit_status = false; // command failed
|
|
|
|
operationdetail.get_last_child().set_success_and_capture_errors( exit_status );
|
|
return exit_status ;
|
|
}
|
|
|
|
bool DMRaid::create_dev_map_entries( const Glib::ustring & dev_path )
|
|
{
|
|
//Create all missing dev mapper entries for a specified device.
|
|
|
|
Glib::ustring output, error ;
|
|
bool exit_status = true ;
|
|
|
|
//Newer dmraid defaults to always inserting the letter 'p' between the device name
|
|
// and the partition number.
|
|
if ( Utils::execute_command( "dmraid -ay -P \"\" -v", output, error, true ) )
|
|
exit_status = false; // command failed
|
|
|
|
return exit_status ;
|
|
}
|
|
|
|
void DMRaid::get_affected_dev_map_entries( const Partition & partition, std::vector<Glib::ustring> & affected_entries )
|
|
{
|
|
//Build list of affected /dev/mapper entries when a partition is to be deleted.
|
|
|
|
//Retrieve list of matching directory entries
|
|
std::vector<Glib::ustring> dir_list ;
|
|
get_dmraid_dir_entries( partition .device_path, dir_list );
|
|
|
|
//All partition numbers equal to the number of the partition to be deleted
|
|
// will be affected.
|
|
// Also, if the partition is inside an extended partition, then all logical
|
|
// partition numbers greater than the number of the partition to be deleted
|
|
// will be affected.
|
|
Glib::ustring dmraid_name = get_dmraid_name( partition .device_path ) ;
|
|
for ( unsigned int k=0; k < dir_list .size(); k++ )
|
|
{
|
|
if ( Utils::regexp_label( dir_list[k], "^(" + dmraid_name + ")" ) == dmraid_name )
|
|
{
|
|
int dir_part_num = get_partition_number( dir_list[k] ) ;
|
|
if ( dir_part_num == partition .partition_number ||
|
|
( partition .inside_extended && dir_part_num > partition .partition_number )
|
|
)
|
|
affected_entries .push_back( dir_list[k] ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DMRaid::get_partition_dev_map_entries( const Partition & partition, std::vector<Glib::ustring> & partition_entries )
|
|
{
|
|
//Build list of all /dev/mapper entries for a partition.
|
|
|
|
//Retrieve list of matching directory entries
|
|
std::vector<Glib::ustring> dir_list ;
|
|
get_dmraid_dir_entries( partition .device_path, dir_list );
|
|
|
|
//Retrieve all partition numbers equal to the number of the partition.
|
|
Glib::ustring dmraid_name = get_dmraid_name( partition .device_path ) ;
|
|
for ( unsigned int k=0; k < dir_list .size(); k++ )
|
|
{
|
|
if ( Utils::regexp_label( dir_list[k], "^(" + dmraid_name + ")" ) == dmraid_name )
|
|
{
|
|
int dir_part_num = get_partition_number( dir_list[k] ) ;
|
|
if ( dir_part_num == partition .partition_number )
|
|
partition_entries .push_back( dir_list[k] ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool DMRaid::delete_affected_dev_map_entries( const Partition & partition, OperationDetail & operationdetail )
|
|
{
|
|
// Delete all affected dev mapper entries (logical partitions >= specified partition)
|
|
|
|
std::vector<Glib::ustring> affected_entries ;
|
|
Glib::ustring command ;
|
|
bool exit_status = true ;
|
|
|
|
/*TO TRANSLATORS: looks like delete affected /dev/mapper entries */
|
|
Glib::ustring tmp = Glib::ustring::compose( _("delete affected %1 entries"), DEV_MAPPER_PATH );
|
|
operationdetail .add_child( OperationDetail( tmp ) );
|
|
|
|
get_affected_dev_map_entries( partition, affected_entries ) ;
|
|
|
|
for ( unsigned int k=0; k < affected_entries .size(); k++ )
|
|
{
|
|
command = "dmsetup remove " + Glib::shell_quote( DEV_MAPPER_PATH + affected_entries[k] );
|
|
if ( execute_command( command, operationdetail .get_last_child() ) )
|
|
exit_status = false ; //command failed
|
|
}
|
|
|
|
operationdetail.get_last_child().set_success_and_capture_errors( exit_status );
|
|
return exit_status ;
|
|
}
|
|
|
|
bool DMRaid::delete_dev_map_entry( const Partition & partition, OperationDetail & operationdetail )
|
|
{
|
|
//Delete a single partition which may be represented by multiple dev mapper entries
|
|
bool exit_status = true ;
|
|
|
|
/*TO TRANSLATORS: looks like delete /dev/mapper entry */
|
|
Glib::ustring tmp = Glib::ustring::compose( _("delete %1 entry"), DEV_MAPPER_PATH );
|
|
operationdetail .add_child( OperationDetail( tmp ) );
|
|
|
|
std::vector<Glib::ustring> partition_entries ;
|
|
get_partition_dev_map_entries( partition, partition_entries ) ;
|
|
|
|
for ( unsigned int k = 0; k < partition_entries .size(); k++ )
|
|
{
|
|
Glib::ustring command = "dmsetup remove " + Glib::shell_quote( partition_entries[k] );
|
|
if ( execute_command( command, operationdetail .get_last_child() ) )
|
|
exit_status = false ; //command failed
|
|
}
|
|
|
|
operationdetail.get_last_child().set_success_and_capture_errors( exit_status );
|
|
return exit_status ;
|
|
}
|
|
|
|
bool DMRaid::purge_dev_map_entries( const Glib::ustring & dev_path )
|
|
{
|
|
//Delete all dev mapper entries for dmraid device
|
|
|
|
std::vector<Glib::ustring> dir_list ;
|
|
Glib::ustring command ;
|
|
Glib::ustring output, error ;
|
|
bool exit_status = true ;
|
|
|
|
get_dmraid_dir_entries( dev_path, dir_list ) ;
|
|
|
|
for ( unsigned int k=0; k < dir_list .size(); k++ )
|
|
{
|
|
command = "dmsetup remove " + Glib::shell_quote( DEV_MAPPER_PATH + dir_list[k] );
|
|
if ( Utils::execute_command( command, output, error, true ) )
|
|
exit_status = false ; //command failed
|
|
}
|
|
|
|
return exit_status ;
|
|
}
|
|
|
|
bool DMRaid::update_dev_map_entry( const Partition & partition, OperationDetail & operationdetail )
|
|
{
|
|
//Update dmraid entry by first deleting the entry then recreating the entry
|
|
|
|
//Skip if extended partition because the only change is to the partition table.
|
|
if (partition.type == TYPE_EXTENDED)
|
|
return true ;
|
|
|
|
bool exit_status = true ;
|
|
|
|
/*TO TRANSLATORS: looks like update /dev/mapper entry */
|
|
Glib::ustring tmp = Glib::ustring::compose( _("update %1 entry"), DEV_MAPPER_PATH );
|
|
operationdetail .add_child( OperationDetail( tmp ) );
|
|
|
|
if( ! delete_dev_map_entry( partition , operationdetail .get_last_child() ) )
|
|
exit_status = false ; //command failed
|
|
|
|
if( ! create_dev_map_entries( partition , operationdetail .get_last_child() ) )
|
|
exit_status = false ; //command failed
|
|
|
|
operationdetail.get_last_child().set_success_and_capture_errors( exit_status );
|
|
return exit_status ;
|
|
}
|
|
|
|
|
|
// Return whether the named device (e.g. "/dev/sdc") is a member of a DMRaid array or not.
|
|
bool DMRaid::is_member(const Glib::ustring& member_path)
|
|
{
|
|
const DMRaid_Member& memb = get_cache_entry_by_member(member_path);
|
|
if (memb.member.m_name.length() > 0)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// Return whether the named device (e.g. "/dev/sdc") is a member of an *active* DMRaid
|
|
// array or not.
|
|
// As the cache only records members of active DMRaid arrays:
|
|
// is_member_active(x) == is_member(x)
|
|
bool DMRaid::is_member_active(const Glib::ustring& member_path)
|
|
{
|
|
return is_member(member_path);
|
|
}
|
|
|
|
|
|
// Return array device containing the specified member, or "" if the array is not running
|
|
// or there is no such member.
|
|
const Glib::ustring& DMRaid::get_array(const Glib::ustring& member_path)
|
|
{
|
|
const DMRaid_Member& memb = get_cache_entry_by_member(member_path);
|
|
return memb.array;
|
|
}
|
|
|
|
|
|
// Return vector of member devices of an active DMRaid array.
|
|
// E.g. lookup_dmraid_members("/dev/mapper/isw_ecccdhhiga_MyArray") -> ["/dev/sdc", "/dev/sdd"]
|
|
std::vector<Glib::ustring> DMRaid::lookup_dmraid_members(const Glib::ustring& array)
|
|
{
|
|
// Method:
|
|
// (1) Query udev for the kernel device name;
|
|
// (2) List member names from the directory /sys/block/${name}/slaves.
|
|
|
|
std::vector<Glib::ustring> members;
|
|
if (! udevadm_found)
|
|
return members; // Empty vector
|
|
|
|
Glib::ustring output;
|
|
Glib::ustring error;
|
|
Utils::execute_command("udevadm info --query=name " + Glib::shell_quote(array),
|
|
output, error, true);
|
|
// Strip terminating new line from output.
|
|
output = Utils::trim_trailing_new_line(output);
|
|
|
|
if (output.empty())
|
|
return members; // Empty vector
|
|
|
|
Glib::ustring filename;
|
|
Glib::Dir dir("/sys/block/" + output + "/slaves");
|
|
while ((filename = dir.read_name()) != "")
|
|
{
|
|
members.push_back("/dev/" + filename);
|
|
}
|
|
|
|
return members;
|
|
}
|
|
|
|
|
|
// Perform linear search of the cache to find the matching member.
|
|
// Return found cache entry or not found substitute.
|
|
const DMRaid_Member& DMRaid::get_cache_entry_by_member(const Glib::ustring& member_path)
|
|
{
|
|
BlockSpecial bs = BlockSpecial(member_path);
|
|
for (unsigned int i = 0; i < dmraid_member_cache.size(); i++)
|
|
{
|
|
if (bs == dmraid_member_cache[i].member)
|
|
return dmraid_member_cache[i];
|
|
}
|
|
|
|
static const DMRaid_Member notfound_memb = {BlockSpecial(), ""};
|
|
return notfound_memb;
|
|
}
|
|
|
|
|
|
}//GParted
|