Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
3 changes: 3 additions & 0 deletions src/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
320 changes: 311 additions & 9 deletions src/logging.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"
#include "nwipe.h"
#include "context.h"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 ) );
}
}
5 changes: 4 additions & 1 deletion src/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */
Loading