Merge pull request #698 from Knogle/benchmark-mode

gui: add interactive PRNG benchmark mode (RAM-only throughput)
This commit is contained in:
PartialVolume
2025-12-16 23:00:50 +00:00
committed by GitHub
5 changed files with 670 additions and 9 deletions

View File

@@ -88,6 +88,8 @@ typedef struct nwipe_speedring_t_
// Device name max size including /dev/ path
#define DEVICE_NAME_MAX_SIZE 100
#define NWIPE_DEVICE_SYSFS_PATH_LENGTH 512
typedef struct nwipe_context_t_
{
/*
@@ -107,6 +109,7 @@ typedef struct nwipe_context_t_
char* device_name; // The device file name.
char device_name_without_path[DEVICE_NAME_MAX_SIZE];
char gui_device_name[DEVICE_NAME_MAX_SIZE];
char device_sysfs_path[NWIPE_DEVICE_SYSFS_PATH_LENGTH]; // sysfs path for topology view
char device_name_terse[DEVICE_NAME_MAX_SIZE];
unsigned long long device_size; // The device size in bytes.
u64 device_size_in_sectors; // The device size in number of logical sectors, this may be 512 or 4096 sectors

View File

@@ -266,7 +266,7 @@ int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount )
if( nwipe_options.nousb )
{
/* retrieve bus and drive serial number, HOWEVER we are only interested in the bus at this time */
r = nwipe_get_device_bus_type_and_serialno( dev->path, &bus, &is_ssd, tmp_serial );
r = nwipe_get_device_bus_type_and_serialno( dev->path, &bus, &is_ssd, tmp_serial, NULL, 0 );
/* See nwipe_get_device_bus_type_and_serialno() function for meaning of these codes */
if( r == 0 || ( r >= 3 && r <= 6 ) )
@@ -401,8 +401,12 @@ int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount )
trim( (char*) next_device->device_serial_no );
/* if we couldn't obtain serial number by using the above method .. try this */
r = nwipe_get_device_bus_type_and_serialno(
next_device->device_name, &next_device->device_type, &next_device->device_is_ssd, tmp_serial );
r = nwipe_get_device_bus_type_and_serialno( next_device->device_name,
&next_device->device_type,
&next_device->device_is_ssd,
tmp_serial,
next_device->device_sysfs_path,
sizeof( next_device->device_sysfs_path ) );
/* If serial number & bus retrieved (0) OR unsupported USB bus identified (5) */
if( r == 0 || r == 5 )
@@ -665,7 +669,13 @@ static void nwipe_normalize_serial( char* serial )
trim( serial );
}
int nwipe_get_device_bus_type_and_serialno( char* device, nwipe_device_t* bus, int* is_ssd, char* serialnumber )
int nwipe_get_device_bus_type_and_serialno( char* device,
nwipe_device_t* bus,
int* is_ssd,
char* serialnumber,
char* sysfs_path,
size_t sysfs_path_size )
{
/* The caller provides a string that contains the device, i.e. /dev/sdc, also a pointer
* to an integer (bus type), another pointer to an integer (is_ssd), and finally a 21 byte
@@ -804,11 +814,19 @@ int nwipe_get_device_bus_type_and_serialno( char* device, nwipe_device_t* bus, i
if( fp != NULL )
{
/* Read the output a line at a time - output it. */
if( fgets( result, sizeof( result ) - 1, fp ) != NULL )
{
strip_CR_LF( result );
if( sysfs_path != NULL && sysfs_path_size > 0 )
{
strncpy( sysfs_path, result, sysfs_path_size - 1 );
sysfs_path[sysfs_path_size - 1] = '\0';
}
if( nwipe_options.verbose )
{
strip_CR_LF( result );
nwipe_log( NWIPE_LOG_DEBUG, "Readlink: %s", result );
}

View File

@@ -40,7 +40,12 @@ int nwipe_device_scan( nwipe_context_t*** c ); // Find devices that we can wipe
*/
int nwipe_device_get( nwipe_context_t*** c, char** devnamelist, int ndevnames ); // Get info about devices to wipe.
int nwipe_get_device_bus_type_and_serialno( char*, nwipe_device_t*, int*, char* );
int nwipe_get_device_bus_type_and_serialno( char* device,
nwipe_device_t* bus,
int* is_ssd,
char* serialnumber,
char* sysfs_path,
size_t sysfs_path_size );
void strip_CR_LF( char* );
void determine_disk_capacity_nomenclature( u64, char* );
void remove_ATA_prefix( char* );

639
src/gui.c
View File

@@ -139,6 +139,8 @@ PANEL* main_panel;
PANEL* options_panel;
PANEL* stats_panel;
extern void strip_CR_LF( char* );
/* Options window title. */
const char* options_title = " Options ";
@@ -147,9 +149,9 @@ const char* stats_title = " Statistics ";
/* Footer labels. */
const char* main_window_footer =
"S=Start m=Method p=PRNG v=Verify r=Rounds b=Blanking Space=Select c=Config CTRL+C=Quit";
const char* shredos_main_window_footer =
"S=Start m=Method p=PRNG v=Verify r=Rounds b=Blanking Space=Select f=Font size c=Config CTRL+C=Quit";
"S=Start m=Method p=PRNG v=Verify t=path o=Benchmark r=Rounds b=Blanking Space=Select c=Config CTRL+C=Quit";
const char* shredos_main_window_footer = "S=Start m=Method p=PRNG v=Verify t=path o=Benchmark r=Rounds b=Blanking "
"Space=Select f=Font size c=Config CTRL+C=Quit";
char** p_main_window_footer;
const char* main_window_footer_warning_lower_case_s = " WARNING: To start the wipe press SHIFT+S (uppercase S) ";
@@ -166,6 +168,7 @@ const char* main_window_footer_warning_no_drive_selected =
* of the footer message when the terminal is resized, a quirk in ncurses? - DO NOT REMOVE THE \" */
const char* selection_footer = "J=Down K=Up Space=Select Backspace=Cancel Ctrl+C=Quit";
const char* selection_footer_config = "J=Down K=Up Return=Select ESC|Backspace=back Ctrl+C=Quit";
const char* selection_footer_benchmark = "ESC|Backspace=Back ENTER=Run Ctrl+C=Quit";
const char* selection_footer_preview_prior_to_drive_selection =
"A=Accept & display drives J=Down K=Up Space=Select Backspace=Cancel Ctrl+C=Quit";
const char* selection_footer_add_customer = "S=Save J=Down K=Up Space=Select Backspace=Cancel Ctrl+C=Quit";
@@ -175,6 +178,7 @@ const char* end_wipe_footer = "B=[Toggle between dark\\blank\\blue screen] Ctrl+
const char* shredos_end_wipe_footer = "b=[Toggle dark\\blank\\blue screen] f=Font size Ctrl+C=Quit";
const char* rounds_footer = "Left=Erase Esc=Cancel Ctrl+C=Quit";
const char* selection_footer_text_entry = "Esc=Cancel Return=Submit Ctrl+C=Quit";
const char* selection_footer_device_view = "ESC|Backspace=Back Ctrl+C=Quit";
/* Keeps track of whether font is standard or double size (applicable to ShredOS only) */
int toggle_font_flag = 0;
@@ -193,6 +197,235 @@ int stdscr_cols_previous;
int tft_saver = 0;
/* Draw one "└── " prefix using ncurses ACS characters (portable, no UTF-8 needed).
* Falls dein Terminal ACS nicht sauber kann, kannst du unten auf ASCII fallbacken.
*/
static void nwipe_gui_draw_acs_prefix( WINDOW* w, int y, int x )
{
mvwaddch( w, y, x + 0, ACS_LLCORNER );
mvwaddch( w, y, x + 1, ACS_HLINE );
mvwaddch( w, y, x + 2, ACS_HLINE );
mvwaddch( w, y, x + 3, ' ' );
}
typedef struct
{
const nwipe_prng_t* prng;
double mbps;
double seconds;
unsigned long long bytes;
int rc;
} nwipe_prng_bench_result_t;
static double nwipe_gui_monotonic_seconds( void )
{
struct timespec ts;
clock_gettime( CLOCK_MONOTONIC, &ts );
return (double) ts.tv_sec + (double) ts.tv_nsec / 1000000000.0;
}
/* Simple deterministic seed for benchmarking (no external deps). */
static void nwipe_gui_make_bench_seed( unsigned char* seed, size_t len )
{
unsigned long t = (unsigned long) time( NULL );
unsigned long x = ( t ^ 0xA5A5A5A5UL ) + (unsigned long) (uintptr_t) seed;
for( size_t i = 0; i < len; i++ )
{
x = x * 1664525UL + 1013904223UL;
seed[i] = (unsigned char) ( ( x >> 16 ) & 0xFF );
}
}
static void* nwipe_gui_alloc_aligned( size_t alignment, size_t size )
{
void* p = NULL;
if( posix_memalign( &p, alignment, size ) != 0 )
return NULL;
return p;
}
static int nwipe_gui_cmp_bench_desc( const void* a, const void* b )
{
const nwipe_prng_bench_result_t* A = (const nwipe_prng_bench_result_t*) a;
const nwipe_prng_bench_result_t* B = (const nwipe_prng_bench_result_t*) b;
if( A->rc != 0 && B->rc == 0 )
return 1;
if( A->rc == 0 && B->rc != 0 )
return -1;
if( A->mbps < B->mbps )
return 1;
if( A->mbps > B->mbps )
return -1;
return 0;
}
/* Benchmark one PRNG by generating keystream into a RAM buffer for ~target_seconds. */
static void nwipe_gui_bench_one_prng( const nwipe_prng_t* prng,
nwipe_prng_bench_result_t* out,
void* io_buf,
size_t io_block,
double target_seconds )
{
void* state = NULL;
unsigned char seedbuf[4096];
nwipe_entropy_t seed;
seed.s = (u8*) seedbuf;
seed.length = sizeof( seedbuf );
nwipe_gui_make_bench_seed( seedbuf, sizeof( seedbuf ) );
out->prng = prng;
out->mbps = 0.0;
out->seconds = 0.0;
out->bytes = 0;
out->rc = 0;
int rc = prng->init( &state, &seed );
if( rc != 0 )
{
out->rc = rc;
if( state )
free( state );
return;
}
const double t0 = nwipe_gui_monotonic_seconds();
double now = t0;
while( ( now - t0 ) < target_seconds )
{
rc = prng->read( &state, io_buf, io_block );
if( rc != 0 )
{
out->rc = rc;
break;
}
out->bytes += (unsigned long long) io_block;
now = nwipe_gui_monotonic_seconds();
}
out->seconds = now - t0;
if( out->rc == 0 && out->seconds > 0.0 )
{
out->mbps = ( (double) out->bytes / ( 1024.0 * 1024.0 ) ) / out->seconds;
}
if( state )
free( state );
}
static void nwipe_gui_trim_to_devices( const char* in, const char** out_start )
{
const char* p = strstr( in ? in : "", "/devices/" );
*out_start = p ? ( p + 9 ) : ( in ? in : "" );
}
static int nwipe_gui_is_pci_bdf( const char* s )
{
return s && strlen( s ) >= 12 && s[4] == ':' && s[7] == ':' && s[10] == '.';
}
static int nwipe_gui_have_lspci( void )
{
return access( "/usr/bin/lspci", X_OK ) == 0 || access( "/bin/lspci", X_OK ) == 0;
}
static void nwipe_gui_lspci_name( const char* bdf, char* out, size_t outsz )
{
out[0] = '\0';
if( !bdf || !out || outsz == 0 || !nwipe_gui_have_lspci() )
return;
char cmd[160];
snprintf( cmd, sizeof( cmd ), "lspci -D -s %s 2>/dev/null", bdf );
FILE* fp = popen( cmd, "r" );
if( !fp )
return;
char buf[256];
if( fgets( buf, sizeof( buf ), fp ) )
{
strip_CR_LF( buf );
char* sp = strchr( buf, ' ' );
if( sp && *( sp + 1 ) )
{
snprintf( out, outsz, "%s", sp + 1 );
}
}
pclose( fp );
}
/* Prints a linear sysfs path as an indented “tree chain” using ACS line-drawing.
* Returns the next free y position after printing.
*/
static int nwipe_gui_print_sysfs_tree( WINDOW* w, int starty, int maxy, int xbase, int width, const char* sysfs_target )
{
const char* s;
nwipe_gui_trim_to_devices( sysfs_target, &s );
char tmp[1024];
strncpy( tmp, s, sizeof( tmp ) - 1 );
tmp[sizeof( tmp ) - 1] = '\0';
int level = 0;
int y = starty;
char* save = NULL;
char* tok = strtok_r( tmp, "/", &save );
while( tok && y < maxy )
{
if( tok[0] == '\0' )
{
tok = strtok_r( NULL, "/", &save );
continue;
}
char line[512];
line[0] = '\0';
if( nwipe_gui_is_pci_bdf( tok ) )
{
char name[256];
nwipe_gui_lspci_name( tok, name, sizeof( name ) );
if( name[0] )
snprintf( line, sizeof( line ), "%s %s", tok, name );
else
snprintf( line, sizeof( line ), "%s", tok );
}
else
{
snprintf( line, sizeof( line ), "%s", tok );
}
/* Column calculation: xbase + level*3, then we draw a 4-char prefix "└── " in ACS. */
int col = xbase + ( level * 3 );
if( col < 0 )
col = 0;
/* Keep inside the box */
int text_col = col + 4;
int avail = width - text_col;
if( avail < 0 )
avail = 0;
/* Draw prefix and text */
nwipe_gui_draw_acs_prefix( w, y, col );
mvwprintw( w, y, text_col, "%.*s", avail, line );
y++;
level++;
tok = strtok_r( NULL, "/", &save );
}
return y;
}
void nwipe_gui_title( WINDOW* w, const char* s )
{
/**
@@ -526,6 +759,176 @@ void nwipe_gui_amend_footer_window( const char* footer_text )
} /* nwipe_gui_amend_footer_window */
void nwipe_gui_benchmark_prng( void )
{
extern nwipe_prng_t nwipe_twister;
extern nwipe_prng_t nwipe_isaac;
extern nwipe_prng_t nwipe_isaac64;
extern nwipe_prng_t nwipe_add_lagg_fibonacci_prng;
extern nwipe_prng_t nwipe_xoroshiro256_prng;
extern nwipe_prng_t nwipe_aes_ctr_prng;
extern int terminate_signal;
const nwipe_prng_t* prngs[] = {
&nwipe_twister,
&nwipe_isaac,
&nwipe_isaac64,
&nwipe_add_lagg_fibonacci_prng,
&nwipe_xoroshiro256_prng,
&nwipe_aes_ctr_prng,
};
const int prng_count = (int) ( sizeof( prngs ) / sizeof( prngs[0] ) );
nwipe_prng_bench_result_t results[8];
memset( results, 0, sizeof( results ) );
/* Settings: keep it quick and comparable */
const double target_seconds = 1.0; /* ~1s per PRNG */
const size_t io_block = 4 * 1024 * 1024; /* 4 MiB block into RAM */
const size_t alignment = 4096;
void* io_buf = nwipe_gui_alloc_aligned( alignment, io_block );
if( !io_buf )
{
/* Minimal error view */
werase( main_window );
box( main_window, 0, 0 );
nwipe_gui_title( main_window, " PRNG Benchmark " );
// wattron( main_window, A_DIM );
mvwprintw( main_window, 3, 2, "Unable to allocate benchmark buffer (%zu bytes).", io_block );
mvwprintw( main_window, 5, 2, "Press ESC to return." );
// wattroff( main_window, A_DIM );
wrefresh( main_window );
int k;
do
{
timeout( 250 );
k = getch();
timeout( -1 );
} while( k != 27 && terminate_signal != 1 );
return;
}
/* Footer */
werase( footer_window );
nwipe_gui_title( footer_window, selection_footer_benchmark );
wrefresh( footer_window );
int keystroke = 0;
int have_results = 0;
do
{
nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_benchmark );
int wlines, wcols;
getmaxyx( main_window, wlines, wcols );
werase( main_window );
box( main_window, 0, 0 );
nwipe_gui_title( main_window, " PRNG Benchmark " );
// wattron( main_window, A_DIM );
mvwprintw( main_window, 2, 2, "RAM-only PRNG throughput test (~%.1fs each).", target_seconds );
mvwprintw( main_window, 3, 2, "ENTER = run benchmark ESC = back" );
int yy = 5;
if( !have_results )
{
mvwprintw( main_window, yy++, 2, "No results yet." );
}
else
{
mvwprintw( main_window, yy++, 2, "Leaderboard (MB/s):" );
yy++;
for( int i = 0; i < prng_count && yy < ( wlines - 2 ); i++ )
{
if( results[i].rc == 0 )
{
mvwprintw( main_window,
yy++,
2,
"%2d) %-40.40s %10.1f MB/s",
i + 1,
results[i].prng->label,
results[i].mbps );
}
else
{
mvwprintw( main_window,
yy++,
2,
"%2d) %-40.40s (failed: rc=%d)",
i + 1,
results[i].prng->label,
results[i].rc );
}
}
}
// wattroff( main_window, A_DIM );
wrefresh( main_window );
timeout( 250 );
keystroke = getch();
timeout( -1 );
if( keystroke == 27 || keystroke == KEY_BACKSPACE || keystroke == KEY_BREAK )
{
break;
}
if( keystroke == 10 || keystroke == KEY_ENTER ) /* ENTER */
{
/* Run benchmark */
have_results = 0;
for( int i = 0; i < prng_count; i++ )
{
/* Update progress screen */
werase( main_window );
box( main_window, 0, 0 );
nwipe_gui_title( main_window, " PRNG Benchmark " );
// wattron( main_window, A_DIM );
mvwprintw( main_window, 2, 2, "Running %d/%d:", i + 1, prng_count );
mvwprintw( main_window, 3, 2, "%s", prngs[i]->label );
mvwprintw(
main_window, 5, 2, "Generating into RAM buffer (%zu MiB blocks)...", io_block / ( 1024 * 1024 ) );
mvwprintw( main_window, 7, 2, "ESC to abort this benchmark." );
// wattroff( main_window, A_DIM );
wrefresh( main_window );
/* Actually benchmark one PRNG */
nwipe_gui_bench_one_prng( prngs[i], &results[i], io_buf, io_block, target_seconds );
/* Allow user abort quickly after each PRNG */
timeout( 0 );
int k = getch();
timeout( -1 );
if( k == 27 || terminate_signal == 1 )
{
break;
}
}
/* Sort results into a leaderboard */
qsort( results, prng_count, sizeof( results[0] ), nwipe_gui_cmp_bench_desc );
have_results = 1;
}
} while( terminate_signal != 1 );
free( io_buf );
}
void nwipe_gui_create_options_window()
{
/* Create the options window. */
@@ -1217,7 +1620,22 @@ void nwipe_gui_select( int count, nwipe_context_t** c )
/* Run the option dialog. */
nwipe_gui_verify();
break;
case 'o':
validkeyhit = 1;
nwipe_gui_benchmark_prng();
break;
case 't':
validkeyhit = 1;
/* Open device view for the currently focused entry.
* We only block disabled entries.
*/
if( count > 0 && c[focus]->select != NWIPE_SELECT_DISABLED )
{
nwipe_gui_view_device( count, c, focus );
}
break;
case 'b':
case 'B':
@@ -2236,6 +2654,221 @@ void nwipe_gui_verify( void )
} /* nwipe_gui_verify */
static nwipe_context_t* nwipe_gui_find_parent_disk( int count, nwipe_context_t** c, int idx )
{
nwipe_context_t* cur = c[idx];
if( cur->device_part == 0 )
{
return cur;
}
for( int i = 0; i < count; i++ )
{
if( c[i]->device_type == cur->device_type && c[i]->device_host == cur->device_host
&& c[i]->device_bus == cur->device_bus && c[i]->device_target == cur->device_target
&& c[i]->device_lun == cur->device_lun && c[i]->device_part == 0 )
{
return c[i];
}
}
return cur; /* fallback */
}
static void nwipe_gui_tail_truncate( const char* in, char* out, size_t outsz, int maxw )
{
if( !out || outsz == 0 )
return;
out[0] = '\0';
if( !in )
{
snprintf( out, outsz, "(null)" );
return;
}
int len = (int) strlen( in );
if( maxw <= 0 )
{
snprintf( out, outsz, "" );
return;
}
if( len <= maxw )
{
snprintf( out, outsz, "%s", in );
return;
}
/* keep tail, prefix with "..." */
int keep = maxw - 3;
if( keep < 1 )
{
snprintf( out, outsz, "..." );
return;
}
const char* tail = in + ( len - keep );
snprintf( out, outsz, "...%s", tail );
}
static void nwipe_gui_format_topology_line( const char* sysfs_target, const char* blockname, char* out, size_t outsz )
{
if( !out || outsz == 0 )
return;
out[0] = '\0';
if( !sysfs_target || sysfs_target[0] == '\0' )
{
snprintf( out, outsz, "Topo: (unknown)" );
return;
}
int is_usb = ( strstr( sysfs_target, "/usb" ) != NULL );
/* PCI BDF like 0000:03:00.0 */
char pcie[32] = { 0 };
{
const char* q = strstr( sysfs_target, "0000:" );
if( q )
{
size_t n = 0;
while( q[n] && q[n] != '/' && n < sizeof( pcie ) - 1 )
n++;
memcpy( pcie, q, n );
pcie[n] = '\0';
}
}
if( is_usb )
{
/* show USB hop tokens like "2-1", "2-1.3" */
char hops[128] = { 0 };
char tmp[512];
strncpy( tmp, sysfs_target, sizeof( tmp ) - 1 );
tmp[sizeof( tmp ) - 1] = '\0';
char* save = NULL;
char* tok = strtok_r( tmp, "/", &save );
while( tok )
{
if( tok[0] >= '0' && tok[0] <= '9' && strchr( tok, '-' ) )
{
if( hops[0] )
strncat( hops, "", sizeof( hops ) - strlen( hops ) - 1 );
strncat( hops, tok, sizeof( hops ) - strlen( hops ) - 1 );
}
tok = strtok_r( NULL, "/", &save );
}
snprintf( out, outsz, "Topo: USB %s → %s", hops[0] ? hops : "(bus)", blockname ? blockname : "disk" );
return;
}
if( strstr( sysfs_target, "/nvme" ) != NULL )
{
if( pcie[0] )
snprintf( out, outsz, "Topo: PCIe %s → NVMe → %s", pcie, blockname ? blockname : "disk" );
else
snprintf( out, outsz, "Topo: NVMe → %s", blockname ? blockname : "disk" );
return;
}
if( pcie[0] )
{
snprintf( out, outsz, "Topo: PCIe %s → ATA/SCSI → %s", pcie, blockname ? blockname : "disk" );
return;
}
snprintf( out, outsz, "Topo: %s", blockname ? blockname : "disk" );
}
void nwipe_gui_view_device( int count, nwipe_context_t** c, int focus )
{
extern int terminate_signal;
nwipe_context_t* disk = nwipe_gui_find_parent_disk( count, c, focus );
/* Read sysfs link target via readlink(2) on /sys/block/<dev> */
char sysfs_link[128];
char sysfs_target[512];
sysfs_target[0] = '\0';
snprintf( sysfs_link, sizeof( sysfs_link ), "/sys/block/%s", disk->device_name_terse );
ssize_t n = readlink( sysfs_link, sysfs_target, sizeof( sysfs_target ) - 1 );
if( n > 0 )
{
sysfs_target[n] = '\0';
}
else
{
snprintf( sysfs_target, sizeof( sysfs_target ), "(readlink failed for %s)", sysfs_link );
}
/* Footer */
werase( footer_window );
nwipe_gui_title( footer_window, selection_footer_device_view );
wrefresh( footer_window );
int keystroke = 0;
do
{
nwipe_gui_create_all_windows_on_terminal_resize( 0, selection_footer_device_view );
int wlines, wcols;
getmaxyx( main_window, wlines, wcols );
werase( main_window );
/* Frame/title normal */
box( main_window, 0, 0 );
nwipe_gui_title( main_window, " Device Topology " );
/* Content grey/dim */
wattron( main_window, A_DIM );
int yy = 2;
mvwprintw( main_window, yy++, 2, "Device: %s", disk->gui_device_name );
mvwprintw( main_window, yy++, 2, "Model : %s", disk->device_model ? disk->device_model : "(unknown)" );
mvwprintw(
main_window, yy++, 2, "Serial: %s", disk->device_serial_no[0] ? disk->device_serial_no : "(unknown)" );
mvwprintw(
main_window, yy++, 2, "Type : %s (%s)", disk->device_type_str, disk->device_is_ssd ? "SSD" : "HDD" );
yy++;
mvwprintw( main_window, yy++, 2, "Sysfs: %s", sysfs_link );
mvwprintw( main_window, yy++, 2, "Path :" );
/* Tree view (keeps within the box: last line is wlines-2) */
(void) nwipe_gui_print_sysfs_tree( main_window, yy, wlines - 2, 4, wcols - 4, sysfs_target );
/* Back to normal */
wattroff( main_window, A_DIM );
wrefresh( main_window );
timeout( 250 );
keystroke = getch();
timeout( -1 );
switch( keystroke )
{
case KEY_BACKSPACE:
case KEY_BREAK:
case 27: /* ESC */
return;
}
} while( terminate_signal != 1 );
}
void nwipe_gui_noblank( void )
{
/**

View File

@@ -69,6 +69,8 @@ void nwipe_gui_add_customer_contact_phone( char* ); // Add new customer contact
int nwipe_gui_yes_no_footer( void ); // Change footer to yes no
void nwipe_gui_user_defined_tag( void ); // Edit user defined text to be added to pdf report
void nwipe_gui_pdf_certificate_edit_user_defined_tag( const char* );
void nwipe_gui_view_device( int count, nwipe_context_t** c, int focus );
void nwipe_gui_benchmark_prng( void );
/** nwipe_gui_preview_org_customer( int )
* Display a editable preview of organisation, customer and date/time