Stage 1 temperature monitor feature.

Stage 1 adds the additional variables to the drive
context and creates the temperature initialisation
function, which associates a hwmonX directory with
a block device. Also wrote the context update function,
that reads hwmon for each drive context and writes the
temperatures back to the context.

Stage 2 commit to follow which will make changes within
the GUI to call the update function every 60 seconds
and display the temperature information.
This commit is contained in:
PartialVolume
2021-11-10 01:27:52 +00:00
parent 4d59c31b8f
commit 397f6fceb3
9 changed files with 312 additions and 32 deletions

View File

@@ -6,6 +6,5 @@ AM_LDFLAGS =
# this lists the binaries to produce, the (non-PHONY, binary) targets in
# the previous manual Makefile
bin_PROGRAMS = nwipe
nwipe_SOURCES = context.h isaac_rand/isaac_rand.c logging.h options.h prng.h nwipe.c gui.c isaac_rand/isaac_rand.h method.h pass.c device.c gui.h isaac_rand/isaac_standard.h mt19937ar-cok/mt19937ar-cok.c nwipe.h mt19937ar-cok/mt19937ar-cok.h pass.h device.h logging.c method.c options.c prng.c version.c version.h
nwipe_CFLAGS = $(PARTED_CFLAGS)
nwipe_SOURCES = context.h isaac_rand/isaac_rand.c logging.h options.h prng.h version.h temperature.h nwipe.c gui.c isaac_rand/isaac_rand.h method.h pass.c device.c gui.h isaac_rand/isaac_standard.h mt19937ar-cok/mt19937ar-cok.c nwipe.h mt19937ar-cok/mt19937ar-cok.h pass.h device.h logging.c method.c options.c prng.c version.c temperature.c
nwipe_LDADD = $(PARTED_LIBS)

View File

@@ -72,6 +72,9 @@ typedef struct nwipe_speedring_t_
#define NWIPE_DEVICE_LABEL_LENGTH 200
#define NWIPE_DEVICE_SIZE_TXT_LENGTH 7
// Arbitary length, so far most paths don't exceed about 25 characters
#define MAX_HWMON_PATH_LENGTH 100
typedef struct nwipe_context_t_
{
/*
@@ -124,6 +127,17 @@ 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.
char temp1_path[MAX_HWMON_PATH_LENGTH]; // path to temperature variables /sys/class/hwmon/hwmon2/ etc.
u64 temp1_crit; // Critical high drive temperature, -1=unitialised, millidegree celsius.
u64 temp1_highest; // Historical highest temperature reached, -1=unitialised, millidegree celsius.
u64 temp1_input; // drive temperature, -1=unitialised. -1=unitialised, millidegree celsius.
u64 temp1_lcrit; // Critical low drive temperature, -1=unitialised, millidegree celsius.
u64 temp1_lowest; // Historically lowest temperature, -1=unitialised, millidegree celsius.
u64 temp1_max; // Maximum allowed temperature, -1=unitialised, millidegree celsius.
u64 temp1_min; // Miniumum allowed temperature, -1=unitialised, millidegree celsius.
u64 temp1_monitored_wipe_max;
u64 temp1_monitored_wipe_min;
u64 temp1_monitored_wipe_avg;
int wipe_status; // Wipe finished = 0, wipe in progress = 1, wipe yet to start = -1.
int spinner_idx; // Index into the spinner character array
char spinner_character[1]; // The current spinner character

View File

@@ -30,5 +30,6 @@ int nwipe_get_device_bus_type_and_serialno( char*, nwipe_device_t*, char* );
void strip_CR_LF( char* );
void determine_disk_capacity_nomenclature( u64, char* );
void remove_ATA_prefix( char* );
char* trim( char* );
#endif /* DEVICE_H_ */

View File

@@ -691,19 +691,8 @@ void nwipe_log_summary( nwipe_context_t** ptr, int nwipe_selected )
idx_src = strlen( c[i]->device_name );
idx_src--;
while( idx_dest >= 0 )
{
/* if the device name contains a / start prefixing spaces */
if( c[i]->device_name[idx_src] == '/' )
{
device[idx_dest--] = ' ';
continue;
}
if( idx_src >= 0 )
{
device[idx_dest--] = c[i]->device_name[idx_src--];
}
}
nwipe_strip_path( device, c[i]->device_name );
nwipe_log( NWIPE_LOG_NOTIMESTAMP,
"%s %s | %10llu | %10llu | %10llu",
exclamation_flag,
@@ -743,24 +732,8 @@ void nwipe_log_summary( nwipe_context_t** ptr, int nwipe_selected )
* characters eg " sda", prefixed with space to 6 characters, note that
* we are processing the strings right to left */
idx_dest = 6;
device[idx_dest--] = 0;
idx_src = strlen( c[i]->device_name );
idx_src--;
nwipe_strip_path( device, c[i]->device_name );
while( idx_dest >= 0 )
{
/* if the device name contains a / start prefixing spaces */
if( c[i]->device_name[idx_src] == '/' )
{
device[idx_dest--] = ' ';
continue;
}
if( idx_src >= 0 )
{
device[idx_dest--] = c[i]->device_name[idx_src--];
}
}
extern int user_abort;
/* Any errors ? if so set the exclamation_flag and fail message,
@@ -986,3 +959,28 @@ void convert_seconds_to_hours_minutes_seconds( u64 total_seconds, int* hours, in
}
}
}
int nwipe_strip_path( char* output, char* input )
{
int idx_dest;
int idx_src;
idx_dest = 6;
output[idx_dest--] = 0;
// idx_src = strlen( c[i]->device_name );
idx_src = strlen( input );
idx_src--;
while( idx_dest >= 0 )
{
/* if the device name contains a / start prefixing spaces */
if( input[idx_src] == '/' )
{
output[idx_dest--] = ' ';
continue;
}
if( idx_src >= 0 )
{
output[idx_dest--] = input[idx_src--];
}
}
}

View File

@@ -47,5 +47,6 @@ int nwipe_log_sysinfo();
void nwipe_log_summary( nwipe_context_t**, int ); // This produces the wipe status table on exit
void Determine_C_B_nomenclature( u64, char*, int );
void convert_seconds_to_hours_minutes_seconds( u64, int*, int*, int* );
int nwipe_strip_path( char*, char* );
#endif /* LOGGING_H_ */

View File

@@ -41,6 +41,7 @@
#include "device.h"
#include "logging.h"
#include "gui.h"
#include "temperature.h"
#include <sys/ioctl.h> /* FIXME: Twice Included */
#include <sys/shm.h>
@@ -202,6 +203,16 @@ int main( int argc, char** argv )
pthread_create( &nwipe_sigint_thread, &pthread_attr, signal_hand, &nwipe_thread_data_ptr );
}
/* Makesure the drivetemp module is loaded, else drives hwmon entries won't appear in /sys/class/hwmon */
if( system( "modprobe drivetemp" ) != 0 )
{
nwipe_log( NWIPE_LOG_ERROR, "Unable to load module drivetemp, drive temperatures may not be available" );
}
else
{
nwipe_log( NWIPE_LOG_NOTICE, "Module drivetemp loaded, drive temperatures available" );
}
/* A context struct for each device has already been created. */
/* Now set specific nwipe options */
for( i = 0; i < nwipe_enumerated; i++ )
@@ -223,6 +234,15 @@ int main( int argc, char** argv )
/* The user must manually select devices. */
c1[i]->select = NWIPE_SELECT_FALSE;
}
/* Initialise temperature variables for device */
nwipe_init_temperature( c1[i] );
if( nwipe_options.verbose )
{
nwipe_log( NWIPE_LOG_NOTICE, "Device %s hwmon path = %s", c1[i]->device_name, c1[i]->temp1_path );
}
nwipe_update_temperature( c1[i] );
}
/* Check for initialization errors. */

View File

@@ -21,6 +21,8 @@
#ifndef PRNG_H_
#define PRNG_H_
#include <sys/types.h>
/* A chunk of random data. */
typedef struct
{

215
src/temperature.c Normal file
View File

@@ -0,0 +1,215 @@
/*
* temperature.c: functions that populate the drive temperature variables
* in each drives context structure.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
//#define _LARGEFILE64_SOURCE
//#define _FILE_OFFSET_BITS 64
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <dirent.h>
#include "nwipe.h"
#include "context.h"
#include "method.h"
#include "device.h"
#include "prng.h"
#include "options.h"
#include "device.h"
#include "logging.h"
#include "temperature.h"
int nwipe_init_temperature( nwipe_context_t* c )
{
/* This function is called after each nwipe_context_t has been created.
* It initialises the temperature variables in each context and then
* constructs a path that is placed in the context that points to the
* appropriate /sys/class/hwmon/hwmonX directory that corresponds with
* the particular drive represented in the context structure.
*/
DIR* dir;
DIR* dir2;
const char dirpath[] = "/sys/class/hwmon";
char dirpath_tmp[256];
char dirpath_hwmonX[256];
char device[256];
char device_context_name[256];
// const char dirpath[] = "/home/nick/mouse/hwmon1";
struct dirent* dp;
struct dirent* dp2;
int match;
/* Why Initialise with 1000000? Because the GUI needs to know whether data
* has been obtained so it can display appropriate information when a
* device is unable to provide temperature data */
c->temp1_crit = 1000000;
c->temp1_highest = 1000000;
c->temp1_input = 1000000;
c->temp1_lcrit = 1000000;
c->temp1_lowest = 1000000;
c->temp1_max = 1000000;
c->temp1_min = 1000000;
c->temp1_monitored_wipe_max = 1000000;
c->temp1_monitored_wipe_min = 1000000;
c->temp1_monitored_wipe_avg = 1000000;
c->temp1_path[0] = 0;
/* Each hwmonX directory is processed in turn and once a hwmonX directory has been
* found that is a block device and the block device name matches the drive
* name in the current context then the path to ../hwmonX is constructed and written
* to the drive context structure '* c'. This path is used in the nwipe_update_temperature
* function to retrieve temperature data and store it in the device context
*/
if( ( dir = opendir( dirpath ) ) != NULL )
{
while( ( dp = readdir( dir ) ) != NULL )
{
/* Does the directory start with 'hwmon' */
if( strstr( dp->d_name, "hwmon" ) != NULL )
{
strcpy( dirpath_tmp, dirpath );
strcat( dirpath_tmp, "/" );
strcat( dirpath_tmp, dp->d_name );
strcpy( dirpath_hwmonX, dirpath_tmp );
strcat( dirpath_tmp, "/device/block" );
/* Is this hardware monitor a block device ? i.e. does
* /sys/class/hwmon/hwmonX/device/block exist?*/
if( ( dir2 = opendir( dirpath_tmp ) ) != NULL )
{
/* Read the device name */
while( ( dp2 = readdir( dir2 ) ) != NULL )
{
/* Skip the '.' and '..' directories */
if( dp2->d_name[0] == '.' )
{
continue;
}
strcpy( device, dp2->d_name );
/* Create a copy of the device name from the context but strip the path from it. */
nwipe_strip_path( device_context_name, c->device_name );
/* Remove leading/training whitespace from a string and left justify result */
trim( device_context_name );
/* Does the hwmon device match the device for this drive context */
if( strcmp( device, device_context_name ) != 0 )
{
/* No, so try next hwmon device */
continue;
}
else
{
/* Match ! This hwmon device matches this context, so write the hwmonX path to the context
*/
nwipe_log( NWIPE_LOG_NOTICE, "Device %s has \'hwmon\' temperature monitoring", device );
/* Copy the hwmon path to the drive context structure */
strcpy( c->temp1_path, dirpath_hwmonX );
}
}
closedir( dir2 );
}
}
}
closedir( dir );
}
return 0;
}
void nwipe_update_temperature( nwipe_context_t* c )
{
/* For the given drive context obtain the path to it's hwmon temperature settings
* and read then write the temperature values back to the context. A numeric ascii to integer conversion is
* performed. The temperaures should be updated no more frequently than every 60 seconds
*/
char temperature_label[NUMBER_OF_FILES][20] = {
"temp1_crit", "temp1_highest", "temp1_input", "temp1_lcrit", "temp1_lowest", "temp1_max", "temp1_min" };
u64* temperature_pcontext[NUMBER_OF_FILES] = {
&( c->temp1_crit ),
&( c->temp1_highest ),
&( c->temp1_input ),
&( c->temp1_lcrit ),
&( c->temp1_lowest ),
&( c->temp1_max ),
&( c->temp1_min ) };
char path[256];
char temperature[256];
FILE* fptr;
int idx;
for( idx = 0; idx < NUMBER_OF_FILES; idx++ )
{
/* Construct the full path including filename */
strcpy( path, c->temp1_path );
strcat( path, "/" );
strcat( path, &( temperature_label[idx][0] ) );
if( nwipe_options.verbose )
{
nwipe_log( NWIPE_LOG_NOTICE, "hwmon: path=%s", path );
}
/* Open the file */
if( ( fptr = fopen( path, "r" ) ) != NULL )
{
/* Acquire data until we reach a newline */
fscanf( fptr, "%[^\n]", temperature );
/* Convert numeric ascii to binary integer */
*( temperature_pcontext[idx] ) = atoi( temperature );
/* Divide by 1000 to get degrees celcius */
*( temperature_pcontext[idx] ) = *( temperature_pcontext[idx] ) / 1000;
fclose( fptr );
}
else
{
if( nwipe_options.verbose )
{
nwipe_log( NWIPE_LOG_NOTICE, "hwmon: Unable to open %s", path );
}
}
}
if( nwipe_options.verbose )
{
nwipe_log( NWIPE_LOG_NOTICE,
"hwmon: %lluC, %lluC, %lluC, %lluC, %lluC, %lluC, %lluC",
c->temp1_crit,
c->temp1_highest,
c->temp1_input,
c->temp1_lcrit,
c->temp1_lowest,
c->temp1_max,
c->temp1_min );
}
return;
}

30
src/temperature.h Normal file
View File

@@ -0,0 +1,30 @@
/*.
* temperature.h: The header file for disk drive temperature sensing
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef TEMPERATURE_H_
#define TEMPERATURE_H_
#include <sys/types.h>
#include "context.h"
int nwipe_init_temperature( nwipe_context_t* );
void nwipe_update_temperature( nwipe_context_t* );
#define NUMBER_OF_FILES 7
#endif /* TEMPERATURE_H_ */