mirror of
https://github.com/martijnvanbrummelen/nwipe.git
synced 2026-02-20 13:42:14 +00:00
Merge pull request #698 from Knogle/benchmark-mode
gui: add interactive PRNG benchmark mode (RAM-only throughput)
This commit is contained in:
@@ -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
|
||||
|
||||
28
src/device.c
28
src/device.c
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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
639
src/gui.c
@@ -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 )
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user