Skip to content

Commit

Permalink
Add serial number support for USB devices
Browse files Browse the repository at this point in the history
Add serial number support for USB devices for USB
to IDE/SATA adapters. Note this will only work
with USB IDE/SATA adapters that support ATA pass
through. See martijnvanbrummelen#149 for further details of
supported devices.

This patch requires readlink and smartmontools (smartctl)
to be installed. If not installed the serial number for
supported USB hardware will be missing.

The device type, i.e USB or ATA is now shown on the selection
and wipe windows.
  • Loading branch information
PartialVolume committed Mar 24, 2020
1 parent c291859 commit 541a002
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ other items in 0.29 are proposed and yet to be implemented.
- [DONE] Add ETA to --nogui wipes status when SIGUSR1 (kill -s USR1 (nwipes PID) is issued on the command line.
- [DONE] Fix misleading throughput calculation. Throughput now shows average throughput calculated from start of wipe.
- [DONE] Fix system info not being displayed in Debian Sid. #229 (Thanks PartialVolume)
- [DONE] Add serial number display for USB to IDE/SATA adapters. This only works if the USB to IDE/SATA adapter supports ATA pass through. See #149 for further details (Thanks PartialVolume)
- Add enhancement fibre channel wiping of non 512 bytes/sector drives such as 524/528 bytes/sector etc (work in progress by PartialVolume)
- HPA/DCO detection and adjustment to wipe full drive. (work in progress by PartialVolume)

Expand Down
8 changes: 5 additions & 3 deletions src/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ typedef enum nwipe_device_t_ {
NWIPE_DEVICE_IDE,
NWIPE_DEVICE_SCSI,
NWIPE_DEVICE_COMPAQ, // Unimplemented.
NWIPE_DEVICE_USB, // Unimplemented.
NWIPE_DEVICE_IEEE1394 // Unimplemented.
NWIPE_DEVICE_USB,
NWIPE_DEVICE_IEEE1394, // Unimplemented.
NWIPE_DEVICE_ATA
} nwipe_device_t;

typedef enum nwipe_pass_t_ {
Expand Down Expand Up @@ -88,7 +89,8 @@ typedef struct nwipe_context_t_
char* device_model; // The model of the device.
char device_label[NWIPE_DEVICE_LABEL_LENGTH]; // The label (name, model, size and serial) of the device.
struct stat device_stat; // The device file state from fstat().
nwipe_device_t device_type; // Indicates an IDE, SCSI, or Compaq SMART device.
nwipe_device_t device_type; // Indicates an IDE, SCSI, or Compaq SMART device in enumerated form (int)
char device_type_str[14]; // Indicates an IDE, SCSI, USB etc as per nwipe_device_t but in ascii
char device_serial_no[21]; // Serial number(processed, 20 characters plus null termination) of the device.
int device_target; // The device target.

Expand Down
197 changes: 194 additions & 3 deletions src/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@
*
*/

#ifndef _DEFAULT_SOURCE
#define _DEFAULT_SOURCE
#endif

#include <stdio.h>
#include <stdint.h>

#include "nwipe.h"
#include "context.h"
#include "device.h"
#include "method.h"
#include "options.h"
#include "logging.h"
Expand Down Expand Up @@ -111,6 +117,7 @@ int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount )
nwipe_context_t* next_device;
int fd;
int idx;
char tmp_serial[21];

/* Check whether this drive is on the excluded drive list ? */
idx = 0;
Expand Down Expand Up @@ -178,12 +185,36 @@ int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount )
// Remove leading/trailing whitespace from serial number and left justify.
trim( (char*) next_device->device_serial_no );

/* if we couldn't obtain serial number by using the above method .. this this */
nwipe_get_device_bus_type_and_serialno( next_device->device_name, &next_device->device_type, tmp_serial );

if( next_device->device_serial_no[0] == 0 )
{
strcpy( next_device->device_serial_no, tmp_serial );
}

switch( next_device->device_type )
{
case NWIPE_DEVICE_UNKNOWN:
strcpy( next_device->device_type_str, "UNK" );
break;

case NWIPE_DEVICE_USB:
strcpy( next_device->device_type_str, "USB" );
break;

case NWIPE_DEVICE_ATA:
strcpy( next_device->device_type_str, "ATA" );
break;
}

if( strlen( (const char*) next_device->device_serial_no ) )
{
snprintf( next_device->device_label,
NWIPE_DEVICE_LABEL_LENGTH,
"%s (%s) - %s S/N:%s",
"%s %s (%s) - %s S/N:%s",
next_device->device_name,
next_device->device_type_str,
next_device->device_size_text,
next_device->device_model,
next_device->device_serial_no );
Expand All @@ -192,15 +223,19 @@ int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount )
{
snprintf( next_device->device_label,
NWIPE_DEVICE_LABEL_LENGTH,
"%s (%s) - %s",
"%s %s (%s) - %s",
next_device->device_name,
next_device->device_type_str,
next_device->device_size_text,
next_device->device_model );
}

next_device->device_type_str[0] = 0;

nwipe_log( NWIPE_LOG_NOTICE,
"Found %s, %s, %s, S/N=%s",
"Found %s, %s, %s, %s, S/N=%s",
next_device->device_name,
next_device->device_type_str,
next_device->device_model,
next_device->device_size_text,
next_device->device_serial_no );
Expand Down Expand Up @@ -261,3 +296,159 @@ char* trim( char* str )
}
return str;
}

int nwipe_get_device_bus_type_and_serialno( char* device, nwipe_device_t* bus, char* serialnumber )
{
/* The caller provides a string that contains the device, i.e. /dev/sdc, also a pointer
* to a 5 byte string (4 charaacters + null terminator) and thirdly a 21 byte
* character string (20 characters + null terminator).
*
* The function populates the bus and serial number strings for the given device.
* Results for bus would typically be ATA or USB but can also 4 digits.
*/

FILE* fp;

int r; // A result buffer.
int idx_src;
int idx_dest;
int device_len;
int set_return_value;

char readlink_command[] = "readlink /sys/block/%s";
char smartctl_command[] = "smartctl -i %s";
char device_shortform[50];
char result[512];
char final_cmd_readlink[sizeof( readlink_command ) + sizeof( device_shortform )];
char final_cmd_smartctl[sizeof( smartctl_command ) + 256];

/* Initialise return value */
set_return_value = 0;

*bus = 0;

/* Scan device name and if device is for instance /dev/sdx then convert to sdx
* If already sdx then just copy. */

idx_dest = 0;
device_shortform[idx_dest] = 0;
device_len = strlen( device );
idx_src = device_len;

while( idx_src >= 0 )
{
if( device[idx_src] == '/' || idx_src == 0 )
{
idx_src++;

/* Now scan forwards copying the short form device i.e sdc */
while( idx_src < device_len )
{
device_shortform[idx_dest++] = device[idx_src++];
}
break;
}
else
{
idx_src--;
}
}
device_shortform[idx_dest] = 0;

/* Obtain the devices link information
*/
sprintf( final_cmd_readlink, readlink_command, device_shortform );
fp = popen( final_cmd_readlink, "r" );
if( fp == NULL )
{
nwipe_log( NWIPE_LOG_WARNING,
"nwipe_get_device_bus_type_and_serialno: Failed to create stream to %s",
readlink_command );
set_return_value = 1;
}
else
{
/* Read the output a line at a time - output it. */
if( fgets( result, sizeof( result ) - 1, fp ) != NULL )
{
if( nwipe_options.verbose )
{
nwipe_log( NWIPE_LOG_DEBUG, "Readlink result = %s", result );
}

/* Scan the readlink results for bus types, i.e. USB or ATA
* Example: readlink
* /sys/block/sdd../devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/host6/target6:0:0/6:0:0:0/block/sdd
*/

if( strstr( result, "/usb" ) != 0 )
{
*bus = NWIPE_DEVICE_USB;
}
else
{
if( strstr( result, "/ata" ) != 0 )
{
*bus = NWIPE_DEVICE_ATA;
}
}
}
/* close */
r = pclose( fp );

if( r > 0 )
{
nwipe_log( NWIPE_LOG_WARNING,
"nwipe_get_device_bus_type_and_serialno(): readlink failed, \"%s\" exit status = %u",
final_cmd_readlink,
WEXITSTATUS( r ) );
set_return_value = 1;
}
}

/*
* Retrieve smartmontools drive information if USB bridge supports it, so we can retrieve the serial number of the
* drive that's on the other side of the USB bridge.. */

sprintf( final_cmd_smartctl, smartctl_command, device );
fp = popen( final_cmd_smartctl, "r" );
if( fp == NULL )
{
nwipe_log( NWIPE_LOG_WARNING,
"nwipe_get_device_bus_type_and_serialno(): Failed to create stream to %s",
smartctl_command );
set_return_value = 2;
}
else
{
/* Read the output a line at a time - output it. */
while( fgets( result, sizeof( result ) - 1, fp ) != NULL )
{
if( nwipe_options.verbose )
{
nwipe_log( NWIPE_LOG_DEBUG, "Smartctl result = %s", result );
}

if( strstr( result, "Serial Number:" ) != 0 )
{
/* strip any leading or trailing spaces and left justify, +15 is the length of "Serial Number:" */
trim( &result[15] );

strncpy( serialnumber, &result[15], 20 );
}
}
/* close */
r = pclose( fp );

if( r > 0 )
{
nwipe_log( NWIPE_LOG_WARNING,
"nwipe_get_device_bus_type_and_serialno(): smartctl failed, \"%s\" exit status = %u",
final_cmd_smartctl,
WEXITSTATUS( r ) );
set_return_value = 1;
}
}

return set_return_value;
}
1 change: 1 addition & 0 deletions src/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
void nwipe_device_identify( nwipe_context_t* c ); // Get hardware information about the device.
int nwipe_device_scan( nwipe_context_t*** c ); // Find devices that we can wipe.
int nwipe_device_get( nwipe_context_t*** c, char** devnamelist, int ndevnames ); // Get info about devices to wipe.
int nwipe_get_device_bus_type_and_serialno( char*, nwipe_device_t*, char* );

#endif /* DEVICE_H_ */

0 comments on commit 541a002

Please sign in to comment.