/** * @file reHDD.cpp * @brief app logic * @author hendrik schutter * @date 01.05.2020 */ #include "../include/reHDD.h" static int fdSearchDrives[2];//File descriptor for pipe that informs if new drives are found static int fdUserInput[2];//File descriptor for pipe that informs if a user input occoures static int fdWhipe[2];//File descriptor for pipe that informs if a wipe thread signals static std::mutex mxScannDrives; static vector vecNewDrives; //store found drives that are updated every 5sec static fd_set selectSet; /** * \brief app constructor * \param void * \return instance of App */ reHDD::reHDD(void) { cout << "created app" << endl; } /** * \brief app logic * \param void * \return void */ void reHDD::app_logic(void) { cout << "app logic" << endl; ui = new TUI(); ui->initTUI(); pipe(fdSearchDrives); pipe(fdWhipe); FD_ZERO(&selectSet); FD_SET(fdSearchDrives[0], &selectSet); FD_SET(fdWhipe[0], &selectSet); thread thDevices(ThreadScannDevices); //start thread that scanns for drives thread thUserInput(ThreadUserInput); //start thread that reads user input while(1) { select(FD_SETSIZE, &selectSet, NULL, NULL, NULL); if( FD_ISSET(fdSearchDrives[0], &selectSet)) { char dummy; read (fdSearchDrives[0],&dummy,1); mxScannDrives.lock(); filterNewDrives(&vecDrives, &vecNewDrives); //printDrives(&vecDrives); //TODO update UI ui->updateTUI(&vecDrives); mxScannDrives.unlock(); } else if (FD_ISSET(fdWhipe[0], &selectSet)) { cout << "Whipe signal" << endl; } } //endless loop thDevices.join(); thUserInput.join(); } 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 (fdSearchDrives[1], "A",1); sleep(5); //sleep 5 sec } } void reHDD::ThreadUserInput() { while(true) { // cout << TUI::readUserInput() << endl; switch (TUI::readUserInput()) { case TUI::UserInput::DownKey: /* code */ //cout << "Down" << endl; break; case TUI::UserInput::UpKey: //cout << "Up" << endl; break; case TUI::UserInput::Undefined: //cout << "Undefined" << endl; break; case TUI::UserInput::Abort: //cout << "Abort" << endl; break; case TUI::UserInput::Delete: //cout << "Delete" << endl; break; case TUI::UserInput::Shred: //cout << "Shred" << endl; break; case TUI::UserInput::Enter: //cout << "Enter" << endl; break; case TUI::UserInput::ESC: //cout << "ESC" << endl; break; default: break; } } } void reHDD::filterNewDrives(vector * pvecOldDrives, vector * pvecNewDrives) { vector ::iterator itOld; //Iterator for current (old) drive list vector ::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; // cout << "already online drive found: " << itOld->getPath() << endl; } } if(bOldDriveIsOffline == true) { //cout << "offline drive found: " << itOld->getPath() << endl; //TODO kill wipe thread } } pvecOldDrives->clear(); for (long unsigned int i=0; isize(); i++) { pvecOldDrives->push_back((*pvecNewDrives)[i]); } } /** * \brief search attached drives on /dev/sd* * \param pointer of vector * pvecDrives * \return void */ void reHDD::searchDrives(vector * 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)); pvecDrives->push_back(*tmpDrive); } } fclose(outputfileHwinfo); } /** * \brief filter out drives that are listed in "ignoreDrives.conf" * \param pointer of vector * pvecDrives * \return void */ void reHDD::filterIgnoredDrives(vector * pvecDrives) { string sDelimiter = ":"; string sIgnoredDrivePath; string sIgnoredDriveUUID; vector> vtlIgnoredDevices; //store drives from ingnore file //vector 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 ::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 * pvecDrives * \return void */ void reHDD::printDrives(vector * pvecDrives) { cout << "------------DRIVES---------------" << endl; vector ::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 * pvecDrives * \return void */ void reHDD::addSMARTData(vector * pvecDrives) { vector ::iterator it; for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it) { Drive* pTmpDrive = iterator_to_pointer::iterator > (it); SMART::readSMARTData(pTmpDrive); } }