Add a summary table to the log that shows each drives status

Add a summary table to the log that shows each drives status
i.e. erased or failed, throughput, duration of wipe, model,
serial no etc. In particular it benefits those that wipe many
drives simultaneously in rack servers. At a glance any failed
drives can be seen without having to browse back through the
log. Especially useful in --nogui mode, but also useful in GUI
mode.
This commit is contained in:
PartialVolume
2020-03-18 20:03:35 +00:00
parent 06fe803eb1
commit 6c99166b75
8 changed files with 418 additions and 25 deletions

View File

@@ -10,7 +10,8 @@ other items in 0.29 are proposed and yet to be implemented.
- [DONE] Add verbose option. -v, --verbose.
- [DONE] Add a spinner to the GUI for each drive being wiped. When nwipe is syncing the percentage completion pauses, having a spinner gives a clear indication that the wipe is still running. Each devices spinner disappears on completion of a given devices wipe.
- [DONE] Make log messages, especially the ones with the tag 'notice' succinct and less than 80 characters including the timestamp. This is of more importance when nwipe is used on a 80x30 terminal (ALT-F2, Shredos etc) but generally makes the logs more readable. While doing this all information was still retained.
- [DONE] Add a summary table to the log that shows each drives status, i.e. erased or failed, throughput, duration of wipe, model, serial no etc. In particular it benefits
those that wipe many drives simultaneously in rack servers. At a glance any failed drives can be seen without having to browse back through the log.
- 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)

View File

@@ -120,6 +120,9 @@ typedef struct nwipe_context_t_
int wipe_status; // Wipe finished = 0, wipe in progress = 1, wipe yet to start = -1.
int spinner_idx; // Index into the spinner character array
char spinner_character[1]; // The current spinner character
double duration; // Duration of the wipe in seconds
time_t start_time; // Start time of wipe
time_t end_time; // End time of wipe
/*
* Identity contains the raw serial number of the drive
* (where applicable), however, for use within nwipe use the

View File

@@ -28,6 +28,7 @@
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"
#include "nwipe.h"
#include "context.h"
@@ -77,16 +78,22 @@ void nwipe_log( nwipe_log_t level, const char* format, ... )
/* Position of writing to current log string */
int line_current_pos = 0;
/* initialise characters written */
chars_written = 0;
/* Print the date. The rc script uses the same format. */
chars_written = snprintf( message_buffer,
MAX_LOG_LINE_CHARS,
"[%i/%02i/%02i %02i:%02i:%02i] ",
1900 + p->tm_year,
1 + p->tm_mon,
p->tm_mday,
p->tm_hour,
p->tm_min,
p->tm_sec );
if( level != NWIPE_LOG_NOTIMESTAMP )
{
chars_written = snprintf( message_buffer,
MAX_LOG_LINE_CHARS,
"[%i/%02i/%02i %02i:%02i:%02i] ",
1900 + p->tm_year,
1 + p->tm_mon,
p->tm_mday,
p->tm_hour,
p->tm_min,
p->tm_sec );
}
/*
* Has the end of the buffer been reached ?, snprintf returns the number of characters that would have been
@@ -127,6 +134,7 @@ void nwipe_log( nwipe_log_t level, const char* format, ... )
{
case NWIPE_LOG_NONE:
case NWIPE_LOG_NOTIMESTAMP:
/* Do nothing. */
break;
@@ -471,3 +479,297 @@ int nwipe_log_sysinfo()
}
return 0;
}
void nwipe_log_summary( nwipe_context_t** ptr, int nwipe_selected )
{
int i;
int idx_src;
int idx_dest;
char device[7];
char status[9];
char throughput[13];
char total_throughput_string[13];
char summary_top_border[256];
char summary_top_column_titles[256];
char blank[3];
char verify[3];
// char duration[5];
char duration[314];
char model[18];
char serial_no[20];
char exclamation_flag[2];
int hours;
int minutes;
int seconds;
u64 total_duration_seconds;
u64 total_throughput;
nwipe_context_t** c;
c = ptr;
exclamation_flag[0] = 0;
device[0] = 0;
status[0] = 0;
throughput[0] = 0;
summary_top_border[0] = 0;
summary_top_column_titles[0] = 0;
blank[0] = 0;
verify[0] = 0;
duration[0] = 0;
model[0] = 0;
serial_no[0] = 0;
hours = 0;
minutes = 0;
seconds = 0;
/* A time buffer. */
time_t t;
/* A pointer to the system time struct. */
struct tm* p;
/* Nothing to do, user didn't select any devices */
if( nwipe_selected == 0 )
{
return;
}
/* initialise */
total_throughput = 0;
/* Get the current time. */
t = time( NULL );
p = localtime( &t );
/* IMPORTANT: Keep maximum columns (line length) to 80 characters for use with 80x30 terminals, Shredos, ALT-F2 etc
* --------------------------------01234567890123456789012345678901234567890123456789012345678901234567890123456789-*/
nwipe_log( NWIPE_LOG_NOTIMESTAMP, "" );
nwipe_log( NWIPE_LOG_NOTIMESTAMP,
"********************************************************************************" );
nwipe_log( NWIPE_LOG_NOTIMESTAMP, "! Device | Status | Thru-put | HH:MM:SS | Model/Serial Number" );
nwipe_log( NWIPE_LOG_NOTIMESTAMP,
"--------------------------------------------------------------------------------" );
/* Example layout:
* "! sdv |--FAIL--| 120MB/s | 01:22:01 | WD6788.8488YNHj/ZX677888388-N "
* ); " sdv | Erased | 120MB/s | 01:25:04 | WD6784.8488JKGG/ZX677888388-N " ); " sdv | Erased |
* 120MB/s | 01:19:07 | WD6788.848HHDDR/ZX677888388-N " ); End of Example layout */
for( i = 0; i < nwipe_selected; i++ )
{
/* Device name, strip any prefixed /dev/.. leaving up to 6 right justified
* characters eg " sda", prefixed with space to 6 characters, note that
* we are processing the strings right to left */
idx_dest = 6;
device[idx_dest--] = 0;
idx_src = strlen( c[i]->device_name );
idx_src--;
while( idx_dest >= 0 )
{
/* if the device name contains a / start prefixing spaces */
if( c[i]->device_name[idx_src] == '/' )
{
device[idx_dest--] = ' ';
continue;
}
if( idx_src >= 0 )
{
device[idx_dest--] = c[i]->device_name[idx_src--];
}
}
extern int user_abort;
/* Any errors ? if so set the exclamation_flag and fail message,
* All status messages should be eight characters EXACTLY !
*/
if( user_abort == 1 )
{
strncpy( exclamation_flag, "!", 1 );
exclamation_flag[1] = 0;
strncpy( status, "UABORTED", 8 );
status[8] = 0;
}
else
{
if( c[i]->result != 0 )
{
strncpy( exclamation_flag, "!", 1 );
exclamation_flag[1] = 0;
strncpy( status, "-FAILED-", 8 );
status[8] = 0;
}
else
{
if( c[i]->pass_errors != 0 )
{
strncpy( exclamation_flag, "!", 1 );
exclamation_flag[1] = 0;
strncpy( status, "-FAILED-", 8 );
status[8] = 0;
}
else
{
strncpy( exclamation_flag, " ", 1 );
exclamation_flag[1] = 0;
strncpy( status, " Erased ", 8 );
status[8] = 0;
}
}
}
/* Determine the size of throughput so that the correct nomenclature can be used */
Determine_bandwidth_nomenclature( c[i]->throughput, throughput, 13 );
/* Add this devices throughput to the total throughput */
total_throughput += c[i]->throughput;
/* Retrieve the duration of the wipe in seconds and convert hours and minutes and seconds */
/* WARNING More work needs doing on ..
*
* model
* serial no
* the footer
* testing under various fault situations ... WARNING */
c[i]->duration = difftime( c[i]->end_time, c[i]->start_time );
total_duration_seconds = (u64) c[i]->duration;
if( total_duration_seconds % 60 )
{
minutes = total_duration_seconds / 60;
seconds = total_duration_seconds - ( minutes * 60 );
}
else
{
minutes = total_duration_seconds / 60;
seconds = 0;
}
if( minutes > 59 )
{
hours = minutes / 60;
if( minutes % 60 )
{
minutes = minutes - ( hours * 60 );
}
else
{
minutes = 0;
}
}
/* Device Model */
strncpy( model, c[i]->device_model, 17 );
model[17] = 0;
/* Serial No. */
strncpy( serial_no, c[i]->device_serial_no, 20 );
model[17] = 0;
nwipe_log( NWIPE_LOG_NOTIMESTAMP,
"%s %s |%s| %s | %02i:%02i:%02i | %s/%s",
exclamation_flag,
device,
status,
throughput,
hours,
minutes,
seconds,
model,
serial_no );
}
/* Determine the size of throughput so that the correct nomenclature can be used */
Determine_bandwidth_nomenclature( total_throughput, total_throughput_string, 13 );
/* Blank abreviations used in summary table B=blank, NB=no blank */
if( nwipe_options.noblank )
{
strcpy( blank, "NB" );
}
else
{
strcpy( blank, "B" );
}
/* Verify abreviations used in summary table */
switch( nwipe_options.verify )
{
case NWIPE_VERIFY_NONE:
strcpy( verify, "NV" );
break;
case NWIPE_VERIFY_LAST:
strcpy( verify, "VL" );
break;
case NWIPE_VERIFY_ALL:
strcpy( verify, "VA" );
break;
}
nwipe_log( NWIPE_LOG_NOTIMESTAMP,
"--------------------------------------------------------------------------------" );
nwipe_log( NWIPE_LOG_NOTIMESTAMP,
"[%i/%02i/%02i %02i:%02i:%02i] Total Throughput %s, %s, %iR+%s+%s",
1900 + p->tm_year,
1 + p->tm_mon,
p->tm_mday,
p->tm_hour,
p->tm_min,
p->tm_sec,
total_throughput_string,
nwipe_method_label( nwipe_options.method ),
nwipe_options.rounds,
blank,
verify );
nwipe_log( NWIPE_LOG_NOTIMESTAMP,
"********************************************************************************" );
nwipe_log( NWIPE_LOG_NOTIMESTAMP, "" );
}
void Determine_bandwidth_nomenclature( u64 speed, char* result, int result_array_size )
{
int idx;
/* A pointer to a result character string with a minimum of 13 characters in length
* should be provided.
*
* Outputs a string of the form xxxTB/s, xxxGB/s, xxxMB/s, xxxKB/s B/s depending on the value of 'speed'
*/
/* Initialise the output array */
idx = 0;
while( idx < result_array_size )
{
result[idx++] = 0;
}
/* Determine the size of throughput so that the correct nomenclature can be used */
if( speed >= INT64_C( 1000000000000 ) )
{
snprintf( result, result_array_size, "%4lluTB/s", speed / INT64_C( 1000000000000 ) );
}
else if( speed >= INT64_C( 1000000000 ) )
{
snprintf( result, result_array_size, "%4lluGB/s", speed / INT64_C( 1000000000 ) );
}
else if( speed >= INT64_C( 1000000 ) )
{
snprintf( result, result_array_size, "%4lluMB/s", speed / INT64_C( 1000000 ) );
}
else if( speed >= INT64_C( 1000 ) )
{
snprintf( result, result_array_size, "%4lluKB/s", speed / INT64_C( 1000 ) );
}
else
{
snprintf( result, result_array_size, "%4llu B/s", speed / INT64_C( 1 ) );
}
}

View File

@@ -32,11 +32,14 @@ typedef enum nwipe_log_t_ {
NWIPE_LOG_WARNING, // Things that the user should know about.
NWIPE_LOG_ERROR, // Non-fatal errors that result in failure.
NWIPE_LOG_FATAL, // Errors that cause the program to exit.
NWIPE_LOG_SANITY // Programming errors.
NWIPE_LOG_SANITY, // Programming errors.
NWIPE_LOG_NOTIMESTAMP // logs the message without the timestamp
} nwipe_log_t;
void nwipe_log( nwipe_log_t level, const char* format, ... );
void nwipe_perror( int nwipe_errno, const char* f, const char* s );
int nwipe_log_sysinfo();
void nwipe_log_summary( nwipe_context_t**, int ); // This produces the wipe status table on exit
void Determine_bandwidth_nomenclature( u64, char*, int );
#endif /* LOGGING_H_ */

View File

@@ -123,6 +123,9 @@ void* nwipe_zero( void* ptr )
nwipe_context_t* c;
c = (nwipe_context_t*) ptr;
/* get current time at the start of the wipe */
time( &c->start_time );
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
@@ -138,6 +141,9 @@ void* nwipe_zero( void* ptr )
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
/* get current time at the end of the wipe */
time( &c->end_time );
return NULL;
} /* nwipe_zero */
@@ -150,6 +156,9 @@ void* nwipe_verify( void* ptr )
nwipe_context_t* c;
c = (nwipe_context_t*) ptr;
/* get current time at the start of the wipe */
time( &c->start_time );
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
@@ -162,6 +171,9 @@ void* nwipe_verify( void* ptr )
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
/* get current time at the end of the wipe */
time( &c->end_time );
return NULL;
} /* nwipe_verify */
@@ -175,6 +187,9 @@ void* nwipe_dod522022m( void* ptr )
nwipe_context_t* c;
c = (nwipe_context_t*) ptr;
/* get current time at the start of the wipe */
time( &c->start_time );
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
@@ -230,6 +245,9 @@ void* nwipe_dod522022m( void* ptr )
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
/* get current time at the end of the wipe */
time( &c->end_time );
return NULL;
} /* nwipe_dod522022m */
@@ -244,6 +262,9 @@ void* nwipe_dodshort( void* ptr )
nwipe_context_t* c;
c = (nwipe_context_t*) ptr;
/* get current time at the start of the wipe */
time( &c->start_time );
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
@@ -292,6 +313,9 @@ void* nwipe_dodshort( void* ptr )
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
/* get current time at the end of the wipe */
time( &c->end_time );
return NULL;
} /* nwipe_dodshort */
@@ -305,6 +329,9 @@ void* nwipe_gutmann( void* ptr )
nwipe_context_t* c;
c = (nwipe_context_t*) ptr;
/* get current time at the start of the wipe */
time( &c->start_time );
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
@@ -426,6 +453,9 @@ void* nwipe_gutmann( void* ptr )
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
/* get current time at the end of the wipe */
time( &c->end_time );
return NULL;
} /* nwipe_gutmann */
@@ -443,6 +473,9 @@ void* nwipe_ops2( void* ptr )
nwipe_context_t* c;
c = (nwipe_context_t*) ptr;
/* get current time at the start of the wipe */
time( &c->start_time );
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
@@ -588,12 +621,19 @@ void* nwipe_ops2( void* ptr )
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
/* get current time at the end of the wipe */
time( &c->end_time );
return NULL;
} /* nwipe_ops2 */
void* nwipe_is5enh( void* ptr )
{
nwipe_context_t* c = (nwipe_context_t*) ptr;
/* get current time at the start of the wipe */
time( &c->start_time );
c->wipe_status = 1;
char is5enh[3] = {'\x00', '\xFF', '\x00'};
@@ -604,6 +644,10 @@ void* nwipe_is5enh( void* ptr )
c->result = nwipe_runmethod( c, patterns );
c->wipe_status = 0;
/* get current time at the end of the wipe */
time( &c->end_time );
return NULL;
} /* nwipe_is5enh */
@@ -617,6 +661,9 @@ void* nwipe_random( void* ptr )
nwipe_context_t* c;
c = (nwipe_context_t*) ptr;
/* get current time at the start of the wipe */
time( &c->start_time );
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
@@ -629,6 +676,9 @@ void* nwipe_random( void* ptr )
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
/* get current time at the end of the wipe */
time( &c->end_time );
return NULL;
} /* nwipe_random */
@@ -879,8 +929,19 @@ int nwipe_runmethod( nwipe_context_t* c, nwipe_pattern_t* patterns )
} /* for passes */
nwipe_log(
NWIPE_LOG_NOTICE, "Finished round %i of %i on %s", c->round_working, c->round_count, c->device_name );
if( c->round_working < c->round_count )
{
nwipe_log(
NWIPE_LOG_NOTICE, "Finished round %i of %i on %s", c->round_working, c->round_count, c->device_name );
}
else
{
nwipe_log( NWIPE_LOG_NOTICE,
"Finished final round %i of %i on %s",
c->round_working,
c->round_count,
c->device_name );
}
} /* while rounds */
@@ -955,8 +1016,14 @@ int nwipe_runmethod( nwipe_context_t* c, nwipe_pattern_t* patterns )
{
return r;
}
nwipe_log( NWIPE_LOG_NOTICE, "[SUCCESS] Verified that %s is empty.", c->device_name );
if( c->verify_errors == 0 )
{
nwipe_log( NWIPE_LOG_NOTICE, "[SUCCESS] Verified that %s is empty.", c->device_name );
}
else
{
nwipe_log( NWIPE_LOG_ERROR, "[FAILURE] %s IS NOT empty.", c->device_name );
}
} /* verify */
@@ -989,7 +1056,14 @@ int nwipe_runmethod( nwipe_context_t* c, nwipe_pattern_t* patterns )
return r;
}
nwipe_log( NWIPE_LOG_NOTICE, "[SUCCESS] Verified that %s is empty.", c->device_name );
if( c->verify_errors == 0 )
{
nwipe_log( NWIPE_LOG_NOTICE, "[SUCCESS] Verified that %s is empty.", c->device_name );
}
else
{
nwipe_log( NWIPE_LOG_NOTICE, "[FAILURE] %s Verification errors, not empty", c->device_name );
}
}
nwipe_log( NWIPE_LOG_NOTICE, "[SUCCESS] Blanked device %s", c->device_name );

View File

@@ -51,6 +51,7 @@
#include <parted/debug.h>
int terminate_signal;
int user_abort;
int main( int argc, char** argv )
{
@@ -74,6 +75,9 @@ int main( int argc, char** argv )
/* Initialise the termintaion signal, 1=terminate nwipe */
terminate_signal = 0;
/* Initialise the user abort signal, 1=User aborted with CNTRL-C,SIGTERM, SIGQUIT, SIGINT etc.. */
user_abort = 0;
/* nwipes return status value, set prior to exit at the end of nwipe, as no other exit points allowed */
int return_status = 0;
@@ -313,7 +317,7 @@ int main( int argc, char** argv )
/* Print serial number of device if it exists. */
if( strlen( (const char*) c2[i]->device_serial_no ) )
{
nwipe_log( NWIPE_LOG_INFO, "Device %s has serial number %s", c2[i]->device_name, c2[i]->device_serial_no );
nwipe_log( NWIPE_LOG_NOTICE, "%s has serial number %s", c2[i]->device_name, c2[i]->device_serial_no );
}
/* Do sector size and block size checking. */
@@ -458,9 +462,10 @@ int main( int argc, char** argv )
} while( terminate_signal != 1 );
}
}
nwipe_log( NWIPE_LOG_INFO, "Exit in progress" );
if( nwipe_options.verbose )
{
nwipe_log( NWIPE_LOG_INFO, "Exit in progress" );
}
/* Send a REQUEST for the wipe threads to be cancelled */
for( i = 0; i < nwipe_selected; i++ )
{
@@ -548,6 +553,9 @@ int main( int argc, char** argv )
}
}
/* Generate and send the drive status summary to the log */
nwipe_log_summary( c2, nwipe_selected );
if( return_status == 0 )
{
nwipe_log( NWIPE_LOG_INFO, "Nwipe successfully exited." );
@@ -595,8 +603,7 @@ void* signal_hand( void* ptr )
{
// Log current status. All values are automatically updated by the GUI
case SIGUSR1:
{
case SIGUSR1: {
compute_stats( ptr );
for( i = 0; i < nwipe_misc_thread_data->nwipe_selected; i++ )
@@ -665,11 +672,13 @@ void* signal_hand( void* ptr )
case SIGHUP:
case SIGINT:
case SIGQUIT:
case SIGTERM:
{
case SIGTERM: {
/* Set termination flag for main() which will do housekeeping prior to exit */
terminate_signal = 1;
/* Set the user abort flag */
user_abort = 1;
/* Return control to the main thread, returning the signal received */
return ( (void*) 0 );

View File

@@ -68,7 +68,7 @@ void* signal_hand( void* );
#include <time.h>
#include <unistd.h>
#include "config.h"
/*#include "config.h"*/
/* System errors. */
extern int errno;

View File

@@ -19,6 +19,7 @@
#include "nwipe.h"
#include "prng.h"
#include "context.h"
#include "logging.h"
#include "mt19937ar-cok/mt19937ar-cok.h"