mirror of
https://github.com/martijnvanbrummelen/nwipe.git
synced 2026-02-20 13:42:14 +00:00
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:
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
45
src/method.c
45
src/method.c
@@ -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 */
|
||||
|
||||
56
src/nwipe.c
56
src/nwipe.c
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 )
|
||||
|
||||
Reference in New Issue
Block a user