reHDD/src/reHDD.cpp

510 lines
18 KiB
C++
Raw Normal View History

/**
2020-05-02 22:06:47 +02:00
* @file reHDD.cpp
* @brief app logic
* @author hendrik schutter
* @date 01.05.2020
*/
2020-05-02 22:06:47 +02:00
#include "../include/reHDD.h"
2020-08-23 09:26:32 +02:00
static int fdNewDrivesInformPipe[2];//File descriptor for pipe that informs if new drives are found
2020-08-04 11:59:45 +02:00
2020-08-23 09:26:32 +02:00
static int fdShredInformPipe[2];//File descriptor for pipe that informs if a wipe thread signals
2020-08-04 22:35:29 +02:00
2020-08-04 11:59:45 +02:00
static std::mutex mxScannDrives;
vector <Drive> vecNewDrives; //store found drives that are updated every 5sec
2020-08-04 11:59:45 +02:00
2020-08-07 11:38:00 +02:00
static vector <Drive> vecDrives; //stores all drive data from scann thread
TUI *ui;
static uint8_t u8SelectedEntry;
2020-08-04 11:59:45 +02:00
static fd_set selectSet;
2020-08-03 22:40:07 +02:00
2020-08-10 22:52:13 +02:00
//static struct TUI::MenuState menustate;
2020-08-09 21:41:28 +02:00
/**
* \brief app constructor
* \param void
* \return instance of App
*/
2020-05-02 22:06:47 +02:00
reHDD::reHDD(void)
{
u8SelectedEntry = 0U;
vecDrives.reserve(128);
}
/**
* \brief app logic
* \param void
* \return void
*/
2020-05-02 22:06:47 +02:00
void reHDD::app_logic(void)
{
2020-08-04 22:35:29 +02:00
ui = new TUI();
ui->initTUI();
2020-08-03 22:40:07 +02:00
2020-08-23 09:26:32 +02:00
pipe(fdNewDrivesInformPipe);
pipe(fdShredInformPipe);
2020-08-04 17:18:32 +02:00
thread thDevices(ThreadScannDevices); //start thread that scanns for drives
2020-08-06 22:45:05 +02:00
thread thUserInput(ThreadUserInput); //start thread that reads user input
2020-08-03 22:40:07 +02:00
2020-08-07 11:38:00 +02:00
while(1)
{
2020-08-23 09:26:32 +02:00
FD_ZERO(&selectSet);
FD_SET(fdNewDrivesInformPipe[0], &selectSet);
FD_SET(fdShredInformPipe[0], &selectSet);
2020-08-07 11:38:00 +02:00
select(FD_SETSIZE, &selectSet, NULL, NULL, NULL);
2020-08-04 11:59:45 +02:00
2020-08-23 09:26:32 +02:00
if( FD_ISSET(fdNewDrivesInformPipe[0], &selectSet))
2020-08-07 11:38:00 +02:00
{
char dummy;
2020-08-23 09:26:32 +02:00
read (fdNewDrivesInformPipe[0],&dummy,1);
2020-08-07 11:38:00 +02:00
mxScannDrives.lock();
filterNewDrives(&vecDrives, &vecNewDrives); //filter and copy to app logic vector
printDrives(&vecDrives);
2020-08-07 11:38:00 +02:00
mxScannDrives.unlock();
}
2020-08-23 09:26:32 +02:00
if (FD_ISSET(fdShredInformPipe[0], &selectSet))
2020-08-07 11:38:00 +02:00
{
2020-08-23 09:26:32 +02:00
char dummy;
read (fdShredInformPipe[0],&dummy,1);
2020-08-07 11:38:00 +02:00
}
ui->updateTUI(&vecDrives, u8SelectedEntry);
2020-08-07 11:38:00 +02:00
} //endless loop
2020-08-04 22:35:29 +02:00
thDevices.join();
2020-08-06 22:45:05 +02:00
thUserInput.join();
2020-08-03 22:40:07 +02:00
}
Drive* reHDD::getSelectedDrive()
{
if(u8SelectedEntry < vecDrives.size() )
{
return &(vecDrives.at(u8SelectedEntry));
}
else
{
2020-09-07 17:23:15 +02:00
Logger::logThis()->warning("selected drive not present");
return {};
}
}
2020-08-07 11:38:00 +02:00
void reHDD::ThreadScannDevices()
{
while(true)
{
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();
2020-08-23 09:26:32 +02:00
write(fdNewDrivesInformPipe[1], "A",1);
2020-08-07 11:38:00 +02:00
sleep(5); //sleep 5 sec
}
2020-08-04 17:18:32 +02:00
}
2020-08-03 22:40:07 +02:00
2020-08-07 11:38:00 +02:00
void reHDD::ThreadUserInput()
{
while(true)
2020-08-06 22:45:05 +02:00
{
2020-08-07 11:38:00 +02:00
// cout << TUI::readUserInput() << endl;
switch (TUI::readUserInput())
{
case TUI::UserInput::DownKey:
//cout << "Down" << endl;
handleArrowKey(TUI::UserInput::DownKey);
ui->updateTUI(&vecDrives, u8SelectedEntry);
2020-08-07 11:38:00 +02:00
break;
case TUI::UserInput::UpKey:
//cout << "Up" << endl;
handleArrowKey(TUI::UserInput::UpKey);
ui->updateTUI(&vecDrives, u8SelectedEntry);
2020-08-07 11:38:00 +02:00
break;
case TUI::UserInput::Undefined:
//cout << "Undefined" << endl;
break;
case TUI::UserInput::Abort:
//cout << "Abort" << endl;
2020-08-09 21:41:28 +02:00
handleAbort();
ui->updateTUI(&vecDrives, u8SelectedEntry);
2020-08-07 11:38:00 +02:00
break;
case TUI::UserInput::Delete:
//cout << "Delete" << endl;
if (getSelectedDrive() != nullptr)
2020-08-09 21:41:28 +02:00
{
if(getSelectedDrive()->state == Drive::NONE)
{
getSelectedDrive()->state = Drive::DELETE_SELECTED;
}
2020-08-09 21:41:28 +02:00
}
ui->updateTUI(&vecDrives, u8SelectedEntry);
2020-08-07 11:38:00 +02:00
break;
case TUI::UserInput::Shred:
//cout << "Shred" << endl;
if (getSelectedDrive() != nullptr)
2020-08-09 21:41:28 +02:00
{
if(getSelectedDrive()->state == Drive::NONE)
{
getSelectedDrive()->state = Drive::SHRED_SELECTED;
}
2020-08-09 21:41:28 +02:00
}
ui->updateTUI(&vecDrives, u8SelectedEntry);
2020-08-07 11:38:00 +02:00
break;
case TUI::UserInput::Enter:
//cout << "Enter" << endl;
2020-08-09 21:41:28 +02:00
handleEnter();
ui->updateTUI(&vecDrives, u8SelectedEntry);
2020-08-07 11:38:00 +02:00
break;
case TUI::UserInput::ESC:
//cout << "ESC" << endl;
2020-08-09 23:05:32 +02:00
handleESC();
ui->updateTUI(&vecDrives, u8SelectedEntry);
2020-08-07 11:38:00 +02:00
break;
default:
break;
}
2020-08-06 22:45:05 +02:00
}
}
2020-08-04 22:35:29 +02:00
2020-08-23 09:26:32 +02:00
void reHDD::ThreadShred()
{
if (getSelectedDrive() != nullptr)
{
Shred* pShredTask = new Shred(); //create new shred task
pShredTask->shredDrive(getSelectedDrive(), &fdShredInformPipe[1]); //start new shred task
delete pShredTask; //delete shred task
2020-08-30 16:05:22 +02:00
ui->updateTUI(&vecDrives, u8SelectedEntry);
}
2020-08-23 09:26:32 +02:00
}
2020-08-07 11:38:00 +02:00
void reHDD::filterNewDrives(vector <Drive>* pvecOldDrives, vector <Drive>* pvecNewDrives)
{
2020-08-04 17:18:32 +02:00
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
2020-08-03 22:40:07 +02:00
//remove offline old drives from previously run
for (itOld = pvecOldDrives->begin(); itOld != pvecOldDrives->end();)
{
if(itOld->bIsOffline == true)
{
Logger::logThis()->warning("Offline drive found: " + itOld->getPath());
itOld = pvecOldDrives->erase(itOld);
/*
if(pvecOldDrives->size() > 0){ //This can be a risk if the user starts a task for the selected drive and the selected drive changes
u8SelectedEntry = 0U;
}
*/
}
else
{
++itOld;
}
}
//search offline drives and mark them
2020-08-04 17:18:32 +02:00
for (itOld = pvecOldDrives->begin(); itOld != pvecOldDrives->end(); ++itOld)
{
itOld->bIsOffline = true; //set offline befor seachring in the new list
for (itNew = pvecNewDrives->begin(); itNew != pvecNewDrives->end();)
2020-08-07 11:38:00 +02:00
{
if(itOld->getSerial() == itNew->getSerial())
{
itOld->bIsOffline = false; //drive is still attached
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Delete new drive, because allready attached: " + itNew->getModelName());
#endif
itNew = pvecNewDrives->erase(itNew); //This drive is allready attached, remove from new list
}
else
{
++itNew;
2020-08-07 11:38:00 +02:00
}
}
}
//mark offline old drives
for (itOld = pvecOldDrives->begin(); itOld != pvecOldDrives->end(); ++itOld)
{
if(itOld->bIsOffline == true)
2020-08-07 11:38:00 +02:00
{
//cout << "offline drive found: " << itOld->getPath() << endl;
Logger::logThis()->warning("Mark offline drive found: " + itOld->getPath());
itOld->state = Drive::NONE; //clear state --> shred task will terminate
2020-08-07 11:38:00 +02:00
}
2020-08-04 19:51:34 +02:00
}
2020-08-03 22:40:07 +02:00
//add new drives to drive list
for (itNew = pvecNewDrives->begin(); itNew != pvecNewDrives->end(); ++itNew)
2020-08-07 11:38:00 +02:00
{
pvecOldDrives->push_back(pvecNewDrives->at(itNew - pvecNewDrives->begin()));
Logger::logThis()->info("Add new drive: " + itNew->getModelName());
2020-08-07 11:38:00 +02:00
}
pvecNewDrives->clear();
2020-08-03 22:40:07 +02:00
}
/**
* \brief search attached drives on /dev/sd*
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
2020-08-04 17:18:32 +02:00
void reHDD::searchDrives(vector <Drive>* pvecDrives)
{
2020-08-06 11:41:38 +02:00
// cout << "search drives ..." << endl;
Logger::logThis()->info("--> search drives <--");
char * cLine = NULL;
size_t len = 0;
FILE* outputfileHwinfo = popen("hwinfo --short --disk", "r");
if (outputfileHwinfo == NULL)
2020-08-07 11:38:00 +02:00
{
exit(EXIT_FAILURE);
}
while ((getline(&cLine, &len, outputfileHwinfo)) != -1)
{
2020-08-07 11:38:00 +02:00
if (string(cLine).find("/dev/sd") != string::npos)
{
Drive* tmpDrive = new Drive(string(cLine).substr (2,8));
2020-08-26 15:07:53 +02:00
tmpDrive->state = Drive::NONE;
tmpDrive->bIsOffline = false;
2020-08-07 11:38:00 +02:00
pvecDrives->push_back(*tmpDrive);
}
}
fclose(outputfileHwinfo);
}
/**
* \brief filter out drives that are listed in "ignoreDrives.conf"
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
2020-05-02 22:06:47 +02:00
void reHDD::filterIgnoredDrives(vector <Drive>* pvecDrives)
{
string sDelimiter = ":";
string sIgnoredDrivePath;
string sIgnoredDriveUUID;
vector<tuple<string, string>> vtlIgnoredDevices; //store drives from ingnore file
ifstream input( "ignoreDrives.conf" ); //read ingnore file
for(string sLine; getline( input, sLine );)
{
2020-08-07 11:38:00 +02:00
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
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)
{
2020-08-07 11:38:00 +02:00
vector <Drive>::iterator it;
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it)
{
2020-08-07 11:38:00 +02:00
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;
2020-09-07 17:23:15 +02:00
Logger::logThis()->error("[ERROR] different uuid found than in ignore file: " + it->getPath());
2020-08-07 11:38:00 +02:00
exit(EXIT_FAILURE); // exit to prevent accidentally shred a system drive
}
else
{
// same uuid found than in ignore file --> ignore this drive
#ifdef LOG_LEVEL_HIGH
2020-09-07 17:23:15 +02:00
Logger::logThis()->info("same uuid found than in ignore file --> ignore this drive: " + it->getPath());
#endif
2020-08-07 11:38:00 +02:00
it = pvecDrives->erase(it);
it--;
}
}
}
}
}
/**
* \brief print drives with all information
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
2020-05-02 22:06:47 +02:00
void reHDD::printDrives(vector <Drive>* pvecDrives)
{
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("------------DRIVES---------------");
//cout << "------------DRIVES---------------" << endl;
vector <Drive>::iterator it;
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it)
2020-08-07 11:38:00 +02:00
{
/*
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;*/
ostringstream address;
address << (void const *)&pvecDrives->at(it - pvecDrives->begin());
Logger::logThis()->info(to_string(it - pvecDrives->begin()) + ": " + it->getPath() + " - " + it->getModelFamily() + " - " + it->getSerial() + " @" + address.str());
2020-08-07 11:38:00 +02:00
}
Logger::logThis()->info("---------------------------------");
//cout << "---------------------------------" << endl;
#endif
}
2020-05-02 00:49:11 +02:00
/**
* \brief add S.M.A.R.T data from SMART
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
2020-05-02 22:06:47 +02:00
void reHDD::addSMARTData(vector <Drive>* pvecDrives)
{
vector <Drive>::iterator it;
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it)
2020-08-07 11:38:00 +02:00
{
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();
2020-08-07 11:38:00 +02:00
switch (userInput)
{
case TUI::UserInput::DownKey:
u8SelectedEntry++;
if(u8SelectedEntry >= u8EntrySize)
2020-08-07 11:38:00 +02:00
{
u8SelectedEntry = 0;
2020-08-07 11:38:00 +02:00
}
break;
case TUI::UserInput::UpKey:
if(u8SelectedEntry == 0)
2020-08-07 11:38:00 +02:00
{
u8SelectedEntry = (u8EntrySize-1);
}
else
{
u8SelectedEntry--;
2020-08-07 11:38:00 +02:00
}
break;
default:
u8SelectedEntry = 0;
2020-08-07 11:38:00 +02:00
break;
}
2020-09-07 17:23:15 +02:00
Logger::logThis()->info("ArrowKey - selected drive: " + to_string(u8SelectedEntry));
2020-08-09 21:41:28 +02:00
}
void reHDD::handleEnter()
{
if (getSelectedDrive() != nullptr)
2020-08-09 21:41:28 +02:00
{
if(getSelectedDrive()->state == Drive::TaskState::SHRED_SELECTED)
{
2020-09-07 17:23:15 +02:00
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();
}
2020-08-09 21:41:28 +02:00
if(getSelectedDrive()->state == Drive::TaskState::DELETE_SELECTED)
{
2020-09-07 17:23:15 +02:00
Logger::logThis()->info("Started delete for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial());
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;
2020-09-07 17:23:15 +02:00
Logger::logThis()->info("Finished delete for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial());
}
2020-08-09 21:41:28 +02:00
}
}
void reHDD::handleESC()
{
if (getSelectedDrive() != nullptr)
2020-08-09 21:41:28 +02:00
{
if(getSelectedDrive()->state == Drive::TaskState::SHRED_SELECTED)
{
getSelectedDrive()->state = Drive::TaskState::NONE;
//task for drive is selected --> remove selection
}
2020-08-09 21:41:28 +02:00
if(getSelectedDrive()->state == Drive::TaskState::DELETE_SELECTED)
{
getSelectedDrive()->state = Drive::TaskState::NONE;
//task for drive is selected --> remove selection
}
2020-08-09 21:41:28 +02:00
}
}
void reHDD::handleAbort()
{
if (getSelectedDrive() != nullptr)
2020-08-09 21:41:28 +02:00
{
if(getSelectedDrive()->state == Drive::SHRED_ACTIVE || getSelectedDrive()->state == Drive::DELETE_ACTIVE )
{
getSelectedDrive()->state = Drive::NONE;
Logger::logThis()->info("Abort-Shred-Signal for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial());
//task for drive is running --> remove selection
}
2020-08-09 21:41:28 +02:00
}
2020-08-23 09:26:32 +02:00
}
2020-08-30 12:03:37 +02:00
2020-08-26 00:12:39 +02:00