Merge pull request #676 from PartialVolume/Add_uuid_to_pdf_filename

Add device name, e.g sda, sdb etc to PDF filename

Closes #664
This commit is contained in:
PartialVolume
2025-11-10 23:30:52 +00:00
committed by GitHub
5 changed files with 228 additions and 5 deletions

View File

@@ -82,6 +82,12 @@ typedef struct nwipe_speedring_t_
// 20 chracters for serial number plus null Byte
#define NWIPE_SERIALNUMBER_LENGTH 20
// UUID size
#define UUID_SIZE 40
// Device name max size including /dev/ path
#define DEVICE_NAME_MAX_SIZE 100
typedef struct nwipe_context_t_
{
/*
@@ -99,8 +105,9 @@ typedef struct nwipe_context_t_
int device_minor; // The minor device number.
int device_part; // The device partition or slice number.
char* device_name; // The device file name.
char device_name_without_path[100];
char gui_device_name[100];
char device_name_without_path[DEVICE_NAME_MAX_SIZE];
char gui_device_name[DEVICE_NAME_MAX_SIZE];
char device_name_terse[DEVICE_NAME_MAX_SIZE];
unsigned long long device_size; // The device size in bytes.
u64 device_size_in_sectors; // The device size in number of logical sectors, this may be 512 or 4096 sectors
u64 device_size_in_512byte_sectors; // The device size in number of 512byte sectors, irrespective of logical sector
@@ -117,6 +124,7 @@ typedef struct nwipe_context_t_
int device_is_ssd; // 0 = no SSD, 1 = is a SSD
char device_serial_no[NWIPE_SERIALNUMBER_LENGTH
+ 1]; // Serial number(processed, 20 characters plus null termination) of the device.
char device_UUID[UUID_SIZE]; // Only populated with the UUID if device is a partition
int device_target; // The device target.
u64 eta; // The estimated number of seconds until method completion.

View File

@@ -801,18 +801,19 @@ int create_pdf( nwipe_context_t* ptr )
* Create the reports filename
*
* Sanitize the strings that we are going to use to create the report filename
* by converting any non alphanumeric characters to an underscore or hyphon
* by converting any non alphanumeric characters to an underscore or hyphen
*/
replace_non_alphanumeric( end_time_text, '-' );
replace_non_alphanumeric( c->device_model, '_' );
replace_non_alphanumeric( c->device_serial_no, '_' );
snprintf( c->PDF_filename,
sizeof( c->PDF_filename ),
"%s/nwipe_report_%s_Model_%s_Serial_%s.pdf",
"%s/nwipe_report_%s_Model_%s_Serial_%s_device_%s.pdf",
nwipe_options.PDFreportpath,
end_time_text,
c->device_model,
c->device_serial_no );
c->device_serial_no,
c->device_name_terse );
pdf_save( pdf, c->PDF_filename );
pdf_destroy( pdf );

View File

@@ -216,6 +216,19 @@ int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount )
/* remove /dev/ from device, right justify and prefix name so string length is eight characters */
nwipe_strip_path( next_device->device_name_without_path, next_device->device_name );
const char* device_name_terse;
device_name_terse = skip_whitespace( next_device->device_name_without_path );
if( device_name_terse != NULL )
{
/* remove the leading whitespace and save result, we use the device without path and no leading or trailing
* space in pdf file creation later */
strcpy( next_device->device_name_terse, device_name_terse );
}
else
{
strcpy( next_device->device_name_terse, "_" );
}
/* To maintain column alignment in the gui we have to remove /dev/ from device names that
* exceed eight characters including the /dev/ path.
*/
@@ -428,6 +441,20 @@ int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount )
hpa_dco_status( next_device );
}
/*************************************
* Check whether the device has a UUID
*/
char uuid[UUID_SIZE] = "";
if( get_device_uuid( next_device->device_name, uuid ) == 0 )
{
strncpy( next_device->device_UUID, uuid, UUID_SIZE );
nwipe_log( NWIPE_LOG_INFO, "UUID for %s is: %s\n", next_device->device_name, next_device->device_UUID );
}
else
{
nwipe_log( NWIPE_LOG_INFO, "No UUID available for %s\n", next_device->device_name );
}
/* print an empty line to separate the drives in the log */
nwipe_log( NWIPE_LOG_INFO, " " );

View File

@@ -32,6 +32,14 @@
#include "context.h"
#include "logging.h"
#include "miscellaneous.h"
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h> // for isspace()
#include <stddef.h> // for NULL
/* Convert string to upper case
*/
@@ -739,3 +747,150 @@ void fix_endian_model_names( char* model )
free( tmp_string );
free( model_lower_case );
}
/*
* get_device_uuid - Find the UUID corresponding to a given block device
* @device_path: e.g., "/dev/sda1"
* @uuid_buf: pointer to a 40-byte buffer where the UUID string will be stored
*
* Returns 0 on success, -1 on failure.
*/
int get_device_uuid( const char* device_path, char* uuid_buf )
{
const char* uuid_dir = "/dev/disk/by-uuid";
struct dirent* entry;
DIR* dir;
char link_path[PATH_MAX];
char resolved_path[PATH_MAX];
ssize_t len;
if( !device_path || !uuid_buf )
{
errno = EINVAL;
return -1;
}
dir = opendir( uuid_dir );
if( !dir )
{
perror( "opendir" );
return -1;
}
while( ( entry = readdir( dir ) ) != NULL )
{
// Skip "." and ".."
if( strcmp( entry->d_name, "." ) == 0 || strcmp( entry->d_name, ".." ) == 0 )
continue;
snprintf( link_path, sizeof( link_path ), "%s/%s", uuid_dir, entry->d_name );
// readlink() doesn't null-terminate, so we must handle that
len = readlink( link_path, resolved_path, sizeof( resolved_path ) - 1 );
if( len == -1 )
continue; // skip unreadable links
resolved_path[len] = '\0';
// Construct full path (readlink gives a relative path, usually "../../sda1")
char full_path[PATH_MAX + strlen( uuid_dir ) + 1];
if( resolved_path[0] != '/' )
{
// Resolve relative symlink path
snprintf( full_path, sizeof( full_path ), "%s/%s", uuid_dir, resolved_path );
if( realpath( full_path, full_path ) == NULL )
{
closedir( dir );
return -1;
}
}
else
{
strncpy( full_path, resolved_path, sizeof( full_path ) );
full_path[sizeof( full_path ) - 1] = '\0';
}
// Compare with the given device path
if( strcmp( full_path, device_path ) == 0 )
{
strncpy( uuid_buf, entry->d_name, 40 );
uuid_buf[39] = '\0';
closedir( dir );
return 0;
}
}
closedir( dir );
errno = ENOENT;
return -1; // not found
}
/**
* find_base_device - searches /sys/block for a device that matches
* the prefix of the provided name.
*
* @devname: the input device name (e.g. "sda1", "sdb2")
* @result: buffer to store the matched base device name
* @size: size of the result buffer
*
* Returns: 0 on success (match found), -1 on failure (no match or error)
*/
int find_base_device( const char* devname, char* result, size_t size )
{
if( !devname || !result || size == 0 )
{
fprintf( stderr, "Invalid argument(s)\n" );
return -1;
}
DIR* dir = opendir( "/sys/block" );
if( !dir )
{
perror( "opendir" );
return -1;
}
struct dirent* entry;
int found = -1;
while( ( entry = readdir( dir ) ) != NULL )
{
// Skip "." and ".."
if( entry->d_name[0] == '.' )
continue;
// Check if the given devname starts with the block device name
size_t len = strlen( entry->d_name );
if( strncmp( devname, entry->d_name, len ) == 0 )
{
// Match found
strncpy( result, entry->d_name, size - 1 );
result[size - 1] = '\0';
found = 0;
break;
}
}
closedir( dir );
return found;
}
/**
* skip_whitespace - Returns a pointer to the first non-whitespace character
* in a given string.
*
* @str: input string
*
* Returns: pointer to the first non-whitespace character,
* or NULL if str is NULL or the string contains only whitespace.
*/
const char* skip_whitespace( const char* str )
{
if( !str )
return NULL;
while( *str && isspace( (unsigned char) *str ) )
str++;
return *str ? str : NULL;
}

View File

@@ -129,4 +129,36 @@ int write_system_datetime( char*, char*, char*, char*, char*, char* );
*/
void fix_endian_model_names( char* model );
/**
* Obtains the UUID of the drive partition
*
* @param constchar* device path, example /dev/sda1
* @param char* pointer to UUID string UUID_SIZE long
* @return 0 = success, -1 = failure.
*/
int get_device_uuid( const char*, char* );
/**
* find_base_device - searches /sys/block for a device that matches
* the prefix of the provided name.
*
* @devname: the input device name (e.g. "sda1", "sdb2")
* @result: buffer to store the matched base device name
* @size: size of the result buffer
*
* Returns: 0 on success (match found), -1 on failure (no match or error)
*/
int find_base_device( const char*, char*, size_t );
/**
* skip_whitespace - Returns a pointer to the first non-whitespace character
* in a given string.
*
* @str: input string
*
* Returns: pointer to the first non-whitespace character,
* or NULL if str is NULL or the string contains only whitespace.
*/
const char* skip_whitespace( const char* );
#endif /* HPA_DCO_H_ */