Compare commits

..

No commits in common. "master" and "prototype" have entirely different histories.

43 changed files with 403 additions and 2901 deletions

7
.gitignore vendored
View File

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

3
.gitmodules vendored
View File

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

View File

@ -1,68 +1,14 @@
# reHDD
## Features:
* show S.M.A.R.T values of attached drives
* checking used drives for their next live based on threshold limits
* delete a drive instant with wipefs
* deleting a drive securely via overwriting
* only needs a display and keyboard
* process multiple drives at once
## Useful for:
* checking new drives for the first time
* checking used drives for their next live
* deleting a drive securely
## Download USB Image ##
[2.5GB image v1.0.0](https://schuttercloud.com/s/ggxGH9sA326aRfK) (`wget` is your friend)
## planned Features:
Use [Etcher](https://www.balena.io/etcher/#download) or `dd` to create an bootable USB drive .
* search for new attached Hard Drives via USB
* display Hard Drive Manufacturer, Model, Rotation Rate and Capacity
* Check S.M.A.R.T. values and make an 'passed' or 'not passed' decision
* If passed, wipe the data securely
## Screenshot
![Screenshot of reHDD with multiple drives in different states](https://git.mosad.xyz/localhorst/reHDD/raw/commit/c40dfe2cbb8f86490b49caf82db70a10015f06f9/doc/screenshot.png "Screenshot")
## Debian Build Notes
* `apt-get install ncurses-dev git make g++`
* `git submodule init`
* `git submodule update`
* `make release`
## Enable Label Printer ##
Just install [reHDDPrinter](https://git.mosad.xyz/localhorst/reHDDPrinter).
No further settings needed.
## Create Standalone with Debian 11
Instructions how to create a standalone machine that boots directly to reHDD. This is aimed for production use, like several drives a day shredding.
* Start reHDD after boot without login (as a tty1 shell)
* Start dmesg after boot without login (as a tty2 shell)
* Start htop after boot without login (as a tty3 shell)
* Upload reHDD log every 12h if wanted
### Software requirements
* `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`
`bash scripts/install_reHDD.bash`
If you want to upload the logs, edit `scripts/reHDDLogUploader.bash` with your nextcloud token
Add your system drive in `/root/reHDD/ignoreDrives.conf` like:
```e102f49d```
Get the first 8 Bytes from your UUID via `blkid /dev/sdX`
`reboot`
## Build docs
`make docs`
open `doc/html/index.html` in browser

View File

@ -1 +1 @@
<mxfile host="app.diagrams.net" modified="2020-08-23T07:05:27.762Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36" etag="SGyuMJOWQf98SwQRl4R2" version="13.6.4" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">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</diagram></mxfile>
<mxfile host="app.diagrams.net" modified="2020-04-30T20:05:53.432Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36" etag="5yI57G0tj_AETib5-SCg" version="13.0.4" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">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</diagram></mxfile>

Binary file not shown.

View File

@ -1 +0,0 @@
<mxfile host="app.diagrams.net" modified="2020-08-23T06:57:40.722Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36" etag="hfpQUXi749i-5e3peR6Z" version="13.6.4" type="device"><diagram id="uYiMRnSvU_g0LN3LXuwh" name="Page-1">5Vtbd6M2EP41fkwOkrg+Ojbb3Z5sNo192u4jiRWbXYxcWV7b/fUVRgIL4Usag0jykqBBkmFmvtE3I9FDg/nmNxotZl/JBCc9aE02PTTsQeh6Dv+bCba5ANl+LpjSeJKLQCkYxf9iIbSEdBVP8FLpyAhJWLxQhU8kTfETU2QRpWStdnsmifqri2iKNcHoKUp06V/xhM1yqQ+9Uv4Zx9OZ/GXgBvmdeSQ7izdZzqIJWe+JUNhDA0oIy6/mmwFOMt1JveTjPh24WzwYxSk7ZwD78uOPwA1nv4++jj9B9/4n+7a+ssXTLtlWvjGecAWIJqFsRqYkjZKwlN5QskonOJvW4q2yzy0hCy4EXPgDM7YV1oxWjHDRjM0TcRdvYvZ3NvzaEa3ve3eGGzHzrrGVjZTR7d6grPl9/145bNeS4/L3y17qoN6EaElW9AkfUZb0v4hOMTvSDxbW5ajAZI758/BxFCcRi3+pzxEJ/5wW/UoT8gthxRdYVMz7K0pW4pd60E344948E/7C+6Z2/1kReeNquTNWn3cA/mJT3uRX0+z/aNx/GMup+JPls+X3dB9KEg7QzFfWs5jh0SLaKXbNQ4TqCeJhMWV4c9w+uj7FACQRJyOMwNu6hGsgRLM9pNpWQwaANQaoqEcFUAsqcmxFRYGuIgBrdOQ2pSMANJ20EXbKEGJ7Sgy5hs6JMLJr3WMacwVgevnYgs6MLZ7R2KK7crtmMxX5z7WO/0rr7Ib2KY22ex0WJE7Zcm/m+0xQotsGKroBqhCBSn8HwWP9+UX+BKWfFK/y/10HaVFxtKNjlP8dzSj3D7G0PFK5qgyLDkOccNR1LowCcGYcbWytsRta7O++3YXnrvVcn5l8ySj5iQckIVl0TEmaYf85TpKKaM8k2bQC9dCWbTFxdj8zVsypeD+JpymXzePJZBdSIiF44obLgvFlaIRqXL/GtlabtnW6xyN49qYCwDNOJBzDKxKwXZVJBL53Yl1qmkq4Zy5WyMRiBQPVhaB1fLFCHjzWv5nFCnga9sLRoNbTbqNHnKjeoUWng3GMYh6Io8fdfJkTCOXxyZ2bnjM8BlpR7xCDe0WVYd9hjiDmIMQ5NXaQKNG8zBNK08ku5Pl5yT2wivELGAgiw7A3RUTPxTYIXgnuV0VlV4fP3Th8KPjcFi91urdDmOiQku6tdecmzY0RAj0ovZjswdrKzueHMOPao/A2HIyzyw9F/KCNVEO7ppmf3z3mZ1eW4Q4wP9fwEuD5Sg0JXFvINsz8gi4zv2rZ4RTzs+VOUavMT8fe+2F+7gnm5yDXVVQuNxO6SwSRHho/BhE8F+rwtSXJVwXp4B0QQW3pM04EZdnx4kxwyBngOPy4VND2K6Y2TgVBbd28XvsNLURZ+Msd52J1dKnCI3X0OkDBxrSs19GHb17LDuialvXVwHhwr2b5sA7xreY10HReg5BS0eZ5DSh6GMprpAG6mdigSkkbtZGoQL0a1K91nDeXpsBTaYqN1AM/Iop0OEnxzUK697KjLiaAC00At/DJeuCe7A8sp3mg2/qBPlmwHZD5ovZgRAu4p4Rxy5BsVGA1EgfQgcxVTH/FVyrL87qOfajnav0iu+0/clx3jwPVHX1oNcGFus9fdqujPxh/+fOjnXCBdsXOjunsFupnXER96I3nXtCvqLrmULLbZu4F38CekvncCxk/VhBU95TM516d3lSyobpj0UruhfRy0TvJvdABI5a5l1U5Jtn95MvMF04lpoOg8q0BKAssXce0kbTMBS9Ly6r9A7/5EGDrtL7YPHnnadmBk2VlWga9SkLR/W1kCYgOZ2kaWzKepSEdAxfehvyQaVp1E7LJNI03yw+QczCVX3Gj8D8=</diagram></mxfile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

View File

@ -467,7 +467,7 @@ LOOKUP_CACHE_SIZE = 0
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
EXTRACT_ALL = YES
EXTRACT_ALL = NO
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
@ -904,7 +904,7 @@ FILE_PATTERNS = *.c \
# be searched for input files as well.
# The default value is: NO.
RECURSIVE = YES
RECURSIVE = NO
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
@ -1493,7 +1493,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
DISABLE_INDEX = YES
DISABLE_INDEX = NO
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information. If the tag
@ -1510,7 +1510,7 @@ DISABLE_INDEX = YES
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = YES
GENERATE_TREEVIEW = NO
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
@ -2260,7 +2260,7 @@ HIDE_UNDOC_RELATIONS = YES
# set to NO
# The default value is: NO.
HAVE_DOT = YES
HAVE_DOT = NO
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
# to run in parallel. When set to 0 doxygen will base this on the number of
@ -2326,7 +2326,7 @@ GROUP_GRAPHS = YES
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
UML_LOOK = YES
UML_LOOK = NO
# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
# class node. If there are many fields or methods and many nodes the graph may
@ -2377,7 +2377,7 @@ INCLUDED_BY_GRAPH = YES
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
CALL_GRAPH = YES
CALL_GRAPH = NO
# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
# dependency graph for every global function or class method.
@ -2389,7 +2389,7 @@ CALL_GRAPH = YES
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
CALLER_GRAPH = YES
CALLER_GRAPH = NO
# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
# hierarchy of all classes instead of a textual one.

View File

@ -0,0 +1,60 @@
# Installation
**[1]** In terminal als root einloggen\
**[2]** In reHDD_prototype wechseln\
**[3]** Abhängigkeiten installieren\
`apt-get install smartmontools`\
`apt-get install hwinfo`\
`apt-get install util-linux`
**[4]** reHDD ausführbar machen\
`chmod +x reHDD`\
**[5]** ignoreDrives.conf bearbeiten
##### Ein Eintrag in der ignoreDrives-Datei sorgt dafür das die Software bestimmte Festplatten ignoriert. Dies ist wichtig damit nicht unbeabsichtigt die Systemfestplatte oder weitere Festplatten bearbeitet (gelöscht) werden.
Beispiel Inhalt:
```
/dev/sda:508eff7d-f039-4efb-9e2c-22dffdfdfdfd
/dev/sdb:07dfffff-c4b6-46e7-9cdf-3cfdfdffd53d
/dev/sdc:dfff974d-1af2-4dfd-9dfd-a2d8e4c43dff
```
Ein Eintrag setzt sich aus zwei Teilen zusammen:
**[Pfad]:[PARTUUID]**
Der Pfad kann mittels `fdisk -l` ermittelt werden.\
Die PARTUUID kann mittels `blkid /dev/sda` ermittelt werden, wobei `/dev/sda` derzuvor ermittelte Pfad ist.
# Benutzung
reHDD starten mit `./reHDD` (Wichtig ist das reHDD mit root-Rechen ausgeführt wird, entwender als root einloggen oder mit `sudo`)
reHDD sucht automatisch nach allen verfügbaren Festplatten und filtert die zu ignorierenden heraus.\
Für die verbleibenden Festplatten wird eine Übersicht ausgegeben.
Der Nutzer wird gefragt, welche Festplatte bearbeitet werden soll und gibt die Nummer ein.
Beispiel:
```
hostname@hendrik:/reHDD_prototype # ./reHDD
refurbishingHddTool
created app
app logic
search drives ...
------------DRIVES---------------
Drive: 0
Path: /dev/sdd
ModelFamily:
ModelName: ADATA SU650
Capacity: 120034123776
Serial: H50125K001601
PowerOnHours: 93
PowerCycle: 187
ErrorCount: 0
---------------------------------
Select drive to wipe:
0
Selected drive index: 0
wipe: shred -v /dev/sdd
shred: /dev/sdd: Durchgang 1/3 (random)…
shred: /dev/sdd: Durchgang 1/3 (random)…847MiB/112GiB 0%
...
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

View File

@ -1,3 +1,3 @@
4673974d
2cb3dea4
8ffbc421
/dev/sda:508ef27d-5039-4e8b-9e2c-22d7528b7149
/dev/sdb:07f4ad14-c4b6-46e7-9cdf-3cfa9841d53d
/dev/sdc:4673974d-1af2-44fd-996b-a2d8e4c43d9a

View File

@ -1,23 +0,0 @@
/**
* @file delete.h
* @brief delete drive
* @author hendrik schutter
* @date 23.08.2020
*/
#ifndef DELETE_H_
#define DELETE_H_
#include "reHDD.h"
class Delete
{
protected:
public:
static void deleteDrive(Drive *drive);
private:
Delete(void);
};
#endif // DELETE_H_

View File

@ -12,56 +12,8 @@
class Drive
{
public:
enum TaskState
{
NONE,
SHRED_SELECTED,
SHRED_ACTIVE, // shred iterations active
CHECK_ACTIVE, // optional checking active
DELETE_SELECTED,
DELETE_ACTIVE,
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; // all shred iterations done
bool bWasChecked = false; // all shred iterations and optional checking done
bool bWasDeleted = false;
bool bIsOffline = false;
uint32_t u32DriveChecksumAfterShredding = 0U;
private:
string sPath;
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();
protected:
public:
Drive(string path)
{
@ -72,36 +24,28 @@ public:
string getModelFamily(void);
string getModelName(void);
string getSerial(void);
uint64_t getCapacity(void); // in byte
uint64_t getCapacity(void); //in byte
uint32_t getErrorCount(void);
uint32_t getPowerOnHours(void); // in hours
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,
string modelName,
string serial,
uint64_t capacity,
uint32_t errorCount,
uint32_t powerOnHours,
uint32_t powerCycles,
uint32_t temperature);
void setDriveSMARTData( string modelFamily,
string modelName,
string serial,
uint64_t capacity,
uint32_t errorCount,
uint32_t powerOnHours,
uint32_t powerCycles);
string sCapacityToText();
string sErrorCountToText();
string sPowerOnHoursToText();
string sPowerCyclesToText();
string sTemperatureToText();
void setTaskPercentage(double d32TaskPercentage);
double getTaskPercentage(void);
void setActionStartTimestamp();
time_t getActionStartTimestamp();
void calculateTaskDuration();
time_t getTaskDuration();
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;
};
#endif // DRIVE_H_
#endif // DRIVE_H_

View File

@ -1,79 +0,0 @@
/**
* @file logger.h
* @brief cppSimpleLogger Header
* @author hendrik schutter
* @date 04.09.2020
*/
#ifndef LOGGER_H_
#define LOGGER_H_
#include <time.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <net/if.h>
#include <unistd.h>
#include <sys/time.h>
#include <math.h>
#include <mutex>
using namespace std;
#define MENU_LINE_SIZE 110 // Size of menu lines
#ifndef LOG_PATH
// #define LOG_PATH "./test.txt"
#endif
#ifndef DESCRIPTION
#define DESCRIPTION "Software-Name - Copyright Company 2020" // use your values here
#endif
#ifndef DEVICE_ID
#define DEVICE_ID "Device-Name" // use your values here
#endif
#ifndef SOFTWARE_VERSION
#define SOFTWARE_VERSION "0.1.1.8" // use your values here
#endif
#ifndef HARDWARE_VERSION
#define HARDWARE_VERSION "7.77.9" // use your values here
#endif
class Logger
{
private:
string logPath;
mutex mtxLog;
static bool instanceFlag;
static Logger *single;
string getTimestamp();
void writeLog(string s);
string getMacAddress();
string padStringMenu(char cBorder, string text, uint8_t u8LineLenght);
string menuLine(char cBorder, uint8_t u8LineLenght);
Logger();
~Logger();
public:
void info(string s);
void warning(string s);
void error(string s);
void newLine();
static Logger *logThis();
};
#endif // LOGGER_H_

View File

@ -1,56 +0,0 @@
/**
* @file printer.h
* @brief Send drive data to printer service using ipc msg queue
* @author Hendrik Schutter
* @date 24.11.2022
*/
#ifndef PRINTER_H_
#define PRINTER_H_
#include "reHDD.h"
#include <sys/ipc.h>
#include <sys/msg.h>
#define STR_BUFFER_SIZE 64U
#define IPC_MSG_QUEUE_KEY 0x1B11193C0
typedef struct
{
char caDriveIndex[STR_BUFFER_SIZE];
char caDriveHours[STR_BUFFER_SIZE];
char caDriveCycles[STR_BUFFER_SIZE];
char caDriveErrors[STR_BUFFER_SIZE];
char caDriveShredTimestamp[STR_BUFFER_SIZE];
char caDriveShredDuration[STR_BUFFER_SIZE];
char caDriveCapacity[STR_BUFFER_SIZE];
char caDriveState[STR_BUFFER_SIZE];
char caDriveModelFamily[STR_BUFFER_SIZE];
char caDriveModelName[STR_BUFFER_SIZE];
char caDriveSerialnumber[STR_BUFFER_SIZE];
char caDriveReHddVersion[STR_BUFFER_SIZE];
} t_driveData;
typedef struct
{
long msg_queue_type;
t_driveData driveData;
} t_msgQueueData;
class Printer
{
protected:
public:
static Printer *getPrinter();
void print(Drive *drive);
private:
static bool instanceFlag;
static Printer *single;
int msqid;
Printer();
~Printer();
};
#endif // PRINTER_H_

View File

@ -1,6 +1,6 @@
/**
* @file reHDD.h
* @brief app logic header
* @brief represent
* @author hendrik schutter
* @date 01.05.2020
*/
@ -8,69 +8,21 @@
#ifndef REHDD_H_
#define REHDD_H_
#define REHDD_VERSION "V1.1.1"
// 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 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"
#define DESCRIPTION "reHDD - Copyright Hendrik Schutter 2024"
#define DEVICE_ID "generic"
#define SOFTWARE_VERSION REHDD_VERSION
#define HARDWARE_VERSION "generic"
// #define LOG_LEVEL_HIGH //log everything, like drive scan thread
#ifndef LOG_LEVEL_HIGH
#define LOG_LEVEL_LOW // log only user actions and tasks
#endif
// Logic
// #define DRYRUN //don´t touch the drives
#define FROZEN_ALERT // show alert if drive is frozen
#define ZERO_CHECK // check drive after shred if all bytes are zero, show alert if this fails
// IPC pipes
#define READ 0
#define WRITE 1
#include <iostream>
#include <string>
#include <fstream>
#include <tuple>
#include <list>
#include <vector>
#include <time.h>
#include <chrono>
#include <curses.h>
#include <thread>
#include <unistd.h>
#include <mutex>
#include <sys/select.h>
#include <algorithm>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <signal.h>
using namespace std;
#include "drive.h"
#include "smart.h"
#include "shred.h"
#include "delete.h"
#include "tui.h"
#include "printer.h"
#include "logger/logger.h"
#include "wipe.h"
extern Logger *logging;
template <typename T, typename I>
T *iterator_to_pointer(I i)
template <typename T, typename I> T* iterator_to_pointer(I i)
{
return (&(*i));
}
@ -78,29 +30,20 @@ T *iterator_to_pointer(I i)
class reHDD
{
protected:
public:
reHDD(void);
static void app_logic();
void app_logic();
private:
static void searchDrives(list<Drive> *plistDrives);
static void printDrives(list<Drive> *plistDrives);
static void startShredAllDrives(list<Drive> *plistDrives);
static void updateShredMetrics(list<Drive> *plistDrives);
static void filterIgnoredDrives(list<Drive> *plistDrives);
static void filterInvalidDrives(list<Drive> *plistDrives);
static void filterNewDrives(list<Drive> *plistOldDrives, list<Drive> *plistNewDrives);
static void addSMARTData(list<Drive> *plistDrives);
static void ThreadScanDevices();
static void ThreadUserInput();
static void ThreadShred(Drive *const pDrive);
static void ThreadDelete();
static void ThreadCheckFrozenDrives();
static void handleArrowKey(TUI::UserInput userInput);
static void handleEnter();
static void handleESC();
static void handleAbort();
static Drive *getSelectedDrive();
vector <Drive> vecDrives; //stores all drive data
void searchDrives(vector <Drive>* pvecDrives);
void printDrives(vector <Drive>* pvecDrives);
void filterIgnoredDrives(vector <Drive>* pvecDrives);
void addSMARTData(vector <Drive>* pvecDrives);
};
#endif // REHDD_H_
#endif // REHDD_H_

View File

@ -1,55 +0,0 @@
/**
* @file shred.h
* @brief shred drive
* @author hendrik schutter
* @date 03.05.2020
*/
#ifndef SHRED_H_
#define SHRED_H_
#include "reHDD.h"
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#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;
class Shred
{
protected:
public:
Shred();
~Shred();
int shredDrive(Drive *drive, int *ipSignalFd);
private:
fileDescriptor randomSrcFileDiscr;
fileDescriptor driveFileDiscr;
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;
double d32TmpPercent = 0.0;
inline double calcProgress();
int iRewindDrive(fileDescriptor file);
unsigned long getDriveSizeInBytes(fileDescriptor file);
unsigned int uiCalcChecksum(fileDescriptor file, Drive *drive, int *ipSignalFd);
void cleanup();
};
#endif // SHRED_H_

View File

@ -13,13 +13,13 @@
class SMART
{
protected:
public:
static void readSMARTData(Drive *drive);
static void readSMARTData(Drive* drive);
private:
SMART(void);
static uint8_t parseExitStatus(string sLine);
static void parseModelFamily(string sLine);
static void parseModelName(string sLine);
static void parseSerial(string sLine);
@ -27,16 +27,14 @@ 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;
static string serial;
static uint64_t capacity;
static uint32_t errorCount;
static uint32_t powerOnHours;
static uint32_t powerCycle;
static uint32_t temperature;
static string modelFamily;
static string modelName;
static string serial;
static uint64_t capacity;
static uint32_t errorCount;
static uint32_t powerOnHours;
static uint32_t powerCycle;
};
#endif // SMART_H_
#endif // SMART_H_

View File

@ -1,82 +0,0 @@
/**
* @file tui.h
* @brief display user interface
* @author hendrik schutter
* @date 03.08.2020
*/
#ifndef TUI_H_
#define TUI_H_
#include "reHDD.h"
#define COLOR_AREA_STDSCR 1
#define COLOR_AREA_OVERVIEW 2
#define COLOR_AREA_ENTRY_EVEN 3
#define COLOR_AREA_ENTRY_ODD 4
#define COLOR_AREA_ENTRY_SELECTED 5
#define COLOR_AREA_DETAIL 6
class TUI
{
protected:
public:
enum UserInput
{
UpKey,
DownKey,
Abort,
Shred,
ShredAll,
Delete,
Enter,
ESC,
Undefined
};
struct MenuState
{
bool bAbort;
bool bShred;
bool bDelete;
bool bConfirmShred;
bool bConfirmDelete;
};
TUI(void);
static void initTUI();
void updateTUI(list<Drive> *plistDrives, uint8_t u8SelectedEntry);
static enum UserInput readUserInput();
private:
static string sCpuUsage;
static string sRamUsage;
static string sLocalTime;
WINDOW *overview;
WINDOW *systemview;
WINDOW *detailview;
WINDOW *menuview;
WINDOW *dialog;
WINDOW *smartWarning;
static void centerTitle(WINDOW *pwin, const char *title);
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, 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, 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);
static void vTruncateText(string *psText, uint16_t u16MaxLenght);
};
#endif // TUI_H_

25
include/wipe.h Normal file
View File

@ -0,0 +1,25 @@
/**
* @file wipe.h
* @brief wipe drive
* @author hendrik schutter
* @date 03.05.2020
*/
#ifndef WIPE_H_
#define WIPE_H_
#include "reHDD.h"
class Wipe
{
protected:
public:
static void wipeDrive(Drive* drive);
private:
Wipe(void);
};
#endif // WIPE_H_

View File

@ -8,22 +8,19 @@ 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 = lib
LIBS =
# General compiler flags
COMPILE_FLAGS = -std=c++23 -Wall -Wextra -g
COMPILE_FLAGS = -std=c++11 -Wall -Wextra -g
# Additional release-specific flags
RCOMPILE_FLAGS = -D NDEBUG -Ofast
RCOMPILE_FLAGS = -D NDEBUG
# Additional debug-specific flags
DCOMPILE_FLAGS = -D DEBUG
# Add additional include paths
INCLUDES = include
# General linker settings
LINK_FLAGS = -Llib -lpthread -lncurses -ltfng
LINK_FLAGS =
# 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
@ -161,7 +158,6 @@ dirs:
@echo "Creating directories"
@mkdir -p $(dir $(OBJECTS))
@mkdir -p $(BIN_PATH)
@mkdir -p $(LIBS)
# Removes all build files
.PHONY: clean
@ -171,22 +167,15 @@ 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 $@
@ -210,7 +199,6 @@ $(BUILD_PATH)/%.o: $(SRC_PATH)/%.$(SRC_EXT)
docs:
@$(RM) -r $(DOCDIR)/html
@doxygen $(DOCDIR)/doxyfile
.PHONY: style
style:
@bash astyle.sh

View File

@ -1,17 +0,0 @@
[Unit]
Description=reHDD on tty1
[Service]
WorkingDirectory=/root/reHDD/
ExecStart=
ExecStart=-/root/reHDD/reHDD
StandardInput=tty
StandardOutput=tty
Restart=always
RestartSec=1
UtmpIdentifier=tty1
TTYPath=/dev/tty1
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
SendSIGHUP=yes

View File

@ -1,17 +0,0 @@
[Unit]
Description=dmesg on tty2
[Service]
WorkingDirectory=/usr/bin/
ExecStart=
ExecStart=-/usr/bin/dmesg -wHT
StandardInput=tty
StandardOutput=tty
Restart=always
RestartSec=1
UtmpIdentifier=tty2
TTYPath=/dev/tty2
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
SendSIGHUP=yes

View File

@ -1,17 +0,0 @@
[Unit]
Description=htop on tty3
[Service]
WorkingDirectory=/usr/bin/
ExecStart=
ExecStart=-/usr/bin/htop
StandardInput=tty
StandardOutput=tty
Restart=always
RestartSec=1
UtmpIdentifier=tty3
TTYPath=/dev/tty3
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
SendSIGHUP=yes

View File

@ -1,27 +0,0 @@
#!/bin/bash
cd /root/reHDD/scripts/
chmod +x reHDDLogUploader.bash
cp reHDDLogUploader.service /lib/systemd/system/reHDDLogUploader.service
cp reHDDLogUploader.timer /lib/systemd/system/reHDDLogUploader.timer
systemctl daemon-reload
systemctl enable /lib/systemd/system/reHDDLogUploader.timer
chmod +x reHDDStartHelper.bash
cp reHDDStartHelper.service /lib/systemd/system/reHDDStartHelper.service
systemctl daemon-reload
systemctl enable /lib/systemd/system/reHDDStartHelper.service
mkdir -p /lib/systemd/system/getty@tty1.service.d
cp getty@tty1.service.d_override.conf /lib/systemd/system/getty@tty1.service.d/override.conf
systemctl daemon-reload
mkdir -p /lib/systemd/system/getty@tty2.service.d
cp getty@tty2.service.d_override.conf /lib/systemd/system/getty@tty2.service.d/override.conf
systemctl daemon-reload
mkdir -p /lib/systemd/system/getty@tty3.service.d
cp getty@tty3.service.d_override.conf /lib/systemd/system/getty@tty3.service.d/override.conf
systemctl daemon-reload

View File

@ -1,6 +0,0 @@
#!/bin/bash
# remove comment for the following to activate log telemetie
curl -k -T /root/reHDD/reHDD.log -u "__Place_your_token_here__:" -H 'X-Requested-With: XMLHttpRequest' https://schuttercloud.com/public.php/webdav/`echo $(date '+%Y-%m-%d_%H-%M')`_reHDD.log
rm -f /root/reHDD/reHDD.log

View File

@ -1,18 +0,0 @@
[Unit]
Description=reHDD log uploader
After=syslog.target
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=root
Group=root
RemainAfterExit=yes
ExecStart=/usr/bin/bash /root/reHDD/scripts/reHDDLogUploader.bash
[Install]
WantedBy=multi-user.target

View File

@ -1,11 +0,0 @@
[Unit]
Description=reHDD log uploader timer
[Timer]
OnActiveSec=30s
OnBootSec=10min
OnUnitActiveSec=12h
[Install]
WantedBy=basic.target

View File

@ -1,4 +0,0 @@
#!/bin/bash
dmesg -n 1 #disable overlay if a drive is attached/detached

View File

@ -1,16 +0,0 @@
[Install]
WantedBy=multi-user.target
[Unit]
Description=reHDD start helper
After=syslog.target
[Service]
Type=oneshot
User=root
Group=root
RemainAfterExit=yes
ExecStart=/usr/bin/bash /root/reHDD/scripts/reHDDStartHelper.bash
[Install]
WantedBy=multi-user.target

View File

@ -1,36 +0,0 @@
#! /usr/bin/bash
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 already"
else
cp /root/reHDD/ignoreDrives.conf /root/ignoreDrives.conf
fi
git reset
git stash force
git stash
git checkout master
git pull
git submodule init
git submodule update
make clean
make release
cp /root/ignoreDrives.conf /root/reHDD/ignoreDrives.conf
systemctl start /lib/systemd/system/getty@tty1.service.d

View File

@ -1,42 +0,0 @@
/**
* @file delete.cpp
* @brief delete drive
* @author hendrik schutter
* @date 23.08.2020
*/
#include "../include/reHDD.h"
/**
* \brief delete drive with wipefs
* \param pointer of Drive instance
* \return void
*/
void Delete::deleteDrive(Drive *drive)
{
size_t len = 0; // lenght of found line
char *cLine = NULL; // found line
#ifndef DRYRUN
string sCMD = ("wipefs -af ");
sCMD.append(drive->getPath());
sCMD.append("*");
#endif
#ifdef DRYRUN
// cout << "dryrun for " << drive->getPath() << endl;
string sCMD = ("echo");
#endif
const char *cpComand = sCMD.c_str();
// cout << "delete: " << cpComand << endl;
FILE *deleteCmdOutput = popen(cpComand, "r");
while ((getline(&cLine, &len, deleteCmdOutput)) != -1)
{
// wipefs running
}
pclose(deleteCmdOutput);
}

View File

@ -14,105 +14,36 @@ string Drive::getPath(void)
string Drive::getModelFamily(void)
{
return sSmartData.sModelFamily;
return sModelFamily;
}
string Drive::getModelName(void)
{
return sSmartData.sModelName;
return sModelName;
}
string Drive::getSerial(void)
{
return sSmartData.sSerial;
return sSerial;
}
uint64_t Drive::getCapacity(void)
{
return sSmartData.u64Capacity;
return u64Capacity;
}
uint32_t Drive::getErrorCount(void)
{
return sSmartData.u32ErrorCount;
return u32ErrorCount;
}
uint32_t Drive::getPowerOnHours(void)
{
return sSmartData.u32PowerOnHours;
return u32PowerOnHours;
}
uint32_t Drive::getPowerCycles(void)
{
return sSmartData.u32PowerCycles;
}
uint32_t Drive::getTemperature(void)
{
return sSmartData.u32Temperature;
}
string Drive::sCapacityToText()
{
char acBuffer[16];
double dSize = (double)getCapacity();
uint16_t u16UnitIndex = 0;
const char *units[] = {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
while (dSize >= 1000) // using the marketing capacity
{
dSize /= 1000;
u16UnitIndex++;
}
sprintf(acBuffer, "%.*f %s", u16UnitIndex - 3, dSize, units[u16UnitIndex]);
return acBuffer;
}
string Drive::sErrorCountToText()
{
return to_string(getErrorCount());
}
string Drive::sPowerOnHoursToText()
{
double dDays = 0U;
double dYears = 0U;
uint32_t u32Hours = getPowerOnHours();
stringstream streamDays;
stringstream streamYears;
dDays = (double)((double)u32Hours / (double)24U);
dYears = (double)((double)u32Hours / (double)8760U);
streamDays << fixed << setprecision(0) << dDays;
streamYears << fixed << setprecision(1) << dYears;
string sRet = to_string(getPowerOnHours()) + " hours or " + streamDays.str() + " days or " + streamYears.str() + " years";
return sRet;
}
string Drive::sPowerCyclesToText()
{
return to_string(getPowerCycles());
}
string Drive::sTemperatureToText()
{
return to_string(getTemperature()) + " C";
;
}
void Drive::setTaskPercentage(double d32TaskPercentage)
{
if (d32TaskPercentage <= 100)
{
this->d32TaskPercentage = d32TaskPercentage;
this->setTimestamp(); // set timestamp for this progress for detecting a frozen drive
}
}
double Drive::getTaskPercentage(void)
{
return this->d32TaskPercentage;
return u32PowerCycles;
}
/**
@ -124,66 +55,21 @@ 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,
string modelName,
string serial,
uint64_t capacity,
uint32_t errorCount,
uint32_t powerOnHours,
uint32_t powerCycle,
uint32_t temperature)
void Drive::setDriveSMARTData( string modelFamily,
string modelName,
string serial,
uint64_t capacity,
uint32_t errorCount,
uint32_t powerOnHours,
uint32_t 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()
{
time(&this->u32Timestamp);
}
void Drive::setActionStartTimestamp()
{
time(&this->u32TimestampTaskStart);
}
time_t Drive::getActionStartTimestamp()
{
return this->u32TimestampTaskStart;
}
void Drive::calculateTaskDuration()
{
time_t u32localtime;
time(&u32localtime);
this->u32TaskDuration = u32localtime - this->u32TimestampTaskStart;
}
time_t Drive::getTaskDuration()
{
return this->u32TaskDuration;
}
void Drive::checkFrozenDrive(void)
{
time_t u32localtime;
time(&u32localtime);
if ((u32localtime - this->u32Timestamp) >= (FROZEN_TIMEOUT * 60) && (this->u32Timestamp > 0) && (this->getTaskPercentage() < 100.0))
{
Logger::logThis()->warning("Drive Frozen: " + this->getModelName() + " " + this->getSerial());
this->bWasDeleted = false;
this->bWasShredded = false;
this->state = Drive::FROZEN;
}
this->sModelFamily = modelFamily;
sModelName = modelName;
sSerial = serial;
u64Capacity = capacity;
u32ErrorCount = errorCount;
u32PowerOnHours = powerOnHours;
u32PowerCycles = powerCycle;
}

View File

@ -1,229 +0,0 @@
/**
* @file logger.cpp
* @brief cppSimpleLogger implementation
* @author hendrik schutter
* @date 04.09.2020
*/
#include "../../include/reHDD.h" //for logger settings
#include "../../include/logger/logger.h"
using namespace std;
string version = "0.2.1"; // logger version
bool Logger::instanceFlag = false;
Logger *Logger::single = NULL;
/**
* \brief create new logger instance
* \return instance of Logger
*/
Logger::Logger()
{
this->logPath = LOG_PATH;
writeLog(menuLine('+', MENU_LINE_SIZE));
writeLog(padStringMenu('+', " ", MENU_LINE_SIZE));
writeLog(padStringMenu('+', ("Device: " + string(DEVICE_ID) + " -- " + string(DESCRIPTION)), MENU_LINE_SIZE));
writeLog(padStringMenu('+', " ", MENU_LINE_SIZE));
writeLog(padStringMenu('+', ("Software ID: " + string(SOFTWARE_VERSION) + " -- Build time: " + __DATE__ + " " + __TIME__), MENU_LINE_SIZE));
writeLog(padStringMenu('+', " ", MENU_LINE_SIZE));
writeLog(padStringMenu('+', ("Hardware ID: " + string(HARDWARE_VERSION) + " -- MAC: " + getMacAddress()), MENU_LINE_SIZE));
writeLog(padStringMenu('+', " ", MENU_LINE_SIZE));
writeLog(padStringMenu('+', ("cppSimpleLogger -- available from https://git.mosad.xyz/localhorst/cppSimpleLogger -- Version: " + version), MENU_LINE_SIZE));
writeLog(padStringMenu('+', " ", MENU_LINE_SIZE));
writeLog(menuLine('+', MENU_LINE_SIZE));
newLine();
info("Created new log file");
newLine();
}
/**
* \brief deconstructor
* \return void
*/
Logger::~Logger()
{
instanceFlag = false;
}
/**
* \brief log info
* \param log-text as string
* \return void
*/
void Logger::info(string s)
{
string tmp = getTimestamp() + " [INFO] " + s;
writeLog(tmp);
}
/**
* \brief log warning
* \param log-text as string
* \return void
*/
void Logger::warning(string s)
{
string tmp = getTimestamp() + " [WARNING] " + s;
writeLog(tmp);
}
/**
* \brief log error
* \param log-text as string
* \return void
*/
void Logger::error(string s)
{
string tmp = getTimestamp() + " [ERROR] " + s;
writeLog(tmp);
}
/**
* \brief write to log file
* \param log as string
* \return void
*/
void Logger::writeLog(string s)
{
ofstream logFile;
Logger::mtxLog.lock(); // lock this section for other threads
logFile.open(this->logPath, ios_base::app);
logFile << (s + "\n"); // append to existing file
logFile.close();
Logger::mtxLog.unlock(); // unlock this section for other threads
}
/**
* \brief write new line to log file
* \return void
*/
void Logger::newLine()
{
writeLog(" ");
}
/**
* \brief get timestamp (system time) as string
* \param void
* \return string timestamp (formatted)
*/
string Logger::getTimestamp()
{
struct tm *timeinfo;
struct timeval tv;
int millisec;
char cpDate[80];
char buffer[120];
gettimeofday(&tv, NULL);
millisec = lrint(tv.tv_usec / 1000.0); // Round to nearest millisec
if (millisec >= 1000) // Allow for rounding up to nearest second
{
millisec -= 1000;
tv.tv_sec++;
}
timeinfo = localtime(&tv.tv_sec);
strftime(cpDate, 80, "%d/%m/%Y %T", timeinfo);
sprintf(buffer, "%s.%03d", cpDate, millisec);
return buffer;
}
/**
* \brief get MAC address (system first eth0 interface) as string
* \param void
* \return string MAC address (formatted)
*/
string Logger::getMacAddress()
{
struct ifreq ifr;
int s = socket(AF_INET, SOCK_STREAM, 0);
strcpy(ifr.ifr_name, "eth0");
if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
{
strcpy(ifr.ifr_name, "eno1");
}
unsigned char *hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data;
char buffer[80];
sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X", hwaddr[0], hwaddr[1], hwaddr[2],
hwaddr[3], hwaddr[4], hwaddr[5]);
close(s);
string tmp = buffer;
return tmp;
}
/**
* \brief format menu text in center
* \param char for border
* \param menu text
* \param size of menu line
* \return string menu line
*/
string Logger::padStringMenu(char cBorder, string text, uint8_t u8LineLenght)
{
string result(1, cBorder);
uint8_t u8TextSize = text.length();
uint8_t u8Padding = ((u8LineLenght - u8TextSize) / 2);
for (uint8_t i = 0; i < u8Padding; i++)
{
result.append(" ");
}
result.append(text);
while ((uint8_t)result.length() < (u8LineLenght - 1))
{
result.append(" ");
}
result.append(string(1, cBorder));
return result;
}
/**
* \brief format a separator
* \param char for border
* \param size of menu line
* \return string menu line
*/
string Logger::menuLine(char cBorder, uint8_t u8LineLenght)
{
string result(1, cBorder);
while ((uint8_t)result.length() < u8LineLenght)
{
result.append(string(1, cBorder));
}
return result;
}
/**
* \brief return a instance of the logger
* \return logger obj
*/
Logger *Logger::logThis()
{
if (!instanceFlag)
{
single = new Logger(); // create new obj
instanceFlag = true;
return single;
}
else
{
return single; // return existing obj
}
}

View File

@ -14,9 +14,9 @@
*/
int main(void)
{
// cout << "refurbishingHddTool" << endl;
cout << "refurbishingHddTool" << endl;
reHDD *app = new reHDD();
reHDD* app = new reHDD();
app->app_logic();
return EXIT_SUCCESS;
}

View File

@ -1,84 +0,0 @@
/**
* @file printer.cpp
* @brief Send drive data to printer service using ipc msg queue
* @author Hendrik Schutter
* @date 24.11.2022
*/
#include "../include/reHDD.h"
bool Printer::instanceFlag = false;
Printer *Printer::single = NULL;
/**
* \brief create new Printer instance
* \param path to log file
* \param struct with data
* \return instance of Printer
*/
Printer::Printer()
{
if (-1 == (this->msqid = msgget((key_t)IPC_MSG_QUEUE_KEY, IPC_CREAT | 0666)))
{
Logger::logThis()->error("Printer: Create mgs queue failed!");
}
}
/**
* \brief deconstructor
* \return void
*/
Printer::~Printer()
{
instanceFlag = false;
}
/**
* \brief send data to msg queue
* \return void
*/
void Printer::print(Drive *drive)
{
t_msgQueueData msgQueueData;
msgQueueData.msg_queue_type = 1;
sprintf(msgQueueData.driveData.caDriveIndex, "%i", 42); // TODO: get from tui
sprintf(msgQueueData.driveData.caDriveState, "shredded");
strcpy(msgQueueData.driveData.caDriveModelFamily, drive->getModelFamily().c_str());
strcpy(msgQueueData.driveData.caDriveModelName, drive->getModelName().c_str());
sprintf(msgQueueData.driveData.caDriveCapacity, "%li", drive->getCapacity());
strcpy(msgQueueData.driveData.caDriveSerialnumber, drive->getSerial().c_str());
sprintf(msgQueueData.driveData.caDriveHours, "%i", drive->getPowerOnHours());
sprintf(msgQueueData.driveData.caDriveCycles, "%i", drive->getPowerCycles());
sprintf(msgQueueData.driveData.caDriveErrors, "%i", drive->getErrorCount());
sprintf(msgQueueData.driveData.caDriveShredTimestamp, "%li", drive->getActionStartTimestamp());
sprintf(msgQueueData.driveData.caDriveShredDuration, "%li", drive->getTaskDuration());
sprintf(msgQueueData.driveData.caDriveReHddVersion, REHDD_VERSION);
if (-1 == msgsnd(this->msqid, &msgQueueData, sizeof(t_msgQueueData) - sizeof(long), 0))
{
Logger::logThis()->error("Printer: Send mgs queue failed!");
}
else
{
Logger::logThis()->info("Printer: print triggered - Drive: " + drive->getSerial());
}
}
/**
* \brief return a instance of the printer
* \return printer obj
*/
Printer *Printer::getPrinter()
{
if (!instanceFlag)
{
single = new Printer(); // create new obj
instanceFlag = true;
return single;
}
else
{
return single; // return existing obj
}
}

View File

@ -7,22 +7,6 @@
#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 mxDrives;
list<Drive> listNewDrives; // store found drives that are updated every 5sec
static list<Drive> listDrives; // stores all drive data from scan thread
TUI *ui;
static uint8_t u8SelectedEntry;
static fd_set selectSet;
/**
* \brief app constructor
* \param void
@ -30,7 +14,7 @@ static fd_set selectSet;
*/
reHDD::reHDD(void)
{
u8SelectedEntry = 0U;
cout << "created app" << endl;
}
/**
@ -40,568 +24,177 @@ reHDD::reHDD(void)
*/
void reHDD::app_logic(void)
{
ui = new TUI();
ui->initTUI();
cout << "app logic" << endl;
pipe(fdNewDrivesInformPipe);
pipe(fdShredInformPipe);
searchDrives(&vecDrives); //search for new drives and store them in list
filterIgnoredDrives(&vecDrives); //filter out ignored drives
addSMARTData(&vecDrives); //add S.M.A.R.T. Data to the drives
printDrives(&vecDrives); //print currently attached drives
thread thDevices(ThreadScanDevices); // start thread that scans for drives
thread thUserInput(ThreadUserInput); // start thread that reads user input
thread thCheckFrozenDrives(ThreadCheckFrozenDrives); // start thread that checks timeout for drives
size_t u64SelectedDriveIndex = 0U;
size_t u64DriveVecSize = (vecDrives.size());
while (1)
{
FD_ZERO(&selectSet);
FD_SET(fdNewDrivesInformPipe[0], &selectSet);
FD_SET(fdShredInformPipe[0], &selectSet);
cout << "Select drive to wipe:" << endl;
cin >> u64SelectedDriveIndex;
cout << "Selected drive index: " << u64SelectedDriveIndex << endl;
select(FD_SETSIZE, &selectSet, NULL, NULL, NULL);
if (FD_ISSET(fdNewDrivesInformPipe[0], &selectSet))
{
mxDrives.lock();
char dummy;
read(fdNewDrivesInformPipe[0], &dummy, 1);
filterNewDrives(&listDrives, &listNewDrives); // filter and copy to app logic vector
printDrives(&listDrives);
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
thDevices.join();
thUserInput.join();
thCheckFrozenDrives.join();
}
Drive *reHDD::getSelectedDrive()
{
if (u8SelectedEntry < listDrives.size())
{
list<Drive>::iterator it = listDrives.begin();
advance(it, u8SelectedEntry);
return &(*it);
}
else
{
Logger::logThis()->warning("selected drive not present");
return {};
}
}
void reHDD::ThreadScanDevices()
{
while (true)
{
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
filterInvalidDrives(&listNewDrives); // filter out drives that report zero capacity
mxDrives.unlock();
write(fdNewDrivesInformPipe[1], "A", 1);
sleep(5); // sleep 5 sec
}
}
void reHDD::ThreadCheckFrozenDrives()
{
while (true)
{
mxDrives.lock();
for (auto it = begin(listDrives); it != end(listDrives); ++it)
{
if (it->state == Drive::SHRED_ACTIVE)
{
it->checkFrozenDrive();
}
}
mxDrives.unlock();
sleep(13); // sleep 13 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(&listDrives, u8SelectedEntry);
break;
case TUI::UserInput::UpKey:
// cout << "Up" << endl;
handleArrowKey(TUI::UserInput::UpKey);
ui->updateTUI(&listDrives, u8SelectedEntry);
break;
case TUI::UserInput::Undefined:
// cout << "Undefined" << endl;
break;
case TUI::UserInput::Abort:
// cout << "Abort" << endl;
handleAbort();
ui->updateTUI(&listDrives, u8SelectedEntry);
break;
case TUI::UserInput::Delete:
// cout << "Delete" << endl;
if (getSelectedDrive() != nullptr)
{
if (getSelectedDrive()->state == Drive::NONE)
{
getSelectedDrive()->state = Drive::DELETE_SELECTED;
}
}
ui->updateTUI(&listDrives, u8SelectedEntry);
break;
case TUI::UserInput::Shred:
// cout << "Shred" << endl;
if (getSelectedDrive() != nullptr)
{
if (getSelectedDrive()->state == Drive::NONE)
{
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:
// cout << "Enter" << endl;
handleEnter();
ui->updateTUI(&listDrives, u8SelectedEntry);
break;
case TUI::UserInput::ESC:
// cout << "ESC" << endl;
handleESC();
ui->updateTUI(&listDrives, u8SelectedEntry);
break;
default:
break;
}
}
}
void reHDD::ThreadShred(Drive *const pDrive)
{
if (pDrive != nullptr)
{
pDrive->setActionStartTimestamp(); // save timestamp at start of shredding
Shred *pShredTask = new Shred(); // create new shred task
pShredTask->shredDrive(pDrive, &fdShredInformPipe[1]); // start new shred task
delete pShredTask; // delete shred task
ui->updateTUI(&listDrives, u8SelectedEntry);
}
}
void reHDD::ThreadDelete()
{
if (getSelectedDrive() != nullptr)
{
getSelectedDrive()->setActionStartTimestamp(); // save timestamp at start of deleting
Delete::deleteDrive(getSelectedDrive()); // blocking, no thread
getSelectedDrive()->state = Drive::TaskState::NONE; // delete finished
getSelectedDrive()->bWasDeleted = true;
Logger::logThis()->info("Finished delete for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial());
ui->updateTUI(&listDrives, u8SelectedEntry);
}
}
void reHDD::filterNewDrives(list<Drive> *plistOldDrives, list<Drive> *plistNewDrives)
{
list<Drive>::iterator itOld; // Iterator for current (old) drive list
list<Drive>::iterator itNew; // Iterator for new drive list that was created from to scan thread
// remove offline old drives from previously run
for (itOld = plistOldDrives->begin(); itOld != plistOldDrives->end();)
{
if (itOld->bIsOffline == true)
{
Logger::logThis()->warning("Offline drive found: " + itOld->getPath());
itOld = plistOldDrives->erase(itOld);
/*
if(plistOldDrives->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;
}
if(u64SelectedDriveIndex < (u64DriveVecSize)) {
Wipe::wipeDrive(&vecDrives[u64SelectedDriveIndex]);
}
// search offline drives and mark them
for (itOld = plistOldDrives->begin(); itOld != plistOldDrives->end(); ++itOld)
{
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 already attached: " + itNew->getModelName());
#endif
itNew = plistNewDrives->erase(itNew); // This drive is already attached, remove from new list
}
else
{
++itNew;
}
}
}
// mark offline old drives
for (itOld = plistOldDrives->begin(); itOld != plistOldDrives->end(); ++itOld)
{
if (itOld->bIsOffline == true)
{
// 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
}
}
// add new drives to drive list
for (itNew = plistNewDrives->begin(); itNew != plistNewDrives->end(); ++itNew)
{
plistOldDrives->push_back(*itNew);
// Logger::logThis()->info("Add new drive: " + itNew->getModelName());
}
plistNewDrives->clear();
}
/**
* \brief search attached drives on /dev/sd*
* \param pointer of list <Drive>* plistDrives
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
void reHDD::searchDrives(list<Drive> *plistDrives)
void reHDD::searchDrives(vector <Drive>* pvecDrives)
{
// Logger::logThis()->info("--> search drives <--");
char *cLine = NULL;
cout << "search drives ..." << endl;
char * cLine = NULL;
size_t len = 0;
FILE *outputfileHwinfo = popen("lsblk -e 11 -d -o NAME", "r");
FILE* outputfileHwinfo = popen("hwinfo --short --disk", "r");
if (outputfileHwinfo == NULL)
{
Logger::logThis()->error("Unable to scan attached drives");
exit(EXIT_FAILURE);
}
while ((getline(&cLine, &len, outputfileHwinfo)) != -1)
{
if (string(cLine).length() == 4)
if (string(cLine).find("/dev/sd") != string::npos)
{
Drive *tmpDrive = new Drive("/dev/" + string(cLine).substr(0, 3));
tmpDrive->state = Drive::NONE;
tmpDrive->bIsOffline = false;
plistDrives->push_back(*tmpDrive);
// Logger::logThis()->info("SATA drive found: " + tmpDrive->getPath());
}
if (string(cLine).length() == 8)
{
Drive *tmpDrive = new Drive("/dev/" + string(cLine).substr(0, 7));
tmpDrive->state = Drive::NONE;
tmpDrive->bIsOffline = false;
plistDrives->push_back(*tmpDrive);
// Logger::logThis()->info("NVME drive found: " + tmpDrive->getPath());
Drive* tmpDrive = new Drive(string(cLine).substr (2,8));
pvecDrives->push_back(*tmpDrive);
}
}
pclose(outputfileHwinfo);
fclose(outputfileHwinfo);
}
/**
* \brief filter out drives that are listed in "ignoreDrives.conf"
* \param pointer of list <Drive>* plistDrives
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
void reHDD::filterIgnoredDrives(list<Drive> *plistDrives)
void reHDD::filterIgnoredDrives(vector <Drive>* pvecDrives)
{
list<tuple<string>> vtlIgnoredDevices; // store drives from ignore file
ifstream input("ignoreDrives.conf"); // read ignore file
string sDelimiter = ":";
string sIgnoredDrivePath;
string sIgnoredDriveUUID;
for (string sLine; getline(input, sLine);)
vector<tuple<string, string>> vtlIgnoredDevices; //store drives from ingnore file
ifstream input( "ignoreDrives.conf" ); //read ingnore file
for(string sLine; getline( input, 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 ignore file
for (auto row : vtlIgnoredDevices)
{
list<Drive>::iterator it;
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
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)
{
auto it = pvecDrives->begin();
while (it != pvecDrives->end())
{
it++;
string sUUID;
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)
if (!get<0>(row).compare(it->getPath())) //find same drive based on path
{
exit(EXIT_FAILURE);
}
while ((getline(&cLine, &len, outputfileBlkid)) != -1) // parse UUID from blkid
{
if (string(cLine).find("PTUUID") != string::npos)
// cout << "Same drive path found" << endl;
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)
{
string sBlkidOut = string(cLine);
sBlkidOut.erase(0, 18);
sBlkidOut.erase(8, sBlkidOut.length());
sUUID = sBlkidOut;
// cout << "blkid uuid:" << sUUID << endl;
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);
}
}
pclose(outputfileBlkid);
// cout << "blkid uuid:" << sUUID << endl;
if (!get<0>(row).compare(sUUID)) // compare uuid from ignore file and uuid from drive
{
// same uuid found than in ignore file --> ignore this drive
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("same uuid found than in ignore file --> ignore this drive: " + it->getPath());
#endif
it = plistDrives->erase(it);
it--;
}
}
}
}
/**
* \brief filter out drives that are not indented for processing
* \param pointer of list <Drive>* plistDrives
* \return void
*/
void reHDD::filterInvalidDrives(list<Drive> *plistDrives)
{
list<Drive>::iterator it;
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
{
if (it->getCapacity() == 0U)
{
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Drive reports zero capacity --> ignore this drive: " + it->getPath());
#endif
it = plistDrives->erase(it);
it--;
}
}
}
/**
* \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
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
void reHDD::printDrives(list<Drive> *plistDrives)
void reHDD::printDrives(vector <Drive>* pvecDrives)
{
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("------------DRIVES START------------");
// cout << "------------DRIVES---------------" << endl;
list<Drive>::iterator it;
uint8_t u8Index = 0;
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
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;*/
ostringstream address;
address << (void const *)&(*it);
Logger::logThis()->info(to_string(u8Index++) + ": " + it->getPath() + " - " + it->getModelFamily() + " - " + it->getSerial() + " @" + address.str());
}
Logger::logThis()->info("------------DRIVES END--------------");
// cout << "---------------------------------" << endl;
#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;
}
}
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 list <Drive>* plistDrives
* \param pointer of vector <Drive>* pvecDrives
* \return void
*/
void reHDD::addSMARTData(list<Drive> *plistDrives)
void reHDD::addSMARTData(vector <Drive>* pvecDrives)
{
list<Drive>::iterator it;
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
vector <Drive>::iterator it;
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it)
{
Drive *pTmpDrive = iterator_to_pointer<Drive, std::list<Drive>::iterator>(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)listDrives.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;
}
// Logger::logThis()->info("ArrowKey - selected drive: " + to_string(u8SelectedEntry));
}
void reHDD::handleEnter()
{
if (getSelectedDrive() != nullptr)
{
if (getSelectedDrive()->state == Drive::TaskState::SHRED_SELECTED)
{
Logger::logThis()->info("Started shred/check for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial());
getSelectedDrive()->state = Drive::TaskState::SHRED_ACTIVE;
// task for drive is running --> don´t show more task options
Drive *pTmpDrive = getSelectedDrive();
thread(ThreadShred, pTmpDrive).detach();
}
if (getSelectedDrive()->state == Drive::TaskState::DELETE_SELECTED)
{
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
thread(ThreadDelete).detach();
}
}
}
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;
Logger::logThis()->info("Abort-Shred-Signal for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial());
// task for drive is running --> remove selection
}
}
}
}

View File

@ -1,303 +0,0 @@
/**
* @file shred.cpp
* @brief shred drive
* @author hendrik schutter
* @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()
{
}
Shred::~Shred()
{
}
/**
* \brief shred drive with shred
* \param pointer of Drive instance
* \return void
*/
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++)
{
if (drive->state != Drive::SHRED_ACTIVE)
{
return 0;
}
drive->setTaskPercentage(i + 0.05);
write(*ipSignalFd, "A", 1);
usleep(20000);
}
#endif
#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);
if (randomSrcFileDiscr == -1)
{
std::string errorMsg(strerror(randomSrcFileDiscr));
Logger::logThis()->error("Shred-Task: Open random source failed! " + errorMsg + " - Drive: " + drive->getSerial());
perror(randomsrc);
cleanup();
return -1;
}
// open disk
driveFileDiscr = open(cpDrivePath, O_RDWR | O_LARGEFILE);
if (driveFileDiscr == -1)
{
std::string errorMsg(strerror(driveFileDiscr));
Logger::logThis()->error("Shred-Task: Open drive failed! " + errorMsg + " - Drive: " + drive->getSerial());
perror(cpDrivePath);
cleanup();
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());
#endif
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
if (uiShredIterationCounter == (SHRED_ITERATIONS - 1))
{
// 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 (uiShredIterationCounter != (SHRED_ITERATIONS - 1))
{
// NOT last shred iteration --> generate new random data
tfng_prng_genrandom(caTfngData, TFNG_DATA_SIZE);
}
if ((ulDriveByteSize - ulDriveByteCounter) < CHUNK_SIZE)
{
iBytesToShred = (ulDriveByteSize - ulDriveByteCounter);
}
else
{
iBytesToShred = CHUNK_SIZE;
}
int iByteShredded = write(driveFileDiscr, caTfngData, iBytesToShred);
if (iByteShredded <= 0)
{
std::string errorMsg(strerror(iByteShredded));
Logger::logThis()->error("Shred-Task: Write to drive failed! " + errorMsg + " - Drive: " + drive->getSerial());
perror("unable to write random data");
cleanup();
return -1;
}
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);
}
if (drive->state != Drive::SHRED_ACTIVE)
{
drive->setTaskPercentage(0);
d32Percent = 0.00;
d32TmpPercent = 0.00;
ulDriveByteCounter = 0U;
Logger::logThis()->info("Aborted shred for: " + drive->getModelName() + "-" + drive->getSerial());
cleanup();
return -1;
}
// 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 of all shred iteratio
tfng_prng_seedkey(NULL); // reset random generator
drive->bWasShredded = true;
Logger::logThis()->info("Shred-Task finished - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
#ifdef ZERO_CHECK
drive->state = Drive::CHECK_ACTIVE;
Logger::logThis()->info("Check-Task started - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
drive->u32DriveChecksumAfterShredding = uiCalcChecksum(driveFileDiscr, drive, ipSignalFd);
#ifdef LOG_LEVEL_HIGH
if (drive->u32DriveChecksumAferShredding != 0)
{
Logger::logThis()->info("Shred-Task: Checksum not zero: " + to_string(drive->u32DriveChecksumAfterShredding) + " - Drive: " + drive->getSerial());
}
else
{
Logger::logThis()->info("Shred-Task: Checksum zero: " + to_string(drive->u32DriveChecksumAfterShredding) + " - Drive: " + drive->getSerial());
}
#endif
#endif
#endif
cleanup();
if ((drive->state == Drive::SHRED_ACTIVE) || (drive->state == Drive::CHECK_ACTIVE))
{
drive->state = Drive::NONE;
drive->setTaskPercentage(0.0);
Printer::getPrinter()->print(drive);
Logger::logThis()->info("Finished shred/check for: " + drive->getModelName() + "-" + drive->getSerial());
}
return 0;
}
/**
* \brief calc shredding progress in %
* \param current byte index of the drive
* \param current shred iteration
* \return double percentage
*/
double Shred::calcProgress()
{
unsigned int uiMaxShredIteration = SHRED_ITERATIONS;
#ifdef ZERO_CHECK
uiMaxShredIteration++; // increment because we will check after SHRED_ITERATIONS the drive for non-zero bytes
#endif
return (double)(((double)ulDriveByteOverallCount) / ((double)this->ulDriveByteSize * uiMaxShredIteration)) * 100.0f;
}
int Shred::iRewindDrive(fileDescriptor file)
{
if (0 != lseek(file, 0L, SEEK_SET))
{
perror("unable to rewind drive");
return -1;
}
else
{
return 0;
}
}
unsigned long Shred::getDriveSizeInBytes(fileDescriptor file)
{
unsigned long ulDriveSizeTmp = lseek(file, 0L, SEEK_END);
if (0 != iRewindDrive(file))
{
ulDriveSizeTmp = 0U;
}
#ifdef DEMO_DRIVE_SIZE
ulDriveSizeTmp = DEMO_DRIVE_SIZE;
#endif
return ulDriveSizeTmp;
}
unsigned int Shred::uiCalcChecksum(fileDescriptor file, Drive *drive, int *ipSignalFd)
{
unsigned int uiChecksum = 0;
unsigned long ulDriveByteCounter = 0U;
while (ulDriveByteCounter < ulDriveByteSize)
{
int iBytesToCheck = 0;
if ((ulDriveByteSize - ulDriveByteCounter) < CHUNK_SIZE)
{
iBytesToCheck = (ulDriveByteSize - ulDriveByteCounter);
}
else
{
iBytesToCheck = CHUNK_SIZE;
}
int iReadBytes = read(file, caReadBuffer, iBytesToCheck);
for (int iReadBytesCounter = 0U; iReadBytesCounter < iReadBytes; 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.01) || (d32Percent == 100.0))
{
drive->setTaskPercentage(d32TmpPercent);
d32TmpPercent = d32Percent;
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("send progress signal to main loop (check)");
#endif
write(*ipSignalFd, "A", 1);
}
}
drive->bWasChecked = true;
return uiChecksum;
}
void Shred::cleanup()
{
close(driveFileDiscr);
close(randomSrcFileDiscr);
}

View File

@ -14,14 +14,13 @@ 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
* \param pointer of Drive instance
* \return void
*/
void SMART::readSMARTData(Drive *drive)
void SMART::readSMARTData(Drive* drive)
{
modelFamily.clear();
modelName.clear();
@ -30,65 +29,30 @@ void SMART::readSMARTData(Drive *drive)
errorCount = 0U;
powerOnHours = 0U;
powerCycle = 0U;
temperature = 0U;
string sSmartctlCommands[] = {" --json -a ", " --json -d sntjmicron -a ", " --json -d sntasmedia -a ", " --json -d sntrealtek -a "};
size_t len = 0; //lenght of found line
char* cLine = NULL; //found line
for (string sSmartctlCommand : sSmartctlCommands)
string sCMD = ("smartctl --json -a ");
sCMD.append(drive->getPath());
const char* cpComand = sCMD.c_str();
FILE* outputfileSmart = popen(cpComand, "r");
while ((getline(&cLine, &len, outputfileSmart)) != -1)
{
string sCMD = ("smartctl");
sCMD.append(sSmartctlCommand);
sCMD.append(drive->getPath());
const char *cpComand = sCMD.c_str();
string sLine = string(cLine);
FILE *outputfileSmart = popen(cpComand, "r");
size_t len = 0; // length of found line
char *cLine = NULL; // found line
uint8_t status = 255;
while ((getline(&cLine, &len, outputfileSmart)) != -1)
{
string sLine = string(cLine);
status = SMART::parseExitStatus(sLine);
SMART::parseModelFamily(sLine);
SMART::parseModelName(sLine);
SMART::parseSerial(sLine);
SMART::parseCapacity(sLine);
SMART::parseErrorCount(sLine);
SMART::parsePowerOnHours(sLine);
SMART::parsePowerCycle(sLine);
SMART::parseTemperature(sLine);
}
pclose(outputfileSmart);
if (status == 0U)
{
// Found S.M.A.R.T. data with this command
break;
}
SMART::parseModelFamily(sLine);
SMART::parseModelName(sLine);
SMART::parseSerial(sLine);
SMART::parseCapacity(sLine);
SMART::parseErrorCount(sLine);
SMART::parsePowerOnHours(sLine);
SMART::parsePowerCycle(sLine);
}
drive->setDriveSMARTData(modelFamily, modelName, serial, capacity, errorCount, powerOnHours, powerCycle, temperature); // wirte data in drive
}
/**
* \brief parse ExitStatus
* \param string output line of smartctl
* \return uint_8 exit status
*/
uint8_t SMART::parseExitStatus(string sLine)
{
uint8_t exitStatus = -1;
string search("\"exit_status\": ");
size_t found = sLine.find(search);
if (found != string::npos)
{
sLine.erase(0, sLine.find(": ") + 1);
exitStatus = stol(sLine);
}
return exitStatus;
fclose(outputfileSmart);
drive->setDriveSMARTData(modelFamily, modelName, serial, capacity, errorCount, powerOnHours, powerCycle); //wirte data in drive
}
/**
@ -100,10 +64,9 @@ void SMART::parseModelFamily(string sLine)
{
string search("\"model_family\": ");
size_t found = sLine.find(search);
if (found != string::npos)
{
if (found!=string::npos) {
sLine.erase(0, sLine.find(": ") + 3);
sLine.erase(sLine.length() - 3, 3);
sLine.erase(sLine.length()-3, 3);
modelFamily = sLine;
}
}
@ -117,10 +80,9 @@ void SMART::parseModelName(string sLine)
{
string search("\"model_name\": ");
size_t found = sLine.find(search);
if (found != string::npos)
{
if (found!=string::npos) {
sLine.erase(0, sLine.find(": ") + 3);
sLine.erase(sLine.length() - 3, 3);
sLine.erase(sLine.length()-3, 3);
modelName = sLine;
}
}
@ -134,10 +96,9 @@ void SMART::parseSerial(string sLine)
{
string search("\"serial_number\": ");
size_t found = sLine.find(search);
if (found != string::npos)
{
if (found!=string::npos) {
sLine.erase(0, sLine.find(": ") + 3);
sLine.erase(sLine.length() - 3, 3);
sLine.erase(sLine.length()-3, 3);
serial = sLine;
}
}
@ -151,10 +112,9 @@ void SMART::parseCapacity(string sLine)
{
string search("\"bytes\": ");
size_t found = sLine.find(search);
if (found != string::npos)
{
if (found!=string::npos) {
sLine.erase(0, sLine.find(": ") + 2);
sLine.erase(sLine.length() - 1, 1);
sLine.erase(sLine.length()-1, 1);
capacity = stol(sLine);
}
}
@ -168,10 +128,10 @@ void SMART::parseErrorCount(string sLine)
{
string search("\"error_count_total\": ");
size_t found = sLine.find(search);
if (found != string::npos)
if (found!=string::npos)
{
sLine.erase(0, sLine.find(": ") + 2);
sLine.erase(sLine.length() - 2, 2);
sLine.erase(0, sLine.find(": ")+2);
sLine.erase(sLine.length()-2, 2);
errorCount = stol(sLine);
}
}
@ -185,11 +145,12 @@ void SMART::parsePowerOnHours(string sLine)
{
string search("\"hours\": ");
size_t found = sLine.find(search);
if (found != string::npos)
if (found!=string::npos)
{
sLine.erase(0, sLine.find(": ") + 2);
sLine.erase(sLine.length() - 1, 1);
sLine.erase(sLine.length()-1, 1);
powerOnHours = stol(sLine);
}
}
@ -202,34 +163,12 @@ void SMART::parsePowerCycle(string sLine)
{
string search("\"power_cycle_count\": ");
size_t found = sLine.find(search);
if (found != string::npos)
if (found!=string::npos)
{
sLine.erase(0, sLine.find(": ") + 2);
sLine.erase(sLine.length() - 2, 2);
sLine.erase(sLine.length()-2, 2);
powerCycle = stol(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 temperature
}
else
{
temperature = stol(sLine);
}
}
}

View File

@ -1,708 +0,0 @@
/**
* @file tui.cpp
* @brief display user interface
* @author hendrik schutter
* @date 03.08.2020
*/
#include "../include/reHDD.h"
static std::mutex mxUIrefresh;
TUI::TUI(void)
{
}
/**
* \brief wipe drive with shred
* \param pointer of Drive instance
* \return void
*/
void TUI::initTUI()
{
initscr();
raw();
keypad(stdscr, TRUE);
if (has_colors() == TRUE)
{
start_color();
}
else
{
printf("Your terminal does not support color\n");
Logger::logThis()->error("Your terminal does not support color");
exit(1);
}
clear();
curs_set(0);
noecho();
cbreak();
init_pair(COLOR_AREA_STDSCR, COLOR_WHITE, COLOR_BLUE);
wbkgd(stdscr, COLOR_PAIR(COLOR_AREA_STDSCR));
init_pair(COLOR_AREA_ENTRY_EVEN, COLOR_BLACK, COLOR_WHITE);
init_pair(COLOR_AREA_ENTRY_ODD, COLOR_BLUE, COLOR_WHITE);
init_pair(COLOR_AREA_ENTRY_SELECTED, COLOR_WHITE, COLOR_RED);
init_pair(COLOR_AREA_OVERVIEW, COLOR_BLACK, COLOR_WHITE);
init_pair(COLOR_AREA_DETAIL, COLOR_BLACK, COLOR_WHITE);
mvprintw(0, 2, "reHDD - HDD refurbishing tool - GPL 3.0 ");
Logger::logThis()->info("UI successfully initialized");
}
void TUI::updateTUI(list<Drive> *plistDrives, uint8_t u8SelectedEntry)
{
mxUIrefresh.lock();
uint16_t u16StdscrX, u16StdscrY;
getmaxyx(stdscr, u16StdscrY, u16StdscrX);
init_pair(COLOR_AREA_STDSCR, COLOR_WHITE, COLOR_BLUE);
wbkgd(stdscr, COLOR_PAIR(COLOR_AREA_STDSCR));
refresh();
// overview window is 3/7 of the x-size
overview = createOverViewWindow((int)(u16StdscrX * (float)(3.0 / 7.0)), (u16StdscrY - 1));
wrefresh(overview);
// system stat window is 2/7 of the x-size
systemview = createSystemStats(((int)(u16StdscrX * (float)(2.0 / 7.0))) - 6, 12, (int)(u16StdscrX * (float)(5.0 / 7.0) + 4), (u16StdscrY - 13));
wrefresh(systemview);
delwin(detailview);
list<Drive>::iterator it;
uint8_t u8Index = 0U;
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
{
string sModelFamily = it->getModelFamily();
string sSerial = "SN: " + it->getSerial();
string sCapacity = it->sCapacityToText();
string sState = " ";
string sSpeed = " ";
string sTime = " ";
string sTemp = it->sTemperatureToText();
bool bSelectedEntry = false;
if (u8SelectedEntry == u8Index)
{
bSelectedEntry = true; // mark this drive in entries list
displaySelectedDrive(*it, u16StdscrX, u16StdscrY);
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(), it->getTemperature());
wrefresh(smartWarning);
}
}
stringstream stream;
switch (it->state)
{
case Drive::SHRED_ACTIVE:
stream << fixed << setprecision(3) << (it->getTaskPercentage());
sState = "Shredding: " + stream.str() + "%";
it->calculateTaskDuration();
sTime = this->formatTimeDuration(it->getTaskDuration());
sSpeed = this->formatSpeed(it->sShredSpeed.u32ShredTimeDelta, it->sShredSpeed.ulWrittenBytes);
break;
case Drive::CHECK_ACTIVE:
stream << fixed << setprecision(3) << (it->getTaskPercentage());
sState = "Checking: " + stream.str() + "%";
it->calculateTaskDuration();
sTime = this->formatTimeDuration(it->getTaskDuration());
sSpeed = this->formatSpeed(it->sShredSpeed.u32ShredTimeDelta, it->sShredSpeed.ulWrittenBytes);
break;
case Drive::DELETE_ACTIVE:
sState = "Deleting ...";
it->calculateTaskDuration();
sTime = this->formatTimeDuration(it->getTaskDuration());
break;
case Drive::NONE:
case Drive::SHRED_SELECTED:
case Drive::DELETE_SELECTED:
if (it->bWasDeleted)
{
sState = "DELETED"; // mark drive as deleted previously
}
if (it->bWasShredded)
{
if (it->bWasChecked)
{
// drive was also checked after shredding
sState = "SHREDDED & CHECKED"; // mark drive as shredded previously and optional checked
}
else
{
// shredded and not checked yet
sState = "SHREDDED"; // mark drive as shredded previously
}
sTime = this->formatTimeDuration(it->getTaskDuration());
}
#ifdef ZERO_CHECK
if (bSelectedEntry && it->bWasChecked && (it->u32DriveChecksumAfterShredding != 0U))
{
dialog = createZeroChecksumWarning(70, 16, ((u16StdscrX) - (int)(u16StdscrX / 2) - 20), (int)(u16StdscrY / 2) - 8, it->getPath(), it->getModelFamily(), it->getModelName(), it->getSerial(), it->u32DriveChecksumAfterShredding);
wrefresh(dialog);
}
#endif
break;
case Drive::FROZEN:
stream << fixed << setprecision(3) << (it->getTaskPercentage());
#ifdef FROZEN_ALERT
if (bSelectedEntry)
{
dialog = createFrozenWarning(70, 16, ((u16StdscrX) - (int)(u16StdscrX / 2) - 20), (int)(u16StdscrY / 2) - 8, it->getPath(), it->getModelFamily(), it->getModelName(), it->getSerial(), stream.str() + "%");
wrefresh(dialog);
}
#endif
sState = "FROZEN " + stream.str() + "%"; // mark drive as frozen and reached progress
break;
default:
break;
}
uint16_t u16StartOffsetY = (2 * (u8Index));
WINDOW *tmp = createEntryWindow((int)(u16StdscrX * (float)(3.0 / 7.0) - 2), 2, 3, u16StartOffsetY + 2, (distance(plistDrives->begin(), it) + 1), sModelFamily, sSerial, sCapacity, sState, sTime, sSpeed, sTemp, bSelectedEntry);
wrefresh(tmp);
u8Index++;
} // end loop though drives
if (plistDrives->size() == 0)
{
// no selected drive present
Logger::logThis()->warning("no selected drive present");
struct MenuState menustate;
menustate.bAbort = false;
menustate.bConfirmDelete = false;
menustate.bConfirmShred = false;
menustate.bDelete = false;
menustate.bShred = false;
detailview = overwriteDetailViewWindow((u16StdscrX) - ((int)(u16StdscrX * (float)(3.0 / 7.0))) - 7, (u16StdscrY - 15), (int)(u16StdscrX * (float)(3.0 / 7.0) + 5));
wrefresh(detailview);
menuview = createMenuView(((int)(u16StdscrX * (float)(2.0 / 7.0))) - 3, 12, (int)(u16StdscrX * (float)(3.0 / 7.0) + 5), (u16StdscrY - 13), menustate);
wrefresh(menuview);
}
mxUIrefresh.unlock();
}
enum TUI::UserInput TUI::readUserInput()
{
int ch = wgetch(stdscr);
switch (ch)
{
case KEY_UP:
return TUI::UserInput::UpKey;
break;
case KEY_DOWN:
return TUI::UserInput::DownKey;
break;
case 10:
return TUI::UserInput::Enter;
break;
case 27:
return TUI::UserInput::ESC;
break;
case 'a':
return TUI::UserInput::Abort;
break;
case 'd':
return TUI::UserInput::Delete;
break;
case 's':
return TUI::UserInput::Shred;
break;
case 'S':
return TUI::UserInput::ShredAll;
break;
default:
return TUI::UserInput::Undefined;
break;
}
return TUI::UserInput::Undefined;
}
void TUI::centerTitle(WINDOW *pwin, const char *title)
{
int x, maxX, stringSize;
getmaxyx(pwin, maxX, maxX);
stringSize = 4 + strlen(title);
x = (maxX - stringSize) / 2;
mvwaddch(pwin, 0, x, ACS_RTEE);
waddch(pwin, ' ');
waddstr(pwin, title);
waddch(pwin, ' ');
waddch(pwin, ACS_LTEE);
}
/*
left window that contains the drive entries
*/
WINDOW *TUI::createOverViewWindow(int iXSize, int iYSize)
{
WINDOW *newWindow;
newWindow = newwin(iYSize, iXSize, 1, 2);
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_OVERVIEW));
box(newWindow, ACS_VLINE, ACS_HLINE);
centerTitle(newWindow, "Detected Drives");
return newWindow;
}
WINDOW *TUI::createDetailViewWindow(int iXSize, int iYSize, int iXStart, Drive drive)
{
WINDOW *newWindow;
newWindow = newwin(iYSize, iXSize, 1, iXStart);
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_DETAIL));
box(newWindow, ACS_VLINE, ACS_HLINE);
string title = "Selected Drive: " + drive.getModelName() + " " + drive.sCapacityToText();
centerTitle(newWindow, title.c_str());
string sPath = "Path: " + drive.getPath();
string sModelFamily = "ModelFamily: " + drive.getModelFamily();
string sModelName = "ModelName: " + drive.getModelName();
string sCapacity = "Capacity: " + drive.sCapacityToText();
string sSerial = "Serial: " + drive.getSerial();
string sPowerOnHours = "PowerOnHours: " + drive.sPowerOnHoursToText();
string sPowerCycle = "PowerCycle: " + drive.sPowerCyclesToText();
string sErrorCount = "ErrorCount: " + drive.sErrorCountToText();
uint16_t u16Line = 2;
mvwaddstr(newWindow, u16Line++, 3, sPath.c_str());
mvwaddstr(newWindow, u16Line++, 3, sModelFamily.c_str());
mvwaddstr(newWindow, u16Line++, 3, sModelName.c_str());
mvwaddstr(newWindow, u16Line++, 3, sCapacity.c_str());
mvwaddstr(newWindow, u16Line++, 3, sSerial.c_str());
attroff(COLOR_PAIR(COLOR_AREA_DETAIL));
mvwaddstr(newWindow, u16Line++, 3, sPowerOnHours.c_str());
mvwaddstr(newWindow, u16Line++, 3, sPowerCycle.c_str());
mvwaddstr(newWindow, u16Line++, 3, sErrorCount.c_str());
return newWindow;
}
WINDOW *TUI::overwriteDetailViewWindow(int iXSize, int iYSize, int iXStart)
{
WINDOW *newWindow;
newWindow = newwin(iYSize, iXSize, 1, iXStart);
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_DETAIL));
box(newWindow, ACS_VLINE, ACS_HLINE);
string title = "About this tool";
centerTitle(newWindow, title.c_str());
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 sLine05 = "Delete: Wipe format table - this is NOT secure";
string sLine06 = "Shred: Overwrite drive " + to_string(SHRED_ITERATIONS) + " iterations - this is secure";
uint16_t u16Line = 5;
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLine01.c_str());
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine02.size() / 2), sLine02.c_str());
u16Line++;
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine03.size() / 2), sLine03.c_str());
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine04.size() / 2), sLine04.c_str());
u16Line++;
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine05.size() / 2), sLine05.c_str());
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine06.size() / 2), sLine06.c_str());
attroff(COLOR_PAIR(COLOR_AREA_DETAIL));
return newWindow;
}
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);
if (!bSelected)
{
// entry is NOT selected
if (iListIndex % 2 == 0)
{
// even
attron(COLOR_PAIR(COLOR_AREA_ENTRY_EVEN));
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_EVEN));
}
else
{
// odd
attron(COLOR_PAIR(COLOR_AREA_ENTRY_ODD));
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_ODD));
}
}
else
{
// entry IS selected
attron(COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
}
// box(newWindow, ACS_VLINE, ACS_HLINE);
// index number
mvwaddstr(newWindow, 0, 1, to_string(iListIndex).c_str());
/*
70 chars in x-axis
line:01
0: space
1: index number
2: space
3-35: ModelFamily
36: space
37-43: Capacity
44: space
47-49: Temp
line:02
0-2: space
3-31: Serial
32: space
33-45: Speed
46: space
47-58: Time
59: space
60-70: State (but right side aligned)
*/
vTruncateText(&sModelFamily, 32);
mvwaddstr(newWindow, 0, 3, sModelFamily.c_str());
mvwaddstr(newWindow, 0, 37, sCapacity.c_str());
mvwaddstr(newWindow, 0, 47, sTemp.c_str());
vTruncateText(&sSerial, 28);
mvwaddstr(newWindow, 1, 3, sSerial.c_str());
mvwaddstr(newWindow, 1, 33, sSpeed.c_str());
mvwaddstr(newWindow, 1, 47, sTime.c_str());
mvwaddstr(newWindow, 1, iXSize - sState.length() - 2, sState.c_str());
return newWindow;
}
WINDOW *TUI::createSystemStats(int iXSize, int iYSize, int iXStart, int iYStart)
{
WINDOW *newWindow;
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_OVERVIEW));
box(newWindow, ACS_VLINE, ACS_HLINE);
centerTitle(newWindow, "System");
time_t rawtime;
struct tm *timeinfo;
char buffer[80];
time(&rawtime);
timeinfo = localtime(&rawtime);
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 = "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;
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLine01.c_str());
u16Line++;
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());
return newWindow;
}
WINDOW *TUI::createMenuView(int iXSize, int iYSize, int iXStart, int iYStart, struct MenuState menustate)
{
WINDOW *newWindow;
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_OVERVIEW));
box(newWindow, ACS_VLINE, ACS_HLINE);
centerTitle(newWindow, "Controls");
uint16_t u16Line = 4;
if (menustate.bAbort)
{
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 (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";
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLineTmp.size() / 2), sLineTmp.c_str());
}
return newWindow;
}
WINDOW *TUI::createDialog(int iXSize, int iYSize, int iXStart, int iYStart, string task, string optionA, string optionB)
{
WINDOW *newWindow;
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
box(newWindow, ACS_VLINE, ACS_HLINE);
centerTitle(newWindow, task.c_str());
uint16_t u16Line = 3;
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (optionA.size() / 2), optionA.c_str());
u16Line++;
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (optionB.size() / 2), optionB.c_str());
return newWindow;
}
WINDOW *TUI::createFrozenWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, string sModelFamily, string sModelName, string sSerial, string sProgress)
{
WINDOW *newWindow;
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
box(newWindow, ACS_VLINE, ACS_HLINE);
string sHeader = "Drive " + sPath + " is frozen";
string sLine01 = "Please detach this drive and check it manually:";
string sShredState = "Shredding stopped after " + sProgress;
string sLinePath = "Path: " + sPath;
string sLineModelFamlily = "ModelFamily: " + sModelFamily;
string sLineModelName = "ModelName: " + sModelName;
string sLineSerial = "Serial: " + sSerial;
string sLine02 = "reHDD was not able to write data to the drive.";
string sLine03 = "This can be caused by an malfunctioning drive.";
centerTitle(newWindow, sHeader.c_str());
uint16_t u16Line = 2;
mvwaddstr(newWindow, u16Line++, 3, sLine01.c_str());
u16Line++;
mvwaddstr(newWindow, u16Line++, 3, sLinePath.c_str());
mvwaddstr(newWindow, u16Line++, 3, sLineModelFamlily.c_str());
mvwaddstr(newWindow, u16Line++, 3, sLineModelName.c_str());
mvwaddstr(newWindow, u16Line++, 3, sLineSerial.c_str());
u16Line++;
mvwaddstr(newWindow, u16Line++, 3, sLine02.c_str());
mvwaddstr(newWindow, u16Line++, 3, sLine03.c_str());
mvwaddstr(newWindow, u16Line++, 3, sShredState.c_str());
return newWindow;
}
WINDOW *TUI::createZeroChecksumWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, string sModelFamily, string sModelName, string sSerial, uint32_t u32Checksum)
{
WINDOW *newWindow;
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
box(newWindow, ACS_VLINE, ACS_HLINE);
string sHeader = "Drive " + sPath + " is NOT successfully shredded!";
string sLine01 = "Please detach this drive and check it manually:";
string sShredChecksum = "After shredding the checksum was: " + to_string(u32Checksum);
string sLinePath = "Path: " + sPath;
string sLineModelFamily = "ModelFamily: " + sModelFamily;
string sLineModelName = "ModelName: " + sModelName;
string sLineSerial = "Serial: " + sSerial;
string sLine02 = "reHDD was not able to write zero into every byte on the drive.";
string sLine03 = "This can be caused by an malfunctioning drive.";
centerTitle(newWindow, sHeader.c_str());
uint16_t u16Line = 2;
mvwaddstr(newWindow, u16Line++, 3, sLine01.c_str());
u16Line++;
mvwaddstr(newWindow, u16Line++, 3, sLinePath.c_str());
mvwaddstr(newWindow, u16Line++, 3, sLineModelFamily.c_str());
mvwaddstr(newWindow, u16Line++, 3, sLineModelName.c_str());
mvwaddstr(newWindow, u16Line++, 3, sLineSerial.c_str());
u16Line++;
mvwaddstr(newWindow, u16Line++, 3, sLine02.c_str());
mvwaddstr(newWindow, u16Line++, 3, sLine03.c_str());
mvwaddstr(newWindow, u16Line++, 3, sShredChecksum.c_str());
return newWindow;
}
string TUI::formatTimeDuration(time_t u32Duration)
{
std::ostringstream out;
int dy = (int)((u32Duration) / 86400);
int hr = (int)(((u32Duration) / 3600) % 24);
int min = ((int)((u32Duration) / 60)) % 60;
int sec = (int)((u32Duration) % 60);
char s[25];
sprintf(s, "%02d:%02d:%02d:%02d", dy, hr, min, sec);
out << s;
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::vTruncateText(string *psText, uint16_t u16MaxLenght)
{
if (psText->length() > u16MaxLenght)
{
psText->resize(u16MaxLenght - 3);
*psText = *psText + "...";
}
}
void TUI::displaySelectedDrive(Drive drive, int stdscrX, int stdscrY)
{
struct MenuState menustate;
menustate.bAbort = false;
menustate.bConfirmDelete = false;
menustate.bConfirmShred = false;
menustate.bDelete = false;
menustate.bShred = false;
// set menustate based on drive state
switch (drive.state)
{
case Drive::NONE: // no task running or selected for this drive
menustate.bShred = true;
menustate.bDelete = true;
break;
case Drive::DELETE_ACTIVE: // delete task running for this drive
menustate.bAbort = true;
break;
case Drive::SHRED_ACTIVE: // shred task running for this drive
menustate.bAbort = true;
break;
case Drive::CHECK_ACTIVE: // check task running for this drive
menustate.bAbort = true;
break;
case Drive::DELETE_SELECTED: // delete task selected for this drive
menustate.bConfirmDelete = true;
break;
case Drive::SHRED_SELECTED: // shred task selected for this drive
menustate.bConfirmShred = true;
break;
default:
break;
}
detailview = createDetailViewWindow((stdscrX) - ((int)(stdscrX * (float)(3.0 / 7.0))) - 7, (stdscrY - 15), (int)(stdscrX * (float)(3.0 / 7.0) + 5), drive);
wrefresh(detailview);
menuview = createMenuView(((int)(stdscrX * (float)(2.0 / 7.0))) - 3, 12, (int)(stdscrX * (float)(3.0 / 7.0) + 5), (stdscrY - 13), menustate);
wrefresh(menuview);
if (menustate.bConfirmShred == true)
{
dialog = createDialog(40, 10, ((stdscrX) - (int)(stdscrX / 3) - 7) - (int)((stdscrX / 3) + 5) / 2, (int)(stdscrY / 2) - 5, "Confirm SHRED", "Press ENTER for SHRED", "Press ESC for cancel");
wrefresh(dialog);
}
else if (menustate.bConfirmDelete == true)
{
dialog = createDialog(40, 10, ((stdscrX) - (int)(stdscrX / 3) - 7) - (int)((stdscrX / 3) + 5) / 2, (int)(stdscrY / 2) - 5, "Confirm DELETE", "Press ENTER for DELETE", "Press ESC for cancel");
wrefresh(dialog);
}
else
{
delwin(dialog);
}
}
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);
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
box(newWindow, ACS_VLINE, ACS_HLINE);
string sHeader = "Drive " + sPath + " is suspicious";
string sLine01 = "Please evaluate this drive carefully.";
centerTitle(newWindow, sHeader.c_str());
uint16_t u16Line = 2;
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLine01.c_str());
u16Line++;
if (u32PowerOnHours > WORSE_HOURS)
{
string sLineTmp = "Operating hours exceeded " + to_string(WORSE_HOURS) + " hours: " + to_string(u32PowerOnHours);
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLineTmp.c_str());
u16Line++;
}
if (u32PowerCycles > WORSE_POWERUP)
{
string sLineTmp = "Power-on exceeded " + to_string(WORSE_POWERUP) + " cycles: " + to_string(u32PowerCycles);
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLineTmp.c_str());
u16Line++;
}
if (u32ErrorCount > 0)
{
string sLineTmp = "S.M.A.R.T. errors 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;
}

72
src/wipe.cpp Normal file
View File

@ -0,0 +1,72 @@
/**
* @file wipe.cpp
* @brief wipe drive
* @author hendrik schutter
* @date 03.05.2020
*/
#include "../include/reHDD.h"
//#define DRYRUN //if defined the drive will not be wiped, a ping cmd is attempted instead
/**
* \brief wipe drive with shred
* \param pointer of Drive instance
* \return void
*/
void Wipe::wipeDrive(Drive* drive)
{
size_t len = 0; //lenght of found line
char* cLine = NULL; //found line
#ifndef DRYRUN
string sCMD = ("shred -v ");
sCMD.append(drive->getPath());
#endif
#ifdef DRYRUN
cout << "dryrun for " << drive->getPath() << endl;
string sCMD = ("ping ::1 -c 5");
#endif
const char* cpComand = sCMD.c_str();
cout << "wipe: " << cpComand << endl;
auto t_start = chrono::high_resolution_clock::now();
FILE* outputfileSmart = popen(cpComand, "r");
while ((getline(&cLine, &len, outputfileSmart)) != -1)
{
string sLine = string(cLine);
cout << sLine;
}
fclose(outputfileSmart);
auto t_end = chrono::high_resolution_clock::now();
uint64_t u64TimeMS = chrono::duration<double, std::milli>(t_end-t_start).count();
uint64_t u64hours = 0U;
uint64_t u64minutes = 0U;
uint64_t u64seconds = 0U;
while(u64TimeMS >= 1000)
{
u64seconds++;
u64TimeMS = u64TimeMS - 1000;
}
while(u64seconds >= 60)
{
u64minutes++;
u64seconds = u64seconds - 60;
}
while(u64minutes >= 60)
{
u64hours++;
u64minutes = u64minutes - 60;
}
cout << "Elapsed time: " << u64hours << " h - " << u64minutes << " min - " << u64seconds << " sec" << endl;
}

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

View File

@ -12,57 +12,7 @@
"unordered_map": "cpp",
"string_view": "cpp",
"ostream": "cpp",
"chrono": "cpp",
"thread": "cpp",
"deque": "cpp",
"vector": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"compare": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"ranges": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"typeinfo": "cpp",
"iomanip": "cpp"
},
"git.ignoreLimitWarning": true
"chrono": "cpp"
}
}
}