Merge branch 'v0.15'

This commit is contained in:
Andy Beverley
2014-03-28 17:17:32 +00:00
10 changed files with 166 additions and 73 deletions

5
README
View File

@@ -14,6 +14,11 @@ Andy Beverley
RELEASE NOTES
=============
v0.15
=====
- Add more detailed information to status page when wiping
- Add ability to send SIGUSR1 to print wiping current status to log
v0.14
=====
- Added explicit check for ncurses (required for Fedora). See bug 3604008.

View File

@@ -2,8 +2,8 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.64])
AC_INIT(nwipe, 0.14, andy@andybev.com)
AM_INIT_AUTOMAKE(nwipe, 0.14)
AC_INIT(nwipe, 0.15, andy@andybev.com)
AM_INIT_AUTOMAKE(nwipe, 0.15)
AC_OUTPUT(Makefile src/Makefile man/Makefile)
AC_CONFIG_SRCDIR([src/nwipe.c])
AC_CONFIG_HEADERS([config.h])

View File

@@ -18,6 +18,8 @@ same as dwipe, with a few changes:
- The parted library is used to detect drives
.TP
- The code is designed to be compiled with gcc
.TP
- SIGUSR1 can be used to log the stats of the current wipe
.SH OPTIONS
.TP
@@ -41,6 +43,7 @@ Do not wait for a key before exiting (default is to wait).
\fB\-\-nogui\fR
Do not show the GUI interface. Can only be used with the autonuke option.
Nowait option is automatically invoked with the nogui option.
SIGUSR1 can be used to retrieve the current wiping statistics.
.TP
\fB\-\-verify\fR=\fITYPE\fR
Whether to perform verification of erasure (default: last)

View File

@@ -123,9 +123,12 @@ typedef struct nwipe_context_t_
/* Values cannot form part of the second array below, hence the need for this. */
typedef struct
{
int nwipe_enumerated; /* The number of devices available. */
int nwipe_selected; /* The number of devices being wiped. */
pthread_t *gui_thread; /* The ID of GUI thread. */
int nwipe_enumerated; /* The number of devices available. */
int nwipe_selected; /* The number of devices being wiped. */
time_t maxeta; /* The estimated runtime of the slowest device. */
u64 throughput; /* Total throughput */
u64 errors; /* The combined number of errors of all processes. */
pthread_t *gui_thread; /* The ID of GUI thread. */
} nwipe_misc_thread_data_t;
/* The second points to the first structure, as well as the structure of all the devices */

View File

@@ -124,6 +124,8 @@ int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount )
next_device->label = dev->model;
next_device->device_name = dev->path;
next_device->device_size = dev->length * dev->sector_size;
/* Attempt to get serial number of device. */
ioctl(next_device->device_fd, HDIO_GET_IDENTITY, &next_device->identity);
(*c)[dcount] = next_device;

145
src/gui.c
View File

@@ -446,35 +446,39 @@ void nwipe_gui_select( int count, nwipe_context_t** c )
{
case NWIPE_SELECT_TRUE:
wprintw( main_window, " [wipe] %i. %s - %s (%lld bytes)", (i + offset + 1),
wprintw( main_window, " [wipe] %i. %s - %s %s (%lld bytes)", (i + offset + 1),
c[i+offset]->device_name,
c[i+offset]->label,
c[i+offset]->identity.serial_no,
c[i+offset]->device_size );
break;
case NWIPE_SELECT_FALSE:
/* Print an element that is not selected. */
wprintw( main_window, " [ ] %i. %s - %s (%lld bytes)", (i + offset +1),
wprintw( main_window, " [ ] %i. %s - %s %s (%lld bytes)", (i + offset +1),
c[i+offset]->device_name,
c[i+offset]->label,
c[i+offset]->identity.serial_no,
c[i+offset]->device_size );
break;
case NWIPE_SELECT_TRUE_PARENT:
/* This element will be wiped when its parent is wiped. */
wprintw( main_window, " [****] %i. %s - %s (%lld bytes)", (i + offset +1),
wprintw( main_window, " [****] %i. %s - %s %s (%lld bytes)", (i + offset +1),
c[i+offset]->device_name,
c[i+offset]->label,
c[i+offset]->identity.serial_no,
c[i+offset]->device_size );
break;
case NWIPE_SELECT_FALSE_CHILD:
/* We can't wipe this element because it has a child that is being wiped. */
wprintw( main_window, " [----] %i. %s - %s (%lld bytes)", (i + offset +1),
wprintw( main_window, " [----] %i. %s - %s %s (%lld bytes)", (i + offset +1),
c[i+offset]->device_name,
c[i+offset]->label,
c[i+offset]->identity.serial_no,
c[i+offset]->device_size );
break;
@@ -1659,13 +1663,13 @@ void *nwipe_gui_status( void *ptr )
int keystroke;
/* The combined througput of all processes. */
u64 nwipe_throughput = 0;
nwipe_misc_thread_data->throughput = 0;
/* The estimated runtime of the slowest device. */
time_t nwipe_maxeta = 0;
nwipe_misc_thread_data->maxeta = 0;
/* The combined number of errors of all processes. */
u64 nwipe_errors = 0;
nwipe_misc_thread_data->errors = 0;
/* Time values. */
int nwipe_hh;
@@ -1801,59 +1805,22 @@ void *nwipe_gui_status( void *ptr )
if ( nwipe_gui_blank == 0 )
{
nwipe_active = 0; // Number of active wipe threads
/* Enumerate all contexts to compute statistics. */
for( i = 0 ; i < count ; i++ )
{
/* Check whether the child process is still running the wipe. */
if( c[i]->thread > 0 )
{
/* Increment the child counter. */
nwipe_active += 1;
/* Maintain a rolling average of throughput. */
nwipe_update_speedring( &c[i]->speedring, c[i]->round_done, nwipe_time_now );
if( c[i]->speedring.timestotal > 0 )
{
/* Update the current average throughput in bytes-per-second. */
c[i]->throughput = c[i]->speedring.bytestotal / c[i]->speedring.timestotal;
/* Update the estimated remaining runtime. */
/* Check that throughput is not zero (sometimes caused during a sync) */
if (c[i]->throughput == 0)
{
c[i]->throughput = 1;
}
c[i]->eta = ( c[i]->round_size - c[i]->round_done ) / c[i]->throughput;
if( c[i]->eta > nwipe_maxeta )
{
nwipe_maxeta = c[i]->eta;
}
}
/* Update the percentage value. */
c[i]->round_percent = (double) c[i]->round_done / (double) c[i]->round_size * 100;
/* Accumulate combined throughput. */
nwipe_throughput += c[i]->throughput;
} /* child running */
/* Accumulate the error count. */
nwipe_errors += c[i]->pass_errors;
nwipe_errors += c[i]->verify_errors;
} /* for statistics */
nwipe_active = compute_stats(ptr); // Returns number of active wipe threads
/* Print information for the user. */
for( i = offset ; i < offset + slots && i < count ; i++ )
{
/* Print the context label. */
mvwprintw( main_window, yy++, 2, "%s", c[i]->label );
if ( strlen(c[i]->identity.serial_no) )
{
mvwprintw( main_window, yy++, 2, "%s - %s (%s)", c[i]->device_name,
c[i]->label,
c[i]->identity.serial_no);
}
else {
mvwprintw( main_window, yy++, 2, "%s - %s", c[i]->device_name,
c[i]->label );
}
/* Check whether the child process is still running the wipe. */
if( c[i]->thread > 0 )
@@ -1940,6 +1907,7 @@ void *nwipe_gui_status( void *ptr )
nwipe_gui_load();
u64 nwipe_throughput = nwipe_misc_thread_data->throughput;
if( nwipe_throughput >= INT64_C( 1000000000000000 ) )
{ nwipe_throughput /= INT64_C( 1000000000000 ); nwipe_format = nwipe_tera; }
else if( nwipe_throughput >= INT64_C( 1000000000000 ) )
@@ -1975,6 +1943,7 @@ void *nwipe_gui_status( void *ptr )
mvwprintw( stats_window, NWIPE_GUI_STATS_ETA_Y, 1, "Remaining:" );
time_t nwipe_maxeta = nwipe_misc_thread_data->maxeta;
if( nwipe_maxeta > 0 )
{
/* Do it again for the estimated runtime remaining. */
@@ -1990,7 +1959,7 @@ void *nwipe_gui_status( void *ptr )
/* Print the error count. */
mvwprintw( stats_window, NWIPE_GUI_STATS_ERRORS_Y, NWIPE_GUI_STATS_ERRORS_X, "Errors:" );
mvwprintw( stats_window, NWIPE_GUI_STATS_ERRORS_Y, NWIPE_GUI_STATS_TAB, "%llu", nwipe_errors );
mvwprintw( stats_window, NWIPE_GUI_STATS_ERRORS_Y, NWIPE_GUI_STATS_TAB, "%llu", nwipe_misc_thread_data->errors );
/* Add a border. */
box( stats_window, 0, 0 );
@@ -2050,6 +2019,70 @@ void *nwipe_gui_status( void *ptr )
} /* nwipe_gui_status */
int compute_stats(void *ptr)
{
nwipe_thread_data_ptr_t *nwipe_thread_data_ptr;
nwipe_thread_data_ptr = (nwipe_thread_data_ptr_t *) ptr;
nwipe_context_t **c;
nwipe_misc_thread_data_t *nwipe_misc_thread_data;
c = nwipe_thread_data_ptr->c;
nwipe_misc_thread_data = nwipe_thread_data_ptr->nwipe_misc_thread_data;
int count = nwipe_misc_thread_data->nwipe_selected;
int nwipe_active = 0;
int i;
time_t nwipe_time_now = time( NULL );
/* Enumerate all contexts to compute statistics. */
for( i = 0 ; i < count ; i++ )
{
/* Check whether the child process is still running the wipe. */
if( c[i]->thread > 0 )
{
/* Increment the child counter. */
nwipe_active += 1;
/* Maintain a rolling average of throughput. */
nwipe_update_speedring( &c[i]->speedring, c[i]->round_done, nwipe_time_now );
if( c[i]->speedring.timestotal > 0 )
{
/* Update the current average throughput in bytes-per-second. */
c[i]->throughput = c[i]->speedring.bytestotal / c[i]->speedring.timestotal;
/* Update the estimated remaining runtime. */
/* Check that throughput is not zero (sometimes caused during a sync) */
if (c[i]->throughput == 0)
{
c[i]->throughput = 1;
}
c[i]->eta = ( c[i]->round_size - c[i]->round_done ) / c[i]->throughput;
if( c[i]->eta > nwipe_misc_thread_data->maxeta )
{
nwipe_misc_thread_data->maxeta = c[i]->eta;
}
}
/* Update the percentage value. */
c[i]->round_percent = (double) c[i]->round_done / (double) c[i]->round_size * 100;
/* Accumulate combined throughput. */
nwipe_misc_thread_data->throughput += c[i]->throughput;
} /* child running */
/* Accumulate the error count. */
nwipe_misc_thread_data->errors += c[i]->pass_errors;
nwipe_misc_thread_data->errors += c[i]->verify_errors;
} /* for statistics */
return nwipe_active;
}
void nwipe_update_speedring( nwipe_speedring_t* speedring, u64 speedring_bytes, time_t speedring_now )
{

View File

@@ -35,6 +35,7 @@ void nwipe_gui_rounds( void ); /* Change the rounds op
void nwipe_gui_verify( void ); /* Change the verify option. */
void nwipe_gui_noblank( void ); /* Change the noblank option. */
int compute_stats(void *ptr);
void nwipe_update_speedring( nwipe_speedring_t* speedring, u64 speedring_done, time_t speedring_now );

View File

@@ -78,6 +78,9 @@ int main( int argc, char** argv )
/* Initialised and populated in device scan. */
nwipe_context_t **c1 = 0;
/* The array of pointers to contexts that will actually be wiped. */
nwipe_context_t **c2 = (nwipe_context_t **)malloc(nwipe_enumerated * sizeof(nwipe_context_t *));
/* Parse command line options. */
nwipe_optind = nwipe_options_parse( argc, argv );
@@ -130,6 +133,7 @@ int main( int argc, char** argv )
sigaddset(&sigset, SIGTERM);
sigaddset(&sigset, SIGQUIT);
sigaddset(&sigset, SIGINT);
sigaddset(&sigset, SIGUSR1);
pthread_sigmask(SIG_SETMASK, &sigset, NULL);
/* Create a signal handler thread. This thread will catch all */
@@ -141,7 +145,7 @@ int main( int argc, char** argv )
nwipe_misc_thread_data_t nwipe_misc_thread_data;
nwipe_thread_data_ptr_t nwipe_thread_data_ptr;
nwipe_thread_data_ptr.c = c1;
nwipe_thread_data_ptr.c = c2;
nwipe_misc_thread_data.nwipe_enumerated = nwipe_enumerated;
if( !nwipe_options.nogui )
nwipe_misc_thread_data.gui_thread = &nwipe_gui_thread;
@@ -225,9 +229,6 @@ int main( int argc, char** argv )
/* Pass the number selected to the struct for other threads */
nwipe_misc_thread_data.nwipe_selected = nwipe_selected;
/* The array of pointers to contexts that will actually be wiped. */
nwipe_context_t **c2 = (nwipe_context_t **)malloc(nwipe_enumerated * sizeof(nwipe_context_t *));
/* Populate the array of selected contexts. */
for( i = 0, j = 0 ; i < nwipe_enumerated ; i++ )
{
@@ -287,10 +288,8 @@ int main( int argc, char** argv )
}
*/
/* Attempt to get serial number of device. */
ioctl(c2[i]->device_fd, HDIO_GET_IDENTITY, &c2[i]->identity);
if ( c2[i]->identity.serial_no ) {
/* Print serial number of device if it exists. */
if ( strlen(c2[i]->identity.serial_no) ) {
nwipe_log( NWIPE_LOG_INFO, "Device %s has serial number %s", c2[i]->device_name, c2[i]->identity.serial_no);
}
@@ -496,6 +495,7 @@ void *signal_hand(void *ptr)
sigaddset(&sigset, SIGTERM);
sigaddset(&sigset, SIGQUIT);
sigaddset(&sigset, SIGINT);
sigaddset(&sigset, SIGUSR1);
int i;
@@ -517,13 +517,60 @@ void *signal_hand(void *ptr)
switch ( sig ) {
// Log current status. All values are automatically updated by the GUI
case SIGUSR1 :
{
compute_stats(ptr);
for( i = 0; i < nwipe_misc_thread_data->nwipe_selected; i++ )
{
if ( c[i]->thread )
{
char *status;
switch( c[i]->pass_type )
{
case NWIPE_PASS_FINAL_BLANK:
status = "[blanking]";
break;
case NWIPE_PASS_FINAL_OPS2:
status = "[OPS-II final]";
break;
case NWIPE_PASS_WRITE:
status = "[writing]";
break;
case NWIPE_PASS_VERIFY:
status = "[verifying]";
break;
case NWIPE_PASS_NONE:
break;
}
if( c[i]->sync_status ) { status = "[syncing]"; }
nwipe_log( NWIPE_LOG_INFO, "%s: %05.2f%%, round %i of %i, pass %i of %i %s", \
c[i]->device_name, c[i]->round_percent, c[i]->round_working, c[i]->round_count, c[i]->pass_working, c[i]->pass_count, status );
}
else
{
if( c[i]->result == 0 ) { nwipe_log( NWIPE_LOG_INFO, "%s: Success", c[i]->device_name ); }
else if( c[i]->signal ) { nwipe_log( NWIPE_LOG_INFO, "%s: Failure: signal %i", c[i]->device_name, c[i]->signal ); }
else { nwipe_log( NWIPE_LOG_INFO, "%s: Failure: code %i", c[i]->device_name, c[i]->result ); }
}
}
break;
}
case SIGHUP :
case SIGINT :
case SIGQUIT :
case SIGTERM :
{
for( i = 0; i < nwipe_misc_thread_data->nwipe_enumerated; i++ )
for( i = 0; i < nwipe_misc_thread_data->nwipe_selected; i++ )
{
if ( c[i]->thread )
@@ -551,7 +598,6 @@ void *signal_hand(void *ptr)
printf("%s\n", log_lines[i]);
}
printf("Program interrupted (caught signal %d)\n", sig);
// Cleanup

View File

@@ -395,7 +395,7 @@ display_help()
puts(" --noblank Do not blank disk after wipe (default is to complete a final blank pass)" );
puts(" --nowait Do not wait for a key before exiting (default is to wait)" );
puts(" --nogui Do not show the GUI interface. Automatically invokes the nowait option" );
puts(" Must be used with --autonuke option");
puts(" Must be used with --autonuke option. Send SIGUSR1 to log current stats");
puts("");
exit( EXIT_SUCCESS );
}

View File

@@ -4,7 +4,7 @@
* used by configure to dynamically assign those values
* to documentation files.
*/
const char *version_string = "0.14";
const char *version_string = "0.15";
const char *program_name = "nwipe";
const char *author_name = "Andy Beverley";
const char *email_address = "andy@andybev.com";