Fix segfault on Control-C, after a successful wipe

Symptoms: If you control-C to exit nwipe at the end of a successful
wipe you would get a segmentation fault. If nwipe log data was being
sent to stdout rather than to a log file, then you would not see the
log in the terminal windows after nwipe had exited. This patch fixes
those problems by creating a tri-state wipe flag for each wipe
thread. The main thread after having launched the wipe threads
will wait for ALL wipe flags to report that the wipe routine has
completed and the thread has exited. Only at that time does the
main() routine then proceed with joining the threads and waiting
for the join to confirm the thread has indeed exited. This join
is important as the thread will not actually exit until the OS
has flushed the disk buffers. Currently nwipe does not use O_SYNC
where data is sent straight to disk. Therefore it's important
to wait for data to be flushed before exiting nwipe. Part of this
patch is introducing a "please wait .. disks are being flushed"
prior to exiting nwipe otherwise it might look like nwipe had
hung. A disk flush in terms of how long it takes, can be from
instantly to 30 seconds or more, depending on how much system
memory you have, when the last sync occurred and if you have
changed the sync option from it's default. Something else to
note is that when all wipes have finished nwipe displays "Enter
To Exit" on the status line at the bottom of the screen. I
believe typing 'enter' rather than control-c did not produce a
segmentation fault. Irrespective, both methods of exiting nwipe
have been tested and confirmed to now work correctly. Tested
overnight with two drives using multiple wipe methods,
verification and blanking.
This commit is contained in:
PartialVolume
2019-11-11 12:34:28 +00:00
parent df36255e06
commit f6cf615a12
5 changed files with 86 additions and 23 deletions

View File

@@ -114,6 +114,7 @@ typedef struct nwipe_context_t_
pthread_t thread; /* The ID of the thread. */
u64 throughput; /* Average throughput in bytes per second. */
u64 verify_errors; /* The number of verification errors across all passes. */
int wipe_status; /* Wipe finished = 0, wipe in progress = 1, wipe yet to start = -1*/
char serial_no[21]; /* Serial number(processed), 20 characters, plus null termination */
struct hd_driveid identity; /* Identity contains the raw serial number of the drive */
/* (where applicable), however, for use within nwipe use the */

View File

@@ -1829,7 +1829,8 @@ void *nwipe_gui_status( void *ptr )
}
/* Check whether the child process is still running the wipe. */
if( c[i]->thread > 0 )
//if( c[i]->thread > 0 )
if( c[i]->wipe_status == 1 )
{
/* Print percentage and pass information. */
mvwprintw( main_window, yy++, 4, "[%05.2f%%, round %i of %i, pass %i of %i] ", \
@@ -2050,7 +2051,8 @@ int compute_stats(void *ptr)
for( i = 0 ; i < count ; i++ )
{
/* Check whether the child process is still running the wipe. */
if( c[i]->thread > 0 )
// if( c[i]->thread > 0 )
if( c[i]->wipe_status == 1 )
{
/* Increment the child counter. */
nwipe_active += 1;

View File

@@ -97,6 +97,9 @@ void *nwipe_zero( void *ptr )
nwipe_context_t *c;
c = (nwipe_context_t *) ptr;
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
/* Do nothing because nwipe_runmethod appends a zero-fill. */
nwipe_pattern_t patterns [] =
@@ -107,8 +110,8 @@ void *nwipe_zero( void *ptr )
/* Run the method. */
c->result = nwipe_runmethod( c, patterns );
/* Finished. Set the thread ID to 0 so that the GUI knows */
c->thread = 0;
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
return NULL;
} /* nwipe_zero */
@@ -124,6 +127,9 @@ void *nwipe_dod522022m( void *ptr )
nwipe_context_t *c;
c = (nwipe_context_t *) ptr;
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
/* A result holder. */
int r;
@@ -170,8 +176,8 @@ void *nwipe_dod522022m( void *ptr )
/* Run the DoD 5220.22-M method. */
c->result = nwipe_runmethod( c, patterns );
/* Finished. Set the thread ID to 0 so that the GUI knows */
c->thread = 0;
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
return NULL;
} /* nwipe_dod522022m */
@@ -188,6 +194,9 @@ void *nwipe_dodshort( void *ptr )
nwipe_context_t *c;
c = (nwipe_context_t *) ptr;
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
/* A result holder. */
int r;
@@ -227,8 +236,8 @@ void *nwipe_dodshort( void *ptr )
/* Run the DoD 5220.022-M short method. */
c->result = nwipe_runmethod( c, patterns );
/* Finished. Set the thread ID to 0 so that the GUI knows */
c->thread = 0;
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
return NULL;
} /* nwipe_dodshort */
@@ -244,6 +253,9 @@ void *nwipe_gutmann( void *ptr )
nwipe_context_t *c;
c = (nwipe_context_t *) ptr;
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
/* A result buffer. */
int r;
@@ -353,9 +365,8 @@ void *nwipe_gutmann( void *ptr )
/* Run the Gutmann method. */
c->result = nwipe_runmethod( c, patterns );
/* Finished. Set the thread ID to 0 so that the GUI knows */
c->thread = 0;
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
return NULL;
} /* nwipe_gutmann */
@@ -375,6 +386,9 @@ void *nwipe_ops2( void *ptr )
nwipe_context_t *c;
c = (nwipe_context_t *) ptr;
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
/* A generic array index. */
int i;
@@ -522,9 +536,8 @@ void *nwipe_ops2( void *ptr )
/* We're done. */
c->result = nwipe_runmethod( c, patterns );
/* Finished. Set the thread ID to 0 so that the GUI knows */
c->thread = 0;
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
return NULL;
} /* nwipe_ops2 */
@@ -540,6 +553,9 @@ void *nwipe_random( void *ptr )
nwipe_context_t *c;
c = (nwipe_context_t *) ptr;
/* set wipe in progress flag for GUI */
c->wipe_status = 1;
/* Define the random method. */
nwipe_pattern_t patterns [] =
@@ -551,9 +567,8 @@ void *nwipe_random( void *ptr )
/* Run the method. */
c->result = nwipe_runmethod( c, patterns );
/* Finished. Set the thread ID to 0 so that the GUI knows */
c->thread = 0;
/* Finished. Set the wipe_status flag so that the GUI knows */
c->wipe_status = 0;
return NULL;
} /* nwipe_random */

View File

@@ -254,6 +254,9 @@ int main( int argc, char** argv )
/* A result buffer for the BLKGETSIZE64 ioctl. */
u64 size64;
/* Initialise the wipe_status flag, -1 = wipe not yet started */
c2[i]->wipe_status = -1;
/* Open the file for reads and writes. */
c2[i]->device_fd = open( c2[i]->device_name, O_RDWR );
@@ -417,14 +420,44 @@ int main( int argc, char** argv )
errno = pthread_create( &nwipe_gui_thread, NULL, nwipe_gui_status, &nwipe_gui_data);
}
/* Wait for all the wiping threads to finish. */
i = 0;
while( i < nwipe_selected )
{
if( i == nwipe_selected )
{
break;
}
/* Wait for all the wiping threads to finish. */
if ( c2[i]->wipe_status != 0 )
{
i = 0;
}
else
{
i++;
continue;
}
sleep( 2 ); /* DO NOT REMOVE ! Stops the routine hogging CPU cycles */
}
/* Now cancel the wipe threads */
for( i = 0 ; i < nwipe_selected ; i++ )
{
if ( c2[i]->thread )
{
pthread_join( c2[i]->thread, NULL);
nwipe_log( NWIPE_LOG_INFO, "main():Cancelling wipe thread for %s", c2[i]->device_name );
nwipe_log( NWIPE_LOG_INFO, "main():Please wait.. disk cache is being flushed" );
pthread_cancel( c2[i]->thread );
/* Joins the thread and waits for completion before continuing */
r = pthread_join( c2[i]->thread, NULL);
if( r != 0 )
{
nwipe_log( NWIPE_LOG_WARNING, "main()>pthread_join():Error when waiting for wipe thread to cancel." );
}
c2[i]->thread = 0; /* Zero the thread so we know it's been cancelled */
/* Close the device file descriptor. */
close( c2[i]->device_fd );
@@ -450,7 +483,7 @@ int main( int argc, char** argv )
nwipe_gui_free();
}
nwipe_log( NWIPE_LOG_NOTICE, "Nwipe exited." );
for( i = 0 ; i < nwipe_selected ; i++ )
@@ -495,7 +528,8 @@ void *signal_hand(void *ptr)
sigaddset(&sigset, SIGINT);
sigaddset(&sigset, SIGUSR1);
int i;
int i;
int r; /* Generic result buffer */
/* Set up the structs we will use for the data required. */
nwipe_thread_data_ptr_t *nwipe_thread_data_ptr;
@@ -571,12 +605,17 @@ void *signal_hand(void *ptr)
for( i = 0; i < nwipe_misc_thread_data->nwipe_selected; i++ )
{
if ( c[i]->thread )
{
nwipe_log( NWIPE_LOG_INFO, "Cancelling thread for %s", c[i]->device_name );
nwipe_log( NWIPE_LOG_INFO, "Please be patient.. disk cache is being flushed" );
pthread_cancel( c[i]->thread );
r = pthread_join( c[i]->thread, NULL);
if( r != 0 )
{
nwipe_log( NWIPE_LOG_WARNING, "signal_hand()>pthread_join():Error when waiting for wipe thread to cancel." );
}
}
}
@@ -586,6 +625,13 @@ void *signal_hand(void *ptr)
if ( *nwipe_misc_thread_data->gui_thread )
{
pthread_cancel( *nwipe_misc_thread_data->gui_thread );
r = pthread_join( *nwipe_misc_thread_data->gui_thread, NULL);
if( r != 0 )
{
nwipe_log( NWIPE_LOG_WARNING, "signal_hand()>pthread_join():Error when waiting for GUI thread to cancel." );
}
*nwipe_misc_thread_data->gui_thread = 0;
}
}

View File

@@ -703,7 +703,6 @@ int nwipe_static_pass( NWIPE_METHOD_SIGNATURE, nwipe_pattern_t* pattern )
return -1;
}
while( z > 0 )
{
if( c->device_stat.st_blksize <= z )