diff --git a/.gitignore b/.gitignore index d9710be..ee41a9d 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ reHDD +reHDD.log diff --git a/README.md b/README.md index e9642f5..ddf5bc8 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,77 @@ ## Useful for: * checking new drives for the first time * checking used drives for their next live -* deleting a drive securely +* deleting a drive securely via overwriting -## planned Features: +## Screenshot +![alt text](https://git.mosad.xyz/localhorst/reHDD/raw/commit/95828afcc2e417b9cb64a4add98ae9c3c7628e84/doc/screenshot.png "Screenshot") -* 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 +## Debian Build Notes + +* apt-get install ncurses-dev git make g++ +* clone repo +* make release + +## Create Standalone with Debian + +Instructions how to create a standalone machine that boots directly to reHDD. This is aimed for production use, like several drives a day shredding. + +### Software requirements + +* apt-get install hwinfo +* wget http://ftp.de.debian.org/debian/pool/main/s/smartmontools/smartmontools_7.1-1_amd64.deb +* dpkg --install smartmontools_7.1-1_amd64.deb + +### Start reHDD after boot without login (as a tty shell) + +nano /etc/systemd/system/reHDD.service +``` +[Unit] +Description=Custom user interface on tty1 +Conflicts=getty@tty1.service +Before=getty.target + +[Service] +WorkingDirectory=/root/reHDD +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 + +[Install] +WantedBy=multi-user.target +``` + +nano /etc/systemd/system/reHDDSettings.service +``` +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/bash /root/reHDDSettings.sh + +[Install] +WantedBy=multi-user.target +``` + +nano /root/reHDDSettings.sh +``` +#!/bin/bash +dmesg -n 1 #disable overlay if a drive is attached/detached +rm -f /root/reHDD/reHDD.log +``` +Make sure the binary reHDD is in /root/reHDD/ +Add your system drive in /root/reHDD/ignoreDrives.conf like: +``` /dev/sdX:e102f49d-5ed5-462b-94c5-ef66a4345671``` +Get your UUID via blkid /dev/sdX + +systemctl enable reHDD.service + +systemctl enable reHDDSettings.service diff --git a/doc/diagrams/refurbishingHddTool.drawio b/doc/diagrams/refurbishingHddTool.drawio index 3667556..9a4d547 100644 --- a/doc/diagrams/refurbishingHddTool.drawio +++ b/doc/diagrams/refurbishingHddTool.drawio @@ -1 +1 @@ -7VttU+o4FP41zOx+kGnTF+CjgKh3vczdxV31050Ioc1aGkyDiL9+kzalL6mXqlOCrDMONqdpSM85zzlPTkLLGiyezylc+t/JDAUtYMyeW9awBYBpA9ASf8Zsk0jcrpUIPIpnslMmmOAXJIWGlK7wDEWFjoyQgOFlUTglYYimrCCDlJJ1sducBMVvXUIPKYLJFAaq9AbPmJ9Iu6CTyS8Q9vz0m023l9xZwLSzfJPIhzOyzomss5Y1oISw5GrxPECBUF6ql5vLzU1w9eCef/szeoR/9/+4Hv9zkgw2essj21egKGTvHtpe/bx9PJsPfl6ML+l4fHUz8V5O5LtGbJPqC824+mSTUOYTj4QwOMukfUpW4QyJUQ3eyvpcEbLkQpML/0WMbaQvwBUjXOSzRSDv8regm1vxfNtJm3dyuLgxfC60NrKVzFVMsGTaHXqR/SKyolP0C2VIOzNIPcR+0c/aGp+jBpEF4pPkz1EUQIafipOD0n29bb/MRPxCWukNFpOTfILBSn7TD0o8ChcRnzdTzRkEHGnCbGsfMzRZwlgFaw72olHksIgy9PwO9arqkKNYHelj6wx9piHfws8hzzUa0phpqlr5/zq5VdPJTaParPvxckvx8hDxK+AGfM79e8qvPBZry4UL4cnhfST+XQyHYjoL/vFj0LJGVU+UfIH6ZHG/inYjZBv/hZnmJGQjuMCBsNsFCp4Qw1Mob0inMLn++jDAXsgbU24+RMUwjJKHbS6KB+ZfiUOPt9ysdR372Ym9D2huSrDcBdVeY1B1dUC1aciZdROL6ejEnKmmlnEMOiNBlYfmQtGhiqCtAczdKCrjwwtgFEnbVUAjj7nGcOAWcQDMjooDUIEDuzEc2MeIg7qpRyu/Mr8osRKR6oSujlajOUrougznJBLrVp500wgWoEiErzIl+O0C0YjxrxFd+QQMuQoWl+e0NbBafVd89kbo9yMMfnYx+HUrSIBVEfycpoIf+OLrCrBqIBBoJezpNHMInLS/t0/bf7Wva6LwjFJCowR2EyaphmichtHUhwEXeSg8fgRaTk0ENrZiBkdJP0BdGg60EhCg0nAeclbsJYYQ5FmK/xtCJtBhwPCFOwQK2/w6xY/B7SA8hfgoj6RRAUbidQhriTInfcCIHiOttzvtjlOAlm1XQMsFbUcFV6cxcHW1pLdnzG5z13dZpuOtLLeJRpraDjUlgroLCaCVlAI9Kwlp6My4d7k7x2poV6eh09ysydBvQPThGExrpQuo5eUzHHrwHsVUVeTQNOVGalqsWy9uLK91inzRqUpqZgVf7DaV0mwtfHGfkQ6Fs1OxGc2bU8Fs8DQRjnCwN/patxRj66WvailGbso8vKAl41RT3aR8E9NsClbbJVZ60KEKVkZPhVVjVWDH0QKrTwwRtyZEHKAVIm41RIpbmXEqmqOHA4WLVVpa6YeLBY49CzWOn7q1RusV39gTftRao0wxq2iN6PyjtYymIOOah5ZhbD0rl8+bYaz0CGPTe5jxo/xt4SbXYUlwyKLcyD+EIOdgbjEmd7qlI4Gl/h3X+FD/9HBI5oLJjDOH3L76B8K6+Qra15iKOucTiU/7JIfgxCX2QkIPl2eWo0AH6I4CrvX5EmchbmRh5HAjh123NGJrLY3YamkkQRvXmR/vQATJhnjEm2IXYYFFgODk9XElDkL3I59yr9g2DxOD5bWefgw6na9M/DY81S2HOFr3xW21HJJufUdLGKab3yFa8U75HfPtbh4ntR66r9oxTyV8YvmxDhNyoMxNetohp+ecyTvK9p8Ypk7dTXcthLlXTAPdHfy3p4H+pgrcEUCSJD3nsMXekUWKrqs7Urh6C7Fm67ORXQfsi+y+C/Z2if51zX0AGbzCrOsRauNE3DQPnVmXy8L6mbWr1g/GCKslQq4IVtSR8tMdoS48hcGpvLHAs1mCdRThF3gfDyUgKB2Qj+v0W85QjMXhHcnzUQ2q30lVm6aodD2XU3+q6bz2QWPaV73+GzxO3dtOiR701J+RVB3jfIfueTP73XESoLJfb1tn/wE= \ No newline at end of file +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 \ No newline at end of file diff --git a/doc/diagrams/refurbishingHddTool.pdf b/doc/diagrams/refurbishingHddTool.pdf index 6989d9c..db66b70 100644 Binary files a/doc/diagrams/refurbishingHddTool.pdf and b/doc/diagrams/refurbishingHddTool.pdf differ diff --git a/doc/diagrams/states.drawio b/doc/diagrams/states.drawio new file mode 100644 index 0000000..661e8c0 --- /dev/null +++ b/doc/diagrams/states.drawio @@ -0,0 +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= \ No newline at end of file diff --git a/doc/diagrams/states.png b/doc/diagrams/states.png new file mode 100644 index 0000000..41c861c Binary files /dev/null and b/doc/diagrams/states.png differ diff --git a/doc/screenshot.png b/doc/screenshot.png new file mode 100644 index 0000000..7606712 Binary files /dev/null and b/doc/screenshot.png differ diff --git a/ignoreDrives.conf b/ignoreDrives.conf index aef73e8..8b13789 100644 --- a/ignoreDrives.conf +++ b/ignoreDrives.conf @@ -1,3 +1 @@ -/dev/sda:508ef27d-5039-4e8b-9e2c-22d7528b7149 -/dev/sdb:07f4ad14-c4b6-46e7-9cdf-3cfa9841d53d -/dev/sdc:4673974d-1af2-44fd-996b-a2d8e4c43d9a + diff --git a/include/delete.h b/include/delete.h new file mode 100644 index 0000000..d1e1381 --- /dev/null +++ b/include/delete.h @@ -0,0 +1,25 @@ +/** + * @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_ diff --git a/include/drive.h b/include/drive.h index 3d7f3b1..e3862f7 100644 --- a/include/drive.h +++ b/include/drive.h @@ -12,6 +12,35 @@ class Drive { + +public: + enum TaskState {NONE, + SHRED_SELECTED, + SHRED_ACTIVE, + DELETE_SELECTED, + DELETE_ACTIVE, + FROZEN + } state; + + bool bWasShredded = false; + bool bWasDeleteted = false; + bool bIsOffline = false; + +private: + string sPath; + string sModelFamily; + string sModelName; + string sSerial; + uint64_t u64Capacity = 0U; //in byte + uint32_t u32ErrorCount = 0U; + uint32_t u32PowerOnHours = 0U; //in hours + uint32_t u32PowerCycles = 0U; + time_t u32Timestamp = 0U; //unix timestamp for detecting a frozen drive + double d32TaskPercentage = 0U; //in percent for Shred (1 to 100) + +private: + void setTimestamp(); + protected: public: @@ -28,6 +57,7 @@ public: uint32_t getErrorCount(void); uint32_t getPowerOnHours(void); //in hours uint32_t getPowerCycles(void); + void checkFrozenDrive(void); void setDriveSMARTData( string modelFamily, string modelName, @@ -37,15 +67,14 @@ public: uint32_t powerOnHours, uint32_t powerCycles); -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; + string sCapacityToText(); + string sErrorCountToText(); + string sPowerOnHoursToText(); + string sPowerCyclesToText(); + + void setTaskPercentage(double d32TaskPercentage); + double getTaskPercentage(void); + }; #endif // DRIVE_H_ \ No newline at end of file diff --git a/include/logger/logger.h b/include/logger/logger.h new file mode 100644 index 0000000..b6751ea --- /dev/null +++ b/include/logger/logger.h @@ -0,0 +1,80 @@ +/** + * @file logger.h + * @brief cppSimpleLogger Header + * @author hendrik schutter + * @date 04.09.2020 + */ + +#ifndef LOGGER_H_ +#define LOGGER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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_ \ No newline at end of file diff --git a/include/reHDD.h b/include/reHDD.h index a05e1ad..f10f157 100644 --- a/include/reHDD.h +++ b/include/reHDD.h @@ -8,6 +8,32 @@ #ifndef REHDD_H_ #define REHDD_H_ +#define REHDD_VERSION "bV0.1.0" + +//#define DRYRUN + +// 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 SHRED_ITERATIONS 3 +#define FROZEN_TIMEOUT 5 //After this timeout (minutes) the drive will be marked as frozen + +// Logger Settings +#define LOG_PATH "./reHDD.log" +#define DESCRIPTION "reHDD - Copyright Hendrik Schutter 2020" +#define DEVICE_ID "generic" +#define SOFTWARE_VERSION "alpha" +#define HARDWARE_VERSION "generic" + +#define LOG_LEVEL_HIGH //log everything, like drive scann thread +#ifndef LOG_LEVEL_HIGH +#define LOG_LEVEL_LOW //log only user actions and tasks +#endif + +//IPC pipes +#define READ 0 +#define WRITE 1 + #include #include #include @@ -15,12 +41,27 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace std; #include "drive.h" #include "smart.h" -#include "wipe.h" +#include "shred/shred.h" +#include "delete.h" +#include "tui.h" +#include "logger/logger.h" + +extern Logger* logging; template T* iterator_to_pointer(I i) { @@ -33,17 +74,25 @@ protected: public: reHDD(void); - void app_logic(); + static void app_logic(); private: - vector vecDrives; //stores all drive data - - void searchDrives(vector * pvecDrives); - void printDrives(vector * pvecDrives); - void filterIgnoredDrives(vector * pvecDrives); - void addSMARTData(vector * pvecDrives); + static void searchDrives(vector * pvecDrives); + static void printDrives(vector * pvecDrives); + static void filterIgnoredDrives(vector * pvecDrives); + static void filterNewDrives(vector * pvecOldDrives, vector * pvecNewDrives); + static void addSMARTData(vector * pvecDrives); + static void ThreadScannDevices(); + static void ThreadUserInput(); + static void ThreadShred(); + static void ThreadCheckFrozenDrives(); + static void handleArrowKey(TUI::UserInput userInput); + static void handleEnter(); + static void handleESC(); + static void handleAbort(); + static Drive* getSelectedDrive(); }; -#endif // REHDD_H_ \ No newline at end of file +#endif // REHDD_H_ diff --git a/include/shred/machdefs.h b/include/shred/machdefs.h new file mode 100644 index 0000000..a99d0eb --- /dev/null +++ b/include/shred/machdefs.h @@ -0,0 +1,19 @@ +#ifndef _MACHINE_DEFINITIONS_HEADER +#define _MACHINE_DEFINITIONS_HEADER + +#include +#include + +#undef MACHINE_16BIT +#undef MACHINE_32BIT +#undef MACHINE_64BIT + +#if UINTPTR_MAX == UINT32_MAX +#define MACHINE_32BIT +#elif UINTPTR_MAX == UINT64_MAX +#define MACHINE_64BIT +#elif UINTPTR_MAX == UINT16_MAX +#define MACHINE_16BIT +#endif + +#endif diff --git a/include/shred/shred.h b/include/shred/shred.h new file mode 100644 index 0000000..dcefdfc --- /dev/null +++ b/include/shred/shred.h @@ -0,0 +1,98 @@ +/** + * @file shred.h + * @brief shred drive + * @author hendrik schutter + * @date 03.05.2020 + */ + +#ifndef SHRED_H_ +#define SHRED_H_ + +#include "../reHDD.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "tfdef.h" +#include "tfcore.h" +//#include "tfe.h" + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 700 +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif + +#ifndef _TFNG_STREAM_CIPHER_DEFS +#define _TFNG_STREAM_CIPHER_DEFS +#endif + +#define PROCESS_BLOCKP(x,k1,k2,k3,k4,k5,k6) \ + do { \ + KE_MIX(Y, X, k1 + k2, k3, TFS_KS01); \ + KE_MIX(T, Z, k4 + x, k5 + k6, TFS_KS02); \ + \ + BE_MIX(X, T, TFS_BS01); BE_MIX(Z, Y, TFS_BS02); \ + BE_MIX(X, Y, TFS_BS03); BE_MIX(Z, T, TFS_BS04); \ + BE_MIX(X, T, TFS_BS05); BE_MIX(Z, Y, TFS_BS06); \ + } while (0) + +#define PROCESS_BLOCKN(x,k1,k2,k3,k4,k5,k6) \ + do { \ + KE_MIX(Y, X, k1 + k2, k3, TFS_KS03); \ + KE_MIX(T, Z, k4 + x, k5 + k6, TFS_KS04); \ + \ + BE_MIX(X, T, TFS_BS07); BE_MIX(Z, Y, TFS_BS08); \ + BE_MIX(X, Y, TFS_BS09); BE_MIX(Z, T, TFS_BS10); \ + BE_MIX(X, T, TFS_BS11); BE_MIX(Z, Y, TFS_BS12); \ + } while (0) + + +#define NOSIZE ((size_t)-1) + +#define XRET(x) if (!xret && xret < x) xret = x + +class Shred +{ +protected: + +public: + + Shred(); + ~Shred(); + void shredDrive(Drive* drive, int* ipSignalFd); + +private: + + unsigned long blockcount = 0UL; + long blockcount_max; + double d32Percent; + + inline double calcProgress(); + inline void tfnge_init_iv(struct tfnge_stream *tfe, const void *key, const void *iv); + inline void tfnge_init(struct tfnge_stream *tfe, const void *key); + inline void tfng_encrypt_rawblk(TFNG_UNIT_TYPE *O, const TFNG_UNIT_TYPE *I, const TFNG_UNIT_TYPE *K); + inline void tfnge_emit(void *dst, size_t szdst, struct tfnge_stream *tfe); + +}; + +#endif // SHRED_H_ diff --git a/include/shred/tfcore.h b/include/shred/tfcore.h new file mode 100644 index 0000000..2d9d53e --- /dev/null +++ b/include/shred/tfcore.h @@ -0,0 +1,51 @@ +#ifndef _THREEFISH_NOISE_GENERATOR_CIPHER_CORE_HEADER +#define _THREEFISH_NOISE_GENERATOR_CIPHER_CORE_HEADER + +#ifndef _THREEFISH_NOISE_GENERATOR_CIPHER_DEFINITIONS_HEADER +#error Threefish definitions header is required! Include tfdef.h first. +#endif + +#define ROL(x, s, max) ((x << s) | (x >> (-s & (max-1)))) +#define ROR(x, s, max) ((x >> s) | (x << (-s & (max-1)))) + +#define KE_MIX(x, y, k1, k2, sl) \ + do { \ + x += k1; \ + y += x; \ + y += k2; \ + x = ROL(x, sl, TFNG_UNIT_BITS); \ + x ^= y; \ + } while (0) + +#define BE_MIX(x, y, sl) \ + do { \ + x += y; \ + y = ROL(y, sl, TFNG_UNIT_BITS); \ + y ^= x; \ + } while (0) + +#define KD_MIX(x, y, k1, k2, sr) \ + do { \ + x ^= y; \ + x = ROR(x, sr, TFNG_UNIT_BITS); \ + y -= x; \ + y -= k2; \ + x -= k1; \ + } while (0) + +#define BD_MIX(x, y, sr) \ + do { \ + y ^= x; \ + y = ROR(y, sr, TFNG_UNIT_BITS); \ + x -= y; \ + } while (0) + +enum tfng_rotations +{ + TFS_KS01 = 7, TFS_KS02 = 25, TFS_KS03 = 19, TFS_KS04 = 7, + TFS_BS01 = 5, TFS_BS02 = 27, TFS_BS03 = 26, TFS_BS04 = 6, + TFS_BS05 = 14, TFS_BS06 = 11, TFS_BS07 = 24, TFS_BS08 = 18, + TFS_BS09 = 9, TFS_BS10 = 24, TFS_BS11 = 6, TFS_BS12 = 7, +}; + +#endif diff --git a/include/shred/tfdef.h b/include/shred/tfdef.h new file mode 100644 index 0000000..ea0bd0b --- /dev/null +++ b/include/shred/tfdef.h @@ -0,0 +1,39 @@ +#ifndef _THREEFISH_NOISE_GENERATOR_CIPHER_DEFINITIONS_HEADER +#define _THREEFISH_NOISE_GENERATOR_CIPHER_DEFINITIONS_HEADER + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif + +#include +#include +#include "machdefs.h" + +#if defined(MACHINE_64BIT) +#define TFNG_UNIT_TYPE uint64_t +#define TFNG_NR_BLOCK_BITS 256 +#define TFNG_NR_KEY_BITS 512 +#else +#define TFNG_UNIT_TYPE uint32_t +#define TFNG_NR_BLOCK_BITS 128 +#define TFNG_NR_KEY_BITS 256 +#endif + +#define TFNG_NR_BLOCK_UNITS 4 +#define TFNG_NR_KEY_UNITS 8 + +#define TFNG_BYTE_TYPE uint8_t +#define TFNG_SIZE_UNIT (sizeof(TFNG_UNIT_TYPE)) +#define TFNG_BLOCK_SIZE (TFNG_SIZE_UNIT * TFNG_NR_BLOCK_UNITS) +#define TFNG_KEY_SIZE (TFNG_SIZE_UNIT * TFNG_NR_KEY_UNITS) + +#define TFNG_TO_BITS(x) ((x) * 8) +#define TFNG_FROM_BITS(x) ((x) / 8) +#define TFNG_MAX_BITS TFNG_NR_BLOCK_BITS +#define TFNG_UNIT_BITS (TFNG_SIZE_UNIT * 8) + +#endif diff --git a/include/tui.h b/include/tui.h new file mode 100644 index 0000000..135ff0d --- /dev/null +++ b/include/tui.h @@ -0,0 +1,68 @@ +/** + * @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 3 +#define COLOR_AREA_ENTRY_SELECTED 4 +#define COLOR_AREA_DETAIL 5 + +class TUI +{ +protected: + +public: + + enum UserInput { UpKey, DownKey, Abort, Shred, Delete, Enter, ESC, Undefined}; + struct MenuState + { + bool bAbort; + bool bShred; + bool bDelete; + bool bConfirmShred; + bool bConfirmDelete; + }; + + TUI(void); + + static void initTUI(); + + void updateTUI(vector * pvecDrives, 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; + + 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, string sModelFamily, string sModelName, string sCapacity, string sState, bool bSelected); + static WINDOW *createSystemStats(int iXSize, int iYSize, 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); + + void displaySelectedDrive(Drive drive, int stdscrX, int stdscrY); + +}; +#endif // TUI_H_ \ No newline at end of file diff --git a/include/wipe.h b/include/wipe.h deleted file mode 100644 index 21c8d5f..0000000 --- a/include/wipe.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @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_ \ No newline at end of file diff --git a/makefile b/makefile index c76a225..4e3c0b5 100644 --- a/makefile +++ b/makefile @@ -10,7 +10,7 @@ SRC_PATH = src # Space-separated pkg-config libraries used by this project LIBS = # General compiler flags -COMPILE_FLAGS = -std=c++11 -Wall -Wextra -g +COMPILE_FLAGS = -std=c++17 -Wall -Wextra -g # Additional release-specific flags RCOMPILE_FLAGS = -D NDEBUG # Additional debug-specific flags @@ -18,7 +18,7 @@ DCOMPILE_FLAGS = -D DEBUG # Add additional include paths INCLUDES = include # General linker settings -LINK_FLAGS = +LINK_FLAGS = -lpthread -lncurses # Doc DOCDIR = doc #### END PROJECT SETTINGS #### diff --git a/shred_dummy.sh b/shred_dummy.sh new file mode 100644 index 0000000..afc4268 --- /dev/null +++ b/shred_dummy.sh @@ -0,0 +1,12 @@ +#! /bin/bash + +echo "starting SHRED DUMMY" + +for i in {0..100..10} +do + #echo "DUMMY shred $i%" + echo $date > out.txt + sleep 1 +done + +echo "finished SHRED DUMMY" diff --git a/src/delete.cpp b/src/delete.cpp new file mode 100644 index 0000000..a34db6e --- /dev/null +++ b/src/delete.cpp @@ -0,0 +1,41 @@ +/** + * @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()); +#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 + } + fclose(deleteCmdOutput); +} diff --git a/src/drive.cpp b/src/drive.cpp index c597b1e..36cd7c9 100644 --- a/src/drive.cpp +++ b/src/drive.cpp @@ -46,6 +46,60 @@ uint32_t Drive::getPowerCycles(void) return u32PowerCycles; } +string Drive::sCapacityToText() +{ + if(getCapacity() <= (999*1000000000UL)) + { + // Less or even 999 GB --> GB + return to_string(getCapacity() / 1000000000UL) + " GB"; + } + else + { + // More 999 GB --> TB + return to_string(getCapacity() / 1000000000000UL) + " TB"; + } + return "ERROR"; +} + +string Drive::sErrorCountToText() +{ + return to_string(getErrorCount()); +} + + +string Drive::sPowerOnHoursToText() +{ + double dYears = 0U; + uint32_t u32Hours = getPowerOnHours(); + stringstream stream; + + dYears = (double) ((double)u32Hours/(double)8760U); + + stream << fixed << setprecision(2) << dYears; + string sRet = to_string(getPowerOnHours()) + " hours or " + stream.str() + " years"; + + return sRet; +} + +string Drive::sPowerCyclesToText() +{ + return to_string(getPowerCycles()); +} + +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; +} + + /** * \brief set S.M.A.R.T. values in model * \param string modelFamily @@ -72,4 +126,24 @@ void Drive::setDriveSMARTData( string modelFamily, u32ErrorCount = errorCount; u32PowerOnHours = powerOnHours; u32PowerCycles = powerCycle; +} + + +void Drive::setTimestamp() +{ + time(&this->u32Timestamp); +} + +void Drive::checkFrozenDrive(void) +{ + time_t u32localtime; + time(&u32localtime); + + if((u32localtime - this->u32Timestamp) >= (FROZEN_TIMEOUT*60) && (this->u32Timestamp > 0)) + { + Logger::logThis()->warning("Drive Frozen: " + this->getModelName() + " " + this->getSerial()); + this->bWasDeleteted = false; + this->bWasShredded = false; + this->state = Drive::FROZEN; + } } \ No newline at end of file diff --git a/src/logger/logger.cpp b/src/logger/logger.cpp new file mode 100644 index 0000000..5708359 --- /dev/null +++ b/src/logger/logger.cpp @@ -0,0 +1,235 @@ +/** + * @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 + * \param path to log file + * \param struct with data + * \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 + } +} + + diff --git a/src/main.cpp b/src/main.cpp index 4978cb8..96a915e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,7 @@ */ int main(void) { - cout << "refurbishingHddTool" << endl; + // cout << "refurbishingHddTool" << endl; reHDD* app = new reHDD(); app->app_logic(); diff --git a/src/reHDD.cpp b/src/reHDD.cpp index ec03080..e1f91bc 100644 --- a/src/reHDD.cpp +++ b/src/reHDD.cpp @@ -7,6 +7,24 @@ #include "../include/reHDD.h" +static int fdNewDrivesInformPipe[2];//File descriptor for pipe that informs if new drives are found + +static int fdShredInformPipe[2];//File descriptor for pipe that informs if a wipe thread signals + +static std::mutex mxScannDrives; + +vector vecNewDrives; //store found drives that are updated every 5sec + +static vector vecDrives; //stores all drive data from scann thread + +TUI *ui; + +static uint8_t u8SelectedEntry; + +static fd_set selectSet; + +//static struct TUI::MenuState menustate; + /** * \brief app constructor * \param void @@ -14,7 +32,9 @@ */ reHDD::reHDD(void) { - cout << "created app" << endl; + u8SelectedEntry = 0U; + + vecDrives.reserve(128); } /** @@ -24,24 +44,232 @@ reHDD::reHDD(void) */ void reHDD::app_logic(void) { - cout << "app logic" << endl; + ui = new TUI(); + ui->initTUI(); - 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 + pipe(fdNewDrivesInformPipe); + pipe(fdShredInformPipe); - size_t u64SelectedDriveIndex = 0U; - size_t u64DriveVecSize = (vecDrives.size()); + thread thDevices(ThreadScannDevices); //start thread that scanns for drives + thread thUserInput(ThreadUserInput); //start thread that reads user input + thread thCheckFrozenDrives(ThreadCheckFrozenDrives); //start thread that checks timeout for drives - cout << "Select drive to wipe:" << endl; - cin >> u64SelectedDriveIndex; - cout << "Selected drive index: " << u64SelectedDriveIndex << endl; + while(1) + { + FD_ZERO(&selectSet); + FD_SET(fdNewDrivesInformPipe[0], &selectSet); + FD_SET(fdShredInformPipe[0], &selectSet); - if(u64SelectedDriveIndex < (u64DriveVecSize)) { - Wipe::wipeDrive(&vecDrives[u64SelectedDriveIndex]); - } + select(FD_SETSIZE, &selectSet, NULL, NULL, NULL); + mxScannDrives.lock(); + if( FD_ISSET(fdNewDrivesInformPipe[0], &selectSet)) + { + char dummy; + read (fdNewDrivesInformPipe[0],&dummy,1); + filterNewDrives(&vecDrives, &vecNewDrives); //filter and copy to app logic vector + printDrives(&vecDrives); + } + + if (FD_ISSET(fdShredInformPipe[0], &selectSet)) + { + char dummy; + read (fdShredInformPipe[0],&dummy,1); + } + ui->updateTUI(&vecDrives, u8SelectedEntry); + mxScannDrives.unlock(); + } //endless loop + thDevices.join(); + thUserInput.join(); + thCheckFrozenDrives.join(); +} + +Drive* reHDD::getSelectedDrive() +{ + if(u8SelectedEntry < vecDrives.size() ) + { + return &(vecDrives.at(u8SelectedEntry)); + } + else + { + Logger::logThis()->warning("selected drive not present"); + return {}; + } +} + +void reHDD::ThreadScannDevices() +{ + while(true) + { + mxScannDrives.lock(); + vecNewDrives.clear(); + searchDrives(&vecNewDrives); //search for new drives and store them in list + filterIgnoredDrives(&vecNewDrives); //filter out ignored drives + addSMARTData(&vecNewDrives); //add S.M.A.R.T. Data to the drives + mxScannDrives.unlock(); + write(fdNewDrivesInformPipe[1], "A",1); + sleep(5); //sleep 5 sec + } +} + + + +void reHDD::ThreadCheckFrozenDrives() +{ + while(true) + { + mxScannDrives.lock(); + for(auto it = begin(vecDrives); it != end(vecDrives); ++it) + { + if(it->state == Drive::SHRED_ACTIVE) + { + it->checkFrozenDrive(); + } + } + mxScannDrives.unlock(); + sleep(5); //sleep 5 sec + } +} + +void reHDD::ThreadUserInput() +{ + while(true) + { + // cout << TUI::readUserInput() << endl; + switch (TUI::readUserInput()) + { + case TUI::UserInput::DownKey: + //cout << "Down" << endl; + handleArrowKey(TUI::UserInput::DownKey); + ui->updateTUI(&vecDrives, u8SelectedEntry); + break; + case TUI::UserInput::UpKey: + //cout << "Up" << endl; + handleArrowKey(TUI::UserInput::UpKey); + ui->updateTUI(&vecDrives, u8SelectedEntry); + break; + case TUI::UserInput::Undefined: + //cout << "Undefined" << endl; + break; + case TUI::UserInput::Abort: + //cout << "Abort" << endl; + handleAbort(); + ui->updateTUI(&vecDrives, u8SelectedEntry); + break; + case TUI::UserInput::Delete: + //cout << "Delete" << endl; + + if (getSelectedDrive() != nullptr) + { + if(getSelectedDrive()->state == Drive::NONE) + { + getSelectedDrive()->state = Drive::DELETE_SELECTED; + } + } + ui->updateTUI(&vecDrives, u8SelectedEntry); + break; + case TUI::UserInput::Shred: + //cout << "Shred" << endl; + + if (getSelectedDrive() != nullptr) + { + if(getSelectedDrive()->state == Drive::NONE) + { + getSelectedDrive()->state = Drive::SHRED_SELECTED; + } + } + ui->updateTUI(&vecDrives, u8SelectedEntry); + break; + case TUI::UserInput::Enter: + //cout << "Enter" << endl; + handleEnter(); + ui->updateTUI(&vecDrives, u8SelectedEntry); + break; + case TUI::UserInput::ESC: + //cout << "ESC" << endl; + handleESC(); + ui->updateTUI(&vecDrives, u8SelectedEntry); + break; + default: + break; + } + } +} + +void reHDD::ThreadShred() +{ + if (getSelectedDrive() != nullptr) + { + Shred* pShredTask = new Shred(); //create new shred task + pShredTask->shredDrive(getSelectedDrive(), &fdShredInformPipe[1]); //start new shred task + delete pShredTask; //delete shred task + ui->updateTUI(&vecDrives, u8SelectedEntry); + } +} + +void reHDD::filterNewDrives(vector * pvecOldDrives, vector * pvecNewDrives) +{ + vector ::iterator itOld; //Iterator for current (old) drive list + vector ::iterator itNew; //Iterator for new drive list that was created from to scann thread + + //remove offline old drives from previously run + for (itOld = pvecOldDrives->begin(); itOld != pvecOldDrives->end();) + { + if(itOld->bIsOffline == true) + { + Logger::logThis()->warning("Offline drive found: " + itOld->getPath()); + itOld = pvecOldDrives->erase(itOld); + /* + if(pvecOldDrives->size() > 0){ //This can be a risk if the user starts a task for the selected drive and the selected drive changes + u8SelectedEntry = 0U; + } + */ + } + else + { + ++itOld; + } + } + + //search offline drives and mark them + for (itOld = pvecOldDrives->begin(); itOld != pvecOldDrives->end(); ++itOld) + { + itOld->bIsOffline = true; //set offline befor seachring in the new list + for (itNew = pvecNewDrives->begin(); itNew != pvecNewDrives->end();) + { + if((itOld->getSerial() == itNew->getSerial()) || (itOld->getPath() == itNew->getPath())) + { + itOld->bIsOffline = false; //drive is still attached +#ifdef LOG_LEVEL_HIGH + Logger::logThis()->info("Delete new drive, because allready attached: " + itNew->getModelName()); +#endif + itNew = pvecNewDrives->erase(itNew); //This drive is allready attached, remove from new list + } + else + { + ++itNew; + } + } + } + + //mark offline old drives + for (itOld = pvecOldDrives->begin(); itOld != pvecOldDrives->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 = pvecNewDrives->begin(); itNew != pvecNewDrives->end(); ++itNew) + { + pvecOldDrives->push_back(pvecNewDrives->at(itNew - pvecNewDrives->begin())); + Logger::logThis()->info("Add new drive: " + itNew->getModelName()); + } + pvecNewDrives->clear(); } /** @@ -51,25 +279,28 @@ void reHDD::app_logic(void) */ void reHDD::searchDrives(vector * pvecDrives) { - cout << "search drives ..." << endl; + // cout << "search drives ..." << endl; + Logger::logThis()->info("--> search drives <--"); char * cLine = NULL; size_t len = 0; FILE* outputfileHwinfo = popen("hwinfo --short --disk", "r"); if (outputfileHwinfo == NULL) - { - exit(EXIT_FAILURE); - } + { + exit(EXIT_FAILURE); + } while ((getline(&cLine, &len, outputfileHwinfo)) != -1) - { - if (string(cLine).find("/dev/sd") != string::npos) { - Drive* tmpDrive = new Drive(string(cLine).substr (2,8)); - pvecDrives->push_back(*tmpDrive); + if (string(cLine).find("/dev/sd") != string::npos) + { + Drive* tmpDrive = new Drive(string(cLine).substr (2,8)); + tmpDrive->state = Drive::NONE; + tmpDrive->bIsOffline = false; + pvecDrives->push_back(*tmpDrive); + } } - } fclose(outputfileHwinfo); } @@ -89,74 +320,73 @@ void reHDD::filterIgnoredDrives(vector * pvecDrives) ifstream input( "ignoreDrives.conf" ); //read ingnore file for(string sLine; getline( input, sLine );) - { - if (string(sLine).find("/dev/sd") != string::npos) { - size_t pos = 0; - string token; - while ((pos = sLine.find(sDelimiter)) != string::npos) - { - token = sLine.substr(0, pos); - sIgnoredDrivePath = token; - sLine.erase(0, pos + sDelimiter.length()); - sIgnoredDriveUUID = sLine; - } //end while - //cout << "Path: " << sIgnoredDrivePath << std::endl; - //cout << "UUID: " << sIgnoredDriveUUID << std::endl; - vtlIgnoredDevices.emplace_back(sIgnoredDrivePath, sIgnoredDriveUUID); //add found path and uuid from ingnore file to vector + if (string(sLine).find("/dev/sd") != string::npos) + { + size_t pos = 0; + string token; + while ((pos = sLine.find(sDelimiter)) != string::npos) + { + token = sLine.substr(0, pos); + sIgnoredDrivePath = token; + sLine.erase(0, pos + sDelimiter.length()); + sIgnoredDriveUUID = sLine; + } //end while + vtlIgnoredDevices.emplace_back(sIgnoredDrivePath, sIgnoredDriveUUID); //add found path and uuid from ingnore file to vector + } } - } - //loop through found entries in ingnore file for(auto row : vtlIgnoredDevices) - { - auto it = pvecDrives->begin(); - while (it != pvecDrives->end()) { - it++; - string sUUID; - if (!get<0>(row).compare(it->getPath())) //find same drive based on path - { - // 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) + vector ::iterator it; + for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it) { - exit(EXIT_FAILURE); - } + string sUUID; + if (!get<0>(row).compare(it->getPath())) //find same drive based on path + { + char * cLine = NULL; + size_t len = 0; + string sCMD = "blkid "; + sCMD.append(it->getPath()); + //cout << "cmd: " << sCMD << endl; + FILE* outputfileBlkid = popen(sCMD.c_str(), "r"); //get UUID from drive + if (outputfileBlkid == NULL) + { + exit(EXIT_FAILURE); + } - while ((getline(&cLine, &len, outputfileBlkid)) != -1) //parse UUID from blkid - { - if (string(cLine).find("PTUUID") != string::npos) - { - string sBlkidOut = string(cLine); - sBlkidOut.erase(0, 18); - sBlkidOut.erase(36, sBlkidOut.length() - 36); - sUUID = sBlkidOut; - //cout << "blkid uuid:" << sUUID << endl; - } - } - fclose(outputfileBlkid); - // cout << "blkid uuid:" << sUUID << endl; + 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 + 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; + Logger::logThis()->error("[ERROR] different uuid found than in ignore file: " + it->getPath()); + exit(EXIT_FAILURE); // exit to prevent accidentally shred a system drive + } + else + { + // same uuid found than in ignore file --> ignore this drive +#ifdef LOG_LEVEL_HIGH + Logger::logThis()->info("same uuid found than in ignore file --> ignore this drive: " + it->getPath()); +#endif + it = pvecDrives->erase(it); + it--; + } + } } - else - { - // same uuid found than in ignore file --> ignore this drive - it = pvecDrives->erase(it); - } - - } } - } } /** @@ -166,22 +396,33 @@ void reHDD::filterIgnoredDrives(vector * pvecDrives) */ void reHDD::printDrives(vector * pvecDrives) { - cout << "------------DRIVES---------------" << endl; +#ifdef LOG_LEVEL_HIGH + Logger::logThis()->info("------------DRIVES---------------"); + //cout << "------------DRIVES---------------" << endl; vector ::iterator it; for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it) - { - cout << " Drive: " << distance(pvecDrives->begin(), it) << endl; - cout << "Path: " << it->getPath() << endl; - cout << "ModelFamily: " << it->getModelFamily() << endl; - cout << "ModelName: " << it->getModelName() << endl; - cout << "Capacity: " << it->getCapacity() << endl; - cout << "Serial: " << it->getSerial() << endl; - cout << "PowerOnHours: " << it->getPowerOnHours() << endl; - cout << "PowerCycle: " << it->getPowerCycles() << endl; - cout << "ErrorCount: " << it->getErrorCount() << endl; - cout << endl; - } - cout << "---------------------------------" << endl; + { + /* + cout << " Drive: " << distance(pvecDrives->begin(), it) << endl; + cout << "Path: " << it->getPath() << endl; + cout << "ModelFamily: " << it->getModelFamily() << endl; + cout << "ModelName: " << it->getModelName() << endl; + cout << "Capacity: " << it->getCapacity() << endl; + cout << "Serial: " << it->getSerial() << endl; + cout << "PowerOnHours: " << it->getPowerOnHours() << endl; + cout << "PowerCycle: " << it->getPowerCycles() << endl; + cout << "ErrorCount: " << it->getErrorCount() << endl; + cout << endl;*/ + + ostringstream address; + address << (void const *)&pvecDrives->at(it - pvecDrives->begin()); + + + Logger::logThis()->info(to_string(it - pvecDrives->begin()) + ": " + it->getPath() + " - " + it->getModelFamily() + " - " + it->getSerial() + " @" + address.str()); + } + Logger::logThis()->info("---------------------------------"); + //cout << "---------------------------------" << endl; +#endif } /** @@ -193,8 +434,97 @@ void reHDD::addSMARTData(vector * pvecDrives) { vector ::iterator it; for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it) - { - Drive* pTmpDrive = iterator_to_pointer::iterator > (it); - SMART::readSMARTData(pTmpDrive); - } -} \ No newline at end of file + { + Drive* pTmpDrive = iterator_to_pointer::iterator > (it); + SMART::readSMARTData(pTmpDrive); + } +} + +void reHDD::handleArrowKey(TUI::UserInput userInput) +{ + int8_t u8EntrySize = (int8_t) vecDrives.size(); + switch (userInput) + { + case TUI::UserInput::DownKey: + u8SelectedEntry++; + if(u8SelectedEntry >= u8EntrySize) + { + u8SelectedEntry = 0; + } + break; + case TUI::UserInput::UpKey: + if(u8SelectedEntry == 0) + { + u8SelectedEntry = (u8EntrySize-1); + } + else + { + u8SelectedEntry--; + } + break; + default: + u8SelectedEntry = 0; + break; + } + + 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 for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial()); + getSelectedDrive()->state = Drive::TaskState::SHRED_ACTIVE; + //task for drive is running --> don´t show more task options + thread(ThreadShred).detach(); + } + + 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 + Delete::deleteDrive(getSelectedDrive()); //blocking, no thread + getSelectedDrive()->state = Drive::TaskState::NONE; //delete finished + getSelectedDrive()->bWasDeleteted = true; + Logger::logThis()->info("Finished delete for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial()); + } + } +} + +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 + } + } +} + + + diff --git a/src/shred/shred.cpp b/src/shred/shred.cpp new file mode 100644 index 0000000..7f9377b --- /dev/null +++ b/src/shred/shred.cpp @@ -0,0 +1,404 @@ +/** + * @file shred.cpp + * @brief shred drive + * @author hendrik schutter + * @date 03.05.2020 + */ + +#include "../../include/reHDD.h" +#ifndef DRYRUN +static char *randsrc = (char*) "/dev/urandom"; +static int force = 0, rmf = 0, zrf = 0, noround = 0, verbose = 0, syncio = 0, alwaysrand = 0, reqrand = 0; + +static char sfbuf[PATH_MAX*2]; + +struct tfnge_stream +{ + TFNG_UNIT_TYPE key[TFNG_NR_KEY_UNITS]; + TFNG_UNIT_TYPE iv[TFNG_NR_BLOCK_UNITS]; + TFNG_BYTE_TYPE carry_block[TFNG_BLOCK_SIZE]; + size_t carry_bytes; +}; + +static struct tfnge_stream tfnge; +#endif + +Shred::Shred() +{ + +} + + +Shred::~Shred() +{ + +} + + + +/** + * \brief shred drive with shred + * \param pointer of Drive instance + * \return void + */ +void Shred::shredDrive(Drive* drive, int* ipSignalFd) +{ +#ifdef DRYRUN + for(int i = 0; i<=100; i++) + { + if(drive->state != Drive::SHRED_ACTIVE) + { + return; + } + drive->setTaskPercentage(i+0.05); + write(*ipSignalFd, "A",1); + usleep(20000); + } +#endif + +#ifndef DRYRUN + + struct stat st; + char *buf, *s, *d, rc = 0; + int f, rsf; + int xret = 0, pat = 0, last = 0, special = 0, iIteration = 0; + size_t blksz = 0, x, y; + size_t l, ll = NOSIZE; + + const char *cpDrivePath = drive->getPath().c_str(); + + blockcount_max = SHRED_ITERATIONS*(drive->getCapacity()/4096); + +#ifdef LOG_LEVEL_HIGH + Logger::logThis()->info("Shred-Task: Max-BlockCount: " + to_string(blockcount_max) + " - Drive: " + drive->getSerial()); +#endif + + d32Percent = 0U; + + rsf = open(randsrc, O_RDONLY | O_LARGEFILE); + if (rsf == -1) + { + perror(randsrc); + exit(1); + } + + special = pat = 0; + iIteration = SHRED_ITERATIONS; + if (verbose) fprintf(stderr, "destroying %s ...\n", cpDrivePath); + + if (stat(cpDrivePath, &st) == -1) + { + perror(cpDrivePath); + XRET(1); + goto _return; + } + if (!blksz) blksz = (size_t)st.st_blksize; + + else l = ll = st.st_size; + if (l == 0 && !S_ISREG(st.st_mode)) special = 1; + memset(&st, 0, sizeof(struct stat)); + + if (force) if (chmod(cpDrivePath, S_IRUSR|S_IWUSR) == -1) + { + perror(cpDrivePath); + XRET(1); + } + f = open(cpDrivePath, O_WRONLY | O_LARGEFILE | O_NOCTTY | syncio); + if (f == -1) + { + XRET(1); + perror(cpDrivePath); + goto _return; + } + + buf = (char*) malloc(blksz); + if (!buf) + { + perror("malloc"); + XRET(2); + fprintf(stderr, "Continuing with fixed buffer (%zu bytes long)\n", sizeof(sfbuf)); + buf = sfbuf; + blksz = sizeof(sfbuf); + } + memset(buf, 0, blksz); + + if (read(rsf, buf, blksz) <= 0) fprintf(stderr, "%s: read 0 bytes (wanted %zu)\n", randsrc, blksz); + tfnge_init(&tfnge, buf); + + //iteration loop + while (iIteration) + { + lseek(f, 0L, SEEK_SET); + + if (iIteration <= 1 && zrf) + { + pat = 1; + rc = 0; + } + else if (iIteration == SHRED_ITERATIONS && reqrand) + { + pat = 0; + } + else if (!alwaysrand) + { + if (read(rsf, &rc, 1) <= 0) fprintf(stderr, "%s: read 0 bytes (wanted 1)\n", randsrc); + pat = rc%2; + if (read(rsf, &rc, 1) <= 0) fprintf(stderr, "%s: read 0 bytes (wanted 1)\n", randsrc); + } + else pat = 0; + + if (verbose) + { + if (pat) fprintf(stderr, "iteration (pat) %d (%02hhx%02hhx%02hhx) ...\n", SHRED_ITERATIONS-iIteration+1, rc, rc, rc); + else fprintf(stderr, "iteration (!pat) %d (random) ...\n", SHRED_ITERATIONS-iIteration+1); + } + // write block loop + while (1) + { + if(drive->state != Drive::SHRED_ACTIVE) + { + drive->setTaskPercentage(0); + d32Percent = 0.00; + blockcount = 0; + blockcount_max = 0; + Logger::logThis()->info("Aborted shred for: " + drive->getModelName() + "-" + drive->getSerial()); + goto _return; + } + + double d32TmpPercent = calcProgress(); + + + + if((d32TmpPercent-d32Percent) >= 0.09) + { + drive->setTaskPercentage(d32TmpPercent); + d32Percent = d32TmpPercent; +#ifdef LOG_LEVEL_HIGH + Logger::logThis()->info("Shred-Task: BlockCount: " + to_string(blockcount) + " - progress: " + to_string(d32Percent) + " - Drive: " + drive->getSerial()); +#endif + write(*ipSignalFd, "A",1); + } + + if (!pat) + { + tfnge_emit(buf, blksz, &tfnge); + } + else + { + memset(buf, rc, blksz); + } + + if (l <= blksz && !special) + { + last = 1; + } + errno = 0; + l -= write(f, buf, (noround && last) ? l : blksz); + if (errno) + { + perror(cpDrivePath); + errno = 0; + break; + } + + if (last) + { + last = 0; + break; + } + } + // write block loop end + l = ll; + fdatasync(f); + iIteration--; + } //iteration loop end + + if (rmf) + { + close(f); + f = open(cpDrivePath, O_WRONLY | O_TRUNC | O_LARGEFILE | O_NOCTTY | syncio); + if (verbose) fprintf(stderr, "removing %s ...\n", cpDrivePath); + x = strnlen(cpDrivePath, sizeof(sfbuf)/2); + s = sfbuf+(sizeof(sfbuf)/2); + memcpy(sfbuf, cpDrivePath, x); + *(sfbuf+x) = 0; + d = strrchr(sfbuf, '/'); + if (d) + { + d++; + y = d-sfbuf; + memset(d, '0', x-(d-sfbuf)); + } + else + { + y = 0; + memset(sfbuf, '0', x); + } + memcpy(s, sfbuf, x); + *(s+x) = 0; + + /* Somehow I need to rename original to destination */ + if (access(s, R_OK) != -1) + { + fprintf(stderr, "%s already exists!\n", s); + unlink(cpDrivePath); + goto _return; + } + if (verbose) fprintf(stderr, "%s -> %s\n", cpDrivePath, s); + if (rename(cpDrivePath, s) == -1) + { + perror(s); + goto _return; + } + + while (x > y+1) + { + *(sfbuf+x) = 0; + x--; + *(s+x) = 0; + if (access(s, R_OK) != -1) + { + fprintf(stderr, "%s already exists!\n", s); + unlink(sfbuf); + goto _return; + } + if (verbose) fprintf(stderr, "%s -> %s\n", sfbuf, s); + if (rename(sfbuf, s) == -1) + { + perror(s); + goto _return; + } + } + + if (verbose) fprintf(stderr, "remove %s\n", s); + unlink(s); + if (verbose) fprintf(stderr, "done away with %s.\n", cpDrivePath); + } + + tfnge_emit(NULL, 0, &tfnge); + if (buf && buf != sfbuf) free(buf); + if (f != -1) close(f); + +_return: + optind++; + close(rsf); +#endif + if(drive->state == Drive::SHRED_ACTIVE) + { + drive->bWasShredded = true; + drive->state= Drive::NONE; + drive->setTaskPercentage(0); + Logger::logThis()->info("Finished shred for: " + drive->getModelName() + "-" + drive->getSerial()); + } +} +#ifndef DRYRUN + +double Shred::calcProgress() +{ + blockcount++; + return ((((double)blockcount/(double)blockcount_max))*100); +} + + +void Shred::tfnge_init_iv(struct tfnge_stream *tfe, const void *key, const void *iv) +{ + memset(tfe, 0, sizeof(struct tfnge_stream)); + memcpy(tfe->key, key, TFNG_KEY_SIZE); + if (iv) memcpy(tfe->iv, iv, TFNG_BLOCK_SIZE); + tfe->carry_bytes = 0; +} + +void Shred::tfnge_init(struct tfnge_stream *tfe, const void *key) +{ + tfnge_init_iv(tfe, key, NULL); +} + +void Shred::tfng_encrypt_rawblk(TFNG_UNIT_TYPE *O, const TFNG_UNIT_TYPE *I, const TFNG_UNIT_TYPE *K) +{ + TFNG_UNIT_TYPE X, Y, Z, T; + TFNG_UNIT_TYPE K0, K1, K2, K3; + TFNG_UNIT_TYPE K4, T0, T1, T2; + + X = I[0]; + Y = I[1]; + Z = I[2]; + T = I[3]; + + K0 = K[0]; + K1 = K[1]; + K2 = K[2]; + K3 = K[3]; + K4 = K[4]; + T0 = K[5]; + T1 = K[6]; + T2 = K[7]; + + PROCESS_BLOCKP( 1,K1,T0,K0,K3,K2,T1); + PROCESS_BLOCKN( 2,K2,T1,K1,K4,K3,T2); + PROCESS_BLOCKP( 3,K3,T2,K2,K0,K4,T0); + PROCESS_BLOCKN( 4,K4,T0,K3,K1,K0,T1); + + PROCESS_BLOCKP( 5,K0,T1,K4,K2,K1,T2); + PROCESS_BLOCKN( 6,K1,T2,K0,K3,K2,T0); + PROCESS_BLOCKP( 7,K2,T0,K1,K4,K3,T1); + PROCESS_BLOCKN( 8,K3,T1,K2,K0,K4,T2); + + PROCESS_BLOCKP( 9,K4,T2,K3,K1,K0,T0); + PROCESS_BLOCKN(10,K0,T0,K4,K2,K1,T1); + PROCESS_BLOCKP(11,K1,T1,K0,K3,K2,T2); + PROCESS_BLOCKN(12,K2,T2,K1,K4,K3,T0); + + O[0] = X + K3; + O[1] = Y + K4 + T0; + O[2] = Z + K0 + T1; + O[3] = T + K1 + 18; +} + +void Shred::tfnge_emit(void *dst, size_t szdst, struct tfnge_stream *tfe) +{ + TFNG_BYTE_TYPE *udst = (uint8_t*) dst; + size_t sz = szdst; + + if (!dst && szdst == 0) + { + memset(tfe, 0, sizeof(struct tfnge_stream)); + return; + } + + if (tfe->carry_bytes > 0) + { + if (tfe->carry_bytes > szdst) + { + memcpy(udst, tfe->carry_block, szdst); + memmove(tfe->carry_block, tfe->carry_block+szdst, tfe->carry_bytes-szdst); + tfe->carry_bytes -= szdst; + return; + } + + memcpy(udst, tfe->carry_block, tfe->carry_bytes); + udst += tfe->carry_bytes; + sz -= tfe->carry_bytes; + tfe->carry_bytes = 0; + } + + if (sz >= TFNG_BLOCK_SIZE) + { + do + { + tfng_encrypt_rawblk(tfe->iv, tfe->iv, tfe->key); + memcpy(udst, tfe->iv, TFNG_BLOCK_SIZE); + udst += TFNG_BLOCK_SIZE; + } + while ((sz -= TFNG_BLOCK_SIZE) >= TFNG_BLOCK_SIZE); + } + + if (sz) + { + tfng_encrypt_rawblk(tfe->iv, tfe->iv, tfe->key); + memcpy(udst, tfe->iv, sz); + udst = (TFNG_BYTE_TYPE *)tfe->iv; + tfe->carry_bytes = TFNG_BLOCK_SIZE-sz; + memcpy(tfe->carry_block, udst+sz, tfe->carry_bytes); + } +} +#endif \ No newline at end of file diff --git a/src/smart.cpp b/src/smart.cpp index f85cab1..815ef00 100644 --- a/src/smart.cpp +++ b/src/smart.cpp @@ -40,17 +40,17 @@ void SMART::readSMARTData(Drive* drive) FILE* outputfileSmart = popen(cpComand, "r"); while ((getline(&cLine, &len, outputfileSmart)) != -1) - { - string sLine = string(cLine); + { + string sLine = string(cLine); - SMART::parseModelFamily(sLine); - SMART::parseModelName(sLine); - SMART::parseSerial(sLine); - SMART::parseCapacity(sLine); - SMART::parseErrorCount(sLine); - SMART::parsePowerOnHours(sLine); - SMART::parsePowerCycle(sLine); - } + SMART::parseModelFamily(sLine); + SMART::parseModelName(sLine); + SMART::parseSerial(sLine); + SMART::parseCapacity(sLine); + SMART::parseErrorCount(sLine); + SMART::parsePowerOnHours(sLine); + SMART::parsePowerCycle(sLine); + } fclose(outputfileSmart); drive->setDriveSMARTData(modelFamily, modelName, serial, capacity, errorCount, powerOnHours, powerCycle); //wirte data in drive } @@ -64,11 +64,12 @@ void SMART::parseModelFamily(string sLine) { string search("\"model_family\": "); size_t found = sLine.find(search); - if (found!=string::npos) { - sLine.erase(0, sLine.find(": ") + 3); - sLine.erase(sLine.length()-3, 3); - modelFamily = sLine; - } + if (found!=string::npos) + { + sLine.erase(0, sLine.find(": ") + 3); + sLine.erase(sLine.length()-3, 3); + modelFamily = sLine; + } } /** @@ -80,11 +81,12 @@ void SMART::parseModelName(string sLine) { string search("\"model_name\": "); size_t found = sLine.find(search); - if (found!=string::npos) { - sLine.erase(0, sLine.find(": ") + 3); - sLine.erase(sLine.length()-3, 3); - modelName = sLine; - } + if (found!=string::npos) + { + sLine.erase(0, sLine.find(": ") + 3); + sLine.erase(sLine.length()-3, 3); + modelName = sLine; + } } /** @@ -96,11 +98,12 @@ void SMART::parseSerial(string sLine) { string search("\"serial_number\": "); size_t found = sLine.find(search); - if (found!=string::npos) { - sLine.erase(0, sLine.find(": ") + 3); - sLine.erase(sLine.length()-3, 3); - serial = sLine; - } + if (found!=string::npos) + { + sLine.erase(0, sLine.find(": ") + 3); + sLine.erase(sLine.length()-3, 3); + serial = sLine; + } } /** @@ -112,11 +115,12 @@ void SMART::parseCapacity(string sLine) { string search("\"bytes\": "); size_t found = sLine.find(search); - if (found!=string::npos) { - sLine.erase(0, sLine.find(": ") + 2); - sLine.erase(sLine.length()-1, 1); - capacity = stol(sLine); - } + if (found!=string::npos) + { + sLine.erase(0, sLine.find(": ") + 2); + sLine.erase(sLine.length()-1, 1); + capacity = stol(sLine); + } } /** @@ -129,11 +133,11 @@ void SMART::parseErrorCount(string sLine) string search("\"error_count_total\": "); size_t found = sLine.find(search); if (found!=string::npos) - { - sLine.erase(0, sLine.find(": ")+2); - sLine.erase(sLine.length()-2, 2); - errorCount = stol(sLine); - } + { + sLine.erase(0, sLine.find(": ")+2); + sLine.erase(sLine.length()-2, 2); + errorCount = stol(sLine); + } } /** @@ -146,12 +150,12 @@ void SMART::parsePowerOnHours(string sLine) string search("\"hours\": "); size_t found = sLine.find(search); if (found!=string::npos) - { - sLine.erase(0, sLine.find(": ") + 2); - sLine.erase(sLine.length()-1, 1); - powerOnHours = stol(sLine); + { + sLine.erase(0, sLine.find(": ") + 2); + sLine.erase(sLine.length()-1, 1); + powerOnHours = stol(sLine); - } + } } /** @@ -164,11 +168,11 @@ void SMART::parsePowerCycle(string sLine) string search("\"power_cycle_count\": "); size_t found = sLine.find(search); if (found!=string::npos) - { - sLine.erase(0, sLine.find(": ") + 2); - sLine.erase(sLine.length()-2, 2); - powerCycle = stol(sLine); + { + sLine.erase(0, sLine.find(": ") + 2); + sLine.erase(sLine.length()-2, 2); + powerCycle = stol(sLine); - } + } } diff --git a/src/tui.cpp b/src/tui.cpp new file mode 100644 index 0000000..1f962cc --- /dev/null +++ b/src/tui.cpp @@ -0,0 +1,491 @@ +/** + * @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, COLOR_BLACK, COLOR_WHITE); + init_pair(COLOR_AREA_ENTRY_SELECTED, COLOR_BLACK, 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(vector * pvecDrives, uint8_t u8SelectedEntry) +{ + mxUIrefresh.lock(); + int stdscrX, stdscrY; + getmaxyx(stdscr, stdscrY, stdscrX); + + init_pair(COLOR_AREA_STDSCR,COLOR_WHITE, COLOR_BLUE); + wbkgd(stdscr, COLOR_PAIR(COLOR_AREA_STDSCR)); + + refresh(); + + overview=createOverViewWindow((int)(stdscrX/3), (stdscrY-15)); + wrefresh(overview); + + systemview=createSystemStats((int)(stdscrX/3), 10, (stdscrY-11)); + wrefresh(systemview); + + delwin(detailview); + + vector ::iterator it; + for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it) + { + string sModelFamily = it->getModelFamily(); + string sModelName = it->getModelName(); + string sCapacity = it->sCapacityToText(); + string sState = " "; + + bool bSelectedEntry = false; + + if(u8SelectedEntry == (it - pvecDrives->begin())) + { + bSelectedEntry = true; //mark this drive in entries list + displaySelectedDrive(pvecDrives->at(u8SelectedEntry), stdscrX, stdscrY); + } + + stringstream stream; + + switch (it->state) + { + case Drive::SHRED_ACTIVE: + + stream << fixed << setprecision(2) << (it->getTaskPercentage()); + sState = "Shredding: " + stream.str() + "%"; + break; + + case Drive::DELETE_ACTIVE: + sState = "Deleting ..."; + break; + + case Drive::NONE: + case Drive::SHRED_SELECTED: + case Drive::DELETE_SELECTED: + if (it->bWasDeleteted) + { + sState = "DELETED"; //mark drive as deleted previously + } + if (it->bWasShredded) + { + sState = "SHREDDED"; //mark drive as shreded previously, overwrite if deleted + } + break; + case Drive::FROZEN: + dialog=createFrozenWarning(70, 16, ((stdscrX)-(int)(stdscrX/2)-35),(int)(stdscrY/2)-8, it->getPath(), it->getModelFamily(), it->getModelName(), it->getSerial()); + wrefresh(dialog); + break; + default: + break; + } + + WINDOW * tmp = createEntryWindow( ((int)(stdscrX/3) - 2), 5, 3, (5* (it - pvecDrives->begin()) )+3, sModelFamily, sModelName, sCapacity, sState, bSelectedEntry); + wrefresh(tmp); + }//end loop though drives + + if(pvecDrives->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; + + menuview=createMenuView(((stdscrX)-(int)(stdscrX/3)-7), 10, (int)(stdscrX/3)+5,(stdscrY-11), menustate); + wrefresh(menuview); + + detailview=overwriteDetailViewWindow(((stdscrX)-(int)(stdscrX/3)-7), (stdscrY-15), (int)(stdscrX/3)+5); + wrefresh(detailview); + } + + 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; + 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); +} + +WINDOW* TUI::createOverViewWindow( int iXSize, int iYSize) +{ + WINDOW *newWindow; + newWindow = newwin(iYSize, iXSize, 2, 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, 2, 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 sModelFamlily = "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, sModelFamlily.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)); + + if(drive.getPowerOnHours() >= WORSE_HOURS) + { + mvwaddstr(newWindow,u16Line++, 3, "------------> WARNING: OPERATING HOURS <-----------"); + mvwaddstr(newWindow,u16Line++, 3, sPowerOnHours.c_str()); + mvwaddstr(newWindow,u16Line++, 3, "---------------------------------------------------"); + } + else + { + mvwaddstr(newWindow,u16Line++, 3, sPowerOnHours.c_str()); + } + + if(drive.getPowerCycles() >= WORSE_POWERUP) + { + mvwaddstr(newWindow,u16Line++, 3, "------------> WARNING: POWER-ON <------------------"); + mvwaddstr(newWindow,u16Line++, 3, sPowerCycle.c_str()); + mvwaddstr(newWindow,u16Line++, 3, "---------------------------------------------------"); + } + else + { + mvwaddstr(newWindow,u16Line++, 3, sPowerCycle.c_str()); + } + + if(drive.getErrorCount() > 0) + { + mvwaddstr(newWindow,u16Line++, 3, "------------> WARNING: S.M.A.R.T ERROR <-----------"); + mvwaddstr(newWindow,u16Line++, 3, sErrorCount.c_str()); + mvwaddstr(newWindow,u16Line++, 3, "---------------------------------------------------"); + } + else + { + mvwaddstr(newWindow,u16Line++, 3, sErrorCount.c_str()); + } + + return newWindow; +} + +WINDOW* TUI::overwriteDetailViewWindow( int iXSize, int iYSize, int iXStart) +{ + WINDOW *newWindow; + newWindow = newwin(iYSize, iXSize, 2, 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: Overwite 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, string sModelFamily, string sModelName, string sCapacity, string sState, bool bSelected) +{ + WINDOW *newWindow; + newWindow = newwin(iYSize, iXSize, iYStart, iXStart); + + if(!bSelected) + { + // entry is NOT selected + attron(COLOR_PAIR(COLOR_AREA_ENTRY)); + wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY)); + } + else + { + // entry IS selected + attron(COLOR_PAIR(COLOR_AREA_ENTRY)); + wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED)); + } + + box(newWindow, ACS_VLINE, ACS_HLINE); + + mvwaddstr(newWindow,1, 1, sModelFamily.c_str()); + mvwaddstr(newWindow,2, 1, sModelName.c_str()); + mvwaddstr(newWindow,3, 1, sCapacity.c_str()); + + mvwaddstr(newWindow,2, iXSize-sState.length()-5, sState.c_str()); + + return newWindow; +} + +WINDOW* TUI::createSystemStats(int iXSize, int iYSize, int iYStart) +{ + WINDOW *newWindow; + newWindow = newwin(iYSize, iXSize, iYStart, 2); + + 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); + + mvwaddstr(newWindow,2, 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 = 2; + + if(menustate.bAbort) + { + mvwaddstr(newWindow,u16Line++, 3, "Press A for Abort"); + } + if(menustate.bShred) + { + mvwaddstr(newWindow,u16Line++, 3, "Press S for Shred"); + } + if(menustate.bDelete) + { + mvwaddstr(newWindow,u16Line++, 3, "Press D for Delete"); + } + + 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 = 2; + mvwaddstr(newWindow,u16Line++, 3, optionA.c_str()); + mvwaddstr(newWindow,u16Line++, 3, optionB.c_str()); + + return newWindow; +} + +WINDOW* TUI::createFrozenWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, string sModelFamily, string sModelName, string sSerial) +{ + 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 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()); + + return newWindow; +} + +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::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/3)-7), (stdscrY-15), (int)(stdscrX/3)+5, drive); + wrefresh(detailview); + + menuview=createMenuView(((stdscrX)-(int)(stdscrX/3)-7), 10, (int)(stdscrX/3)+5,(stdscrY-11), menustate); + wrefresh(menuview); + + if(menustate.bConfirmShred == true) + { + dialog=createDialog(70, 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(70, 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); + } +} diff --git a/src/wipe.cpp b/src/wipe.cpp deleted file mode 100644 index a5626f9..0000000 --- a/src/wipe.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @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(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; -} diff --git a/vcCodium.code-workspace b/vcCodium.code-workspace index 6b6425d..9e8c99c 100644 --- a/vcCodium.code-workspace +++ b/vcCodium.code-workspace @@ -12,7 +12,57 @@ "unordered_map": "cpp", "string_view": "cpp", "ostream": "cpp", - "chrono": "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 } } \ No newline at end of file