94 Commits

Author SHA1 Message Date
9863c5591e cal metric: shred speed 2022-06-30 00:32:13 +02:00
c61859ed4e added shred speed to TUI 2022-06-29 19:27:37 +02:00
8de45505e4 fix update script 2022-06-29 19:08:43 +02:00
f8ba9c6732 Merge branch 'master' into develop 2022-05-18 22:03:14 +02:00
c01797be7f Merge branch 'develop' 2022-05-18 22:02:47 +02:00
0684744bdb update docs 2022-05-17 09:16:58 +02:00
91b31b6c52 Merge pull request 'feature/shredNG' (#38) from feature/shredNG into develop
Reviewed-on: #38
2022-05-17 09:02:03 +02:00
7930f363bd added newer screenshot 2022-05-17 07:44:44 +02:00
42bc26eac9 added deployment scripts 2022-05-17 07:43:26 +02:00
7f0926a271 removed flush in shred 2022-05-15 21:28:28 +02:00
e49c1a231c read random date in bulk to reduce syscalls 2022-05-15 15:17:49 +02:00
4fc44d9926 changed progress percentage calculation 2022-05-14 15:21:14 +02:00
c8a3220c3a using now own shred impl with check if the complete drive is full of zeros after shredding 2022-05-14 14:06:16 +02:00
0e391cebf3 display also days 2022-05-13 21:14:48 +02:00
ecc8a71c64 display shred duration after completion 2022-05-12 07:40:24 +02:00
48bbad914f display used time to shred drive 2022-05-11 23:45:05 +02:00
818e78796d updated ignoreDrive.conf 2022-05-11 22:32:43 +02:00
161e7f049b start reHDD on tty1 2022-05-11 22:31:08 +02:00
033760c328 disk uuid changed to 8 byte long 2022-05-11 21:53:58 +02:00
8c54e0e7d9 updated REDME 2022-01-26 19:38:16 +01:00
46a2de7bc4 Merge pull request 'change drive filter for system drive' (#36) from develop into master
Reviewed-on: #36
2022-01-26 19:34:37 +01:00
af38d60982 code cleanup 2022-01-26 19:33:41 +01:00
25d8ca6920 filter drives only based on UUID 2022-01-26 19:21:38 +01:00
52f5597ba9 updated service 2022-01-26 17:32:21 +01:00
9b9806b5c2 „README.md“ ändern 2022-01-26 17:18:12 +01:00
1e455bde02 added curl 2022-01-26 16:52:45 +01:00
8034ac496b Merge pull request 'adopt newer debian' (#35) from develop into master
Reviewed-on: #35
2022-01-26 16:41:56 +01:00
354ee04e73 „README.md“ ändern 2022-01-26 16:40:20 +01:00
84e42a430b dis[play capacity as double 2022-01-26 16:31:46 +01:00
77c7849484 Merge pull request 'fix' (#34) from fix into develop
Reviewed-on: #34
2022-01-26 15:45:59 +01:00
f2db85aa33 pclose instead fclose 2022-01-26 15:44:32 +01:00
c942f36e49 using lsblk for listing attached drives 2022-01-26 15:15:34 +01:00
068413c15d log attached drives 2022-01-26 13:52:21 +01:00
45a5cb303b upload log to dev 2020-10-01 17:52:46 +02:00
7748d49b54 Merge branch 'develop' into master 2020-09-21 22:10:00 +02:00
3cd6baed36 Merge branch 'master' into develop 2020-09-21 22:07:45 +02:00
3d34de1311 release of Beta 0.2.0 2020-09-21 21:56:26 +02:00
555da195b2 Merge branch 'develop' into master 2020-09-21 21:50:04 +02:00
e65af04488 changed vector to list; again 2020-09-21 21:47:29 +02:00
5e190ba08f merge 2020-09-21 21:19:58 +02:00
2a2bfc6fe6 delete task thread 2020-09-21 16:50:33 +02:00
13304c4705 update ui layout 2020-09-21 16:11:31 +02:00
ade79add2a increase visibility of smart values 2020-09-21 14:45:52 +02:00
65c19f6fb9 define-switch for frozen alert 2020-09-20 22:40:05 +02:00
66cfbb5da2 ls instead hwinfo; update UI even mutex is locked 2020-09-20 00:12:18 +02:00
04f46bb9d6 fixed delete cmd 2020-09-18 14:42:45 +02:00
1e67ddf5ea Merge pull request 'fix/list change vector to list' (#24) from fix/list into master
Reviewed-on: #24
2020-09-16 15:28:50 +02:00
9b9be1ea4a Merge branch 'master' into fix/list 2020-09-16 15:28:16 +02:00
93a741fc6f code cleanup 2020-09-16 15:27:25 +02:00
0fc3bc222e changed vector to list 2020-09-16 15:13:32 +02:00
6c06943f3e added update script 2020-09-16 14:42:51 +02:00
fc83b60d85 Merge pull request 'create first beta release' (#23) from develop into master
Reviewed-on: #23
2020-09-15 13:47:06 +02:00
44b6792ae9 added screenshot 2020-09-15 13:43:51 +02:00
95828afcc2 first beta release 2020-09-15 13:40:40 +02:00
92bd9a70a3 added notes for standalone 2020-09-15 13:28:02 +02:00
4d967d8a8e added build notes 2020-09-15 13:12:31 +02:00
5e74a99062 detect same drive with serial and path 2020-09-15 11:11:53 +02:00
5a0f92deec added debian install notes 2020-09-15 00:00:17 +02:00
67b8e302be detect frozen drives and show that the user 2020-09-11 17:18:53 +02:00
5f593682e2 updated gitignore 2020-09-10 12:51:07 +02:00
47043afb83 added about tool text 2020-09-10 12:50:18 +02:00
6b366451ed Merge pull request 'merge threading to develop' (#21) from threading into develop
Reviewed-on: #21
2020-09-10 10:31:36 +02:00
cb361acfd4 fixed bug with filtering new attached drives 2020-09-09 16:11:25 +02:00
938f267813 completed logger usage and changed shred task to non-static 2020-09-08 13:01:09 +02:00
730b1205f7 added logging basics 2020-09-07 17:23:15 +02:00
eab95844b8 changed WORSE_POWERUP 2020-08-31 09:40:31 +02:00
8357332b60 upadte ui after shred 2020-08-30 16:05:22 +02:00
37317def9f added mutex for ui refresh 2020-08-30 15:38:14 +02:00
7c00fd638c fixed bug #15 2020-08-30 12:03:37 +02:00
b271f7955a percent are now two digit precision 2020-08-28 15:28:57 +02:00
320e306d06 fixed states if drive is no longer present 2020-08-26 18:38:39 +02:00
424218bb23 dryrun and set states for new drives 2020-08-26 15:07:53 +02:00
f39fbfbd54 added custom implementation for shred 2020-08-26 00:12:39 +02:00
a2a18bbc34 delete task 2020-08-23 11:04:10 +02:00
ec300d7c75 kill shred thread after abort or offline drive 2020-08-23 10:42:03 +02:00
c6a8fd861d shred thread 2020-08-23 09:26:32 +02:00
e4b3923f6d parse percentage from shred cmd 2020-08-22 21:48:34 +02:00
df4ed53693 added shred dummy script 2020-08-18 22:12:10 +02:00
dc5e6b968b refactor menustatr 2020-08-10 22:52:13 +02:00
cf2bb664d7 fully implemented user menu 2020-08-09 23:05:32 +02:00
c2ab7c1c7f added states for tasks 2020-08-09 21:41:28 +02:00
f4726bf08c added system view with time 2020-08-07 22:52:11 +02:00
1e4d9975c6 added warning levels 2020-08-07 16:17:45 +02:00
29eda094a7 show drive stats human readable 2020-08-07 13:17:52 +02:00
99273756da show drive overview 2020-08-07 12:07:29 +02:00
1b0ea97ed1 select drive based on arrow keys 2020-08-07 11:38:00 +02:00
a92a9c2a2a added user input via keys 2020-08-06 22:45:05 +02:00
c13182b77f fixed capacity display 2020-08-06 11:51:13 +02:00
4c6aa1f19c display text on sub-windows 2020-08-06 11:41:38 +02:00
9322ea65a7 started to use the UI 2020-08-04 22:35:29 +02:00
89f900c970 detect offline drives 2020-08-04 19:51:34 +02:00
27b48de32a added filter algo for existing drives 2020-08-04 17:18:32 +02:00
a61d4321f6 added ipc 2020-08-04 11:59:45 +02:00
daa3a27edb stated to implement threading 2020-08-03 22:40:07 +02:00
39 changed files with 2419 additions and 371 deletions

4
.gitignore vendored
View File

@ -41,3 +41,7 @@
reHDD reHDD
reHDD.log
ignoreDrives.conf

View File

@ -3,12 +3,47 @@
## Useful for: ## Useful for:
* checking new drives for the first time * checking new drives for the first time
* checking used drives for their next live * 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/42bc26eac95429e20c0f0d59f684dfec0d600e75/doc/screenshot.png "Screenshot")
* search for new attached Hard Drives via USB ## Debian Build Notes
* 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
* `apt-get install ncurses-dev git make g++`
* `make release`
## 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`
### Installation
clone this repo into /root/
`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

17
astyle.sh Normal file
View File

@ -0,0 +1,17 @@
#! /bin/bash
echo starting astyle for $PWD
astyle --style=gnu src/*.cpp
rm -f src/*.orig
astyle --style=gnu src/logger/*.cpp
rm -f src/logger/*.orig
astyle --style=gnu include/*.h
rm -f include/*.orig
astyle --style=gnu include/logger/*.h
rm -f include//logger/*.orig
echo finished astyle for $PWD

View File

@ -1 +1 @@
<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> <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>

Binary file not shown.

View File

@ -0,0 +1 @@
<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>

BIN
doc/diagrams/states.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -467,7 +467,7 @@ LOOKUP_CACHE_SIZE = 0
# normally produced when WARNINGS is set to YES. # normally produced when WARNINGS is set to YES.
# The default value is: NO. # The default value is: NO.
EXTRACT_ALL = NO EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation. # be included in the documentation.
@ -904,7 +904,7 @@ FILE_PATTERNS = *.c \
# be searched for input files as well. # be searched for input files as well.
# The default value is: NO. # The default value is: NO.
RECURSIVE = NO RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be # 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 # 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. # The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
DISABLE_INDEX = NO DISABLE_INDEX = YES
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information. If the tag # structure should be generated to display hierarchical information. If the tag
@ -1510,7 +1510,7 @@ DISABLE_INDEX = NO
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO GENERATE_TREEVIEW = YES
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # 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. # doxygen will group on one line in the generated HTML documentation.
@ -2260,7 +2260,7 @@ HIDE_UNDOC_RELATIONS = YES
# set to NO # set to NO
# The default value is: NO. # The default value is: NO.
HAVE_DOT = NO HAVE_DOT = YES
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # 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 # 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. # The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
UML_LOOK = NO UML_LOOK = YES
# If the UML_LOOK tag is enabled, the fields and methods are shown inside the # 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 # 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. # The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
CALL_GRAPH = NO CALL_GRAPH = YES
# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller # If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
# dependency graph for every global function or class method. # dependency graph for every global function or class method.
@ -2389,7 +2389,7 @@ CALL_GRAPH = NO
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
CALLER_GRAPH = NO CALLER_GRAPH = YES
# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical # If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
# hierarchy of all classes instead of a textual one. # hierarchy of all classes instead of a textual one.

View File

@ -1,60 +0,0 @@
# 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%
...
```

BIN
doc/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View File

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

25
include/delete.h Normal file
View File

@ -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_

View File

@ -12,6 +12,44 @@
class Drive class Drive
{ {
public:
enum TaskState {NONE,
SHRED_SELECTED,
SHRED_ACTIVE,
DELETE_SELECTED,
DELETE_ACTIVE,
FROZEN
} state;
struct {
time_t u32ShredTimeDelta;
std::chrono::time_point<std::chrono::system_clock> chronoShredTimestamp;
unsigned long ulWrittenBytes;
} sShredSpeed;
bool bWasShredded = false;
bool bWasDeleteted = false;
bool bIsOffline = false;
uint32_t u32DriveChecksumAferShredding = 0U;
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)
time_t u32TimestampTaskStart = 0U; //unix timestamp for duration of an action
time_t u32TaskDuration = 0U; //time needed to complete the task
private:
void setTimestamp();
protected: protected:
public: public:
@ -28,6 +66,7 @@ public:
uint32_t getErrorCount(void); uint32_t getErrorCount(void);
uint32_t getPowerOnHours(void); //in hours uint32_t getPowerOnHours(void); //in hours
uint32_t getPowerCycles(void); uint32_t getPowerCycles(void);
void checkFrozenDrive(void);
void setDriveSMARTData( string modelFamily, void setDriveSMARTData( string modelFamily,
string modelName, string modelName,
@ -37,15 +76,20 @@ public:
uint32_t powerOnHours, uint32_t powerOnHours,
uint32_t powerCycles); uint32_t powerCycles);
private: string sCapacityToText();
string sPath; string sErrorCountToText();
string sModelFamily; string sPowerOnHoursToText();
string sModelName; string sPowerCyclesToText();
string sSerial;
uint64_t u64Capacity = 0U; //in byte void setTaskPercentage(double d32TaskPercentage);
uint32_t u32ErrorCount = 0U; double getTaskPercentage(void);
uint32_t u32PowerOnHours = 0U; //in hours
uint32_t u32PowerCycles = 0U; void setActionStartTimestamp();
time_t getActionStartTimestamp();
void calculateTaskDuration();
time_t getTaskDuration();
}; };
#endif // DRIVE_H_ #endif // DRIVE_H_

80
include/logger/logger.h Normal file
View File

@ -0,0 +1,80 @@
/**
* @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,6 +1,6 @@
/** /**
* @file reHDD.h * @file reHDD.h
* @brief represent * @brief app logic header
* @author hendrik schutter * @author hendrik schutter
* @date 01.05.2020 * @date 01.05.2020
*/ */
@ -8,19 +8,63 @@
#ifndef REHDD_H_ #ifndef REHDD_H_
#define REHDD_H_ #define REHDD_H_
#define REHDD_VERSION "bV0.2.2"
// 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 3U
#define FROZEN_TIMEOUT 10 //After this timeout (minutes) the drive will be marked as frozen
// Logger Settings
#define LOG_PATH "./reHDD.log"
#define DESCRIPTION "reHDD - Copyright Hendrik Schutter 2022"
#define DEVICE_ID "generic"
#define SOFTWARE_VERSION "alpha"
#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_ALERT //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 <iostream>
#include <string> #include <string>
#include <fstream> #include <fstream>
#include <tuple> #include <tuple>
#include <vector> #include <list>
#include <time.h> #include <time.h>
#include <chrono> #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; using namespace std;
#include "drive.h" #include "drive.h"
#include "smart.h" #include "smart.h"
#include "wipe.h" #include "shred.h"
#include "delete.h"
#include "tui.h"
#include "logger/logger.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)
{ {
@ -33,17 +77,25 @@ protected:
public: public:
reHDD(void); reHDD(void);
void app_logic(); static void app_logic();
private: private:
vector <Drive> vecDrives; //stores all drive data static void searchDrives(list <Drive>* plistDrives);
static void printDrives(list <Drive>* plistDrives);
void searchDrives(vector <Drive>* pvecDrives); static void filterIgnoredDrives(list <Drive>* plistDrives);
void printDrives(vector <Drive>* pvecDrives); static void filterNewDrives(list <Drive>* plistOldDrives, list <Drive>* plistNewDrives);
void filterIgnoredDrives(vector <Drive>* pvecDrives); static void addSMARTData(list <Drive>* plistDrives);
void addSMARTData(vector <Drive>* pvecDrives); static void ThreadScannDevices();
static void ThreadUserInput();
static void ThreadShred();
static void ThreadDelete();
static void ThreadCheckFrozenDrives();
static void handleArrowKey(TUI::UserInput userInput);
static void handleEnter();
static void handleESC();
static void handleAbort();
static Drive* getSelectedDrive();
}; };
#endif // REHDD_H_
#endif // REHDD_H_

56
include/shred.h Normal file
View File

@ -0,0 +1,56 @@
/**
* @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*2 //amount of bytes that are overwritten at once --> 2MB
#define CHUNK_DIMENSION 100U //amount of chunks are read at once from random source
//#define DEMO_DRIVE_SIZE 1024*1024*256L // 256MB
//#define DEMO_DRIVE_SIZE 1024*1024*1024L // 1GB
//#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 caChunk[CHUNK_DIMENSION][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_

72
include/tui.h Normal file
View File

@ -0,0 +1,72 @@
/**
* @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(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, string sModelFamily, string sModelName, string sCapacity, string sState, string sTime, string sSpeed, 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);
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);
};
#endif // TUI_H_

View File

@ -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_

View File

@ -10,15 +10,15 @@ SRC_PATH = src
# Space-separated pkg-config libraries used by this project # Space-separated pkg-config libraries used by this project
LIBS = LIBS =
# General compiler flags # General compiler flags
COMPILE_FLAGS = -std=c++11 -Wall -Wextra -g COMPILE_FLAGS = -std=c++17 -Wall -Wextra -g
# Additional release-specific flags # Additional release-specific flags
RCOMPILE_FLAGS = -D NDEBUG RCOMPILE_FLAGS = -D NDEBUG -O3
# Additional debug-specific flags # Additional debug-specific flags
DCOMPILE_FLAGS = -D DEBUG DCOMPILE_FLAGS = -D DEBUG
# Add additional include paths # Add additional include paths
INCLUDES = include INCLUDES = include
# General linker settings # General linker settings
LINK_FLAGS = LINK_FLAGS = -lpthread -lncurses
# Doc # Doc
DOCDIR = doc DOCDIR = doc
#### END PROJECT SETTINGS #### #### END PROJECT SETTINGS ####
@ -51,7 +51,7 @@ ifeq ($(V),true)
endif endif
# Combine compiler and linker flags # Combine compiler and linker flags
release: export CXXFLAGS := $(CXXFLAGS) $(COMPILE_FLAGS) $(RCOMPILE_FLAGS) release: export CXXFLAGS := $(CXXFLAGS) $(COMPILE_FLAGS) $(RCOMPILE_FLAGS)
release: export LDFLAGS := $(LDFLAGS) $(LINK_FLAGS) $(RLINK_FLAGS) release: export LDFLAGS := $(LDFLAGS) $(LINK_FLAGS) $(RLINK_FLAGS)
debug: export CXXFLAGS := $(CXXFLAGS) $(COMPILE_FLAGS) $(DCOMPILE_FLAGS) debug: export CXXFLAGS := $(CXXFLAGS) $(COMPILE_FLAGS) $(DCOMPILE_FLAGS)
debug: export LDFLAGS := $(LDFLAGS) $(LINK_FLAGS) $(DLINK_FLAGS) debug: export LDFLAGS := $(LDFLAGS) $(LINK_FLAGS) $(DLINK_FLAGS)
@ -167,6 +167,7 @@ clean:
@echo "Deleting directories" @echo "Deleting directories"
@$(RM) -r build @$(RM) -r build
@$(RM) -r bin @$(RM) -r bin
@$(RM) -f reHDD.log
# Main rule, checks the executable and symlinks to the output # Main rule, checks the executable and symlinks to the output
all: $(BIN_PATH)/$(BIN_NAME) all: $(BIN_PATH)/$(BIN_NAME)
@ -199,6 +200,7 @@ $(BUILD_PATH)/%.o: $(SRC_PATH)/%.$(SRC_EXT)
docs: docs:
@$(RM) -r $(DOCDIR)/html @$(RM) -r $(DOCDIR)/html
@doxygen $(DOCDIR)/doxyfile @doxygen $(DOCDIR)/doxyfile
.PHONY: style
style:
@bash astyle.sh

View File

@ -0,0 +1,17 @@
[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

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

View File

@ -0,0 +1,17 @@
[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

@ -0,0 +1,27 @@
#!/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

@ -0,0 +1,6 @@
#!/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

@ -0,0 +1,18 @@
[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

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

View File

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

View File

@ -0,0 +1,16 @@
[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

30
scripts/update.sh Normal file
View File

@ -0,0 +1,30 @@
#! /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
else
cp /root/reHDD/ignoreDrives.conf /root/ignoreDrives.conf
fi
git reset
git stash force
git stash
git checkout master
git pull
make release
cp /root/ignoreDrives.conf /root/reHDD/ignoreDrives.conf
systemctl start /lib/systemd/system/getty@tty1.service.d

42
src/delete.cpp Normal file
View File

@ -0,0 +1,42 @@
/**
* @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

@ -46,6 +46,66 @@ uint32_t Drive::getPowerCycles(void)
return u32PowerCycles; return u32PowerCycles;
} }
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());
}
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 * \brief set S.M.A.R.T. values in model
* \param string modelFamily * \param string modelFamily
@ -72,4 +132,47 @@ void Drive::setDriveSMARTData( string modelFamily,
u32ErrorCount = errorCount; u32ErrorCount = errorCount;
u32PowerOnHours = powerOnHours; u32PowerOnHours = powerOnHours;
u32PowerCycles = powerCycle; u32PowerCycles = powerCycle;
}
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))
{
Logger::logThis()->warning("Drive Frozen: " + this->getModelName() + " " + this->getSerial());
this->bWasDeleteted = false;
this->bWasShredded = false;
this->state = Drive::FROZEN;
}
} }

235
src/logger/logger.cpp Normal file
View File

@ -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
}
}

View File

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

View File

@ -7,6 +7,22 @@
#include "../include/reHDD.h" #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;
list <Drive> listNewDrives; //store found drives that are updated every 5sec
static list <Drive> listDrives; //stores all drive data from scann thread
TUI *ui;
static uint8_t u8SelectedEntry;
static fd_set selectSet;
/** /**
* \brief app constructor * \brief app constructor
* \param void * \param void
@ -14,7 +30,7 @@
*/ */
reHDD::reHDD(void) reHDD::reHDD(void)
{ {
cout << "created app" << endl; u8SelectedEntry = 0U;
} }
/** /**
@ -24,177 +40,475 @@ reHDD::reHDD(void)
*/ */
void reHDD::app_logic(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 pipe(fdNewDrivesInformPipe);
filterIgnoredDrives(&vecDrives); //filter out ignored drives pipe(fdShredInformPipe);
addSMARTData(&vecDrives); //add S.M.A.R.T. Data to the drives
printDrives(&vecDrives); //print currently attached drives
size_t u64SelectedDriveIndex = 0U; thread thDevices(ThreadScannDevices); //start thread that scanns for drives
size_t u64DriveVecSize = (vecDrives.size()); 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; while(1)
cin >> u64SelectedDriveIndex; {
cout << "Selected drive index: " << u64SelectedDriveIndex << endl; FD_ZERO(&selectSet);
FD_SET(fdNewDrivesInformPipe[0], &selectSet);
FD_SET(fdShredInformPipe[0], &selectSet);
if(u64SelectedDriveIndex < (u64DriveVecSize)) { select(FD_SETSIZE, &selectSet, NULL, NULL, NULL);
Wipe::wipeDrive(&vecDrives[u64SelectedDriveIndex]);
}
if(FD_ISSET(fdNewDrivesInformPipe[0], &selectSet))
{
mxScannDrives.lock();
char dummy;
read (fdNewDrivesInformPipe[0],&dummy,1);
filterNewDrives(&listDrives, &listNewDrives); //filter and copy to app logic vector
printDrives(&listDrives);
mxScannDrives.unlock();
}
if(FD_ISSET(fdShredInformPipe[0], &selectSet))
{
char dummy;
read (fdShredInformPipe[0],&dummy,1);
#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::ThreadScannDevices()
{
while(true)
{
mxScannDrives.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
mxScannDrives.unlock();
write(fdNewDrivesInformPipe[1], "A",1);
sleep(5); //sleep 5 sec
}
}
void reHDD::ThreadCheckFrozenDrives()
{
while(true)
{
mxScannDrives.lock();
for(auto it = begin(listDrives); it != end(listDrives); ++it)
{
if(it->state == Drive::SHRED_ACTIVE)
{
it->checkFrozenDrive();
}
}
mxScannDrives.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::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()
{
if (getSelectedDrive() != nullptr)
{
getSelectedDrive()->setActionStartTimestamp(); //save timestamp at start of shredding
Shred* pShredTask = new Shred(); //create new shred task
pShredTask->shredDrive(getSelectedDrive(), &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()->bWasDeleteted = 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 scann 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;
}
}
//search offline drives and mark them
for (itOld = plistOldDrives->begin(); itOld != plistOldDrives->end(); ++itOld)
{
itOld->bIsOffline = true; //set offline befor seachring 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
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Delete new drive, because allready attached: " + itNew->getModelName());
#endif
itNew = plistNewDrives->erase(itNew); //This drive is allready 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* * \brief search attached drives on /dev/sd*
* \param pointer of vector <Drive>* pvecDrives * \param pointer of list <Drive>* plistDrives
* \return void * \return void
*/ */
void reHDD::searchDrives(vector <Drive>* pvecDrives) void reHDD::searchDrives(list <Drive>* plistDrives)
{ {
cout << "search drives ..." << endl; Logger::logThis()->info("--> search drives <--");
char * cLine = NULL; char * cLine = NULL;
size_t len = 0; size_t len = 0;
FILE* outputfileHwinfo = popen("hwinfo --short --disk", "r"); FILE* outputfileHwinfo = popen("lsblk -I 8 -d -o NAME", "r");
if (outputfileHwinfo == NULL) if (outputfileHwinfo == NULL)
{ {
exit(EXIT_FAILURE); Logger::logThis()->error("Unable to scan attached drives");
} exit(EXIT_FAILURE);
}
while ((getline(&cLine, &len, outputfileHwinfo)) != -1) while ((getline(&cLine, &len, outputfileHwinfo)) != -1)
{
if (string(cLine).find("/dev/sd") != string::npos)
{ {
Drive* tmpDrive = new Drive(string(cLine).substr (2,8)); if (string(cLine).length() == 4)
pvecDrives->push_back(*tmpDrive); {
Drive* tmpDrive = new Drive("/dev/" + string(cLine).substr(0, 3));
tmpDrive->state = Drive::NONE;
tmpDrive->bIsOffline = false;
plistDrives->push_back(*tmpDrive);
//Logger::logThis()->info("drive found: " + tmpDrive->getPath());
}
} }
} pclose(outputfileHwinfo);
fclose(outputfileHwinfo);
} }
/** /**
* \brief filter out drives that are listed in "ignoreDrives.conf" * \brief filter out drives that are listed in "ignoreDrives.conf"
* \param pointer of vector <Drive>* pvecDrives * \param pointer of list <Drive>* plistDrives
* \return void * \return void
*/ */
void reHDD::filterIgnoredDrives(vector <Drive>* pvecDrives) void reHDD::filterIgnoredDrives(list <Drive>* plistDrives)
{ {
string sDelimiter = ":"; list<tuple<string>> vtlIgnoredDevices; //store drives from ingnore file
string sIgnoredDrivePath;
string sIgnoredDriveUUID;
vector<tuple<string, string>> vtlIgnoredDevices; //store drives from ingnore file
ifstream input( "ignoreDrives.conf" ); //read ingnore file ifstream input( "ignoreDrives.conf" ); //read ingnore file
for(string sLine; getline( input, sLine );) for(string sLine; getline( input, sLine );)
{
if (string(sLine).find("/dev/sd") != string::npos)
{ {
size_t pos = 0; Logger::logThis()->info("read uuid: " + sLine);
string token; vtlIgnoredDevices.emplace_back(sLine); //add found path and uuid from ignore file to vector
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 //loop through found entries in ingnore file
for(auto row : vtlIgnoredDevices) for(auto row : vtlIgnoredDevices)
{
auto it = pvecDrives->begin();
while (it != pvecDrives->end())
{ {
it++; list <Drive>::iterator it;
string sUUID; for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
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)
{ {
exit(EXIT_FAILURE); 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)
{
exit(EXIT_FAILURE);
}
while ((getline(&cLine, &len, outputfileBlkid)) != -1) //parse UUID from blkid while ((getline(&cLine, &len, outputfileBlkid)) != -1) //parse UUID from blkid
{ {
if (string(cLine).find("PTUUID") != string::npos) if (string(cLine).find("PTUUID") != string::npos)
{ {
string sBlkidOut = string(cLine); string sBlkidOut = string(cLine);
sBlkidOut.erase(0, 18); sBlkidOut.erase(0, 18);
sBlkidOut.erase(36, sBlkidOut.length() - 36); sBlkidOut.erase(8, sBlkidOut.length());
sUUID = sBlkidOut; sUUID = sBlkidOut;
//cout << "blkid uuid:" << sUUID << endl; //cout << "blkid uuid:" << sUUID << endl;
} }
} }
fclose(outputfileBlkid); pclose(outputfileBlkid);
// cout << "blkid uuid:" << sUUID << endl; //cout << "blkid uuid:" << sUUID << endl;
if (get<1>(row).compare(sUUID)) //compare uuid from ignore file and uuid from drive if (!get<0>(row).compare(sUUID)) //compare uuid from ignore file and uuid from drive
{ {
cout << "[ERROR] different uuid found than in ignore file:" << it->getPath() << endl; // same uuid found than in ignore file --> ignore this drive
exit(EXIT_FAILURE); // exit to prevent accidentally shred a system 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--;
}
} }
else
{
// same uuid found than in ignore file --> ignore this drive
it = pvecDrives->erase(it);
}
}
} }
}
} }
/** /**
* \brief print drives with all information * \brief print drives with all information
* \param pointer of vector <Drive>* pvecDrives * \param pointer of list <Drive>* plistDrives
* \return void * \return void
*/ */
void reHDD::printDrives(vector <Drive>* pvecDrives) void reHDD::printDrives(list <Drive>* plistDrives)
{ {
cout << "------------DRIVES---------------" << endl; #ifdef LOG_LEVEL_HIGH
vector <Drive>::iterator it; Logger::logThis()->info("------------DRIVES START------------");
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it) //cout << "------------DRIVES---------------" << endl;
{ list <Drive>::iterator it;
cout << " Drive: " << distance(pvecDrives->begin(), it) << endl; uint8_t u8Index = 0;
cout << "Path: " << it->getPath() << endl; for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
cout << "ModelFamily: " << it->getModelFamily() << endl; {
cout << "ModelName: " << it->getModelName() << endl; /*
cout << "Capacity: " << it->getCapacity() << endl; cout << " Drive: " << distance(pvecDrives->begin(), it) << endl;
cout << "Serial: " << it->getSerial() << endl; cout << "Path: " << it->getPath() << endl;
cout << "PowerOnHours: " << it->getPowerOnHours() << endl; cout << "ModelFamily: " << it->getModelFamily() << endl;
cout << "PowerCycle: " << it->getPowerCycles() << endl; cout << "ModelName: " << it->getModelName() << endl;
cout << "ErrorCount: " << it->getErrorCount() << endl; cout << "Capacity: " << it->getCapacity() << endl;
cout << endl; cout << "Serial: " << it->getSerial() << endl;
} cout << "PowerOnHours: " << it->getPowerOnHours() << endl;
cout << "---------------------------------" << 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 add S.M.A.R.T data from SMART * \brief add S.M.A.R.T data from SMART
* \param pointer of vector <Drive>* pvecDrives * \param pointer of list <Drive>* plistDrives
* \return void * \return void
*/ */
void reHDD::addSMARTData(vector <Drive>* pvecDrives) void reHDD::addSMARTData(list <Drive>* plistDrives)
{ {
vector <Drive>::iterator it; list <Drive>::iterator it;
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it) for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
{ {
Drive* pTmpDrive = iterator_to_pointer<Drive, std::vector<Drive>::iterator > (it); Drive* pTmpDrive = iterator_to_pointer<Drive, std::list<Drive>::iterator > (it);
SMART::readSMARTData(pTmpDrive); 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 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
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
}
}
}

292
src/shred.cpp Normal file
View File

@ -0,0 +1,292 @@
/**
* @file shred.cpp
* @brief shred drive
* @author hendrik schutter
* @date 03.05.2020
*/
#include "../include/reHDD.h"
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)
{
#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();
//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;
}
this->ulDriveByteSize = getDriveSizeInBytes(driveFileDiscr);
drive->sShredSpeed.chronoShredTimestamp = std::chrono::system_clock::now();; //set inital timestamp for speed metric
unsigned long 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
uint32_t u32ChunkDimensionIndex = 0U;
if(uiShredIterationCounter == (SHRED_ITERATIONS-1))
{
//last shred iteration --> overwrite with zeros instead with random data
memset(caChunk, 0U, CHUNK_DIMENSION*CHUNK_SIZE);
}
while (ulDriveByteCounter < ulDriveByteSize)
{
int iBytesToShred = 0; //Bytes that will be overwritten in this chunk-iteration
if((u32ChunkDimensionIndex == 0U) && (uiShredIterationCounter != (SHRED_ITERATIONS-1)))
{
//read new chunks from random source if needed and this is NOT the last shred iteration
unsigned long ulBytesInChunkBuffer = 0U;
while (ulBytesInChunkBuffer < CHUNK_DIMENSION*CHUNK_SIZE)
{
//read new random bytes
int iReadBytes = read(randomSrcFileDiscr, caChunk, ((CHUNK_DIMENSION*CHUNK_SIZE)-ulBytesInChunkBuffer));
if (iReadBytes > 0)
{
ulBytesInChunkBuffer += iReadBytes;
}
else
{
std::string errorMsg(strerror(iReadBytes));
Logger::logThis()->error("Shred-Task: Read from random source failed! " + errorMsg + " - Drive: " + drive->getSerial());
perror("unable to read random data");
cleanup();
return -1;;
}
} //end chunk read
#ifdef LOG_LEVEL_HIGH
Logger::logThis()->info("Shred-Task: Read new random data - Drive: " + drive->getSerial());
#endif
}
if((ulDriveByteSize-ulDriveByteCounter) < CHUNK_SIZE)
{
iBytesToShred = (ulDriveByteSize-ulDriveByteCounter);
}
else
{
iBytesToShred = CHUNK_SIZE;
}
int iByteShredded = write(driveFileDiscr, caChunk[u32ChunkDimensionIndex], 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;
}
u32ChunkDimensionIndex = (u32ChunkDimensionIndex+1)%CHUNK_DIMENSION;
ulDriveByteCounter += iByteShredded;
ulDriveByteOverallCount += iByteShredded;
d32Percent = this->calcProgress();
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;
//set metrics for calculating shred speed
std::chrono::time_point<std::chrono::system_clock> chronoCurrentTimestamp = std::chrono::system_clock::now();
drive->sShredSpeed.u32ShredTimeDelta = (chronoCurrentTimestamp - drive->sShredSpeed.chronoShredTimestamp).count();
drive->sShredSpeed.chronoShredTimestamp = std::chrono::system_clock::now();
drive->sShredSpeed.ulWrittenBytes = ulSpeedMetricBytesWritten;
ulSpeedMetricBytesWritten = 0U;
//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))
{
cleanup();
return -1;
}
} //end one shred iteration
#ifdef ZERO_CHECK_ALERT
drive->u32DriveChecksumAferShredding = uiCalcChecksum(driveFileDiscr, drive, ipSignalFd);
#ifdef LOG_LEVEL_HIGH
if (drive->u32DriveChecksumAferShredding != 0)
{
Logger::logThis()->info("Shred-Task: Checksum not zero: " + to_string(drive->u32DriveChecksumAferShredding) + " - Drive: " + drive->getSerial());
}
else
{
Logger::logThis()->info("Shred-Task: Checksum zero: " + to_string(drive->u32DriveChecksumAferShredding) + " - Drive: " + drive->getSerial());
}
#endif
#endif
#endif
cleanup();
if(drive->state == Drive::SHRED_ACTIVE)
{
drive->bWasShredded = true;
drive->state= Drive::NONE;
drive->setTaskPercentage(0.0);
Logger::logThis()->info("Finished shred 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_ALERT
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, caChunk, iBytesToCheck);
for (int iReadBytesCounter = 0U; iReadBytesCounter < iReadBytes; iReadBytesCounter++)
{
uiChecksum += caChunk[0][iReadBytesCounter];
}
ulDriveByteCounter += iReadBytes;
ulDriveByteOverallCount += iReadBytes;
d32Percent = this->calcProgress();
#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.9)
{
drive->setTaskPercentage(d32TmpPercent);
d32TmpPercent = d32Percent;
write(*ipSignalFd, "A",1);
}
}
return uiChecksum;
}
void Shred::cleanup()
{
close(driveFileDiscr);
close( randomSrcFileDiscr);
}

View File

@ -40,18 +40,18 @@ void SMART::readSMARTData(Drive* drive)
FILE* outputfileSmart = popen(cpComand, "r"); FILE* outputfileSmart = popen(cpComand, "r");
while ((getline(&cLine, &len, outputfileSmart)) != -1) while ((getline(&cLine, &len, outputfileSmart)) != -1)
{ {
string sLine = string(cLine); string sLine = string(cLine);
SMART::parseModelFamily(sLine); SMART::parseModelFamily(sLine);
SMART::parseModelName(sLine); SMART::parseModelName(sLine);
SMART::parseSerial(sLine); SMART::parseSerial(sLine);
SMART::parseCapacity(sLine); SMART::parseCapacity(sLine);
SMART::parseErrorCount(sLine); SMART::parseErrorCount(sLine);
SMART::parsePowerOnHours(sLine); SMART::parsePowerOnHours(sLine);
SMART::parsePowerCycle(sLine); SMART::parsePowerCycle(sLine);
} }
fclose(outputfileSmart); pclose(outputfileSmart);
drive->setDriveSMARTData(modelFamily, modelName, serial, capacity, errorCount, powerOnHours, powerCycle); //wirte data in drive 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\": "); string search("\"model_family\": ");
size_t found = sLine.find(search); 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(0, sLine.find(": ") + 3);
modelFamily = sLine; sLine.erase(sLine.length()-3, 3);
} modelFamily = sLine;
}
} }
/** /**
@ -80,11 +81,12 @@ void SMART::parseModelName(string sLine)
{ {
string search("\"model_name\": "); string search("\"model_name\": ");
size_t found = sLine.find(search); 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(0, sLine.find(": ") + 3);
modelName = sLine; sLine.erase(sLine.length()-3, 3);
} modelName = sLine;
}
} }
/** /**
@ -96,11 +98,12 @@ void SMART::parseSerial(string sLine)
{ {
string search("\"serial_number\": "); string search("\"serial_number\": ");
size_t found = sLine.find(search); 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(0, sLine.find(": ") + 3);
serial = sLine; sLine.erase(sLine.length()-3, 3);
} serial = sLine;
}
} }
/** /**
@ -112,11 +115,12 @@ void SMART::parseCapacity(string sLine)
{ {
string search("\"bytes\": "); string search("\"bytes\": ");
size_t found = sLine.find(search); 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(0, sLine.find(": ") + 2);
capacity = stol(sLine); sLine.erase(sLine.length()-1, 1);
} capacity = stol(sLine);
}
} }
/** /**
@ -129,11 +133,11 @@ void SMART::parseErrorCount(string sLine)
string search("\"error_count_total\": "); string search("\"error_count_total\": ");
size_t found = sLine.find(search); size_t found = sLine.find(search);
if (found!=string::npos) if (found!=string::npos)
{ {
sLine.erase(0, sLine.find(": ")+2); sLine.erase(0, sLine.find(": ")+2);
sLine.erase(sLine.length()-2, 2); sLine.erase(sLine.length()-2, 2);
errorCount = stol(sLine); errorCount = stol(sLine);
} }
} }
/** /**
@ -146,12 +150,12 @@ void SMART::parsePowerOnHours(string sLine)
string search("\"hours\": "); string search("\"hours\": ");
size_t found = sLine.find(search); size_t found = sLine.find(search);
if (found!=string::npos) if (found!=string::npos)
{ {
sLine.erase(0, sLine.find(": ") + 2); sLine.erase(0, sLine.find(": ") + 2);
sLine.erase(sLine.length()-1, 1); sLine.erase(sLine.length()-1, 1);
powerOnHours = stol(sLine); powerOnHours = stol(sLine);
} }
} }
/** /**
@ -164,11 +168,11 @@ void SMART::parsePowerCycle(string sLine)
string search("\"power_cycle_count\": "); string search("\"power_cycle_count\": ");
size_t found = sLine.find(search); size_t found = sLine.find(search);
if (found!=string::npos) if (found!=string::npos)
{ {
sLine.erase(0, sLine.find(": ") + 2); sLine.erase(0, sLine.find(": ") + 2);
sLine.erase(sLine.length()-2, 2); sLine.erase(sLine.length()-2, 2);
powerCycle = stol(sLine); powerCycle = stol(sLine);
} }
} }

615
src/tui.cpp Normal file
View File

@ -0,0 +1,615 @@
/**
* @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(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=createOverViewWindow((int)(u16StdscrX/3), (u16StdscrY-3));
wrefresh(overview);
systemview=createSystemStats((int)(u16StdscrX/3), 10, u16StdscrX-(int)(u16StdscrX/3)-2, (u16StdscrY-11 ));
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 sModelName = it->getModelName();
string sCapacity = it->sCapacityToText();
string sState = " ";
string sSpeed = " ";
string sTime = " ";
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))
{
// 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());
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::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->bWasDeleteted)
{
sState = "DELETED"; //mark drive as deleted previously
}
if (it->bWasShredded)
{
sState = "SHREDDED"; //mark drive as shreded previously, overwrite if deleted
sTime = this->formatTimeDuration(it->getTaskDuration());
}
#ifdef ZERO_CHECK_ALERT
if(bSelectedEntry && it->bWasShredded && (it->u32DriveChecksumAferShredding != 0U))
{
dialog=createZeroChecksumWarning(70, 16, ((u16StdscrX)-(int)(u16StdscrX/2)-20),(int)(u16StdscrY/2)-8, it->getPath(), it->getModelFamily(), it->getModelName(), it->getSerial(), it->u32DriveChecksumAferShredding);
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;
}
WINDOW * tmp = createEntryWindow( ((int)(u16StdscrX/3) - 2), 5, 3, (5* (u8Index) )+3, sModelFamily, sModelName, sCapacity, sState, sTime, sSpeed, 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;
menuview=createMenuView(((int)(u16StdscrX/3)-10 ), 10, (int)(u16StdscrX/3)+5,(u16StdscrY-11), menustate);
wrefresh(menuview);
detailview=overwriteDetailViewWindow(((u16StdscrX)-(int)(u16StdscrX/3)-7), (u16StdscrY-15), (int)(u16StdscrX/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));
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, 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, string sTime, string sSpeed, 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,1, iXSize-sSpeed.length()-5, sSpeed.c_str());
mvwaddstr(newWindow,2, iXSize-sState.length()-5, sState.c_str());
mvwaddstr(newWindow,3, iXSize-sTime.length()-5, sTime.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 = "Available under GPL 3.0";
string sLine04 = "https://git.mosad.xyz/localhorst/reHDD";
uint16_t u16Line = 2;
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLine01.size()/2), sLine01.c_str());
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());
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 = 2;
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 ";
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 sLineModelFamlily = "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, 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, 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::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(((int)(stdscrX/3)-10 ), 10, (int)(stdscrX/3)+5,(stdscrY-11), 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)
{
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. erros detected: " + to_string(u32ErrorCount);
mvwaddstr(newWindow,u16Line++, (iXSize/2)-(sLine01.size()/2), sLineTmp.c_str());
}
return newWindow;
}

View File

@ -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<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;
}

View File

@ -12,7 +12,57 @@
"unordered_map": "cpp", "unordered_map": "cpp",
"string_view": "cpp", "string_view": "cpp",
"ostream": "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
} }
} }