Merge pull request #686 from Knogle/persistent-device-paths

Enhances the --exclude option to match devices by their underlying block
This commit is contained in:
PartialVolume
2025-11-26 20:43:10 +00:00
committed by GitHub
2 changed files with 119 additions and 8 deletions

View File

@@ -50,6 +50,119 @@
int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount );
char* trim( char* str );
/*
* Resolve a device path (including /dev/disk/by-* symlinks) to its
* underlying block device id (dev_t).
*
* Returns 0 on success and fills *out_rdev.
* Returns -1 on error or if the path is not a block device.
*/
static int nwipe_path_to_rdev( const char* path, dev_t* out_rdev )
{
struct stat st;
if( path == NULL || out_rdev == NULL )
{
errno = EINVAL;
return -1;
}
/*
* stat() follows symlinks by default, which is what we want for
* persistent names in /dev/disk/by-id, /dev/disk/by-path, etc.
*/
if( stat( path, &st ) != 0 )
{
return -1;
}
if( !S_ISBLK( st.st_mode ) )
{
/* Not a block device node. */
errno = ENOTBLK;
return -1;
}
*out_rdev = st.st_rdev;
return 0;
}
/*
* Check whether a candidate device node should be excluded based on the
* --exclude list. Matching is done primarily by device identity
* (major/minor via st_rdev), so persistent names like /dev/disk/by-id/*
* are safe. We keep legacy string-based matching as a fallback.
*
* Returns 1 if the candidate should be excluded, 0 otherwise.
*/
static int nwipe_is_excluded_device( const char* candidate_devnode )
{
dev_t cand_rdev;
int have_cand_rdev;
int i;
/* Try to resolve the candidate device to a dev_t. */
have_cand_rdev = ( nwipe_path_to_rdev( candidate_devnode, &cand_rdev ) == 0 );
for( i = 0; i < MAX_NUMBER_EXCLUDED_DRIVES; i++ )
{
const char* ex = nwipe_options.exclude[i];
dev_t ex_rdev;
int have_ex_rdev;
const char* base;
/* Empty slot in the exclude array. */
if( ex == NULL || ex[0] == 0 )
{
continue;
}
/*
* First try: both candidate and exclude entry resolve to block
* devices; compare device ids (major/minor).
*/
have_ex_rdev = ( nwipe_path_to_rdev( ex, &ex_rdev ) == 0 );
if( have_cand_rdev && have_ex_rdev && ex_rdev == cand_rdev )
{
nwipe_log( NWIPE_LOG_NOTICE, "Device %s excluded as per command line option -e", candidate_devnode );
return 1;
}
/*
* Fallback 1: exact string match. This keeps compatibility with
* older usage like --exclude=/dev/sda or --exclude=/dev/mapper/cryptswap1.
*/
if( strcmp( candidate_devnode, ex ) == 0 )
{
nwipe_log( NWIPE_LOG_NOTICE, "Device %s excluded as per command line option -e", candidate_devnode );
return 1;
}
/*
* Fallback 2: match against the basename only, so that an
* exclude entry like "sda" still works even if the full path is
* /dev/sda.
*/
base = strrchr( candidate_devnode, '/' );
if( base != NULL )
{
base++;
}
else
{
base = candidate_devnode;
}
if( strcmp( base, ex ) == 0 )
{
nwipe_log( NWIPE_LOG_NOTICE, "Device %s excluded as per command line option -e", candidate_devnode );
return 1;
}
}
return 0;
}
extern int terminate_signal;
int nwipe_device_scan( nwipe_context_t*** c )
@@ -138,15 +251,11 @@ int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount )
bus = 0;
/* Check whether this drive is on the excluded drive list ? */
idx = 0;
while( idx < MAX_NUMBER_EXCLUDED_DRIVES )
/* Check whether this drive is on the excluded drive list. */
if( nwipe_is_excluded_device( dev->path ) )
{
if( !strcmp( dev->path, nwipe_options.exclude[idx++] ) )
{
nwipe_log( NWIPE_LOG_NOTICE, "Device %s excluded as per command line option -e", dev->path );
return 0;
}
/* Already logged inside nwipe_is_excluded_device(). */
return 0;
}
/* Check whether the user has specified using the --nousb option

View File

@@ -789,6 +789,8 @@ void display_help()
puts( " --exclude=/dev/sdc" );
puts( " --exclude=/dev/sdc,/dev/sdd" );
puts( " --exclude=/dev/sdc,/dev/sdd,/dev/mapper/cryptswap1\n" );
puts( " --exclude=/dev/disk/by-id/ata-XXXXXXXX" );
puts( " --exclude=/dev/disk/by-path/pci-0000:00:17.0-ata-1\n" );
puts( "" );
exit( EXIT_SUCCESS );
}