reHDD/src/reHDD.cpp

474 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file reHDD.cpp
* @brief app logic
* @author hendrik schutter
* @date 01.05.2020
*/
#include "../include/reHDD.h"
static int fdNewDrivesInformPipe[2];//File descriptor for pipe that informs if new drives are found
static int fdShredInformPipe[2];//File descriptor for pipe that informs if a wipe thread signals
static std::mutex mxScannDrives;
static vector <Drive> vecNewDrives; //store found drives that are updated every 5sec
static vector <Drive> vecDrives; //stores all drive data from scann thread
TUI *ui;
static uint8_t u8SelectedEntry;
static fd_set selectSet;
//static struct TUI::MenuState menustate;
/**
* \brief app constructor
* \param void
* \return instance of App
*/
reHDD::reHDD(void)
{
cout << "created app" << endl;
u8SelectedEntry = 0U;
}
/**
* \brief app logic
* \param void
* \return void
*/
void reHDD::app_logic(void)
{
cout << "app logic" << endl;
ui = new TUI();
ui->initTUI();
pipe(fdNewDrivesInformPipe);
pipe(fdShredInformPipe);
thread thDevices(ThreadScannDevices); //start thread that scanns for drives
thread thUserInput(ThreadUserInput); //start thread that reads user input
while(1)
{
FD_ZERO(&selectSet);
FD_SET(fdNewDrivesInformPipe[0], &selectSet);
FD_SET(fdShredInformPipe[0], &selectSet);
select(FD_SETSIZE, &selectSet, NULL, NULL, NULL);
if( FD_ISSET(fdNewDrivesInformPipe[0], &selectSet))
{
char dummy;
read (fdNewDrivesInformPipe[0],&dummy,1);
mxScannDrives.lock();
filterNewDrives(&vecDrives, &vecNewDrives); //filter and copy to app logic vector
mxScannDrives.unlock();
}
if (FD_ISSET(fdShredInformPipe[0], &selectSet))
{
char dummy;
read (fdShredInformPipe[0],&dummy,1);
checkShredComplete(&vecDrives);
}
ui->updateTUI(&vecDrives, u8SelectedEntry);
} //endless loop
thDevices.join();
thUserInput.join();
}
Drive* reHDD::getSelectedDrive()
{
if(u8SelectedEntry < vecDrives.size() )
{
return &(vecDrives.at(u8SelectedEntry));
}
else
{
return {};
}
}
void reHDD::ThreadScannDevices()
{
while(true)
{
// cout << "Thread" << endl;
mxScannDrives.lock();
vecNewDrives.clear();
searchDrives(&vecNewDrives); //search for new drives and store them in list
filterIgnoredDrives(&vecNewDrives); //filter out ignored drives
addSMARTData(&vecNewDrives); //add S.M.A.R.T. Data to the drives
mxScannDrives.unlock();
write(fdNewDrivesInformPipe[1], "A",1);
sleep(5); //sleep 5 sec
}
}
void reHDD::ThreadUserInput()
{
while(true)
{
// cout << TUI::readUserInput() << endl;
switch (TUI::readUserInput())
{
case TUI::UserInput::DownKey:
//cout << "Down" << endl;
handleArrowKey(TUI::UserInput::DownKey);
ui->updateTUI(&vecDrives, u8SelectedEntry);
break;
case TUI::UserInput::UpKey:
//cout << "Up" << endl;
handleArrowKey(TUI::UserInput::UpKey);
ui->updateTUI(&vecDrives, u8SelectedEntry);
break;
case TUI::UserInput::Undefined:
//cout << "Undefined" << endl;
break;
case TUI::UserInput::Abort:
//cout << "Abort" << endl;
handleAbort();
ui->updateTUI(&vecDrives, u8SelectedEntry);
break;
case TUI::UserInput::Delete:
//cout << "Delete" << endl;
if (getSelectedDrive() != nullptr)
{
if(getSelectedDrive()->state == Drive::NONE)
{
getSelectedDrive()->state = Drive::DELETE_SELECTED;
}
}
ui->updateTUI(&vecDrives, u8SelectedEntry);
break;
case TUI::UserInput::Shred:
//cout << "Shred" << endl;
if (getSelectedDrive() != nullptr)
{
if(getSelectedDrive()->state == Drive::NONE)
{
getSelectedDrive()->state = Drive::SHRED_SELECTED;
}
}
ui->updateTUI(&vecDrives, u8SelectedEntry);
break;
case TUI::UserInput::Enter:
//cout << "Enter" << endl;
handleEnter();
ui->updateTUI(&vecDrives, u8SelectedEntry);
break;
case TUI::UserInput::ESC:
//cout << "ESC" << endl;
handleESC();
ui->updateTUI(&vecDrives, u8SelectedEntry);
break;
default:
break;
}
}
}
void reHDD::ThreadShred()
{
if (getSelectedDrive() != nullptr)
{
Shred::shredDrive(getSelectedDrive(), &fdShredInformPipe[1]);
}
}
void reHDD::filterNewDrives(vector <Drive>* pvecOldDrives, vector <Drive>* pvecNewDrives)
{
vector <Drive>::iterator itOld; //Iterator for current (old) drive list
vector <Drive>::iterator itNew; //Iterator for new drive list that was created from to scann thread
for (itOld = pvecOldDrives->begin(); itOld != pvecOldDrives->end(); ++itOld)
{
bool bOldDriveIsOffline = true;
for (itNew = pvecNewDrives->begin(); itNew != pvecNewDrives->end(); ++itNew)
{
if(itOld->getSerial() == itNew->getSerial())
{
bOldDriveIsOffline = false;
// copy old drive instance date in new instance
itNew->state = itOld->state; //copy state
itNew->setTaskPercentage(itOld->getTaskPercentage()); //copy percentage
itNew->bWasDeleteted = itOld->bWasDeleteted; //copy finished task delete
itNew->bWasShredded = itOld->bWasShredded; //copy finished task shred
}
}
if(bOldDriveIsOffline == true)
{
//cout << "offline drive found: " << itOld->getPath() << endl;
itOld->state = Drive::NONE;
}
}
pvecOldDrives->clear();
for (long unsigned int i=0; i<pvecNewDrives->size(); i++)
{
pvecOldDrives->push_back((*pvecNewDrives)[i]);
}
}
/**
* \brief search attached drives on /dev/sd*
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
void reHDD::searchDrives(vector <Drive>* pvecDrives)
{
// cout << "search drives ..." << endl;
char * cLine = NULL;
size_t len = 0;
FILE* outputfileHwinfo = popen("hwinfo --short --disk", "r");
if (outputfileHwinfo == NULL)
{
exit(EXIT_FAILURE);
}
while ((getline(&cLine, &len, outputfileHwinfo)) != -1)
{
if (string(cLine).find("/dev/sd") != string::npos)
{
Drive* tmpDrive = new Drive(string(cLine).substr (2,8));
tmpDrive->state = Drive::NONE;
pvecDrives->push_back(*tmpDrive);
}
}
fclose(outputfileHwinfo);
}
/**
* \brief filter out drives that are listed in "ignoreDrives.conf"
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
void reHDD::filterIgnoredDrives(vector <Drive>* pvecDrives)
{
string sDelimiter = ":";
string sIgnoredDrivePath;
string sIgnoredDriveUUID;
vector<tuple<string, string>> vtlIgnoredDevices; //store drives from ingnore file
//vector <Drive> vecTmpDrives
ifstream input( "ignoreDrives.conf" ); //read ingnore file
for(string sLine; getline( input, sLine );)
{
if (string(sLine).find("/dev/sd") != string::npos)
{
size_t pos = 0;
string token;
while ((pos = sLine.find(sDelimiter)) != string::npos)
{
token = sLine.substr(0, pos);
sIgnoredDrivePath = token;
sLine.erase(0, pos + sDelimiter.length());
sIgnoredDriveUUID = sLine;
} //end while
//cout << "Path: " << sIgnoredDrivePath << std::endl;
//cout << "UUID: " << sIgnoredDriveUUID << std::endl;
vtlIgnoredDevices.emplace_back(sIgnoredDrivePath, sIgnoredDriveUUID); //add found path and uuid from ingnore file to vector
}
}
//loop through found entries in ingnore file
for(auto row : vtlIgnoredDevices)
{
vector <Drive>::iterator it;
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it)
{
string sUUID;
if (!get<0>(row).compare(it->getPath())) //find same drive based on path
{
char * cLine = NULL;
size_t len = 0;
string sCMD = "blkid ";
sCMD.append(it->getPath());
//cout << "cmd: " << sCMD << endl;
FILE* outputfileBlkid = popen(sCMD.c_str(), "r"); //get UUID from drive
if (outputfileBlkid == NULL)
{
exit(EXIT_FAILURE);
}
while ((getline(&cLine, &len, outputfileBlkid)) != -1) //parse UUID from blkid
{
if (string(cLine).find("PTUUID") != string::npos)
{
string sBlkidOut = string(cLine);
sBlkidOut.erase(0, 18);
sBlkidOut.erase(36, sBlkidOut.length() - 36);
sUUID = sBlkidOut;
//cout << "blkid uuid:" << sUUID << endl;
}
}
fclose(outputfileBlkid);
//cout << "blkid uuid:" << sUUID << endl;
if (get<1>(row).compare(sUUID)) //compare uuid from ignore file and uuid from drive
{
cout << "[ERROR] different uuid found than in ignore file:" << it->getPath() << endl;
exit(EXIT_FAILURE); // exit to prevent accidentally shred a system drive
}
else
{
// same uuid found than in ignore file --> ignore this drive
it = pvecDrives->erase(it);
it--;
//cout << "same uuid found than in ignore file --> ignore this drive:" << it->getPath() << endl;
}
}
}
}
}
/**
* \brief print drives with all information
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
void reHDD::printDrives(vector <Drive>* pvecDrives)
{
cout << "------------DRIVES---------------" << endl;
vector <Drive>::iterator it;
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it)
{
cout << " Drive: " << distance(pvecDrives->begin(), it) << endl;
cout << "Path: " << it->getPath() << endl;
cout << "ModelFamily: " << it->getModelFamily() << endl;
cout << "ModelName: " << it->getModelName() << endl;
cout << "Capacity: " << it->getCapacity() << endl;
cout << "Serial: " << it->getSerial() << endl;
cout << "PowerOnHours: " << it->getPowerOnHours() << endl;
cout << "PowerCycle: " << it->getPowerCycles() << endl;
cout << "ErrorCount: " << it->getErrorCount() << endl;
cout << endl;
}
cout << "---------------------------------" << endl;
}
/**
* \brief add S.M.A.R.T data from SMART
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
void reHDD::addSMARTData(vector <Drive>* pvecDrives)
{
vector <Drive>::iterator it;
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it)
{
Drive* pTmpDrive = iterator_to_pointer<Drive, std::vector<Drive>::iterator > (it);
SMART::readSMARTData(pTmpDrive);
}
}
void reHDD::handleArrowKey(TUI::UserInput userInput)
{
int8_t u8EntrySize = (int8_t) vecDrives.size();
switch (userInput)
{
case TUI::UserInput::DownKey:
u8SelectedEntry++;
if(u8SelectedEntry >= u8EntrySize)
{
u8SelectedEntry = 0;
}
break;
case TUI::UserInput::UpKey:
if(u8SelectedEntry == 0)
{
u8SelectedEntry = (u8EntrySize-1);
}
else
{
u8SelectedEntry--;
}
break;
default:
u8SelectedEntry = 0;
break;
}
}
void reHDD::handleEnter()
{
if (getSelectedDrive() != nullptr)
{
if(getSelectedDrive()->state == Drive::TaskState::SHRED_SELECTED)
{
getSelectedDrive()->state = Drive::TaskState::SHRED_ACTIVE;
//task for drive is running --> don´t show more task options
thread(ThreadShred).detach();
}
if(getSelectedDrive()->state == Drive::TaskState::DELETE_SELECTED)
{
getSelectedDrive()->state = Drive::TaskState::DELETE_ACTIVE;
//task for drive is running --> don´t show more task options
Delete::deleteDrive(getSelectedDrive()); //blocking, no thread
getSelectedDrive()->state = Drive::TaskState::NONE; //delete finished
getSelectedDrive()->bWasDeleteted = true;
}
}
}
void reHDD::handleESC()
{
if (getSelectedDrive() != nullptr)
{
if(getSelectedDrive()->state == Drive::TaskState::SHRED_SELECTED)
{
getSelectedDrive()->state = Drive::TaskState::NONE;
//task for drive is selected --> remove selection
}
if(getSelectedDrive()->state == Drive::TaskState::DELETE_SELECTED)
{
getSelectedDrive()->state = Drive::TaskState::NONE;
//task for drive is selected --> remove selection
}
}
}
void reHDD::handleAbort()
{
if (getSelectedDrive() != nullptr)
{
if(getSelectedDrive()->state == Drive::SHRED_ACTIVE || getSelectedDrive()->state == Drive::DELETE_ACTIVE )
{
getSelectedDrive()->state = Drive::NONE;
//task for drive is running --> remove selection
}
}
}
void reHDD::checkShredComplete(vector <Drive>* pvecDrives)
{
vector <Drive>::iterator it;
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it)
{
if(it->getTaskPercentage() == 100 )
{
it->bWasShredded = true; //mark this drive as shredded
it->setTaskPercentage(0); //reset for an other shredding
it->state = Drive::NONE; //reset for an other task
}
}
}