Display device serial numbers (#751251)

Run "hdparm -I /dev/DISK" to get the hard drive serial number of
every device which has one and display it in the Device Information.
The displayed value can either be the actual serial number, "none" or
blank.  "none" means the device doesn't have a hard drive serial number,
such as for Linux software RAID arrays, BIOS fake RAID arrays or USB
flash drives.  Blank means something went wrong getting the serial
number.  Either it couldn't be found in the hdparm output or the hdparm
command wasn't installed.

Example real hard drive:
    # hdparm -I /dev/sda
    ...
    ATA device, with non-removable media
            Model Number:       SAMSUNG HM500JI
            Serial Number:      S1WFJDSZ123732
    ...

Example Linux software RAID array:
    # hdparm -I /dev/md127

    /dev/md127:
     HDIO_DRIVE_CMD(identify) failed: Inappropriate ioctl for device

On my desktop with 4 internal hard drives 2 Linux software RAID arrays
on those hard drives, 2 USB flash drives and 1 USB hard drive attached,
running hdparm 9 times added 0.07 seconds to the device refresh time.

Bug 751251 - Show serial number in device information
This commit is contained in:
Mike Fleetwood 2015-06-22 14:08:02 +01:00 committed by Curtis Gedak
parent 8308ee6051
commit 4b72ecd44e
6 changed files with 49 additions and 2 deletions

1
README
View File

@ -243,6 +243,7 @@ Several more commands are optionally used by GParted if found on the system.
These commands include: These commands include:
blkid - used to read volume labels and detect ext4 file systems blkid - used to read volume labels and detect ext4 file systems
hdparm - used to query disk device serial numbers
vol_id - used to read volume labels vol_id - used to read volume labels
udisks - used to prevent automounting of file systems udisks - used to prevent automounting of file systems
devkit-disks - used to prevent automounting of file systems devkit-disks - used to prevent automounting of file systems

View File

@ -50,6 +50,7 @@ public:
Sector cylinders ; Sector cylinders ;
Sector cylsize ; Sector cylsize ;
Glib::ustring model; Glib::ustring model;
Glib::ustring serial_number;
Glib::ustring disktype; Glib::ustring disktype;
int sector_size ; int sector_size ;
int max_prims ; int max_prims ;

View File

@ -78,6 +78,7 @@ private:
static bool have_rootfs_dev( std::map< Glib::ustring, std::vector<Glib::ustring> > & map ) ; static bool have_rootfs_dev( std::map< Glib::ustring, std::vector<Glib::ustring> > & map ) ;
static void read_mountpoints_from_mount_command( std::map< Glib::ustring, std::vector<Glib::ustring> > & map ) ; static void read_mountpoints_from_mount_command( std::map< Glib::ustring, std::vector<Glib::ustring> > & map ) ;
static Glib::ustring get_partition_path( PedPartition * lp_partition ); static Glib::ustring get_partition_path( PedPartition * lp_partition );
void set_device_serial_number( Device & device );
void set_device_partitions( Device & device, PedDevice* lp_device, PedDisk* lp_disk ) ; void set_device_partitions( Device & device, PedDevice* lp_device, PedDisk* lp_disk ) ;
void set_device_one_partition( Device & device, PedDevice * lp_device, FILESYSTEM fstype, void set_device_one_partition( Device & device, PedDevice * lp_device, FILESYSTEM fstype,
std::vector<Glib::ustring> & messages ); std::vector<Glib::ustring> & messages );

View File

@ -31,7 +31,9 @@ void Device::Reset()
partitions .clear() ; partitions .clear() ;
length = cylsize = 0 ; length = cylsize = 0 ;
heads = sectors = cylinders = 0 ; heads = sectors = cylinders = 0 ;
model = disktype = "" ; model = "";
serial_number = "";
disktype = "";
sector_size = max_prims = highest_busy = 0 ; sector_size = max_prims = highest_busy = 0 ;
readonly = false ; readonly = false ;
max_partition_name_length = 0; max_partition_name_length = 0;

View File

@ -275,6 +275,7 @@ void GParted_Core::set_devices_thread( std::vector<Device> * pdevices )
temp_device .sectors = lp_device ->bios_geom .sectors ; temp_device .sectors = lp_device ->bios_geom .sectors ;
temp_device .cylinders = lp_device ->bios_geom .cylinders ; temp_device .cylinders = lp_device ->bios_geom .cylinders ;
temp_device .cylsize = temp_device .heads * temp_device .sectors ; temp_device .cylsize = temp_device .heads * temp_device .sectors ;
set_device_serial_number( temp_device );
//make sure cylsize is at least 1 MiB //make sure cylsize is at least 1 MiB
if ( temp_device .cylsize < (MEBIBYTE / temp_device .sector_size) ) if ( temp_device .cylsize < (MEBIBYTE / temp_device .sector_size) )
@ -1179,6 +1180,40 @@ Glib::ustring GParted_Core::get_partition_path( PedPartition * lp_partition )
return partition_path ; return partition_path ;
} }
void GParted_Core::set_device_serial_number( Device & device )
{
if ( Glib::find_program_in_path( "hdparm" ).empty() )
// Serial number left blank when the hdparm command is not installed.
return;
Glib::ustring output;
Glib::ustring error;
Utils::execute_command( "hdparm -I " + device.get_path(), output, error, true );
if ( ! error.empty() )
{
// hdparm reported an error message to stderr. Assume it's a device
// without a hard drive serial number.
//
// Using hdparm -I to query Linux software RAID arrays and BIOS fake RAID
// arrays, both devices without their own hard drive serial numbers,
// produce this error:
// HDIO_DRIVE_CMD(identify) failed: Inappropriate ioctl for device
//
// And querying USB flash drives, also a device type without their own
// hard drive serial numbers, generates this error:
// SG_IO: bad/missing sense data, sb[]: 70 00 05 00 00 00 00 0a ...
device.serial_number = "none";
}
else
{
Glib::ustring serial_number = Utils::trim( Utils::regexp_label( output,
"^[[:blank:]]*Serial Number:[[:blank:]]*(.*)[[:blank:]]*$" ) );
if ( ! serial_number.empty() )
device.serial_number = serial_number;
}
// Otherwise serial number left blank when not found in the hdparm output.
}
/** /**
* Fills the device.partitions member of device by scanning * Fills the device.partitions member of device by scanning
* all partitions * all partitions

View File

@ -475,6 +475,12 @@ void Win_GParted::init_device_info()
device_info .push_back( Utils::mk_label( "", true, false, true ) ) ; device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
table ->attach( * device_info .back(), 1, 2, top++, bottom++, Gtk::FILL ) ; table ->attach( * device_info .back(), 1, 2, top++, bottom++, Gtk::FILL ) ;
// Serial number
table->attach( *Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Serial:") ) + "</b>" ),
0, 1, top, bottom, Gtk::FILL );
device_info.push_back( Utils::mk_label( "", true, false, true ) );
table->attach( *device_info.back(), 1, 2, top++, bottom++, Gtk::FILL );
//size //size
table ->attach( * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Size:") ) + "</b>" ), table ->attach( * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Size:") ) + "</b>" ),
0, 1, 0, 1,
@ -675,6 +681,7 @@ void Win_GParted::Fill_Label_Device_Info( bool clear )
//global info... //global info...
device_info[ t++ ] ->set_text( devices[ current_device ] .model ) ; device_info[ t++ ] ->set_text( devices[ current_device ] .model ) ;
device_info[ t++ ] ->set_text( devices[current_device].serial_number );
device_info[ t++ ] ->set_text( Utils::format_size( devices[ current_device ] .length, devices[ current_device ] .sector_size ) ) ; device_info[ t++ ] ->set_text( Utils::format_size( devices[ current_device ] .length, devices[ current_device ] .sector_size ) ) ;
device_info[ t++ ] ->set_text( Glib::build_path( "\n", devices[ current_device ] .get_paths() ) ) ; device_info[ t++ ] ->set_text( Glib::build_path( "\n", devices[ current_device ] .get_paths() ) ) ;