diff --git a/src/context.h b/src/context.h index 80edf6e..07de9b2 100644 --- a/src/context.h +++ b/src/context.h @@ -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. diff --git a/src/create_pdf.c b/src/create_pdf.c index e93c975..cf717f2 100644 --- a/src/create_pdf.c +++ b/src/create_pdf.c @@ -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 ); diff --git a/src/device.c b/src/device.c index 144ce86..935afd7 100644 --- a/src/device.c +++ b/src/device.c @@ -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, " " ); diff --git a/src/miscellaneous.c b/src/miscellaneous.c index b07f59d..dd8b84f 100644 --- a/src/miscellaneous.c +++ b/src/miscellaneous.c @@ -32,6 +32,14 @@ #include "context.h" #include "logging.h" #include "miscellaneous.h" +#include +#include +#include +#include +#include +#include +#include // for isspace() +#include // 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; +} diff --git a/src/miscellaneous.h b/src/miscellaneous.h index 4d89a63..7e7b120 100644 --- a/src/miscellaneous.h +++ b/src/miscellaneous.h @@ -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_ */