Merge pull request 'version 0.3.0' (#52) from develop into master

Reviewed-on: #52
This commit is contained in:
Hendrik Schutter 2022-09-20 21:56:04 +02:00
commit 573a0df080
17 changed files with 324 additions and 119 deletions

5
.gitignore vendored
View File

@ -41,7 +41,10 @@
reHDD
reHDD.log
*.log
*.ods
*.txt
.vscode/
ignoreDrives.conf

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "tfnoisegen"]
path = tfnoisegen
url = https://git.mosad.xyz/localhorst/tfnoisegen.git

View File

@ -11,6 +11,8 @@
## Debian Build Notes
* `apt-get install ncurses-dev git make g++`
* `git submodule init`
* `git submodule update`
* `make release`
## Create Standalone with Debian 11
@ -22,13 +24,18 @@ Instructions how to create a standalone machine that boots directly to reHDD. Th
* Upload reHDD log every 12h if wanted
### Software requirements
* `apt-get install hwinfo smartmontools curl`
* `apt-get install hwinfo smartmontools curl htop sudo`
### Installation
clone this repo into /root/
```
git submodule init
git submodule update
```
`cd /root/reHDD/`
`make release`

View File

@ -1,2 +1,3 @@
4673974d
2cb3dea4
8ffbc421

View File

@ -22,6 +22,14 @@ public:
FROZEN
} state;
struct
{
time_t u32ShredTimeDelta;
std::chrono::time_point<std::chrono::system_clock> chronoShredTimestamp;
unsigned long ulWrittenBytes;
unsigned long ulSpeedMetricBytesWritten;
} sShredSpeed;
bool bWasShredded = false;
bool bWasDeleteted = false;
bool bIsOffline = false;
@ -29,18 +37,23 @@ public:
private:
string sPath;
string sModelFamily;
string sModelName;
string sSerial;
uint64_t u64Capacity = 0U; //in byte
uint32_t u32ErrorCount = 0U;
uint32_t u32PowerOnHours = 0U; //in hours
uint32_t u32PowerCycles = 0U;
time_t u32Timestamp = 0U; //unix timestamp for detecting a frozen drive
double d32TaskPercentage = 0U; //in percent for Shred (1 to 100)
time_t u32TimestampTaskStart = 0U; //unix timestamp for duration of an action
time_t u32TaskDuration = 0U; //time needed to complete the task
struct
{
string sModelFamily;
string sModelName;
string sSerial;
uint64_t u64Capacity = 0U; //in byte
uint32_t u32ErrorCount = 0U;
uint32_t u32PowerOnHours = 0U; //in hours
uint32_t u32PowerCycles = 0U;
uint32_t u32Temperature = 0U; //in Fahrenheit, just kidding: degree Celsius
} sSmartData;
private:
void setTimestamp();
@ -60,6 +73,7 @@ public:
uint32_t getErrorCount(void);
uint32_t getPowerOnHours(void); //in hours
uint32_t getPowerCycles(void);
uint32_t getTemperature(void); //in Fahrenheit, just kidding: degree Celsius
void checkFrozenDrive(void);
void setDriveSMARTData( string modelFamily,
@ -68,12 +82,14 @@ public:
uint64_t capacity,
uint32_t errorCount,
uint32_t powerOnHours,
uint32_t powerCycles);
uint32_t powerCycles,
uint32_t temperature);
string sCapacityToText();
string sErrorCountToText();
string sPowerOnHoursToText();
string sPowerCyclesToText();
string sTemperatureToText();
void setTaskPercentage(double d32TaskPercentage);
double getTaskPercentage(void);

View File

@ -8,13 +8,15 @@
#ifndef REHDD_H_
#define REHDD_H_
#define REHDD_VERSION "bV0.2.2"
#define REHDD_VERSION "bV0.3.0"
// Drive handling Settings
#define WORSE_HOURS 19200 //mark drive if at this limit or beyond
#define WORSE_POWERUP 10000 //mark drive if at this limit or beyond
#define WORSE_TEMPERATURE 55 //mark drive if at this limit or beyond
#define SHRED_ITERATIONS 3U
#define FROZEN_TIMEOUT 10 //After this timeout (minutes) the drive will be marked as frozen
#define FROZEN_TIMEOUT 20 //After this timeout (minutes) the drive will be marked as frozen, if no progress
#define METRIC_THRESHOLD 3L*1000L*1000L*1000L //calc shred speed with this minimum of time delta
// Logger Settings
#define LOG_PATH "./reHDD.log"
@ -83,12 +85,14 @@ private:
static void searchDrives(list <Drive>* plistDrives);
static void printDrives(list <Drive>* plistDrives);
static void filterIgnoredDrives(list <Drive>* plistDrives);
static void startShredAllDrives(list <Drive>* plistDrives);
static void updateShredMetrics(list <Drive>* plistDrives);
static void filterIgnoredDrives(list <Drive>* plistDrives);
static void filterNewDrives(list <Drive>* plistOldDrives, list <Drive>* plistNewDrives);
static void addSMARTData(list <Drive>* plistDrives);
static void ThreadScannDevices();
static void ThreadUserInput();
static void ThreadShred();
static void ThreadShred(Drive* const pDrive);
static void ThreadDelete();
static void ThreadCheckFrozenDrives();
static void handleArrowKey(TUI::UserInput userInput);

View File

@ -17,11 +17,13 @@
#include <unistd.h>
#include <string.h>
#define CHUNK_SIZE 1024*1024*2 //amount of bytes that are overwritten at once --> 2MB
#define CHUNK_DIMENSION 100U //amount of chunks are read at once from random source
#define CHUNK_SIZE 1024*1024*32 //amount of bytes that are overwritten at once --> 32MB
#define TFNG_DATA_SIZE CHUNK_SIZE //amount of bytes used by tfng
//#define DEMO_DRIVE_SIZE 1024*1024*256L // 256MB
//#define DEMO_DRIVE_SIZE 1024*1024*1024L // 1GB
//#define DEMO_DRIVE_SIZE 5*1024*1024*1024L // 5GB
//#define DEMO_DRIVE_SIZE 1024*1024*1024*10L // 10GB
typedef int fileDescriptor;
@ -39,7 +41,8 @@ public:
private:
fileDescriptor randomSrcFileDiscr;
fileDescriptor driveFileDiscr;
unsigned char caChunk[CHUNK_DIMENSION][CHUNK_SIZE];
unsigned char caTfngData[TFNG_DATA_SIZE];
unsigned char caReadBuffer[CHUNK_SIZE];
unsigned long ulDriveByteSize;
unsigned long ulDriveByteOverallCount = 0; //all bytes shredded in all iterations + checking -> used for progress calculation
double d32Percent = 0.0;

View File

@ -27,6 +27,7 @@ private:
static void parseErrorCount(string sLine);
static void parsePowerOnHours(string sLine);
static void parsePowerCycle(string sLine);
static void parseTemperature(string sLine);
static string modelFamily;
static string modelName;
@ -35,6 +36,7 @@ private:
static uint32_t errorCount;
static uint32_t powerOnHours;
static uint32_t powerCycle;
static uint32_t temperature;
};
#endif // SMART_H_

View File

@ -22,7 +22,7 @@ protected:
public:
enum UserInput { UpKey, DownKey, Abort, Shred, Delete, Enter, ESC, Undefined};
enum UserInput { UpKey, DownKey, Abort, Shred, ShredAll, Delete, Enter, ESC, Undefined};
struct MenuState
{
bool bAbort;
@ -56,16 +56,17 @@ private:
static WINDOW *createOverViewWindow( int iXSize, int iYSize);
static WINDOW *createDetailViewWindow( int iXSize, int iYSize, int iXStart, Drive drive);
static WINDOW *overwriteDetailViewWindow( int iXSize, int iYSize, int iXStart);
static WINDOW *createEntryWindow(int iXSize, int iYSize, int iXStart, int iYStart, string sModelFamily, string sModelName, string sCapacity, string sState, string sTime, bool bSelected);
static WINDOW *createEntryWindow(int iXSize, int iYSize, int iXStart, int iYStart, int iListIndex, string sModelFamily, string sSerial, string sCapacity, string sState, string sTime, string sSpeed, string sTemp, bool bSelected);
static WINDOW *createSystemStats(int iXSize, int iYSize, int iXStart, int iYStart);
static WINDOW *createMenuView(int iXSize, int iYSize, int iXStart, int iYStart, struct MenuState menustate);
static WINDOW *createDialog(int iXSize, int iYSize, int iXStart, int iYStart, string selectedTask, string optionA, string optionB);
static WINDOW* createFrozenWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, string sModelFamily, string sModelName, string sSerial, string sProgress);
static WINDOW* createSmartWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, uint32_t u32PowerOnHours, uint32_t u32PowerCycles, uint32_t u32ErrorCount);
static WINDOW* createSmartWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, uint32_t u32PowerOnHours, uint32_t u32PowerCycles, uint32_t u32ErrorCount, uint32_t u32Temperature);
static WINDOW* createZeroChecksumWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, string sModelFamily, string sModelName, string sSerial, uint32_t u32Checksum);
void displaySelectedDrive(Drive drive, int stdscrX, int stdscrY);
string formatTimeDuration(time_t u32Duration);
string formatSpeed(time_t u32ShredTimeDelta, unsigned long ulWrittenBytes);
};
#endif // TUI_H_

View File

@ -8,19 +8,22 @@ SRC_EXT = cpp
# Path to the source directory, relative to the makefile
SRC_PATH = src
# Space-separated pkg-config libraries used by this project
LIBS =
LIBS = lib
# General compiler flags
COMPILE_FLAGS = -std=c++17 -Wall -Wextra -g
# Additional release-specific flags
RCOMPILE_FLAGS = -D NDEBUG
RCOMPILE_FLAGS = -D NDEBUG -O3
# Additional debug-specific flags
DCOMPILE_FLAGS = -D DEBUG
# Add additional include paths
INCLUDES = include
# General linker settings
LINK_FLAGS = -lpthread -lncurses
LINK_FLAGS = -Llib -lpthread -lncurses -ltfng
# Doc
DOCDIR = doc
TFRANDDIR = tfnoisegen
TFRANDLIB = libtfng.a
#### END PROJECT SETTINGS ####
# Optionally you may move the section above to a separate config.mk file, and
@ -158,6 +161,7 @@ dirs:
@echo "Creating directories"
@mkdir -p $(dir $(OBJECTS))
@mkdir -p $(BIN_PATH)
@mkdir -p $(LIBS)
# Removes all build files
.PHONY: clean
@ -167,16 +171,22 @@ clean:
@echo "Deleting directories"
@$(RM) -r build
@$(RM) -r bin
@$(RM) -r $(LIBS)
@$(RM) -f reHDD.log
$(MAKE) clean -C tfnoisegen
# Main rule, checks the executable and symlinks to the output
all: $(BIN_PATH)/$(BIN_NAME)
$(MAKE) libtfng.a -C tfnoisegen
@cp $(TFRANDDIR)/$(TFRANDLIB) $(LIBS)
@echo "Making symlink: $(BIN_NAME) -> $<"
@$(RM) $(BIN_NAME)
@ln -s $(BIN_PATH)/$(BIN_NAME) $(BIN_NAME)
# Link the executable
$(BIN_PATH)/$(BIN_NAME): $(OBJECTS)
$(MAKE) libtfng.a -C tfnoisegen
@cp $(TFRANDDIR)/$(TFRANDLIB) $(LIBS)
@echo "Linking: $@"
@$(START_TIME)
$(CMD_PREFIX)$(CXX) $(OBJECTS) $(LDFLAGS) -o $@

View File

@ -2,15 +2,17 @@
echo starting update
systemctl stop /lib/systemd/system/getty@tty1.service.d
cd /root/reHDD/
FILE=./ignoreDrives.conf
if test -f "$FILE"; then
echo backup exits
else
cp reHDD/ignoreDrives.conf ./ignoreDrives.conf
cp /root/reHDD/ignoreDrives.conf /root/ignoreDrives.conf
fi
cd reHDD
git reset
git stash force
@ -23,4 +25,6 @@ git pull
make release
cp ../ignoreDrives.conf ./
cp /root/ignoreDrives.conf /root/reHDD/ignoreDrives.conf
systemctl start /lib/systemd/system/getty@tty1.service.d

View File

@ -14,36 +14,41 @@ string Drive::getPath(void)
string Drive::getModelFamily(void)
{
return sModelFamily;
return sSmartData.sModelFamily;
}
string Drive::getModelName(void)
{
return sModelName;
return sSmartData.sModelName;
}
string Drive::getSerial(void)
{
return sSerial;
return sSmartData.sSerial;
}
uint64_t Drive::getCapacity(void)
{
return u64Capacity;
return sSmartData.u64Capacity;
}
uint32_t Drive::getErrorCount(void)
{
return u32ErrorCount;
return sSmartData.u32ErrorCount;
}
uint32_t Drive::getPowerOnHours(void)
{
return u32PowerOnHours;
return sSmartData.u32PowerOnHours;
}
uint32_t Drive::getPowerCycles(void)
{
return u32PowerCycles;
return sSmartData.u32PowerCycles;
}
uint32_t Drive::getTemperature(void)
{
return sSmartData.u32Temperature;
}
string Drive::sCapacityToText()
@ -67,7 +72,6 @@ string Drive::sErrorCountToText()
return to_string(getErrorCount());
}
string Drive::sPowerOnHoursToText()
{
double dDays = 0U;
@ -92,6 +96,11 @@ string Drive::sPowerCyclesToText()
return to_string(getPowerCycles());
}
string Drive::sTemperatureToText()
{
return to_string(getTemperature())+" C";;
}
void Drive::setTaskPercentage(double d32TaskPercentage)
{
if(d32TaskPercentage <= 100)
@ -115,6 +124,7 @@ double Drive::getTaskPercentage(void)
* \param uint32_t errorCount
* \param uint32_t powerOnHours
* \param uint32_t powerCycle
* \param uint32_t temperature
* \return void
*/
void Drive::setDriveSMARTData( string modelFamily,
@ -123,16 +133,17 @@ void Drive::setDriveSMARTData( string modelFamily,
uint64_t capacity,
uint32_t errorCount,
uint32_t powerOnHours,
uint32_t powerCycle)
uint32_t powerCycle,
uint32_t temperature)
{
this->sModelFamily = modelFamily;
sModelName = modelName;
sSerial = serial;
u64Capacity = capacity;
u32ErrorCount = errorCount;
u32PowerOnHours = powerOnHours;
u32PowerCycles = powerCycle;
this->sSmartData.sModelFamily = modelFamily;
this->sSmartData.sModelName = modelName;
this->sSmartData.sSerial = serial;
this->sSmartData.u64Capacity = capacity;
this->sSmartData.u32ErrorCount = errorCount;
this->sSmartData.u32PowerOnHours = powerOnHours;
this->sSmartData.u32PowerCycles = powerCycle;
this->sSmartData.u32Temperature = temperature;
}
void Drive::setTimestamp()
@ -168,7 +179,7 @@ void Drive::checkFrozenDrive(void)
time_t u32localtime;
time(&u32localtime);
if((u32localtime - this->u32Timestamp) >= (FROZEN_TIMEOUT*60) && (this->u32Timestamp > 0))
if((u32localtime - this->u32Timestamp) >= (FROZEN_TIMEOUT*60) && (this->u32Timestamp > 0) && (this->getTaskPercentage() < 100.0))
{
Logger::logThis()->warning("Drive Frozen: " + this->getModelName() + " " + this->getSerial());
this->bWasDeleteted = false;

View File

@ -11,7 +11,7 @@ static int fdNewDrivesInformPipe[2];//File descriptor for pipe that informs if n
static int fdShredInformPipe[2];//File descriptor for pipe that informs if a wipe thread signals
static std::mutex mxScannDrives;
static std::mutex mxDrives;
list <Drive> listNewDrives; //store found drives that are updated every 5sec
@ -60,20 +60,25 @@ void reHDD::app_logic(void)
if(FD_ISSET(fdNewDrivesInformPipe[0], &selectSet))
{
mxScannDrives.lock();
mxDrives.lock();
char dummy;
read (fdNewDrivesInformPipe[0],&dummy,1);
filterNewDrives(&listDrives, &listNewDrives); //filter and copy to app logic vector
printDrives(&listDrives);
mxScannDrives.unlock();
mxDrives.unlock();
}
if(FD_ISSET(fdShredInformPipe[0], &selectSet))
{
char dummy;
read (fdShredInformPipe[0],&dummy,1);
updateShredMetrics(&listDrives);
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("got progress signal from a shred task");
#endif
}
ui->updateTUI(&listDrives, u8SelectedEntry);
} //endless loop
@ -101,12 +106,12 @@ void reHDD::ThreadScannDevices()
{
while(true)
{
mxScannDrives.lock();
mxDrives.lock();
listNewDrives.clear();
searchDrives(&listNewDrives); //search for new drives and store them in list
filterIgnoredDrives(&listNewDrives); //filter out ignored drives
addSMARTData(&listNewDrives); //add S.M.A.R.T. Data to the drives
mxScannDrives.unlock();
mxDrives.unlock();
write(fdNewDrivesInformPipe[1], "A",1);
sleep(5); //sleep 5 sec
}
@ -116,7 +121,7 @@ void reHDD::ThreadCheckFrozenDrives()
{
while(true)
{
mxScannDrives.lock();
mxDrives.lock();
for(auto it = begin(listDrives); it != end(listDrives); ++it)
{
if(it->state == Drive::SHRED_ACTIVE)
@ -124,7 +129,7 @@ void reHDD::ThreadCheckFrozenDrives()
it->checkFrozenDrive();
}
}
mxScannDrives.unlock();
mxDrives.unlock();
sleep(13); //sleep 13 sec
}
}
@ -164,6 +169,7 @@ void reHDD::ThreadUserInput()
getSelectedDrive()->state = Drive::DELETE_SELECTED;
}
}
ui->updateTUI(&listDrives, u8SelectedEntry);
break;
case TUI::UserInput::Shred:
@ -176,6 +182,12 @@ void reHDD::ThreadUserInput()
getSelectedDrive()->state = Drive::SHRED_SELECTED;
}
}
ui->updateTUI(&listDrives, u8SelectedEntry);
break;
case TUI::UserInput::ShredAll:
//cout << "ShredAll" << endl;
startShredAllDrives(&listDrives);
ui->updateTUI(&listDrives, u8SelectedEntry);
break;
case TUI::UserInput::Enter:
@ -194,13 +206,13 @@ void reHDD::ThreadUserInput()
}
}
void reHDD::ThreadShred()
void reHDD::ThreadShred(Drive* const pDrive)
{
if (getSelectedDrive() != nullptr)
if (pDrive != nullptr)
{
getSelectedDrive()->setActionStartTimestamp(); //save timestamp at start of shredding
pDrive->setActionStartTimestamp(); //save timestamp at start of shredding
Shred* pShredTask = new Shred(); //create new shred task
pShredTask->shredDrive(getSelectedDrive(), &fdShredInformPipe[1]); //start new shred task
pShredTask->shredDrive(pDrive, &fdShredInformPipe[1]); //start new shred task
delete pShredTask; //delete shred task
ui->updateTUI(&listDrives, u8SelectedEntry);
}
@ -246,12 +258,14 @@ void reHDD::filterNewDrives(list <Drive>* plistOldDrives, list <Drive>* plistNew
//search offline drives and mark them
for (itOld = plistOldDrives->begin(); itOld != plistOldDrives->end(); ++itOld)
{
itOld->bIsOffline = true; //set offline befor seachring in the new list
itOld->bIsOffline = true; //set offline before searching in the new list
for (itNew = plistNewDrives->begin(); itNew != plistNewDrives->end();)
{
if((itOld->getSerial() == itNew->getSerial()) || (itOld->getPath() == itNew->getPath()))
{
itOld->bIsOffline = false; //drive is still attached
//copy new smart data to existing drive
itOld->setDriveSMARTData(itNew->getModelFamily(), itNew->getModelName(), itNew->getSerial(), itNew->getCapacity(), itNew->getErrorCount(), itNew->getPowerOnHours(), itNew->getPowerCycles(), itNew->getTemperature());
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Delete new drive, because allready attached: " + itNew->getModelName());
#endif
@ -279,7 +293,7 @@ void reHDD::filterNewDrives(list <Drive>* plistOldDrives, list <Drive>* plistNew
for (itNew = plistNewDrives->begin(); itNew != plistNewDrives->end(); ++itNew)
{
plistOldDrives->push_back(*itNew);
Logger::logThis()->info("Add new drive: " + itNew->getModelName());
//Logger::logThis()->info("Add new drive: " + itNew->getModelName());
}
plistNewDrives->clear();
}
@ -291,7 +305,7 @@ void reHDD::filterNewDrives(list <Drive>* plistOldDrives, list <Drive>* plistNew
*/
void reHDD::searchDrives(list <Drive>* plistDrives)
{
Logger::logThis()->info("--> search drives <--");
//Logger::logThis()->info("--> search drives <--");
char * cLine = NULL;
size_t len = 0;
@ -329,7 +343,7 @@ void reHDD::filterIgnoredDrives(list <Drive>* plistDrives)
for(string sLine; getline( input, sLine );)
{
Logger::logThis()->info("read uuid: " + sLine);
//Logger::logThis()->info("read uuid: " + sLine);
vtlIgnoredDevices.emplace_back(sLine); //add found path and uuid from ignore file to vector
}
//loop through found entries in ingnore file
@ -377,6 +391,32 @@ void reHDD::filterIgnoredDrives(list <Drive>* plistDrives)
}
}
/**
* \brief start shred for all drives
* \param pointer of list <Drive>* plistDrives
* \return void
*/
void reHDD::startShredAllDrives(list <Drive>* plistDrives)
{
list <Drive>::iterator it;
mxDrives.lock();
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
{
if(it->state == Drive::NONE)
{
Drive* pTmpDrive = iterator_to_pointer<Drive, std::list<Drive>::iterator > (it);
#ifdef LOG_LEVEL_HIGH
ostringstream address;
address << (void const *)&(*pTmpDrive);
Logger::logThis()->info("Started shred (all) for: " + pTmpDrive->getModelName() + "-" + pTmpDrive->getSerial() + " @" + address.str());
#endif
pTmpDrive->state = Drive::TaskState::SHRED_ACTIVE;
thread(ThreadShred, pTmpDrive).detach();
}
}
mxDrives.unlock();
}
/**
* \brief print drives with all information
* \param pointer of list <Drive>* plistDrives
@ -412,6 +452,33 @@ void reHDD::printDrives(list <Drive>* plistDrives)
#endif
}
/**
* \brief update shred metrics for all drives
* \param pointer of list <Drive>* plistDrives
* \return void
*/
void reHDD::updateShredMetrics(list <Drive>* plistDrives)
{
list <Drive>::iterator it;
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
{
if(it->state == Drive::SHRED_ACTIVE)
{
Drive* pTmpDrive = iterator_to_pointer<Drive, std::list<Drive>::iterator > (it);
//set metrics for calculating shred speed
std::chrono::time_point<std::chrono::system_clock> chronoCurrentTimestamp = std::chrono::system_clock::now();
time_t u32ShredTimeDelta = (chronoCurrentTimestamp - pTmpDrive->sShredSpeed.chronoShredTimestamp).count();
if(u32ShredTimeDelta > METRIC_THRESHOLD)
{
pTmpDrive->sShredSpeed.u32ShredTimeDelta = u32ShredTimeDelta;
pTmpDrive->sShredSpeed.chronoShredTimestamp = std::chrono::system_clock::now();
pTmpDrive->sShredSpeed.ulWrittenBytes = pTmpDrive->sShredSpeed.ulSpeedMetricBytesWritten;
pTmpDrive->sShredSpeed.ulSpeedMetricBytesWritten = 0U;
}
}
}
}
/**
* \brief add S.M.A.R.T data from SMART
* \param pointer of list <Drive>* plistDrives
@ -454,11 +521,12 @@ void reHDD::handleArrowKey(TUI::UserInput userInput)
break;
}
Logger::logThis()->info("ArrowKey - selected drive: " + to_string(u8SelectedEntry));
//Logger::logThis()->info("ArrowKey - selected drive: " + to_string(u8SelectedEntry));
}
void reHDD::handleEnter()
{
if (getSelectedDrive() != nullptr)
{
if(getSelectedDrive()->state == Drive::TaskState::SHRED_SELECTED)
@ -466,7 +534,8 @@ void reHDD::handleEnter()
Logger::logThis()->info("Started shred for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial());
getSelectedDrive()->state = Drive::TaskState::SHRED_ACTIVE;
//task for drive is running --> don´t show more task options
thread(ThreadShred).detach();
Drive* pTmpDrive = getSelectedDrive();
thread(ThreadShred, pTmpDrive).detach();
}
if(getSelectedDrive()->state == Drive::TaskState::DELETE_SELECTED)

View File

@ -2,11 +2,19 @@
* @file shred.cpp
* @brief shred drive
* @author hendrik schutter
* @date 03.05.2020
* @date 22.08.2022
*/
#include "../include/reHDD.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "../tfnoisegen/tfprng.h"
#ifdef __cplusplus
}
#endif
const static char *randomsrc = (char*) "/dev/urandom";
Shred::Shred()
@ -24,6 +32,9 @@ Shred::~Shred()
*/
int Shred::shredDrive(Drive* drive, int* ipSignalFd)
{
ostringstream address;
address << (void const *)&(*drive);
Logger::logThis()->info("Shred-Task started - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
#ifdef DRYRUN
for(int i = 0; i<=500; i++)
@ -40,6 +51,7 @@ int Shred::shredDrive(Drive* drive, int* ipSignalFd)
#ifndef DRYRUN
const char *cpDrivePath = drive->getPath().c_str();
unsigned char ucKey[TFNG_KEY_SIZE];
//open random source
randomSrcFileDiscr = open(randomsrc, O_RDONLY | O_LARGEFILE);
@ -63,7 +75,22 @@ int Shred::shredDrive(Drive* drive, int* ipSignalFd)
return -1;
}
//read key for random generator
ssize_t readRet = read(randomSrcFileDiscr, ucKey, sizeof(ucKey)) ;
if (readRet <= 0)
{
std::string errorMsg(strerror(readRet));
Logger::logThis()->error("Shred-Task: Read random key failed! " + errorMsg + " - Drive: " + drive->getSerial());
perror(randomsrc);
cleanup();
return -1;
}
tfng_prng_seedkey(ucKey);
this->ulDriveByteSize = getDriveSizeInBytes(driveFileDiscr);
drive->sShredSpeed.chronoShredTimestamp = std::chrono::system_clock::now();; //set inital timestamp for speed metric
drive->sShredSpeed.ulSpeedMetricBytesWritten = 0U; //uses to calculate speed metric
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Shred-Task: Bytes-Size of Drive: " + to_string(this->ulDriveByteSize) + " - Drive: " + drive->getSerial());
@ -72,44 +99,21 @@ int Shred::shredDrive(Drive* drive, int* ipSignalFd)
for (unsigned int uiShredIterationCounter = 0U; uiShredIterationCounter < SHRED_ITERATIONS; uiShredIterationCounter++)
{
unsigned long ulDriveByteCounter = 0U; //used for one shred-iteration to keep track of the current drive position
uint32_t u32ChunkDimensionIndex = 0U;
if(uiShredIterationCounter == (SHRED_ITERATIONS-1))
{
//last shred iteration --> overwrite with zeros instead with random data
memset(caChunk, 0U, CHUNK_DIMENSION*CHUNK_SIZE);
//last shred iteration --> overwrite (just the write chunk) bytes with zeros instead with random data
memset(caTfngData, 0U, CHUNK_SIZE);
}
while (ulDriveByteCounter < ulDriveByteSize)
{
int iBytesToShred = 0; //Bytes that will be overwritten in this chunk-iteration
if((u32ChunkDimensionIndex == 0U) && (uiShredIterationCounter != (SHRED_ITERATIONS-1)))
if(uiShredIterationCounter != (SHRED_ITERATIONS-1))
{
//read new chunks from random source if needed and this is NOT the last shred iteration
unsigned long ulBytesInChunkBuffer = 0U;
while (ulBytesInChunkBuffer < CHUNK_DIMENSION*CHUNK_SIZE)
{
//read new random bytes
int iReadBytes = read(randomSrcFileDiscr, caChunk, ((CHUNK_DIMENSION*CHUNK_SIZE)-ulBytesInChunkBuffer));
if (iReadBytes > 0)
{
ulBytesInChunkBuffer += iReadBytes;
}
else
{
std::string errorMsg(strerror(iReadBytes));
Logger::logThis()->error("Shred-Task: Read from random source failed! " + errorMsg + " - Drive: " + drive->getSerial());
perror("unable to read random data");
cleanup();
return -1;;
}
} //end chunk read
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Shred-Task: Read new random data - Drive: " + drive->getSerial());
#endif
//NOT last shred iteration --> generate new random data
tfng_prng_genrandom(caTfngData, TFNG_DATA_SIZE);
}
if((ulDriveByteSize-ulDriveByteCounter) < CHUNK_SIZE)
@ -121,7 +125,7 @@ int Shred::shredDrive(Drive* drive, int* ipSignalFd)
iBytesToShred = CHUNK_SIZE;
}
int iByteShredded = write(driveFileDiscr, caChunk[u32ChunkDimensionIndex], iBytesToShred);
int iByteShredded = write(driveFileDiscr, caTfngData, iBytesToShred);
if(iByteShredded <= 0)
{
@ -132,18 +136,20 @@ int Shred::shredDrive(Drive* drive, int* ipSignalFd)
return -1;
}
u32ChunkDimensionIndex = (u32ChunkDimensionIndex+1)%CHUNK_DIMENSION;
ulDriveByteCounter += iByteShredded;
ulDriveByteOverallCount += iByteShredded;
d32Percent = this->calcProgress();
drive->sShredSpeed.ulSpeedMetricBytesWritten += iByteShredded;
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Shred-Task: ByteCount: " + to_string(ulDriveByteCounter) + " - iteration: " + to_string((uiShredIterationCounter+1)) + " - progress: " + to_string(d32Percent) + " - Drive: " + drive->getSerial());
#endif
if((d32Percent-d32TmpPercent) >= 0.01)
{
//set shred percantage
drive->setTaskPercentage(d32TmpPercent);
d32TmpPercent = d32Percent;
//signal process in shreding
write(*ipSignalFd, "A",1);
}
@ -157,13 +163,19 @@ int Shred::shredDrive(Drive* drive, int* ipSignalFd)
cleanup();
return -1;
}
}//end one chunk write
//end one chunk write
}
if(0 != iRewindDrive(driveFileDiscr))
{
Logger::logThis()->error("Shred-Task: Unable to rewind drive! - Drive: " + drive->getSerial());
cleanup();
return -1;
}
} //end one shred iteration
//end one shred iteration
}
//end of all shred iteratio
tfng_prng_seedkey(NULL); //reset random generator
#ifdef ZERO_CHECK_ALERT
drive->u32DriveChecksumAferShredding = uiCalcChecksum(driveFileDiscr, drive, ipSignalFd);
@ -250,18 +262,19 @@ unsigned int Shred::uiCalcChecksum(fileDescriptor file,Drive* drive, int* ipSign
{
iBytesToCheck = CHUNK_SIZE;
}
int iReadBytes = read(file, caChunk, iBytesToCheck);
int iReadBytes = read(file, caReadBuffer, iBytesToCheck);
for (int iReadBytesCounter = 0U; iReadBytesCounter < iReadBytes; iReadBytesCounter++)
{
uiChecksum += caChunk[0][iReadBytesCounter];
uiChecksum += caReadBuffer[iReadBytesCounter];
}
ulDriveByteCounter += iReadBytes;
ulDriveByteOverallCount += iReadBytes;
d32Percent = this->calcProgress();
drive->sShredSpeed.ulSpeedMetricBytesWritten += iReadBytes;
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Shred-Task (Checksum): ByteCount: " + to_string(ulDriveByteCounter) + " - progress: " + to_string(d32Percent) + " - Drive: " + drive->getSerial());
#endif
if((d32Percent-d32TmpPercent) >= 0.9)
if((d32Percent-d32TmpPercent) >= 0.01)
{
drive->setTaskPercentage(d32TmpPercent);
d32TmpPercent = d32Percent;
@ -274,5 +287,5 @@ unsigned int Shred::uiCalcChecksum(fileDescriptor file,Drive* drive, int* ipSign
void Shred::cleanup()
{
close(driveFileDiscr);
close( randomSrcFileDiscr);
close(randomSrcFileDiscr);
}

View File

@ -14,6 +14,7 @@ uint64_t SMART::capacity = 0U;
uint32_t SMART::errorCount = 0U;
uint32_t SMART::powerOnHours = 0U;
uint32_t SMART::powerCycle = 0U;
uint32_t SMART::temperature = 0U;
/**
* \brief get and set S.M.A.R.T. values in Drive
@ -29,6 +30,7 @@ void SMART::readSMARTData(Drive* drive)
errorCount = 0U;
powerOnHours = 0U;
powerCycle = 0U;
temperature = 0U;
size_t len = 0; //lenght of found line
char* cLine = NULL; //found line
@ -50,9 +52,10 @@ void SMART::readSMARTData(Drive* drive)
SMART::parseErrorCount(sLine);
SMART::parsePowerOnHours(sLine);
SMART::parsePowerCycle(sLine);
SMART::parseTemperature(sLine);
}
pclose(outputfileSmart);
drive->setDriveSMARTData(modelFamily, modelName, serial, capacity, errorCount, powerOnHours, powerCycle); //wirte data in drive
drive->setDriveSMARTData(modelFamily, modelName, serial, capacity, errorCount, powerOnHours, powerCycle, temperature); //wirte data in drive
}
/**
@ -176,3 +179,26 @@ void SMART::parsePowerCycle(string sLine)
}
}
/**
* \brief parse temperature
* \param string output line of smartctl
* \return void
*/
void SMART::parseTemperature(string sLine)
{
string search("\"current\": ");
size_t found = sLine.find(search);
if (found!=string::npos)
{
sLine.erase(0, sLine.find(": ") + 2);
sLine.erase(sLine.length()-1, 2);
if(sLine == "{")
{
temperature = 0U; // this drive doesn't support temperatur
}
else
{
temperature = stol(sLine);
}
}
}

View File

@ -74,11 +74,12 @@ void TUI::updateTUI(list <Drive>* plistDrives, uint8_t u8SelectedEntry)
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
{
string sModelFamily = it->getModelFamily();
string sModelName = it->getModelName();
string sSerial = "SN: " + it->getSerial();
string sCapacity = it->sCapacityToText();
string sState = " ";
string sSpeed = " ";
string sTime = " ";
string sTemp = it->sTemperatureToText();
bool bSelectedEntry = false;
@ -87,17 +88,16 @@ void TUI::updateTUI(list <Drive>* plistDrives, uint8_t u8SelectedEntry)
bSelectedEntry = true; //mark this drive in entries list
displaySelectedDrive(*it, u16StdscrX, u16StdscrY);
if((it->getPowerOnHours() >= WORSE_HOURS) || (it->getPowerCycles() >= WORSE_POWERUP) || (it->getErrorCount() > 0))
if((it->getPowerOnHours() >= WORSE_HOURS) || (it->getPowerCycles() >= WORSE_POWERUP) || (it->getErrorCount() > 0) || (it->getTemperature() >= WORSE_TEMPERATURE))
{
// smart values are bad --> show warning
smartWarning=createSmartWarning(50, 10, ((u16StdscrX)-(int)(u16StdscrX/2)+35),(int)(u16StdscrY/2)-5, it->getPath(), it->getPowerOnHours(), it->getPowerCycles(), it->getErrorCount());
smartWarning=createSmartWarning(50, 10, ((u16StdscrX)-(int)(u16StdscrX/2)+35),(int)(u16StdscrY/2)-5, it->getPath(), it->getPowerOnHours(), it->getPowerCycles(), it->getErrorCount(), it->getTemperature());
wrefresh(smartWarning);
}
}
stringstream stream;
switch (it->state)
{
case Drive::SHRED_ACTIVE:
@ -107,6 +107,7 @@ void TUI::updateTUI(list <Drive>* plistDrives, uint8_t u8SelectedEntry)
it->calculateTaskDuration();
sTime = this->formatTimeDuration(it->getTaskDuration());
sSpeed = this->formatSpeed(it->sShredSpeed.u32ShredTimeDelta, it->sShredSpeed.ulWrittenBytes);
break;
case Drive::DELETE_ACTIVE:
sState = "Deleting ...";
@ -151,7 +152,7 @@ void TUI::updateTUI(list <Drive>* plistDrives, uint8_t u8SelectedEntry)
break;
}
WINDOW * tmp = createEntryWindow( ((int)(u16StdscrX/3) - 2), 5, 3, (5* (u8Index) )+3, sModelFamily, sModelName, sCapacity, sState, sTime, bSelectedEntry);
WINDOW * tmp = createEntryWindow( ((int)(u16StdscrX/3) - 2), 5, 3, (5* (u8Index) )+3, (distance(plistDrives->begin(), it)+1), sModelFamily, sSerial, sCapacity, sState, sTime, sSpeed, sTemp, bSelectedEntry);
wrefresh(tmp);
u8Index++;
}//end loop though drives
@ -203,6 +204,9 @@ enum TUI::UserInput TUI::readUserInput()
case 's':
return TUI::UserInput::Shred;
break;
case 'S':
return TUI::UserInput::ShredAll;
break;
default:
return TUI::UserInput::Undefined;
break;
@ -305,7 +309,7 @@ WINDOW* TUI::overwriteDetailViewWindow( int iXSize, int iYSize, int iXStart)
return newWindow;
}
WINDOW* TUI::createEntryWindow(int iXSize, int iYSize, int iXStart, int iYStart, string sModelFamily, string sModelName, string sCapacity, string sState, string sTime, bool bSelected)
WINDOW* TUI::createEntryWindow(int iXSize, int iYSize, int iXStart, int iYStart, int iListIndex, string sModelFamily, string sSerial, string sCapacity, string sState, string sTime, string sSpeed, string sTemp, bool bSelected)
{
WINDOW *newWindow;
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
@ -325,12 +329,16 @@ WINDOW* TUI::createEntryWindow(int iXSize, int iYSize, int iXStart, int iYStart,
box(newWindow, ACS_VLINE, ACS_HLINE);
mvwaddstr(newWindow,1, 1, sModelFamily.c_str());
mvwaddstr(newWindow,2, 1, sModelName.c_str());
mvwaddstr(newWindow,3, 1, sCapacity.c_str());
mvwaddstr(newWindow,1, 1, to_string(iListIndex).c_str());
mvwaddstr(newWindow,1, 5, sModelFamily.c_str());
mvwaddstr(newWindow,2, 5, sSerial.c_str());
mvwaddstr(newWindow,3, 5, sCapacity.c_str());
mvwaddstr(newWindow,3, 5+sCapacity.length()+3, sTemp.c_str());
mvwaddstr(newWindow,1, iXSize-sSpeed.length()-5, sSpeed.c_str());
mvwaddstr(newWindow,2, iXSize-sState.length()-5, sState.c_str());
mvwaddstr(newWindow,3, iXSize-sState.length()-5, sTime.c_str());
mvwaddstr(newWindow,3, iXSize-sTime.length()-5, sTime.c_str());
return newWindow;
}
@ -353,10 +361,14 @@ WINDOW* TUI::createSystemStats(int iXSize, int iYSize, int iXStart, int iYStart)
strftime(buffer,sizeof(buffer),"Date: %d-%m-%Y Time: %H:%M",timeinfo);
string time(buffer);
string sLine01 = "reHDD - hard drive refurbishing tool";
string sLine02 = "Version: " + string(REHDD_VERSION);
string sLine03 = "Available under GPL 3.0";
string sLine04 = "https://git.mosad.xyz/localhorst/reHDD";
string sLine01 = "reHDD - hard drive refurbishing tool";
string sLine02 = "Version: " + string(REHDD_VERSION);
string sLine03 = "Build time: ";
sLine03.append(__DATE__);
sLine03.append(" ");
sLine03.append(__TIME__);
string sLine04 = "Available under GPL 3.0";
string sLine05 = "https://git.mosad.xyz/localhorst/reHDD";
uint16_t u16Line = 2;
@ -364,6 +376,7 @@ WINDOW* TUI::createSystemStats(int iXSize, int iYSize, int iXStart, int iYStart)
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLine01.size()/2), sLine02.c_str());
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLine01.size()/2), sLine03.c_str());
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLine01.size()/2), sLine04.c_str());
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLine01.size()/2), sLine05.c_str());
u16Line++;
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLine01.size()/2), time.c_str());
@ -384,19 +397,19 @@ WINDOW* TUI::createMenuView(int iXSize, int iYSize, int iXStart, int iYStart, st
if(menustate.bAbort)
{
string sLineTmp = "Press A for Abort";
string sLineTmp = "Press a for Abort";
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLineTmp.size()/2), sLineTmp.c_str());
u16Line++;
}
if(menustate.bShred)
{
string sLineTmp = "Press S for Shred ";
string sLineTmp = "Press s for Shred (S for all drives)";
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLineTmp.size()/2), sLineTmp.c_str());
u16Line++;
}
if(menustate.bDelete)
{
string sLineTmp = "Press D for Delete";
string sLineTmp = "Press d for Delete";
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLineTmp.size()/2), sLineTmp.c_str());
}
@ -506,6 +519,17 @@ string TUI::formatTimeDuration(time_t u32Duration)
return out.str();
}
string TUI::formatSpeed(time_t u32ShredTimeDelta, unsigned long ulWrittenBytes)
{
std::ostringstream out;
double dDeltaSec = ((double)((u32ShredTimeDelta)/1000000000.0)); //convert nano in sec
double speed = ((ulWrittenBytes/1000000.0)/dDeltaSec);
char s[25];
sprintf(s, "%0.2lf MB/s", speed);
out << s;
return out.str();
}
void TUI::displaySelectedDrive(Drive drive, int stdscrX, int stdscrY)
{
struct MenuState menustate;
@ -563,7 +587,7 @@ void TUI::displaySelectedDrive(Drive drive, int stdscrX, int stdscrY)
}
}
WINDOW* TUI::createSmartWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, uint32_t u32PowerOnHours, uint32_t u32PowerCycles, uint32_t u32ErrorCount)
WINDOW* TUI::createSmartWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, uint32_t u32PowerOnHours, uint32_t u32PowerCycles, uint32_t u32ErrorCount, uint32_t u32Temperature)
{
WINDOW *newWindow;
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
@ -598,6 +622,13 @@ WINDOW* TUI::createSmartWarning(int iXSize, int iYSize, int iXStart, int iYStart
{
string sLineTmp = "S.M.A.R.T. erros detected: " + to_string(u32ErrorCount);
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLine01.size()/2), sLineTmp.c_str());
u16Line++;
}
if(u32Temperature >= WORSE_TEMPERATURE)
{
string sLineTmp = "Drive too hot: " + to_string(u32Temperature)+" C";
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLine01.size()/2), sLineTmp.c_str());
}
return newWindow;
}

1
tfnoisegen Submodule

@ -0,0 +1 @@
Subproject commit 488716ef22ac5a1aae235a59bea2997ac7e8e45a