Compare commits
No commits in common. "master" and "prototype" have entirely different histories.
|
@ -41,10 +41,3 @@
|
|||
|
||||
reHDD
|
||||
|
||||
*.log
|
||||
*.ods
|
||||
*.txt
|
||||
|
||||
.vscode/
|
||||
|
||||
ignoreDrives.conf
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "tfnoisegen"]
|
||||
path = tfnoisegen
|
||||
url = https://git.mosad.xyz/localhorst/tfnoisegen.git
|
72
README.md
72
README.md
|
@ -1,68 +1,14 @@
|
|||
# reHDD
|
||||
|
||||
## Features:
|
||||
* show S.M.A.R.T values of attached drives
|
||||
* checking used drives for their next live based on threshold limits
|
||||
* delete a drive instant with wipefs
|
||||
* deleting a drive securely via overwriting
|
||||
* only needs a display and keyboard
|
||||
* process multiple drives at once
|
||||
## Useful for:
|
||||
* checking new drives for the first time
|
||||
* checking used drives for their next live
|
||||
* deleting a drive securely
|
||||
|
||||
## Download USB Image ##
|
||||
[2.5GB image v1.0.0](https://schuttercloud.com/s/ggxGH9sA326aRfK) (`wget` is your friend)
|
||||
## planned Features:
|
||||
|
||||
Use [Etcher](https://www.balena.io/etcher/#download) or `dd` to create an bootable USB drive .
|
||||
* search for new attached Hard Drives via USB
|
||||
* display Hard Drive Manufacturer, Model, Rotation Rate and Capacity
|
||||
* Check S.M.A.R.T. values and make an 'passed' or 'not passed' decision
|
||||
* If passed, wipe the data securely
|
||||
|
||||
## Screenshot
|
||||
![Screenshot of reHDD with multiple drives in different states](https://git.mosad.xyz/localhorst/reHDD/raw/commit/c40dfe2cbb8f86490b49caf82db70a10015f06f9/doc/screenshot.png "Screenshot")
|
||||
|
||||
## Debian Build Notes
|
||||
|
||||
* `apt-get install ncurses-dev git make g++`
|
||||
* `git submodule init`
|
||||
* `git submodule update`
|
||||
* `make release`
|
||||
|
||||
## Enable Label Printer ##
|
||||
|
||||
Just install [reHDDPrinter](https://git.mosad.xyz/localhorst/reHDDPrinter).
|
||||
No further settings needed.
|
||||
|
||||
## Create Standalone with Debian 11
|
||||
|
||||
Instructions how to create a standalone machine that boots directly to reHDD. This is aimed for production use, like several drives a day shredding.
|
||||
* Start reHDD after boot without login (as a tty1 shell)
|
||||
* Start dmesg after boot without login (as a tty2 shell)
|
||||
* Start htop after boot without login (as a tty3 shell)
|
||||
* Upload reHDD log every 12h if wanted
|
||||
|
||||
### Software requirements
|
||||
* `apt-get install hwinfo smartmontools curl htop sudo`
|
||||
|
||||
### Installation
|
||||
|
||||
clone this repo into /root/
|
||||
|
||||
```
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
`cd /root/reHDD/`
|
||||
|
||||
`make release`
|
||||
|
||||
`bash scripts/install_reHDD.bash`
|
||||
|
||||
If you want to upload the logs, edit `scripts/reHDDLogUploader.bash` with your nextcloud token
|
||||
|
||||
Add your system drive in `/root/reHDD/ignoreDrives.conf` like:
|
||||
```e102f49d```
|
||||
Get the first 8 Bytes from your UUID via `blkid /dev/sdX`
|
||||
|
||||
`reboot`
|
||||
|
||||
## Build docs
|
||||
`make docs`
|
||||
|
||||
open `doc/html/index.html` in browser
|
||||
|
|
|
@ -1 +1 @@
|
|||
<mxfile host="app.diagrams.net" modified="2020-08-23T07:05:27.762Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36" etag="SGyuMJOWQf98SwQRl4R2" version="13.6.4" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">5Vtbd5s4EP41Pmf3wT4gA3YefW26TXN2m3TT7kuPDLLRRkZUiNjOr18JhAGLxmRTbJr4xWgkdJmZb2Y0Ep3+ZL19x2Dof6QeIh1geNtOf9oBwDSHpviTlF1KsZ1hSlgx7KlGOeEGPyJFNBQ1xh6KSg05pYTjsEx0aRAgl5dokDG6KTdbUlIeNYQrpBFuXEh06h32uJ9Sh2CQ0y8RXvnZyKZzkdasYdZYrSTyoUc3BVJ/1ulPGKU8fVpvJ4hI5mV8uXu/uyNX9867P/6KvsPP4w+31393087mz3llvwSGAv6/u7bib1++z5aTb5fX79n19dXdzeqxq9Ya8V3GL+QJ9qkiZdynKxpAMsupY0bjwEOyV0OU8jZXlIaCaAriv4jzndIFGHMqSD5fE1UrVsF2X+T7PTsrflXdJYXptlTaqVJNNih2RTRmLnpi7UqsHLIV4k+066ftJGMKKqWY/A7RNRKTFA0YIpDjh7LeQaW+q327XETiQUnpGRJTs36AJFYj3dyOPt3qciREQEzKa+Njjm5CmDBjI1BelsbzuPqAGEfbJ/mgavsDpVybHHamoabvFyDnGA2xyjR1rrwZ7e7X1O7MTrdEvfuaegdoI90Pk0OLf8SFl5DymWvCZT5dL+LouMrvLbnk+5IGfA7XmEhBXCLygDh2oapQUjYFQ8aQ4FUgCq4QEGKyG87o/d6rJB2LIXGwEiUnL90mitO1ToG13QHOjmHvojHsOefA3k/GkFnXRZh2q0Bk6k6ijKKlZLSOnz37zeMYOkTHisAoUpKrAEYRcY2hwCmjAJgDHQWgAgVWYyiwXgEK6nqSdsVJ5lsObTN7dNxwDdolNFszXB3gELGCsYcfxONKPn5CUBgv43I6lf0FS5q1EWMWmlW8+dsaBvESujxmwoODidzmpTte+RgJqf7+o75ena20yrZyWBEx9Ctspd2UrQRvOVrPcHgUsKBd4Xo271qAvel97I16n3pis2rQpVytjzIc1wXwjDHKohSvvuCqehSQxg9ivTSI3iqC+3ZNBDe23wavIdoBdWN+cLZ45/PdPx+AOZ4N54/egl+5kyC87J7ZepZsZ25Kn7SeB5w7hxD7LxRZ8uqIMbgrNAgpDnhU6PlPSSggFwxLyLUGdlH8R9ubln2gLukMcuXZL+UFYNb3kJ8jGTQZQgnEThJHIUlXnfTlQQ574v8jZPdStMpMG1DuMw1fWJ/cYM8L1jqJ4BKOv8L9qDXoKdHuRW1VGGkH9GzdTA8aM9Pn2RltMS/EWaL0tVCT2wlZyMxES4IzUHcHDJxWBWeZ8z+ToAtizoVeLeizCaxdeTugZ7/j1ObiIIy5biDrJrwbs3CDcgxqV5k3syIGHTZl3KyzxKCnNG4o8EbyXFwUXenjsJsS55g0FRLXzSZZ7UoBAj2blOaMoOuikL804mgKVPtNmwKVUwUq40IHVWNpbNs+C6h+HYA4NQFig3YBxKkGiAPXUteDRRQmzDKWMCZ810649A9C7JPCpXIrfha0VCrWT9Rxq25MZRvV4jqNSlt6CDVjMNrnGY0sO7jIEoMRXCKyKyQNF3nKUOgQ99OXvsc0ae0nO9Ws2GsnJg5dyACcGxODs3oQs9Oq9JT9vBzjqfNTNihrzxAc3Cw80t4eGgf60kB+ytbzUxmGoxAGGYZT0HMYyazUEgc48hP8pjaAHR41iKkU324nuvcZ/Ew+lbd9Tonus1z2eVl2qEF0g1/CU2bTLABoigjiuavUnN8Gh2gZtRMUh2HgSV1eJYMdU2NwQDXmieXxMoe0e4aSCdiFZKQq1tjzUgihCD/CRdKV1Gxl2EW/9rhjT2VfAjWRyoo3yHzbLOeBzCwMKzC/6igSNMZ7Xbl3SNfcV8F8yy67A/NCv/bWFPMrvYEegmuMj3wYyke8Tj7fKErgkOFcuoM99QouEPlTsFWeHonaBeWcrkUDIivG0L1fJeZoQgllyVj9ZfITTZLBRlGYfmYiZQazwhJvpQEbq/lMfc7l9ykjyQgwd70A9LBLAxFAeIj1XDEimMsjL/En6fJQK8LrkKBujLsruJa6NrdNyUhz0DXBsBfKa8HC6XGoZi4vO2VKoQm7rp78WCkssxyTmbo5tIYV1nDYkFJYmlKoWyHlDHd6GsjFLiupTI8PWSyJkfBOydXvNJ5LThdJRA/fOQrx9DQwU5CABlIBl5iQA1J9U1Dl8srhTWNiHh4k4LM7GEWvZzk/BfyimH/slIbx+Sdj/dl/</diagram></mxfile>
|
||||
<mxfile host="app.diagrams.net" modified="2020-04-30T20:05:53.432Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36" etag="5yI57G0tj_AETib5-SCg" version="13.0.4" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">7VttU+o4FP41zOx+kGnTF+CjgKh3vczdxV31050Ioc1aGkyDiL9+kzalL6mXqlOCrDMONqdpSM85zzlPTkLLGiyezylc+t/JDAUtYMyeW9awBYBpA9ASf8Zsk0jcrpUIPIpnslMmmOAXJIWGlK7wDEWFjoyQgOFlUTglYYimrCCDlJJ1sducBMVvXUIPKYLJFAaq9AbPmJ9Iu6CTyS8Q9vz0m023l9xZwLSzfJPIhzOyzomss5Y1oISw5GrxPECBUF6ql5vLzU1w9eCef/szeoR/9/+4Hv9zkgw2essj21egKGTvHtpe/bx9PJsPfl6ML+l4fHUz8V5O5LtGbJPqC824+mSTUOYTj4QwOMukfUpW4QyJUQ3eyvpcEbLkQpML/0WMbaQvwBUjXOSzRSDv8regm1vxfNtJm3dyuLgxfC60NrKVzFVMsGTaHXqR/SKyolP0C2VIOzNIPcR+0c/aGp+jBpEF4pPkz1EUQIafipOD0n29bb/MRPxCWukNFpOTfILBSn7TD0o8ChcRnzdTzRkEHGnCbGsfMzRZwlgFaw72olHksIgy9PwO9arqkKNYHelj6wx9piHfws8hzzUa0phpqlr5/zq5VdPJTaParPvxckvx8hDxK+AGfM79e8qvPBZry4UL4cnhfST+XQyHYjoL/vFj0LJGVU+UfIH6ZHG/inYjZBv/hZnmJGQjuMCBsNsFCp4Qw1Mob0inMLn++jDAXsgbU24+RMUwjJKHbS6KB+ZfiUOPt9ysdR372Ym9D2huSrDcBdVeY1B1dUC1aciZdROL6ejEnKmmlnEMOiNBlYfmQtGhiqCtAczdKCrjwwtgFEnbVUAjj7nGcOAWcQDMjooDUIEDuzEc2MeIg7qpRyu/Mr8osRKR6oSujlajOUrougznJBLrVp500wgWoEiErzIl+O0C0YjxrxFd+QQMuQoWl+e0NbBafVd89kbo9yMMfnYx+HUrSIBVEfycpoIf+OLrCrBqIBBoJezpNHMInLS/t0/bf7Wva6LwjFJCowR2EyaphmichtHUhwEXeSg8fgRaTk0ENrZiBkdJP0BdGg60EhCg0nAeclbsJYYQ5FmK/xtCJtBhwPCFOwQK2/w6xY/B7SA8hfgoj6RRAUbidQhriTInfcCIHiOttzvtjlOAlm1XQMsFbUcFV6cxcHW1pLdnzG5z13dZpuOtLLeJRpraDjUlgroLCaCVlAI9Kwlp6My4d7k7x2poV6eh09ysydBvQPThGExrpQuo5eUzHHrwHsVUVeTQNOVGalqsWy9uLK91inzRqUpqZgVf7DaV0mwtfHGfkQ6Fs1OxGc2bU8Fs8DQRjnCwN/patxRj66WvailGbso8vKAl41RT3aR8E9NsClbbJVZ60KEKVkZPhVVjVWDH0QKrTwwRtyZEHKAVIm41RIpbmXEqmqOHA4WLVVpa6YeLBY49CzWOn7q1RusV39gTftRao0wxq2iN6PyjtYymIOOah5ZhbD0rl8+bYaz0CGPTe5jxo/xt4SbXYUlwyKLcyD+EIOdgbjEmd7qlI4Gl/h3X+FD/9HBI5oLJjDOH3L76B8K6+Qra15iKOucTiU/7JIfgxCX2QkIPl2eWo0AH6I4CrvX5EmchbmRh5HAjh123NGJrLY3YamkkQRvXmR/vQATJhnjEm2IXYYFFgODk9XElDkL3I59yr9g2DxOD5bWefgw6na9M/DY81S2HOFr3xW21HJJufUdLGKab3yFa8U75HfPtbh4ntR66r9oxTyV8YvmxDhNyoMxNetohp+ecyTvK9p8Ypk7dTXcthLlXTAPdHfy3p4H+pgrcEUCSJD3nsMXekUWKrqs7Urh6C7Fm67ORXQfsi+y+C/Z2if51zX0AGbzCrOsRauNE3DQPnVmXy8L6mbWr1g/GCKslQq4IVtSR8tMdoS48hcGpvLHAs1mCdRThF3gfDyUgKB2Qj+v0W85QjMXhHcnzUQ2q30lVm6aodD2XU3+q6bz2QWPaV73+GzxO3dtOiR701J+RVB3jfIfueTP73XESoLJfb1tn/wE=</diagram></mxfile>
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
<mxfile host="app.diagrams.net" modified="2020-08-23T06:57:40.722Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36" etag="hfpQUXi749i-5e3peR6Z" version="13.6.4" type="device"><diagram id="uYiMRnSvU_g0LN3LXuwh" name="Page-1">5Vtbd6M2EP41fkwOkrg+Ojbb3Z5sNo192u4jiRWbXYxcWV7b/fUVRgIL4Usag0jykqBBkmFmvtE3I9FDg/nmNxotZl/JBCc9aE02PTTsQeh6Dv+bCba5ANl+LpjSeJKLQCkYxf9iIbSEdBVP8FLpyAhJWLxQhU8kTfETU2QRpWStdnsmifqri2iKNcHoKUp06V/xhM1yqQ+9Uv4Zx9OZ/GXgBvmdeSQ7izdZzqIJWe+JUNhDA0oIy6/mmwFOMt1JveTjPh24WzwYxSk7ZwD78uOPwA1nv4++jj9B9/4n+7a+ssXTLtlWvjGecAWIJqFsRqYkjZKwlN5QskonOJvW4q2yzy0hCy4EXPgDM7YV1oxWjHDRjM0TcRdvYvZ3NvzaEa3ve3eGGzHzrrGVjZTR7d6grPl9/145bNeS4/L3y17qoN6EaElW9AkfUZb0v4hOMTvSDxbW5ajAZI758/BxFCcRi3+pzxEJ/5wW/UoT8gthxRdYVMz7K0pW4pd60E344948E/7C+6Z2/1kReeNquTNWn3cA/mJT3uRX0+z/aNx/GMup+JPls+X3dB9KEg7QzFfWs5jh0SLaKXbNQ4TqCeJhMWV4c9w+uj7FACQRJyOMwNu6hGsgRLM9pNpWQwaANQaoqEcFUAsqcmxFRYGuIgBrdOQ2pSMANJ20EXbKEGJ7Sgy5hs6JMLJr3WMacwVgevnYgs6MLZ7R2KK7crtmMxX5z7WO/0rr7Ib2KY22ex0WJE7Zcm/m+0xQotsGKroBqhCBSn8HwWP9+UX+BKWfFK/y/10HaVFxtKNjlP8dzSj3D7G0PFK5qgyLDkOccNR1LowCcGYcbWytsRta7O++3YXnrvVcn5l8ySj5iQckIVl0TEmaYf85TpKKaM8k2bQC9dCWbTFxdj8zVsypeD+JpymXzePJZBdSIiF44obLgvFlaIRqXL/GtlabtnW6xyN49qYCwDNOJBzDKxKwXZVJBL53Yl1qmkq4Zy5WyMRiBQPVhaB1fLFCHjzWv5nFCnga9sLRoNbTbqNHnKjeoUWng3GMYh6Io8fdfJkTCOXxyZ2bnjM8BlpR7xCDe0WVYd9hjiDmIMQ5NXaQKNG8zBNK08ku5Pl5yT2wivELGAgiw7A3RUTPxTYIXgnuV0VlV4fP3Th8KPjcFi91urdDmOiQku6tdecmzY0RAj0ovZjswdrKzueHMOPao/A2HIyzyw9F/KCNVEO7ppmf3z3mZ1eW4Q4wP9fwEuD5Sg0JXFvINsz8gi4zv2rZ4RTzs+VOUavMT8fe+2F+7gnm5yDXVVQuNxO6SwSRHho/BhE8F+rwtSXJVwXp4B0QQW3pM04EZdnx4kxwyBngOPy4VND2K6Y2TgVBbd28XvsNLURZ+Msd52J1dKnCI3X0OkDBxrSs19GHb17LDuialvXVwHhwr2b5sA7xreY10HReg5BS0eZ5DSh6GMprpAG6mdigSkkbtZGoQL0a1K91nDeXpsBTaYqN1AM/Iop0OEnxzUK697KjLiaAC00At/DJeuCe7A8sp3mg2/qBPlmwHZD5ovZgRAu4p4Rxy5BsVGA1EgfQgcxVTH/FVyrL87qOfajnav0iu+0/clx3jwPVHX1oNcGFus9fdqujPxh/+fOjnXCBdsXOjunsFupnXER96I3nXtCvqLrmULLbZu4F38CekvncCxk/VhBU95TM516d3lSyobpj0UruhfRy0TvJvdABI5a5l1U5Jtn95MvMF04lpoOg8q0BKAssXce0kbTMBS9Ly6r9A7/5EGDrtL7YPHnnadmBk2VlWga9SkLR/W1kCYgOZ2kaWzKepSEdAxfehvyQaVp1E7LJNI03yw+QczCVX3Gj8D8=</diagram></mxfile>
|
Binary file not shown.
Before Width: | Height: | Size: 61 KiB |
16
doc/doxyfile
16
doc/doxyfile
|
@ -467,7 +467,7 @@ LOOKUP_CACHE_SIZE = 0
|
|||
# normally produced when WARNINGS is set to YES.
|
||||
# The default value is: NO.
|
||||
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_ALL = NO
|
||||
|
||||
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
|
||||
# be included in the documentation.
|
||||
|
@ -904,7 +904,7 @@ FILE_PATTERNS = *.c \
|
|||
# be searched for input files as well.
|
||||
# The default value is: NO.
|
||||
|
||||
RECURSIVE = YES
|
||||
RECURSIVE = NO
|
||||
|
||||
# The EXCLUDE tag can be used to specify files and/or directories that should be
|
||||
# excluded from the INPUT source files. This way you can easily exclude a
|
||||
|
@ -1493,7 +1493,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project
|
|||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
DISABLE_INDEX = YES
|
||||
DISABLE_INDEX = NO
|
||||
|
||||
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
||||
# structure should be generated to display hierarchical information. If the tag
|
||||
|
@ -1510,7 +1510,7 @@ DISABLE_INDEX = YES
|
|||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
GENERATE_TREEVIEW = YES
|
||||
GENERATE_TREEVIEW = NO
|
||||
|
||||
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
|
||||
# doxygen will group on one line in the generated HTML documentation.
|
||||
|
@ -2260,7 +2260,7 @@ HIDE_UNDOC_RELATIONS = YES
|
|||
# set to NO
|
||||
# The default value is: NO.
|
||||
|
||||
HAVE_DOT = YES
|
||||
HAVE_DOT = NO
|
||||
|
||||
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
|
||||
# to run in parallel. When set to 0 doxygen will base this on the number of
|
||||
|
@ -2326,7 +2326,7 @@ GROUP_GRAPHS = YES
|
|||
# The default value is: NO.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
UML_LOOK = YES
|
||||
UML_LOOK = NO
|
||||
|
||||
# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
|
||||
# class node. If there are many fields or methods and many nodes the graph may
|
||||
|
@ -2377,7 +2377,7 @@ INCLUDED_BY_GRAPH = YES
|
|||
# The default value is: NO.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
CALL_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
|
||||
# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
|
||||
# dependency graph for every global function or class method.
|
||||
|
@ -2389,7 +2389,7 @@ CALL_GRAPH = YES
|
|||
# The default value is: NO.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
CALLER_GRAPH = YES
|
||||
CALLER_GRAPH = NO
|
||||
|
||||
# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
|
||||
# hierarchy of all classes instead of a textual one.
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
# Installation
|
||||
**[1]** In terminal als root einloggen\
|
||||
**[2]** In reHDD_prototype wechseln\
|
||||
**[3]** Abhängigkeiten installieren\
|
||||
`apt-get install smartmontools`\
|
||||
`apt-get install hwinfo`\
|
||||
`apt-get install util-linux`
|
||||
|
||||
**[4]** reHDD ausführbar machen\
|
||||
`chmod +x reHDD`\
|
||||
**[5]** ignoreDrives.conf bearbeiten
|
||||
##### Ein Eintrag in der ignoreDrives-Datei sorgt dafür das die Software bestimmte Festplatten ignoriert. Dies ist wichtig damit nicht unbeabsichtigt die Systemfestplatte oder weitere Festplatten bearbeitet (gelöscht) werden.
|
||||
Beispiel Inhalt:
|
||||
```
|
||||
/dev/sda:508eff7d-f039-4efb-9e2c-22dffdfdfdfd
|
||||
/dev/sdb:07dfffff-c4b6-46e7-9cdf-3cfdfdffd53d
|
||||
/dev/sdc:dfff974d-1af2-4dfd-9dfd-a2d8e4c43dff
|
||||
```
|
||||
Ein Eintrag setzt sich aus zwei Teilen zusammen:
|
||||
|
||||
**[Pfad]:[PARTUUID]**
|
||||
|
||||
Der Pfad kann mittels `fdisk -l` ermittelt werden.\
|
||||
Die PARTUUID kann mittels `blkid /dev/sda` ermittelt werden, wobei `/dev/sda` derzuvor ermittelte Pfad ist.
|
||||
|
||||
# Benutzung
|
||||
reHDD starten mit `./reHDD` (Wichtig ist das reHDD mit root-Rechen ausgeführt wird, entwender als root einloggen oder mit `sudo`)
|
||||
|
||||
reHDD sucht automatisch nach allen verfügbaren Festplatten und filtert die zu ignorierenden heraus.\
|
||||
Für die verbleibenden Festplatten wird eine Übersicht ausgegeben.
|
||||
Der Nutzer wird gefragt, welche Festplatte bearbeitet werden soll und gibt die Nummer ein.
|
||||
|
||||
Beispiel:
|
||||
|
||||
```
|
||||
hostname@hendrik:/reHDD_prototype # ./reHDD
|
||||
refurbishingHddTool
|
||||
created app
|
||||
app logic
|
||||
search drives ...
|
||||
------------DRIVES---------------
|
||||
Drive: 0
|
||||
Path: /dev/sdd
|
||||
ModelFamily:
|
||||
ModelName: ADATA SU650
|
||||
Capacity: 120034123776
|
||||
Serial: H50125K001601
|
||||
PowerOnHours: 93
|
||||
PowerCycle: 187
|
||||
ErrorCount: 0
|
||||
|
||||
---------------------------------
|
||||
Select drive to wipe:
|
||||
0
|
||||
Selected drive index: 0
|
||||
wipe: shred -v /dev/sdd
|
||||
shred: /dev/sdd: Durchgang 1/3 (random)…
|
||||
shred: /dev/sdd: Durchgang 1/3 (random)…847MiB/112GiB 0%
|
||||
...
|
||||
```
|
Binary file not shown.
Before Width: | Height: | Size: 92 KiB |
|
@ -1,3 +1,3 @@
|
|||
4673974d
|
||||
2cb3dea4
|
||||
8ffbc421
|
||||
/dev/sda:508ef27d-5039-4e8b-9e2c-22d7528b7149
|
||||
/dev/sdb:07f4ad14-c4b6-46e7-9cdf-3cfa9841d53d
|
||||
/dev/sdc:4673974d-1af2-44fd-996b-a2d8e4c43d9a
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
/**
|
||||
* @file delete.h
|
||||
* @brief delete drive
|
||||
* @author hendrik schutter
|
||||
* @date 23.08.2020
|
||||
*/
|
||||
|
||||
#ifndef DELETE_H_
|
||||
#define DELETE_H_
|
||||
|
||||
#include "reHDD.h"
|
||||
|
||||
class Delete
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
static void deleteDrive(Drive *drive);
|
||||
|
||||
private:
|
||||
Delete(void);
|
||||
};
|
||||
|
||||
#endif // DELETE_H_
|
|
@ -12,56 +12,8 @@
|
|||
|
||||
class Drive
|
||||
{
|
||||
|
||||
public:
|
||||
enum TaskState
|
||||
{
|
||||
NONE,
|
||||
SHRED_SELECTED,
|
||||
SHRED_ACTIVE, // shred iterations active
|
||||
CHECK_ACTIVE, // optional checking active
|
||||
DELETE_SELECTED,
|
||||
DELETE_ACTIVE,
|
||||
FROZEN
|
||||
} state;
|
||||
|
||||
struct
|
||||
{
|
||||
time_t u32ShredTimeDelta;
|
||||
std::chrono::time_point<std::chrono::system_clock> chronoShredTimestamp;
|
||||
unsigned long ulWrittenBytes;
|
||||
unsigned long ulSpeedMetricBytesWritten;
|
||||
} sShredSpeed;
|
||||
|
||||
bool bWasShredded = false; // all shred iterations done
|
||||
bool bWasChecked = false; // all shred iterations and optional checking done
|
||||
bool bWasDeleted = false;
|
||||
bool bIsOffline = false;
|
||||
uint32_t u32DriveChecksumAfterShredding = 0U;
|
||||
|
||||
private:
|
||||
string sPath;
|
||||
time_t u32Timestamp = 0U; // unix timestamp for detecting a frozen drive
|
||||
double d32TaskPercentage = 0U; // in percent for Shred (1 to 100)
|
||||
time_t u32TimestampTaskStart = 0U; // unix timestamp for duration of an action
|
||||
time_t u32TaskDuration = 0U; // time needed to complete the task
|
||||
|
||||
struct
|
||||
{
|
||||
string sModelFamily;
|
||||
string sModelName;
|
||||
string sSerial;
|
||||
uint64_t u64Capacity = 0U; // in byte
|
||||
uint32_t u32ErrorCount = 0U;
|
||||
uint32_t u32PowerOnHours = 0U; // in hours
|
||||
uint32_t u32PowerCycles = 0U;
|
||||
uint32_t u32Temperature = 0U; // in Fahrenheit, just kidding: degree Celsius
|
||||
} sSmartData;
|
||||
|
||||
private:
|
||||
void setTimestamp();
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
Drive(string path)
|
||||
{
|
||||
|
@ -72,36 +24,28 @@ public:
|
|||
string getModelFamily(void);
|
||||
string getModelName(void);
|
||||
string getSerial(void);
|
||||
uint64_t getCapacity(void); // in byte
|
||||
uint64_t getCapacity(void); //in byte
|
||||
uint32_t getErrorCount(void);
|
||||
uint32_t getPowerOnHours(void); // in hours
|
||||
uint32_t getPowerOnHours(void); //in hours
|
||||
uint32_t getPowerCycles(void);
|
||||
uint32_t getTemperature(void); // in Fahrenheit, just kidding: degree Celsius
|
||||
void checkFrozenDrive(void);
|
||||
|
||||
void setDriveSMARTData(string modelFamily,
|
||||
string modelName,
|
||||
string serial,
|
||||
uint64_t capacity,
|
||||
uint32_t errorCount,
|
||||
uint32_t powerOnHours,
|
||||
uint32_t powerCycles,
|
||||
uint32_t temperature);
|
||||
void setDriveSMARTData( string modelFamily,
|
||||
string modelName,
|
||||
string serial,
|
||||
uint64_t capacity,
|
||||
uint32_t errorCount,
|
||||
uint32_t powerOnHours,
|
||||
uint32_t powerCycles);
|
||||
|
||||
string sCapacityToText();
|
||||
string sErrorCountToText();
|
||||
string sPowerOnHoursToText();
|
||||
string sPowerCyclesToText();
|
||||
string sTemperatureToText();
|
||||
|
||||
void setTaskPercentage(double d32TaskPercentage);
|
||||
double getTaskPercentage(void);
|
||||
|
||||
void setActionStartTimestamp();
|
||||
time_t getActionStartTimestamp();
|
||||
|
||||
void calculateTaskDuration();
|
||||
time_t getTaskDuration();
|
||||
private:
|
||||
string sPath;
|
||||
string sModelFamily;
|
||||
string sModelName;
|
||||
string sSerial;
|
||||
uint64_t u64Capacity = 0U; //in byte
|
||||
uint32_t u32ErrorCount = 0U;
|
||||
uint32_t u32PowerOnHours = 0U; //in hours
|
||||
uint32_t u32PowerCycles = 0U;
|
||||
};
|
||||
|
||||
#endif // DRIVE_H_
|
||||
#endif // DRIVE_H_
|
|
@ -1,79 +0,0 @@
|
|||
/**
|
||||
* @file logger.h
|
||||
* @brief cppSimpleLogger Header
|
||||
* @author hendrik schutter
|
||||
* @date 04.09.2020
|
||||
*/
|
||||
|
||||
#ifndef LOGGER_H_
|
||||
#define LOGGER_H_
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
#include <mutex>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define MENU_LINE_SIZE 110 // Size of menu lines
|
||||
|
||||
#ifndef LOG_PATH
|
||||
// #define LOG_PATH "./test.txt"
|
||||
#endif
|
||||
|
||||
#ifndef DESCRIPTION
|
||||
#define DESCRIPTION "Software-Name - Copyright Company 2020" // use your values here
|
||||
#endif
|
||||
|
||||
#ifndef DEVICE_ID
|
||||
#define DEVICE_ID "Device-Name" // use your values here
|
||||
#endif
|
||||
|
||||
#ifndef SOFTWARE_VERSION
|
||||
#define SOFTWARE_VERSION "0.1.1.8" // use your values here
|
||||
#endif
|
||||
|
||||
#ifndef HARDWARE_VERSION
|
||||
#define HARDWARE_VERSION "7.77.9" // use your values here
|
||||
#endif
|
||||
|
||||
class Logger
|
||||
{
|
||||
private:
|
||||
string logPath;
|
||||
mutex mtxLog;
|
||||
|
||||
static bool instanceFlag;
|
||||
static Logger *single;
|
||||
|
||||
string getTimestamp();
|
||||
void writeLog(string s);
|
||||
string getMacAddress();
|
||||
string padStringMenu(char cBorder, string text, uint8_t u8LineLenght);
|
||||
string menuLine(char cBorder, uint8_t u8LineLenght);
|
||||
Logger();
|
||||
~Logger();
|
||||
|
||||
public:
|
||||
void info(string s);
|
||||
void warning(string s);
|
||||
void error(string s);
|
||||
void newLine();
|
||||
|
||||
static Logger *logThis();
|
||||
};
|
||||
|
||||
#endif // LOGGER_H_
|
|
@ -1,56 +0,0 @@
|
|||
/**
|
||||
* @file printer.h
|
||||
* @brief Send drive data to printer service using ipc msg queue
|
||||
* @author Hendrik Schutter
|
||||
* @date 24.11.2022
|
||||
*/
|
||||
|
||||
#ifndef PRINTER_H_
|
||||
#define PRINTER_H_
|
||||
|
||||
#include "reHDD.h"
|
||||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
#define STR_BUFFER_SIZE 64U
|
||||
#define IPC_MSG_QUEUE_KEY 0x1B11193C0
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char caDriveIndex[STR_BUFFER_SIZE];
|
||||
char caDriveHours[STR_BUFFER_SIZE];
|
||||
char caDriveCycles[STR_BUFFER_SIZE];
|
||||
char caDriveErrors[STR_BUFFER_SIZE];
|
||||
char caDriveShredTimestamp[STR_BUFFER_SIZE];
|
||||
char caDriveShredDuration[STR_BUFFER_SIZE];
|
||||
char caDriveCapacity[STR_BUFFER_SIZE];
|
||||
char caDriveState[STR_BUFFER_SIZE];
|
||||
char caDriveModelFamily[STR_BUFFER_SIZE];
|
||||
char caDriveModelName[STR_BUFFER_SIZE];
|
||||
char caDriveSerialnumber[STR_BUFFER_SIZE];
|
||||
char caDriveReHddVersion[STR_BUFFER_SIZE];
|
||||
|
||||
} t_driveData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long msg_queue_type;
|
||||
t_driveData driveData;
|
||||
} t_msgQueueData;
|
||||
|
||||
class Printer
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
static Printer *getPrinter();
|
||||
void print(Drive *drive);
|
||||
|
||||
private:
|
||||
static bool instanceFlag;
|
||||
static Printer *single;
|
||||
int msqid;
|
||||
Printer();
|
||||
~Printer();
|
||||
};
|
||||
#endif // PRINTER_H_
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file reHDD.h
|
||||
* @brief app logic header
|
||||
* @brief represent
|
||||
* @author hendrik schutter
|
||||
* @date 01.05.2020
|
||||
*/
|
||||
|
@ -8,69 +8,21 @@
|
|||
#ifndef REHDD_H_
|
||||
#define REHDD_H_
|
||||
|
||||
#define REHDD_VERSION "V1.1.1"
|
||||
|
||||
// Drive handling Settings
|
||||
#define WORSE_HOURS 19200 // mark drive if at this limit or beyond
|
||||
#define WORSE_POWERUP 10000 // mark drive if at this limit or beyond
|
||||
#define WORSE_TEMPERATURE 55 // mark drive if at this limit or beyond
|
||||
#define SHRED_ITERATIONS 3U
|
||||
#define FROZEN_TIMEOUT 20 // After this timeout (minutes) the drive will be marked as frozen, if no progress
|
||||
#define METRIC_THRESHOLD 3L * 1000L * 1000L * 1000L // calc shred speed with this minimum of time delta
|
||||
|
||||
// Logger Settings
|
||||
#define LOG_PATH "./reHDD.log"
|
||||
#define DESCRIPTION "reHDD - Copyright Hendrik Schutter 2024"
|
||||
#define DEVICE_ID "generic"
|
||||
#define SOFTWARE_VERSION REHDD_VERSION
|
||||
#define HARDWARE_VERSION "generic"
|
||||
|
||||
// #define LOG_LEVEL_HIGH //log everything, like drive scan thread
|
||||
#ifndef LOG_LEVEL_HIGH
|
||||
#define LOG_LEVEL_LOW // log only user actions and tasks
|
||||
#endif
|
||||
|
||||
// Logic
|
||||
// #define DRYRUN //don´t touch the drives
|
||||
#define FROZEN_ALERT // show alert if drive is frozen
|
||||
#define ZERO_CHECK // check drive after shred if all bytes are zero, show alert if this fails
|
||||
|
||||
// IPC pipes
|
||||
#define READ 0
|
||||
#define WRITE 1
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <tuple>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <time.h>
|
||||
#include <chrono>
|
||||
#include <curses.h>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <mutex>
|
||||
#include <sys/select.h>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <signal.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "drive.h"
|
||||
#include "smart.h"
|
||||
#include "shred.h"
|
||||
#include "delete.h"
|
||||
#include "tui.h"
|
||||
#include "printer.h"
|
||||
#include "logger/logger.h"
|
||||
#include "wipe.h"
|
||||
|
||||
extern Logger *logging;
|
||||
|
||||
template <typename T, typename I>
|
||||
T *iterator_to_pointer(I i)
|
||||
template <typename T, typename I> T* iterator_to_pointer(I i)
|
||||
{
|
||||
return (&(*i));
|
||||
}
|
||||
|
@ -78,29 +30,20 @@ T *iterator_to_pointer(I i)
|
|||
class reHDD
|
||||
{
|
||||
protected:
|
||||
|
||||
public:
|
||||
reHDD(void);
|
||||
static void app_logic();
|
||||
void app_logic();
|
||||
|
||||
private:
|
||||
static void searchDrives(list<Drive> *plistDrives);
|
||||
static void printDrives(list<Drive> *plistDrives);
|
||||
static void startShredAllDrives(list<Drive> *plistDrives);
|
||||
static void updateShredMetrics(list<Drive> *plistDrives);
|
||||
static void filterIgnoredDrives(list<Drive> *plistDrives);
|
||||
static void filterInvalidDrives(list<Drive> *plistDrives);
|
||||
static void filterNewDrives(list<Drive> *plistOldDrives, list<Drive> *plistNewDrives);
|
||||
static void addSMARTData(list<Drive> *plistDrives);
|
||||
static void ThreadScanDevices();
|
||||
static void ThreadUserInput();
|
||||
static void ThreadShred(Drive *const pDrive);
|
||||
static void ThreadDelete();
|
||||
static void ThreadCheckFrozenDrives();
|
||||
static void handleArrowKey(TUI::UserInput userInput);
|
||||
static void handleEnter();
|
||||
static void handleESC();
|
||||
static void handleAbort();
|
||||
static Drive *getSelectedDrive();
|
||||
|
||||
vector <Drive> vecDrives; //stores all drive data
|
||||
|
||||
void searchDrives(vector <Drive>* pvecDrives);
|
||||
void printDrives(vector <Drive>* pvecDrives);
|
||||
void filterIgnoredDrives(vector <Drive>* pvecDrives);
|
||||
void addSMARTData(vector <Drive>* pvecDrives);
|
||||
};
|
||||
|
||||
#endif // REHDD_H_
|
||||
|
||||
#endif // REHDD_H_
|
|
@ -1,55 +0,0 @@
|
|||
/**
|
||||
* @file shred.h
|
||||
* @brief shred drive
|
||||
* @author hendrik schutter
|
||||
* @date 03.05.2020
|
||||
*/
|
||||
|
||||
#ifndef SHRED_H_
|
||||
#define SHRED_H_
|
||||
|
||||
#include "reHDD.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CHUNK_SIZE 1024 * 1024 * 32 // amount of bytes that are overwritten at once --> 32MB
|
||||
#define TFNG_DATA_SIZE CHUNK_SIZE // amount of bytes used by tfng
|
||||
|
||||
// #define DEMO_DRIVE_SIZE 1024*1024*256L // 256MB
|
||||
// #define DEMO_DRIVE_SIZE 1024*1024*1024L // 1GB
|
||||
// #define DEMO_DRIVE_SIZE 5*1024*1024*1024L // 5GB
|
||||
// #define DEMO_DRIVE_SIZE 1024*1024*1024*10L // 10GB
|
||||
|
||||
typedef int fileDescriptor;
|
||||
|
||||
class Shred
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
Shred();
|
||||
~Shred();
|
||||
int shredDrive(Drive *drive, int *ipSignalFd);
|
||||
|
||||
private:
|
||||
fileDescriptor randomSrcFileDiscr;
|
||||
fileDescriptor driveFileDiscr;
|
||||
unsigned char caTfngData[TFNG_DATA_SIZE];
|
||||
unsigned char caReadBuffer[CHUNK_SIZE];
|
||||
unsigned long ulDriveByteSize;
|
||||
unsigned long ulDriveByteOverallCount = 0; // all bytes shredded in all iterations + checking -> used for progress calculation
|
||||
double d32Percent = 0.0;
|
||||
double d32TmpPercent = 0.0;
|
||||
|
||||
inline double calcProgress();
|
||||
int iRewindDrive(fileDescriptor file);
|
||||
unsigned long getDriveSizeInBytes(fileDescriptor file);
|
||||
unsigned int uiCalcChecksum(fileDescriptor file, Drive *drive, int *ipSignalFd);
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
#endif // SHRED_H_
|
|
@ -13,13 +13,13 @@
|
|||
class SMART
|
||||
{
|
||||
protected:
|
||||
|
||||
public:
|
||||
static void readSMARTData(Drive *drive);
|
||||
static void readSMARTData(Drive* drive);
|
||||
|
||||
private:
|
||||
SMART(void);
|
||||
|
||||
static uint8_t parseExitStatus(string sLine);
|
||||
static void parseModelFamily(string sLine);
|
||||
static void parseModelName(string sLine);
|
||||
static void parseSerial(string sLine);
|
||||
|
@ -27,16 +27,14 @@ private:
|
|||
static void parseErrorCount(string sLine);
|
||||
static void parsePowerOnHours(string sLine);
|
||||
static void parsePowerCycle(string sLine);
|
||||
static void parseTemperature(string sLine);
|
||||
|
||||
static string modelFamily;
|
||||
static string modelName;
|
||||
static string serial;
|
||||
static uint64_t capacity;
|
||||
static uint32_t errorCount;
|
||||
static uint32_t powerOnHours;
|
||||
static uint32_t powerCycle;
|
||||
static uint32_t temperature;
|
||||
static string modelFamily;
|
||||
static string modelName;
|
||||
static string serial;
|
||||
static uint64_t capacity;
|
||||
static uint32_t errorCount;
|
||||
static uint32_t powerOnHours;
|
||||
static uint32_t powerCycle;
|
||||
};
|
||||
|
||||
#endif // SMART_H_
|
||||
#endif // SMART_H_
|
|
@ -1,82 +0,0 @@
|
|||
/**
|
||||
* @file tui.h
|
||||
* @brief display user interface
|
||||
* @author hendrik schutter
|
||||
* @date 03.08.2020
|
||||
*/
|
||||
|
||||
#ifndef TUI_H_
|
||||
#define TUI_H_
|
||||
|
||||
#include "reHDD.h"
|
||||
|
||||
#define COLOR_AREA_STDSCR 1
|
||||
#define COLOR_AREA_OVERVIEW 2
|
||||
#define COLOR_AREA_ENTRY_EVEN 3
|
||||
#define COLOR_AREA_ENTRY_ODD 4
|
||||
#define COLOR_AREA_ENTRY_SELECTED 5
|
||||
#define COLOR_AREA_DETAIL 6
|
||||
|
||||
class TUI
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
enum UserInput
|
||||
{
|
||||
UpKey,
|
||||
DownKey,
|
||||
Abort,
|
||||
Shred,
|
||||
ShredAll,
|
||||
Delete,
|
||||
Enter,
|
||||
ESC,
|
||||
Undefined
|
||||
};
|
||||
struct MenuState
|
||||
{
|
||||
bool bAbort;
|
||||
bool bShred;
|
||||
bool bDelete;
|
||||
bool bConfirmShred;
|
||||
bool bConfirmDelete;
|
||||
};
|
||||
|
||||
TUI(void);
|
||||
|
||||
static void initTUI();
|
||||
|
||||
void updateTUI(list<Drive> *plistDrives, uint8_t u8SelectedEntry);
|
||||
|
||||
static enum UserInput readUserInput();
|
||||
|
||||
private:
|
||||
static string sCpuUsage;
|
||||
static string sRamUsage;
|
||||
static string sLocalTime;
|
||||
|
||||
WINDOW *overview;
|
||||
WINDOW *systemview;
|
||||
WINDOW *detailview;
|
||||
WINDOW *menuview;
|
||||
WINDOW *dialog;
|
||||
WINDOW *smartWarning;
|
||||
|
||||
static void centerTitle(WINDOW *pwin, const char *title);
|
||||
static WINDOW *createOverViewWindow(int iXSize, int iYSize);
|
||||
static WINDOW *createDetailViewWindow(int iXSize, int iYSize, int iXStart, Drive drive);
|
||||
static WINDOW *overwriteDetailViewWindow(int iXSize, int iYSize, int iXStart);
|
||||
static WINDOW *createEntryWindow(int iXSize, int iYSize, int iXStart, int iYStart, int iListIndex, string sModelFamily, string sSerial, string sCapacity, string sState, string sTime, string sSpeed, string sTemp, bool bSelected);
|
||||
static WINDOW *createSystemStats(int iXSize, int iYSize, int iXStart, int iYStart);
|
||||
static WINDOW *createMenuView(int iXSize, int iYSize, int iXStart, int iYStart, struct MenuState menustate);
|
||||
static WINDOW *createDialog(int iXSize, int iYSize, int iXStart, int iYStart, string selectedTask, string optionA, string optionB);
|
||||
static WINDOW *createFrozenWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, string sModelFamily, string sModelName, string sSerial, string sProgress);
|
||||
static WINDOW *createSmartWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, uint32_t u32PowerOnHours, uint32_t u32PowerCycles, uint32_t u32ErrorCount, uint32_t u32Temperature);
|
||||
static WINDOW *createZeroChecksumWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, string sModelFamily, string sModelName, string sSerial, uint32_t u32Checksum);
|
||||
|
||||
void displaySelectedDrive(Drive drive, int stdscrX, int stdscrY);
|
||||
string formatTimeDuration(time_t u32Duration);
|
||||
string formatSpeed(time_t u32ShredTimeDelta, unsigned long ulWrittenBytes);
|
||||
static void vTruncateText(string *psText, uint16_t u16MaxLenght);
|
||||
};
|
||||
#endif // TUI_H_
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @file wipe.h
|
||||
* @brief wipe drive
|
||||
* @author hendrik schutter
|
||||
* @date 03.05.2020
|
||||
*/
|
||||
|
||||
#ifndef WIPE_H_
|
||||
#define WIPE_H_
|
||||
|
||||
#include "reHDD.h"
|
||||
|
||||
class Wipe
|
||||
{
|
||||
protected:
|
||||
|
||||
public:
|
||||
static void wipeDrive(Drive* drive);
|
||||
|
||||
private:
|
||||
Wipe(void);
|
||||
|
||||
};
|
||||
|
||||
#endif // WIPE_H_
|
24
makefile
24
makefile
|
@ -8,22 +8,19 @@ SRC_EXT = cpp
|
|||
# Path to the source directory, relative to the makefile
|
||||
SRC_PATH = src
|
||||
# Space-separated pkg-config libraries used by this project
|
||||
LIBS = lib
|
||||
LIBS =
|
||||
# General compiler flags
|
||||
COMPILE_FLAGS = -std=c++23 -Wall -Wextra -g
|
||||
COMPILE_FLAGS = -std=c++11 -Wall -Wextra -g
|
||||
# Additional release-specific flags
|
||||
RCOMPILE_FLAGS = -D NDEBUG -Ofast
|
||||
RCOMPILE_FLAGS = -D NDEBUG
|
||||
# Additional debug-specific flags
|
||||
DCOMPILE_FLAGS = -D DEBUG
|
||||
# Add additional include paths
|
||||
INCLUDES = include
|
||||
# General linker settings
|
||||
LINK_FLAGS = -Llib -lpthread -lncurses -ltfng
|
||||
|
||||
LINK_FLAGS =
|
||||
# Doc
|
||||
DOCDIR = doc
|
||||
TFRANDDIR = tfnoisegen
|
||||
TFRANDLIB = libtfng.a
|
||||
#### END PROJECT SETTINGS ####
|
||||
|
||||
# Optionally you may move the section above to a separate config.mk file, and
|
||||
|
@ -161,7 +158,6 @@ dirs:
|
|||
@echo "Creating directories"
|
||||
@mkdir -p $(dir $(OBJECTS))
|
||||
@mkdir -p $(BIN_PATH)
|
||||
@mkdir -p $(LIBS)
|
||||
|
||||
# Removes all build files
|
||||
.PHONY: clean
|
||||
|
@ -171,22 +167,15 @@ clean:
|
|||
@echo "Deleting directories"
|
||||
@$(RM) -r build
|
||||
@$(RM) -r bin
|
||||
@$(RM) -r $(LIBS)
|
||||
@$(RM) -f reHDD.log
|
||||
$(MAKE) clean -C tfnoisegen
|
||||
|
||||
# Main rule, checks the executable and symlinks to the output
|
||||
all: $(BIN_PATH)/$(BIN_NAME)
|
||||
$(MAKE) libtfng.a -C tfnoisegen
|
||||
@cp $(TFRANDDIR)/$(TFRANDLIB) $(LIBS)
|
||||
@echo "Making symlink: $(BIN_NAME) -> $<"
|
||||
@$(RM) $(BIN_NAME)
|
||||
@ln -s $(BIN_PATH)/$(BIN_NAME) $(BIN_NAME)
|
||||
|
||||
# Link the executable
|
||||
$(BIN_PATH)/$(BIN_NAME): $(OBJECTS)
|
||||
$(MAKE) libtfng.a -C tfnoisegen
|
||||
@cp $(TFRANDDIR)/$(TFRANDLIB) $(LIBS)
|
||||
@echo "Linking: $@"
|
||||
@$(START_TIME)
|
||||
$(CMD_PREFIX)$(CXX) $(OBJECTS) $(LDFLAGS) -o $@
|
||||
|
@ -210,7 +199,6 @@ $(BUILD_PATH)/%.o: $(SRC_PATH)/%.$(SRC_EXT)
|
|||
docs:
|
||||
@$(RM) -r $(DOCDIR)/html
|
||||
@doxygen $(DOCDIR)/doxyfile
|
||||
|
||||
|
||||
|
||||
.PHONY: style
|
||||
style:
|
||||
@bash astyle.sh
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
[Unit]
|
||||
Description=reHDD on tty1
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/root/reHDD/
|
||||
ExecStart=
|
||||
ExecStart=-/root/reHDD/reHDD
|
||||
StandardInput=tty
|
||||
StandardOutput=tty
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
UtmpIdentifier=tty1
|
||||
TTYPath=/dev/tty1
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
TTYVTDisallocate=yes
|
||||
SendSIGHUP=yes
|
|
@ -1,17 +0,0 @@
|
|||
[Unit]
|
||||
Description=dmesg on tty2
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/usr/bin/
|
||||
ExecStart=
|
||||
ExecStart=-/usr/bin/dmesg -wHT
|
||||
StandardInput=tty
|
||||
StandardOutput=tty
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
UtmpIdentifier=tty2
|
||||
TTYPath=/dev/tty2
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
TTYVTDisallocate=yes
|
||||
SendSIGHUP=yes
|
|
@ -1,17 +0,0 @@
|
|||
[Unit]
|
||||
Description=htop on tty3
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/usr/bin/
|
||||
ExecStart=
|
||||
ExecStart=-/usr/bin/htop
|
||||
StandardInput=tty
|
||||
StandardOutput=tty
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
UtmpIdentifier=tty3
|
||||
TTYPath=/dev/tty3
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
TTYVTDisallocate=yes
|
||||
SendSIGHUP=yes
|
|
@ -1,27 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
cd /root/reHDD/scripts/
|
||||
|
||||
chmod +x reHDDLogUploader.bash
|
||||
cp reHDDLogUploader.service /lib/systemd/system/reHDDLogUploader.service
|
||||
cp reHDDLogUploader.timer /lib/systemd/system/reHDDLogUploader.timer
|
||||
systemctl daemon-reload
|
||||
systemctl enable /lib/systemd/system/reHDDLogUploader.timer
|
||||
|
||||
chmod +x reHDDStartHelper.bash
|
||||
cp reHDDStartHelper.service /lib/systemd/system/reHDDStartHelper.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable /lib/systemd/system/reHDDStartHelper.service
|
||||
|
||||
mkdir -p /lib/systemd/system/getty@tty1.service.d
|
||||
cp getty@tty1.service.d_override.conf /lib/systemd/system/getty@tty1.service.d/override.conf
|
||||
systemctl daemon-reload
|
||||
|
||||
mkdir -p /lib/systemd/system/getty@tty2.service.d
|
||||
cp getty@tty2.service.d_override.conf /lib/systemd/system/getty@tty2.service.d/override.conf
|
||||
systemctl daemon-reload
|
||||
|
||||
mkdir -p /lib/systemd/system/getty@tty3.service.d
|
||||
cp getty@tty3.service.d_override.conf /lib/systemd/system/getty@tty3.service.d/override.conf
|
||||
systemctl daemon-reload
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#!/bin/bash
|
||||
# remove comment for the following to activate log telemetie
|
||||
curl -k -T /root/reHDD/reHDD.log -u "__Place_your_token_here__:" -H 'X-Requested-With: XMLHttpRequest' https://schuttercloud.com/public.php/webdav/`echo $(date '+%Y-%m-%d_%H-%M')`_reHDD.log
|
||||
rm -f /root/reHDD/reHDD.log
|
||||
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
[Unit]
|
||||
Description=reHDD log uploader
|
||||
After=syslog.target
|
||||
After=network.target
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=root
|
||||
Group=root
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/bin/bash /root/reHDD/scripts/reHDDLogUploader.bash
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
[Unit]
|
||||
Description=reHDD log uploader timer
|
||||
|
||||
[Timer]
|
||||
OnActiveSec=30s
|
||||
OnBootSec=10min
|
||||
OnUnitActiveSec=12h
|
||||
|
||||
[Install]
|
||||
WantedBy=basic.target
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/bash
|
||||
dmesg -n 1 #disable overlay if a drive is attached/detached
|
||||
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
[Unit]
|
||||
Description=reHDD start helper
|
||||
After=syslog.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=root
|
||||
Group=root
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/bin/bash /root/reHDD/scripts/reHDDStartHelper.bash
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,36 +0,0 @@
|
|||
#! /usr/bin/bash
|
||||
|
||||
echo starting update
|
||||
|
||||
systemctl stop /lib/systemd/system/getty@tty1.service.d
|
||||
|
||||
cd /root/reHDD/
|
||||
|
||||
FILE=../ignoreDrives.conf
|
||||
if test -f "$FILE"; then
|
||||
echo "backup exits already"
|
||||
else
|
||||
cp /root/reHDD/ignoreDrives.conf /root/ignoreDrives.conf
|
||||
fi
|
||||
|
||||
git reset
|
||||
|
||||
git stash force
|
||||
|
||||
git stash
|
||||
|
||||
git checkout master
|
||||
|
||||
git pull
|
||||
|
||||
git submodule init
|
||||
|
||||
git submodule update
|
||||
|
||||
make clean
|
||||
|
||||
make release
|
||||
|
||||
cp /root/ignoreDrives.conf /root/reHDD/ignoreDrives.conf
|
||||
|
||||
systemctl start /lib/systemd/system/getty@tty1.service.d
|
|
@ -1,42 +0,0 @@
|
|||
/**
|
||||
* @file delete.cpp
|
||||
* @brief delete drive
|
||||
* @author hendrik schutter
|
||||
* @date 23.08.2020
|
||||
*/
|
||||
|
||||
#include "../include/reHDD.h"
|
||||
|
||||
/**
|
||||
* \brief delete drive with wipefs
|
||||
* \param pointer of Drive instance
|
||||
* \return void
|
||||
*/
|
||||
void Delete::deleteDrive(Drive *drive)
|
||||
|
||||
{
|
||||
size_t len = 0; // lenght of found line
|
||||
char *cLine = NULL; // found line
|
||||
|
||||
#ifndef DRYRUN
|
||||
string sCMD = ("wipefs -af ");
|
||||
sCMD.append(drive->getPath());
|
||||
sCMD.append("*");
|
||||
#endif
|
||||
|
||||
#ifdef DRYRUN
|
||||
// cout << "dryrun for " << drive->getPath() << endl;
|
||||
string sCMD = ("echo");
|
||||
#endif
|
||||
|
||||
const char *cpComand = sCMD.c_str();
|
||||
// cout << "delete: " << cpComand << endl;
|
||||
|
||||
FILE *deleteCmdOutput = popen(cpComand, "r");
|
||||
|
||||
while ((getline(&cLine, &len, deleteCmdOutput)) != -1)
|
||||
{
|
||||
// wipefs running
|
||||
}
|
||||
pclose(deleteCmdOutput);
|
||||
}
|
156
src/drive.cpp
156
src/drive.cpp
|
@ -14,105 +14,36 @@ string Drive::getPath(void)
|
|||
|
||||
string Drive::getModelFamily(void)
|
||||
{
|
||||
return sSmartData.sModelFamily;
|
||||
return sModelFamily;
|
||||
}
|
||||
|
||||
string Drive::getModelName(void)
|
||||
{
|
||||
return sSmartData.sModelName;
|
||||
return sModelName;
|
||||
}
|
||||
|
||||
string Drive::getSerial(void)
|
||||
{
|
||||
return sSmartData.sSerial;
|
||||
return sSerial;
|
||||
}
|
||||
|
||||
uint64_t Drive::getCapacity(void)
|
||||
{
|
||||
return sSmartData.u64Capacity;
|
||||
return u64Capacity;
|
||||
}
|
||||
|
||||
uint32_t Drive::getErrorCount(void)
|
||||
{
|
||||
return sSmartData.u32ErrorCount;
|
||||
return u32ErrorCount;
|
||||
}
|
||||
uint32_t Drive::getPowerOnHours(void)
|
||||
{
|
||||
return sSmartData.u32PowerOnHours;
|
||||
return u32PowerOnHours;
|
||||
}
|
||||
|
||||
uint32_t Drive::getPowerCycles(void)
|
||||
{
|
||||
return sSmartData.u32PowerCycles;
|
||||
}
|
||||
|
||||
uint32_t Drive::getTemperature(void)
|
||||
{
|
||||
return sSmartData.u32Temperature;
|
||||
}
|
||||
|
||||
string Drive::sCapacityToText()
|
||||
{
|
||||
char acBuffer[16];
|
||||
double dSize = (double)getCapacity();
|
||||
uint16_t u16UnitIndex = 0;
|
||||
const char *units[] = {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
|
||||
while (dSize >= 1000) // using the marketing capacity
|
||||
{
|
||||
dSize /= 1000;
|
||||
u16UnitIndex++;
|
||||
}
|
||||
|
||||
sprintf(acBuffer, "%.*f %s", u16UnitIndex - 3, dSize, units[u16UnitIndex]);
|
||||
return acBuffer;
|
||||
}
|
||||
|
||||
string Drive::sErrorCountToText()
|
||||
{
|
||||
return to_string(getErrorCount());
|
||||
}
|
||||
|
||||
string Drive::sPowerOnHoursToText()
|
||||
{
|
||||
double dDays = 0U;
|
||||
double dYears = 0U;
|
||||
uint32_t u32Hours = getPowerOnHours();
|
||||
stringstream streamDays;
|
||||
stringstream streamYears;
|
||||
|
||||
dDays = (double)((double)u32Hours / (double)24U);
|
||||
dYears = (double)((double)u32Hours / (double)8760U);
|
||||
|
||||
streamDays << fixed << setprecision(0) << dDays;
|
||||
streamYears << fixed << setprecision(1) << dYears;
|
||||
|
||||
string sRet = to_string(getPowerOnHours()) + " hours or " + streamDays.str() + " days or " + streamYears.str() + " years";
|
||||
|
||||
return sRet;
|
||||
}
|
||||
|
||||
string Drive::sPowerCyclesToText()
|
||||
{
|
||||
return to_string(getPowerCycles());
|
||||
}
|
||||
|
||||
string Drive::sTemperatureToText()
|
||||
{
|
||||
return to_string(getTemperature()) + " C";
|
||||
;
|
||||
}
|
||||
|
||||
void Drive::setTaskPercentage(double d32TaskPercentage)
|
||||
{
|
||||
if (d32TaskPercentage <= 100)
|
||||
{
|
||||
this->d32TaskPercentage = d32TaskPercentage;
|
||||
this->setTimestamp(); // set timestamp for this progress for detecting a frozen drive
|
||||
}
|
||||
}
|
||||
double Drive::getTaskPercentage(void)
|
||||
{
|
||||
return this->d32TaskPercentage;
|
||||
return u32PowerCycles;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,66 +55,21 @@ double Drive::getTaskPercentage(void)
|
|||
* \param uint32_t errorCount
|
||||
* \param uint32_t powerOnHours
|
||||
* \param uint32_t powerCycle
|
||||
* \param uint32_t temperature
|
||||
* \return void
|
||||
*/
|
||||
void Drive::setDriveSMARTData(string modelFamily,
|
||||
string modelName,
|
||||
string serial,
|
||||
uint64_t capacity,
|
||||
uint32_t errorCount,
|
||||
uint32_t powerOnHours,
|
||||
uint32_t powerCycle,
|
||||
uint32_t temperature)
|
||||
void Drive::setDriveSMARTData( string modelFamily,
|
||||
string modelName,
|
||||
string serial,
|
||||
uint64_t capacity,
|
||||
uint32_t errorCount,
|
||||
uint32_t powerOnHours,
|
||||
uint32_t powerCycle)
|
||||
{
|
||||
this->sSmartData.sModelFamily = modelFamily;
|
||||
this->sSmartData.sModelName = modelName;
|
||||
this->sSmartData.sSerial = serial;
|
||||
this->sSmartData.u64Capacity = capacity;
|
||||
this->sSmartData.u32ErrorCount = errorCount;
|
||||
this->sSmartData.u32PowerOnHours = powerOnHours;
|
||||
this->sSmartData.u32PowerCycles = powerCycle;
|
||||
this->sSmartData.u32Temperature = temperature;
|
||||
}
|
||||
|
||||
void Drive::setTimestamp()
|
||||
{
|
||||
time(&this->u32Timestamp);
|
||||
}
|
||||
|
||||
void Drive::setActionStartTimestamp()
|
||||
{
|
||||
time(&this->u32TimestampTaskStart);
|
||||
}
|
||||
|
||||
time_t Drive::getActionStartTimestamp()
|
||||
{
|
||||
return this->u32TimestampTaskStart;
|
||||
}
|
||||
|
||||
void Drive::calculateTaskDuration()
|
||||
{
|
||||
time_t u32localtime;
|
||||
time(&u32localtime);
|
||||
|
||||
this->u32TaskDuration = u32localtime - this->u32TimestampTaskStart;
|
||||
}
|
||||
|
||||
time_t Drive::getTaskDuration()
|
||||
{
|
||||
return this->u32TaskDuration;
|
||||
}
|
||||
|
||||
void Drive::checkFrozenDrive(void)
|
||||
{
|
||||
time_t u32localtime;
|
||||
time(&u32localtime);
|
||||
|
||||
if ((u32localtime - this->u32Timestamp) >= (FROZEN_TIMEOUT * 60) && (this->u32Timestamp > 0) && (this->getTaskPercentage() < 100.0))
|
||||
{
|
||||
Logger::logThis()->warning("Drive Frozen: " + this->getModelName() + " " + this->getSerial());
|
||||
this->bWasDeleted = false;
|
||||
this->bWasShredded = false;
|
||||
this->state = Drive::FROZEN;
|
||||
}
|
||||
this->sModelFamily = modelFamily;
|
||||
sModelName = modelName;
|
||||
sSerial = serial;
|
||||
u64Capacity = capacity;
|
||||
u32ErrorCount = errorCount;
|
||||
u32PowerOnHours = powerOnHours;
|
||||
u32PowerCycles = powerCycle;
|
||||
}
|
|
@ -1,229 +0,0 @@
|
|||
/**
|
||||
* @file logger.cpp
|
||||
* @brief cppSimpleLogger implementation
|
||||
* @author hendrik schutter
|
||||
* @date 04.09.2020
|
||||
*/
|
||||
|
||||
#include "../../include/reHDD.h" //for logger settings
|
||||
#include "../../include/logger/logger.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
string version = "0.2.1"; // logger version
|
||||
|
||||
bool Logger::instanceFlag = false;
|
||||
Logger *Logger::single = NULL;
|
||||
|
||||
/**
|
||||
* \brief create new logger instance
|
||||
* \return instance of Logger
|
||||
*/
|
||||
Logger::Logger()
|
||||
{
|
||||
this->logPath = LOG_PATH;
|
||||
|
||||
writeLog(menuLine('+', MENU_LINE_SIZE));
|
||||
writeLog(padStringMenu('+', " ", MENU_LINE_SIZE));
|
||||
|
||||
writeLog(padStringMenu('+', ("Device: " + string(DEVICE_ID) + " -- " + string(DESCRIPTION)), MENU_LINE_SIZE));
|
||||
writeLog(padStringMenu('+', " ", MENU_LINE_SIZE));
|
||||
|
||||
writeLog(padStringMenu('+', ("Software ID: " + string(SOFTWARE_VERSION) + " -- Build time: " + __DATE__ + " " + __TIME__), MENU_LINE_SIZE));
|
||||
writeLog(padStringMenu('+', " ", MENU_LINE_SIZE));
|
||||
|
||||
writeLog(padStringMenu('+', ("Hardware ID: " + string(HARDWARE_VERSION) + " -- MAC: " + getMacAddress()), MENU_LINE_SIZE));
|
||||
writeLog(padStringMenu('+', " ", MENU_LINE_SIZE));
|
||||
|
||||
writeLog(padStringMenu('+', ("cppSimpleLogger -- available from https://git.mosad.xyz/localhorst/cppSimpleLogger -- Version: " + version), MENU_LINE_SIZE));
|
||||
writeLog(padStringMenu('+', " ", MENU_LINE_SIZE));
|
||||
|
||||
writeLog(menuLine('+', MENU_LINE_SIZE));
|
||||
newLine();
|
||||
info("Created new log file");
|
||||
newLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief deconstructor
|
||||
* \return void
|
||||
*/
|
||||
Logger::~Logger()
|
||||
{
|
||||
instanceFlag = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief log info
|
||||
* \param log-text as string
|
||||
* \return void
|
||||
*/
|
||||
void Logger::info(string s)
|
||||
{
|
||||
string tmp = getTimestamp() + " [INFO] " + s;
|
||||
writeLog(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief log warning
|
||||
* \param log-text as string
|
||||
* \return void
|
||||
*/
|
||||
void Logger::warning(string s)
|
||||
{
|
||||
string tmp = getTimestamp() + " [WARNING] " + s;
|
||||
writeLog(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief log error
|
||||
* \param log-text as string
|
||||
* \return void
|
||||
*/
|
||||
void Logger::error(string s)
|
||||
{
|
||||
string tmp = getTimestamp() + " [ERROR] " + s;
|
||||
writeLog(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief write to log file
|
||||
* \param log as string
|
||||
* \return void
|
||||
*/
|
||||
void Logger::writeLog(string s)
|
||||
{
|
||||
ofstream logFile;
|
||||
Logger::mtxLog.lock(); // lock this section for other threads
|
||||
logFile.open(this->logPath, ios_base::app);
|
||||
|
||||
logFile << (s + "\n"); // append to existing file
|
||||
|
||||
logFile.close();
|
||||
Logger::mtxLog.unlock(); // unlock this section for other threads
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief write new line to log file
|
||||
* \return void
|
||||
*/
|
||||
void Logger::newLine()
|
||||
{
|
||||
writeLog(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief get timestamp (system time) as string
|
||||
* \param void
|
||||
* \return string timestamp (formatted)
|
||||
*/
|
||||
string Logger::getTimestamp()
|
||||
{
|
||||
struct tm *timeinfo;
|
||||
struct timeval tv;
|
||||
int millisec;
|
||||
char cpDate[80];
|
||||
char buffer[120];
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
millisec = lrint(tv.tv_usec / 1000.0); // Round to nearest millisec
|
||||
if (millisec >= 1000) // Allow for rounding up to nearest second
|
||||
{
|
||||
millisec -= 1000;
|
||||
tv.tv_sec++;
|
||||
}
|
||||
timeinfo = localtime(&tv.tv_sec);
|
||||
strftime(cpDate, 80, "%d/%m/%Y %T", timeinfo);
|
||||
sprintf(buffer, "%s.%03d", cpDate, millisec);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief get MAC address (system first eth0 interface) as string
|
||||
* \param void
|
||||
* \return string MAC address (formatted)
|
||||
*/
|
||||
string Logger::getMacAddress()
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
strcpy(ifr.ifr_name, "eth0");
|
||||
if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
|
||||
{
|
||||
strcpy(ifr.ifr_name, "eno1");
|
||||
}
|
||||
|
||||
unsigned char *hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data;
|
||||
char buffer[80];
|
||||
sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X", hwaddr[0], hwaddr[1], hwaddr[2],
|
||||
hwaddr[3], hwaddr[4], hwaddr[5]);
|
||||
close(s);
|
||||
string tmp = buffer;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief format menu text in center
|
||||
* \param char for border
|
||||
* \param menu text
|
||||
* \param size of menu line
|
||||
* \return string menu line
|
||||
*/
|
||||
string Logger::padStringMenu(char cBorder, string text, uint8_t u8LineLenght)
|
||||
{
|
||||
string result(1, cBorder);
|
||||
uint8_t u8TextSize = text.length();
|
||||
uint8_t u8Padding = ((u8LineLenght - u8TextSize) / 2);
|
||||
|
||||
for (uint8_t i = 0; i < u8Padding; i++)
|
||||
{
|
||||
result.append(" ");
|
||||
}
|
||||
|
||||
result.append(text);
|
||||
|
||||
while ((uint8_t)result.length() < (u8LineLenght - 1))
|
||||
{
|
||||
|
||||
result.append(" ");
|
||||
}
|
||||
|
||||
result.append(string(1, cBorder));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief format a separator
|
||||
* \param char for border
|
||||
* \param size of menu line
|
||||
* \return string menu line
|
||||
*/
|
||||
string Logger::menuLine(char cBorder, uint8_t u8LineLenght)
|
||||
{
|
||||
string result(1, cBorder);
|
||||
|
||||
while ((uint8_t)result.length() < u8LineLenght)
|
||||
{
|
||||
result.append(string(1, cBorder));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief return a instance of the logger
|
||||
* \return logger obj
|
||||
*/
|
||||
Logger *Logger::logThis()
|
||||
{
|
||||
if (!instanceFlag)
|
||||
{
|
||||
single = new Logger(); // create new obj
|
||||
instanceFlag = true;
|
||||
return single;
|
||||
}
|
||||
else
|
||||
{
|
||||
return single; // return existing obj
|
||||
}
|
||||
}
|
|
@ -14,9 +14,9 @@
|
|||
*/
|
||||
int main(void)
|
||||
{
|
||||
// cout << "refurbishingHddTool" << endl;
|
||||
cout << "refurbishingHddTool" << endl;
|
||||
|
||||
reHDD *app = new reHDD();
|
||||
reHDD* app = new reHDD();
|
||||
app->app_logic();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
/**
|
||||
* @file printer.cpp
|
||||
* @brief Send drive data to printer service using ipc msg queue
|
||||
* @author Hendrik Schutter
|
||||
* @date 24.11.2022
|
||||
*/
|
||||
|
||||
#include "../include/reHDD.h"
|
||||
|
||||
bool Printer::instanceFlag = false;
|
||||
Printer *Printer::single = NULL;
|
||||
|
||||
/**
|
||||
* \brief create new Printer instance
|
||||
* \param path to log file
|
||||
* \param struct with data
|
||||
* \return instance of Printer
|
||||
*/
|
||||
Printer::Printer()
|
||||
{
|
||||
if (-1 == (this->msqid = msgget((key_t)IPC_MSG_QUEUE_KEY, IPC_CREAT | 0666)))
|
||||
{
|
||||
Logger::logThis()->error("Printer: Create mgs queue failed!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief deconstructor
|
||||
* \return void
|
||||
*/
|
||||
Printer::~Printer()
|
||||
{
|
||||
instanceFlag = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief send data to msg queue
|
||||
* \return void
|
||||
*/
|
||||
void Printer::print(Drive *drive)
|
||||
{
|
||||
t_msgQueueData msgQueueData;
|
||||
msgQueueData.msg_queue_type = 1;
|
||||
|
||||
sprintf(msgQueueData.driveData.caDriveIndex, "%i", 42); // TODO: get from tui
|
||||
sprintf(msgQueueData.driveData.caDriveState, "shredded");
|
||||
strcpy(msgQueueData.driveData.caDriveModelFamily, drive->getModelFamily().c_str());
|
||||
strcpy(msgQueueData.driveData.caDriveModelName, drive->getModelName().c_str());
|
||||
sprintf(msgQueueData.driveData.caDriveCapacity, "%li", drive->getCapacity());
|
||||
strcpy(msgQueueData.driveData.caDriveSerialnumber, drive->getSerial().c_str());
|
||||
sprintf(msgQueueData.driveData.caDriveHours, "%i", drive->getPowerOnHours());
|
||||
sprintf(msgQueueData.driveData.caDriveCycles, "%i", drive->getPowerCycles());
|
||||
sprintf(msgQueueData.driveData.caDriveErrors, "%i", drive->getErrorCount());
|
||||
sprintf(msgQueueData.driveData.caDriveShredTimestamp, "%li", drive->getActionStartTimestamp());
|
||||
sprintf(msgQueueData.driveData.caDriveShredDuration, "%li", drive->getTaskDuration());
|
||||
sprintf(msgQueueData.driveData.caDriveReHddVersion, REHDD_VERSION);
|
||||
|
||||
if (-1 == msgsnd(this->msqid, &msgQueueData, sizeof(t_msgQueueData) - sizeof(long), 0))
|
||||
{
|
||||
Logger::logThis()->error("Printer: Send mgs queue failed!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::logThis()->info("Printer: print triggered - Drive: " + drive->getSerial());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief return a instance of the printer
|
||||
* \return printer obj
|
||||
*/
|
||||
Printer *Printer::getPrinter()
|
||||
{
|
||||
if (!instanceFlag)
|
||||
{
|
||||
single = new Printer(); // create new obj
|
||||
instanceFlag = true;
|
||||
return single;
|
||||
}
|
||||
else
|
||||
{
|
||||
return single; // return existing obj
|
||||
}
|
||||
}
|
631
src/reHDD.cpp
631
src/reHDD.cpp
|
@ -7,22 +7,6 @@
|
|||
|
||||
#include "../include/reHDD.h"
|
||||
|
||||
static int fdNewDrivesInformPipe[2]; // File descriptor for pipe that informs if new drives are found
|
||||
|
||||
static int fdShredInformPipe[2]; // File descriptor for pipe that informs if a wipe thread signals
|
||||
|
||||
static std::mutex mxDrives;
|
||||
|
||||
list<Drive> listNewDrives; // store found drives that are updated every 5sec
|
||||
|
||||
static list<Drive> listDrives; // stores all drive data from scan thread
|
||||
|
||||
TUI *ui;
|
||||
|
||||
static uint8_t u8SelectedEntry;
|
||||
|
||||
static fd_set selectSet;
|
||||
|
||||
/**
|
||||
* \brief app constructor
|
||||
* \param void
|
||||
|
@ -30,7 +14,7 @@ static fd_set selectSet;
|
|||
*/
|
||||
reHDD::reHDD(void)
|
||||
{
|
||||
u8SelectedEntry = 0U;
|
||||
cout << "created app" << endl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,568 +24,177 @@ reHDD::reHDD(void)
|
|||
*/
|
||||
void reHDD::app_logic(void)
|
||||
{
|
||||
ui = new TUI();
|
||||
ui->initTUI();
|
||||
cout << "app logic" << endl;
|
||||
|
||||
pipe(fdNewDrivesInformPipe);
|
||||
pipe(fdShredInformPipe);
|
||||
searchDrives(&vecDrives); //search for new drives and store them in list
|
||||
filterIgnoredDrives(&vecDrives); //filter out ignored drives
|
||||
addSMARTData(&vecDrives); //add S.M.A.R.T. Data to the drives
|
||||
printDrives(&vecDrives); //print currently attached drives
|
||||
|
||||
thread thDevices(ThreadScanDevices); // start thread that scans for drives
|
||||
thread thUserInput(ThreadUserInput); // start thread that reads user input
|
||||
thread thCheckFrozenDrives(ThreadCheckFrozenDrives); // start thread that checks timeout for drives
|
||||
size_t u64SelectedDriveIndex = 0U;
|
||||
size_t u64DriveVecSize = (vecDrives.size());
|
||||
|
||||
while (1)
|
||||
{
|
||||
FD_ZERO(&selectSet);
|
||||
FD_SET(fdNewDrivesInformPipe[0], &selectSet);
|
||||
FD_SET(fdShredInformPipe[0], &selectSet);
|
||||
cout << "Select drive to wipe:" << endl;
|
||||
cin >> u64SelectedDriveIndex;
|
||||
cout << "Selected drive index: " << u64SelectedDriveIndex << endl;
|
||||
|
||||
select(FD_SETSIZE, &selectSet, NULL, NULL, NULL);
|
||||
|
||||
if (FD_ISSET(fdNewDrivesInformPipe[0], &selectSet))
|
||||
{
|
||||
mxDrives.lock();
|
||||
char dummy;
|
||||
read(fdNewDrivesInformPipe[0], &dummy, 1);
|
||||
filterNewDrives(&listDrives, &listNewDrives); // filter and copy to app logic vector
|
||||
printDrives(&listDrives);
|
||||
mxDrives.unlock();
|
||||
}
|
||||
if (FD_ISSET(fdShredInformPipe[0], &selectSet))
|
||||
{
|
||||
char dummy;
|
||||
read(fdShredInformPipe[0], &dummy, 1);
|
||||
updateShredMetrics(&listDrives);
|
||||
#ifdef LOG_LEVEL_HIGH
|
||||
Logger::logThis()->info("got progress signal from a shred task");
|
||||
#endif
|
||||
}
|
||||
ui->updateTUI(&listDrives, u8SelectedEntry);
|
||||
} // endless loop
|
||||
thDevices.join();
|
||||
thUserInput.join();
|
||||
thCheckFrozenDrives.join();
|
||||
}
|
||||
|
||||
Drive *reHDD::getSelectedDrive()
|
||||
{
|
||||
if (u8SelectedEntry < listDrives.size())
|
||||
{
|
||||
list<Drive>::iterator it = listDrives.begin();
|
||||
advance(it, u8SelectedEntry);
|
||||
return &(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::logThis()->warning("selected drive not present");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void reHDD::ThreadScanDevices()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
mxDrives.lock();
|
||||
listNewDrives.clear();
|
||||
searchDrives(&listNewDrives); // search for new drives and store them in list
|
||||
filterIgnoredDrives(&listNewDrives); // filter out ignored drives
|
||||
addSMARTData(&listNewDrives); // add S.M.A.R.T. Data to the drives
|
||||
filterInvalidDrives(&listNewDrives); // filter out drives that report zero capacity
|
||||
mxDrives.unlock();
|
||||
write(fdNewDrivesInformPipe[1], "A", 1);
|
||||
sleep(5); // sleep 5 sec
|
||||
}
|
||||
}
|
||||
|
||||
void reHDD::ThreadCheckFrozenDrives()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
mxDrives.lock();
|
||||
for (auto it = begin(listDrives); it != end(listDrives); ++it)
|
||||
{
|
||||
if (it->state == Drive::SHRED_ACTIVE)
|
||||
{
|
||||
it->checkFrozenDrive();
|
||||
}
|
||||
}
|
||||
mxDrives.unlock();
|
||||
sleep(13); // sleep 13 sec
|
||||
}
|
||||
}
|
||||
|
||||
void reHDD::ThreadUserInput()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// cout << TUI::readUserInput() << endl;
|
||||
switch (TUI::readUserInput())
|
||||
{
|
||||
case TUI::UserInput::DownKey:
|
||||
// cout << "Down" << endl;
|
||||
handleArrowKey(TUI::UserInput::DownKey);
|
||||
ui->updateTUI(&listDrives, u8SelectedEntry);
|
||||
break;
|
||||
case TUI::UserInput::UpKey:
|
||||
// cout << "Up" << endl;
|
||||
handleArrowKey(TUI::UserInput::UpKey);
|
||||
ui->updateTUI(&listDrives, u8SelectedEntry);
|
||||
break;
|
||||
case TUI::UserInput::Undefined:
|
||||
// cout << "Undefined" << endl;
|
||||
break;
|
||||
case TUI::UserInput::Abort:
|
||||
// cout << "Abort" << endl;
|
||||
handleAbort();
|
||||
ui->updateTUI(&listDrives, u8SelectedEntry);
|
||||
break;
|
||||
case TUI::UserInput::Delete:
|
||||
// cout << "Delete" << endl;
|
||||
|
||||
if (getSelectedDrive() != nullptr)
|
||||
{
|
||||
if (getSelectedDrive()->state == Drive::NONE)
|
||||
{
|
||||
getSelectedDrive()->state = Drive::DELETE_SELECTED;
|
||||
}
|
||||
}
|
||||
|
||||
ui->updateTUI(&listDrives, u8SelectedEntry);
|
||||
break;
|
||||
case TUI::UserInput::Shred:
|
||||
// cout << "Shred" << endl;
|
||||
|
||||
if (getSelectedDrive() != nullptr)
|
||||
{
|
||||
if (getSelectedDrive()->state == Drive::NONE)
|
||||
{
|
||||
getSelectedDrive()->state = Drive::SHRED_SELECTED;
|
||||
}
|
||||
}
|
||||
|
||||
ui->updateTUI(&listDrives, u8SelectedEntry);
|
||||
break;
|
||||
case TUI::UserInput::ShredAll:
|
||||
// cout << "ShredAll" << endl;
|
||||
startShredAllDrives(&listDrives);
|
||||
ui->updateTUI(&listDrives, u8SelectedEntry);
|
||||
break;
|
||||
case TUI::UserInput::Enter:
|
||||
// cout << "Enter" << endl;
|
||||
handleEnter();
|
||||
ui->updateTUI(&listDrives, u8SelectedEntry);
|
||||
break;
|
||||
case TUI::UserInput::ESC:
|
||||
// cout << "ESC" << endl;
|
||||
handleESC();
|
||||
ui->updateTUI(&listDrives, u8SelectedEntry);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reHDD::ThreadShred(Drive *const pDrive)
|
||||
{
|
||||
if (pDrive != nullptr)
|
||||
{
|
||||
pDrive->setActionStartTimestamp(); // save timestamp at start of shredding
|
||||
Shred *pShredTask = new Shred(); // create new shred task
|
||||
pShredTask->shredDrive(pDrive, &fdShredInformPipe[1]); // start new shred task
|
||||
delete pShredTask; // delete shred task
|
||||
ui->updateTUI(&listDrives, u8SelectedEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void reHDD::ThreadDelete()
|
||||
{
|
||||
if (getSelectedDrive() != nullptr)
|
||||
{
|
||||
getSelectedDrive()->setActionStartTimestamp(); // save timestamp at start of deleting
|
||||
Delete::deleteDrive(getSelectedDrive()); // blocking, no thread
|
||||
getSelectedDrive()->state = Drive::TaskState::NONE; // delete finished
|
||||
getSelectedDrive()->bWasDeleted = true;
|
||||
Logger::logThis()->info("Finished delete for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial());
|
||||
ui->updateTUI(&listDrives, u8SelectedEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void reHDD::filterNewDrives(list<Drive> *plistOldDrives, list<Drive> *plistNewDrives)
|
||||
{
|
||||
list<Drive>::iterator itOld; // Iterator for current (old) drive list
|
||||
list<Drive>::iterator itNew; // Iterator for new drive list that was created from to scan thread
|
||||
|
||||
// remove offline old drives from previously run
|
||||
for (itOld = plistOldDrives->begin(); itOld != plistOldDrives->end();)
|
||||
{
|
||||
if (itOld->bIsOffline == true)
|
||||
{
|
||||
Logger::logThis()->warning("Offline drive found: " + itOld->getPath());
|
||||
itOld = plistOldDrives->erase(itOld);
|
||||
/*
|
||||
if(plistOldDrives->size() > 0){ //This can be a risk if the user starts a task for the selected drive and the selected drive changes
|
||||
u8SelectedEntry = 0U;
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
++itOld;
|
||||
}
|
||||
if(u64SelectedDriveIndex < (u64DriveVecSize)) {
|
||||
Wipe::wipeDrive(&vecDrives[u64SelectedDriveIndex]);
|
||||
}
|
||||
|
||||
// search offline drives and mark them
|
||||
for (itOld = plistOldDrives->begin(); itOld != plistOldDrives->end(); ++itOld)
|
||||
{
|
||||
itOld->bIsOffline = true; // set offline before searching in the new list
|
||||
for (itNew = plistNewDrives->begin(); itNew != plistNewDrives->end();)
|
||||
{
|
||||
if ((itOld->getSerial() == itNew->getSerial()) || (itOld->getPath() == itNew->getPath()))
|
||||
{
|
||||
itOld->bIsOffline = false; // drive is still attached
|
||||
// copy new smart data to existing drive
|
||||
itOld->setDriveSMARTData(itNew->getModelFamily(), itNew->getModelName(), itNew->getSerial(), itNew->getCapacity(), itNew->getErrorCount(), itNew->getPowerOnHours(), itNew->getPowerCycles(), itNew->getTemperature());
|
||||
#ifdef LOG_LEVEL_HIGH
|
||||
Logger::logThis()->info("Delete new drive, because already attached: " + itNew->getModelName());
|
||||
#endif
|
||||
itNew = plistNewDrives->erase(itNew); // This drive is already attached, remove from new list
|
||||
}
|
||||
else
|
||||
{
|
||||
++itNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mark offline old drives
|
||||
for (itOld = plistOldDrives->begin(); itOld != plistOldDrives->end(); ++itOld)
|
||||
{
|
||||
if (itOld->bIsOffline == true)
|
||||
{
|
||||
// cout << "offline drive found: " << itOld->getPath() << endl;
|
||||
Logger::logThis()->warning("Mark offline drive found: " + itOld->getPath());
|
||||
itOld->state = Drive::NONE; // clear state --> shred task will terminate
|
||||
}
|
||||
}
|
||||
|
||||
// add new drives to drive list
|
||||
for (itNew = plistNewDrives->begin(); itNew != plistNewDrives->end(); ++itNew)
|
||||
{
|
||||
plistOldDrives->push_back(*itNew);
|
||||
// Logger::logThis()->info("Add new drive: " + itNew->getModelName());
|
||||
}
|
||||
plistNewDrives->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief search attached drives on /dev/sd*
|
||||
* \param pointer of list <Drive>* plistDrives
|
||||
* \param pointer of vector <Drive>* pvecDrives
|
||||
* \return void
|
||||
*/
|
||||
void reHDD::searchDrives(list<Drive> *plistDrives)
|
||||
void reHDD::searchDrives(vector <Drive>* pvecDrives)
|
||||
{
|
||||
// Logger::logThis()->info("--> search drives <--");
|
||||
char *cLine = NULL;
|
||||
cout << "search drives ..." << endl;
|
||||
char * cLine = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
FILE *outputfileHwinfo = popen("lsblk -e 11 -d -o NAME", "r");
|
||||
FILE* outputfileHwinfo = popen("hwinfo --short --disk", "r");
|
||||
|
||||
if (outputfileHwinfo == NULL)
|
||||
{
|
||||
Logger::logThis()->error("Unable to scan attached drives");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
while ((getline(&cLine, &len, outputfileHwinfo)) != -1)
|
||||
{
|
||||
if (string(cLine).length() == 4)
|
||||
if (string(cLine).find("/dev/sd") != string::npos)
|
||||
{
|
||||
Drive *tmpDrive = new Drive("/dev/" + string(cLine).substr(0, 3));
|
||||
tmpDrive->state = Drive::NONE;
|
||||
tmpDrive->bIsOffline = false;
|
||||
plistDrives->push_back(*tmpDrive);
|
||||
// Logger::logThis()->info("SATA drive found: " + tmpDrive->getPath());
|
||||
}
|
||||
|
||||
if (string(cLine).length() == 8)
|
||||
{
|
||||
Drive *tmpDrive = new Drive("/dev/" + string(cLine).substr(0, 7));
|
||||
tmpDrive->state = Drive::NONE;
|
||||
tmpDrive->bIsOffline = false;
|
||||
plistDrives->push_back(*tmpDrive);
|
||||
// Logger::logThis()->info("NVME drive found: " + tmpDrive->getPath());
|
||||
Drive* tmpDrive = new Drive(string(cLine).substr (2,8));
|
||||
pvecDrives->push_back(*tmpDrive);
|
||||
}
|
||||
}
|
||||
pclose(outputfileHwinfo);
|
||||
fclose(outputfileHwinfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief filter out drives that are listed in "ignoreDrives.conf"
|
||||
* \param pointer of list <Drive>* plistDrives
|
||||
* \param pointer of vector <Drive>* pvecDrives
|
||||
* \return void
|
||||
*/
|
||||
void reHDD::filterIgnoredDrives(list<Drive> *plistDrives)
|
||||
void reHDD::filterIgnoredDrives(vector <Drive>* pvecDrives)
|
||||
{
|
||||
list<tuple<string>> vtlIgnoredDevices; // store drives from ignore file
|
||||
ifstream input("ignoreDrives.conf"); // read ignore file
|
||||
string sDelimiter = ":";
|
||||
string sIgnoredDrivePath;
|
||||
string sIgnoredDriveUUID;
|
||||
|
||||
for (string sLine; getline(input, sLine);)
|
||||
vector<tuple<string, string>> vtlIgnoredDevices; //store drives from ingnore file
|
||||
|
||||
ifstream input( "ignoreDrives.conf" ); //read ingnore file
|
||||
|
||||
for(string sLine; getline( input, sLine );)
|
||||
{
|
||||
// Logger::logThis()->info("read uuid: " + sLine);
|
||||
vtlIgnoredDevices.emplace_back(sLine); // add found path and uuid from ignore file to vector
|
||||
}
|
||||
// loop through found entries in ignore file
|
||||
for (auto row : vtlIgnoredDevices)
|
||||
{
|
||||
list<Drive>::iterator it;
|
||||
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
|
||||
if (string(sLine).find("/dev/sd") != string::npos)
|
||||
{
|
||||
size_t pos = 0;
|
||||
string token;
|
||||
while ((pos = sLine.find(sDelimiter)) != string::npos)
|
||||
{
|
||||
token = sLine.substr(0, pos);
|
||||
sIgnoredDrivePath = token;
|
||||
sLine.erase(0, pos + sDelimiter.length());
|
||||
sIgnoredDriveUUID = sLine;
|
||||
} //end while
|
||||
//cout << "Path: " << sIgnoredDrivePath << std::endl;
|
||||
//cout << "UUID: " << sIgnoredDriveUUID << std::endl;
|
||||
vtlIgnoredDevices.emplace_back(sIgnoredDrivePath, sIgnoredDriveUUID); //add found path and uuid from ingnore file to vector
|
||||
}
|
||||
}
|
||||
|
||||
//loop through found entries in ingnore file
|
||||
for(auto row : vtlIgnoredDevices)
|
||||
{
|
||||
auto it = pvecDrives->begin();
|
||||
while (it != pvecDrives->end())
|
||||
{
|
||||
it++;
|
||||
string sUUID;
|
||||
char *cLine = NULL;
|
||||
size_t len = 0;
|
||||
string sCMD = "blkid ";
|
||||
sCMD.append(it->getPath());
|
||||
// cout << "cmd: " << sCMD << endl;
|
||||
FILE *outputfileBlkid = popen(sCMD.c_str(), "r"); // get UUID from drive
|
||||
if (outputfileBlkid == NULL)
|
||||
if (!get<0>(row).compare(it->getPath())) //find same drive based on path
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
while ((getline(&cLine, &len, outputfileBlkid)) != -1) // parse UUID from blkid
|
||||
{
|
||||
if (string(cLine).find("PTUUID") != string::npos)
|
||||
// cout << "Same drive path found" << endl;
|
||||
char * cLine = NULL;
|
||||
size_t len = 0;
|
||||
string sCMD = "blkid ";
|
||||
sCMD.append(it->getPath());
|
||||
// cout << "cmd: " << sCMD << endl;
|
||||
FILE* outputfileBlkid = popen(sCMD.c_str(), "r"); //get UUID from drive
|
||||
if (outputfileBlkid == NULL)
|
||||
{
|
||||
string sBlkidOut = string(cLine);
|
||||
sBlkidOut.erase(0, 18);
|
||||
sBlkidOut.erase(8, sBlkidOut.length());
|
||||
sUUID = sBlkidOut;
|
||||
// cout << "blkid uuid:" << sUUID << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
while ((getline(&cLine, &len, outputfileBlkid)) != -1) //parse UUID from blkid
|
||||
{
|
||||
if (string(cLine).find("PTUUID") != string::npos)
|
||||
{
|
||||
string sBlkidOut = string(cLine);
|
||||
sBlkidOut.erase(0, 18);
|
||||
sBlkidOut.erase(36, sBlkidOut.length() - 36);
|
||||
sUUID = sBlkidOut;
|
||||
//cout << "blkid uuid:" << sUUID << endl;
|
||||
}
|
||||
}
|
||||
fclose(outputfileBlkid);
|
||||
// cout << "blkid uuid:" << sUUID << endl;
|
||||
|
||||
if (get<1>(row).compare(sUUID)) //compare uuid from ignore file and uuid from drive
|
||||
{
|
||||
cout << "[ERROR] different uuid found than in ignore file:" << it->getPath() << endl;
|
||||
exit(EXIT_FAILURE); // exit to prevent accidentally shred a system drive
|
||||
}
|
||||
else
|
||||
{
|
||||
// same uuid found than in ignore file --> ignore this drive
|
||||
it = pvecDrives->erase(it);
|
||||
}
|
||||
}
|
||||
pclose(outputfileBlkid);
|
||||
// cout << "blkid uuid:" << sUUID << endl;
|
||||
|
||||
if (!get<0>(row).compare(sUUID)) // compare uuid from ignore file and uuid from drive
|
||||
{
|
||||
// same uuid found than in ignore file --> ignore this drive
|
||||
#ifdef LOG_LEVEL_HIGH
|
||||
Logger::logThis()->info("same uuid found than in ignore file --> ignore this drive: " + it->getPath());
|
||||
#endif
|
||||
it = plistDrives->erase(it);
|
||||
it--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief filter out drives that are not indented for processing
|
||||
* \param pointer of list <Drive>* plistDrives
|
||||
* \return void
|
||||
*/
|
||||
void reHDD::filterInvalidDrives(list<Drive> *plistDrives)
|
||||
{
|
||||
list<Drive>::iterator it;
|
||||
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
|
||||
{
|
||||
if (it->getCapacity() == 0U)
|
||||
{
|
||||
#ifdef LOG_LEVEL_HIGH
|
||||
Logger::logThis()->info("Drive reports zero capacity --> ignore this drive: " + it->getPath());
|
||||
#endif
|
||||
it = plistDrives->erase(it);
|
||||
it--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief start shred for all drives
|
||||
* \param pointer of list <Drive>* plistDrives
|
||||
* \return void
|
||||
*/
|
||||
void reHDD::startShredAllDrives(list<Drive> *plistDrives)
|
||||
{
|
||||
list<Drive>::iterator it;
|
||||
mxDrives.lock();
|
||||
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
|
||||
{
|
||||
if (it->state == Drive::NONE)
|
||||
{
|
||||
Drive *pTmpDrive = iterator_to_pointer<Drive, std::list<Drive>::iterator>(it);
|
||||
#ifdef LOG_LEVEL_HIGH
|
||||
ostringstream address;
|
||||
address << (void const *)&(*pTmpDrive);
|
||||
Logger::logThis()->info("Started shred (all) for: " + pTmpDrive->getModelName() + "-" + pTmpDrive->getSerial() + " @" + address.str());
|
||||
#endif
|
||||
pTmpDrive->state = Drive::TaskState::SHRED_ACTIVE;
|
||||
thread(ThreadShred, pTmpDrive).detach();
|
||||
}
|
||||
}
|
||||
mxDrives.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief print drives with all information
|
||||
* \param pointer of list <Drive>* plistDrives
|
||||
* \param pointer of vector <Drive>* pvecDrives
|
||||
* \return void
|
||||
*/
|
||||
void reHDD::printDrives(list<Drive> *plistDrives)
|
||||
void reHDD::printDrives(vector <Drive>* pvecDrives)
|
||||
{
|
||||
#ifdef LOG_LEVEL_HIGH
|
||||
Logger::logThis()->info("------------DRIVES START------------");
|
||||
// cout << "------------DRIVES---------------" << endl;
|
||||
list<Drive>::iterator it;
|
||||
uint8_t u8Index = 0;
|
||||
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
|
||||
cout << "------------DRIVES---------------" << endl;
|
||||
vector <Drive>::iterator it;
|
||||
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it)
|
||||
{
|
||||
/*
|
||||
cout << " Drive: " << distance(pvecDrives->begin(), it) << endl;
|
||||
cout << "Path: " << it->getPath() << endl;
|
||||
cout << "ModelFamily: " << it->getModelFamily() << endl;
|
||||
cout << "ModelName: " << it->getModelName() << endl;
|
||||
cout << "Capacity: " << it->getCapacity() << endl;
|
||||
cout << "Serial: " << it->getSerial() << endl;
|
||||
cout << "PowerOnHours: " << it->getPowerOnHours() << endl;
|
||||
cout << "PowerCycle: " << it->getPowerCycles() << endl;
|
||||
cout << "ErrorCount: " << it->getErrorCount() << endl;
|
||||
cout << endl;*/
|
||||
|
||||
ostringstream address;
|
||||
address << (void const *)&(*it);
|
||||
Logger::logThis()->info(to_string(u8Index++) + ": " + it->getPath() + " - " + it->getModelFamily() + " - " + it->getSerial() + " @" + address.str());
|
||||
}
|
||||
Logger::logThis()->info("------------DRIVES END--------------");
|
||||
// cout << "---------------------------------" << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief update shred metrics for all drives
|
||||
* \param pointer of list <Drive>* plistDrives
|
||||
* \return void
|
||||
*/
|
||||
void reHDD::updateShredMetrics(list<Drive> *plistDrives)
|
||||
{
|
||||
list<Drive>::iterator it;
|
||||
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
|
||||
{
|
||||
if (it->state == Drive::SHRED_ACTIVE)
|
||||
{
|
||||
Drive *pTmpDrive = iterator_to_pointer<Drive, std::list<Drive>::iterator>(it);
|
||||
// set metrics for calculating shred speed
|
||||
std::chrono::time_point<std::chrono::system_clock> chronoCurrentTimestamp = std::chrono::system_clock::now();
|
||||
time_t u32ShredTimeDelta = (chronoCurrentTimestamp - pTmpDrive->sShredSpeed.chronoShredTimestamp).count();
|
||||
if (u32ShredTimeDelta > METRIC_THRESHOLD)
|
||||
{
|
||||
pTmpDrive->sShredSpeed.u32ShredTimeDelta = u32ShredTimeDelta;
|
||||
pTmpDrive->sShredSpeed.chronoShredTimestamp = std::chrono::system_clock::now();
|
||||
pTmpDrive->sShredSpeed.ulWrittenBytes = pTmpDrive->sShredSpeed.ulSpeedMetricBytesWritten;
|
||||
pTmpDrive->sShredSpeed.ulSpeedMetricBytesWritten = 0U;
|
||||
}
|
||||
}
|
||||
cout << " Drive: " << distance(pvecDrives->begin(), it) << endl;
|
||||
cout << "Path: " << it->getPath() << endl;
|
||||
cout << "ModelFamily: " << it->getModelFamily() << endl;
|
||||
cout << "ModelName: " << it->getModelName() << endl;
|
||||
cout << "Capacity: " << it->getCapacity() << endl;
|
||||
cout << "Serial: " << it->getSerial() << endl;
|
||||
cout << "PowerOnHours: " << it->getPowerOnHours() << endl;
|
||||
cout << "PowerCycle: " << it->getPowerCycles() << endl;
|
||||
cout << "ErrorCount: " << it->getErrorCount() << endl;
|
||||
cout << endl;
|
||||
}
|
||||
cout << "---------------------------------" << endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief add S.M.A.R.T data from SMART
|
||||
* \param pointer of list <Drive>* plistDrives
|
||||
* \param pointer of vector <Drive>* pvecDrives
|
||||
* \return void
|
||||
*/
|
||||
void reHDD::addSMARTData(list<Drive> *plistDrives)
|
||||
void reHDD::addSMARTData(vector <Drive>* pvecDrives)
|
||||
{
|
||||
list<Drive>::iterator it;
|
||||
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
|
||||
vector <Drive>::iterator it;
|
||||
for (it = pvecDrives->begin(); it != pvecDrives->end(); ++it)
|
||||
{
|
||||
Drive *pTmpDrive = iterator_to_pointer<Drive, std::list<Drive>::iterator>(it);
|
||||
Drive* pTmpDrive = iterator_to_pointer<Drive, std::vector<Drive>::iterator > (it);
|
||||
SMART::readSMARTData(pTmpDrive);
|
||||
}
|
||||
}
|
||||
|
||||
void reHDD::handleArrowKey(TUI::UserInput userInput)
|
||||
{
|
||||
int8_t u8EntrySize = (int8_t)listDrives.size();
|
||||
switch (userInput)
|
||||
{
|
||||
case TUI::UserInput::DownKey:
|
||||
u8SelectedEntry++;
|
||||
if (u8SelectedEntry >= u8EntrySize)
|
||||
{
|
||||
u8SelectedEntry = 0;
|
||||
}
|
||||
break;
|
||||
case TUI::UserInput::UpKey:
|
||||
if (u8SelectedEntry == 0)
|
||||
{
|
||||
u8SelectedEntry = (u8EntrySize - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
u8SelectedEntry--;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
u8SelectedEntry = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Logger::logThis()->info("ArrowKey - selected drive: " + to_string(u8SelectedEntry));
|
||||
}
|
||||
|
||||
void reHDD::handleEnter()
|
||||
{
|
||||
|
||||
if (getSelectedDrive() != nullptr)
|
||||
{
|
||||
if (getSelectedDrive()->state == Drive::TaskState::SHRED_SELECTED)
|
||||
{
|
||||
Logger::logThis()->info("Started shred/check for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial());
|
||||
getSelectedDrive()->state = Drive::TaskState::SHRED_ACTIVE;
|
||||
// task for drive is running --> don´t show more task options
|
||||
Drive *pTmpDrive = getSelectedDrive();
|
||||
thread(ThreadShred, pTmpDrive).detach();
|
||||
}
|
||||
|
||||
if (getSelectedDrive()->state == Drive::TaskState::DELETE_SELECTED)
|
||||
{
|
||||
Logger::logThis()->info("Started delete for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial());
|
||||
getSelectedDrive()->state = Drive::TaskState::DELETE_ACTIVE;
|
||||
// task for drive is running --> don´t show more task options
|
||||
thread(ThreadDelete).detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reHDD::handleESC()
|
||||
{
|
||||
if (getSelectedDrive() != nullptr)
|
||||
{
|
||||
if (getSelectedDrive()->state == Drive::TaskState::SHRED_SELECTED)
|
||||
{
|
||||
getSelectedDrive()->state = Drive::TaskState::NONE;
|
||||
// task for drive is selected --> remove selection
|
||||
}
|
||||
|
||||
if (getSelectedDrive()->state == Drive::TaskState::DELETE_SELECTED)
|
||||
{
|
||||
getSelectedDrive()->state = Drive::TaskState::NONE;
|
||||
// task for drive is selected --> remove selection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reHDD::handleAbort()
|
||||
{
|
||||
if (getSelectedDrive() != nullptr)
|
||||
{
|
||||
if (getSelectedDrive()->state == Drive::SHRED_ACTIVE || getSelectedDrive()->state == Drive::DELETE_ACTIVE)
|
||||
{
|
||||
getSelectedDrive()->state = Drive::NONE;
|
||||
Logger::logThis()->info("Abort-Shred-Signal for: " + getSelectedDrive()->getModelName() + "-" + getSelectedDrive()->getSerial());
|
||||
// task for drive is running --> remove selection
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
303
src/shred.cpp
303
src/shred.cpp
|
@ -1,303 +0,0 @@
|
|||
/**
|
||||
* @file shred.cpp
|
||||
* @brief shred drive
|
||||
* @author hendrik schutter
|
||||
* @date 22.08.2022
|
||||
*/
|
||||
|
||||
#include "../include/reHDD.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#include "../tfnoisegen/tfprng.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
const static char *randomsrc = (char *)"/dev/urandom";
|
||||
|
||||
Shred::Shred()
|
||||
{
|
||||
}
|
||||
|
||||
Shred::~Shred()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief shred drive with shred
|
||||
* \param pointer of Drive instance
|
||||
* \return void
|
||||
*/
|
||||
int Shred::shredDrive(Drive *drive, int *ipSignalFd)
|
||||
{
|
||||
ostringstream address;
|
||||
address << (void const *)&(*drive);
|
||||
Logger::logThis()->info("Shred-Task started - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
|
||||
|
||||
#ifdef DRYRUN
|
||||
for (int i = 0; i <= 500; i++)
|
||||
{
|
||||
if (drive->state != Drive::SHRED_ACTIVE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
drive->setTaskPercentage(i + 0.05);
|
||||
write(*ipSignalFd, "A", 1);
|
||||
usleep(20000);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef DRYRUN
|
||||
const char *cpDrivePath = drive->getPath().c_str();
|
||||
unsigned char ucKey[TFNG_KEY_SIZE];
|
||||
|
||||
// open random source
|
||||
randomSrcFileDiscr = open(randomsrc, O_RDONLY | O_LARGEFILE);
|
||||
if (randomSrcFileDiscr == -1)
|
||||
{
|
||||
std::string errorMsg(strerror(randomSrcFileDiscr));
|
||||
Logger::logThis()->error("Shred-Task: Open random source failed! " + errorMsg + " - Drive: " + drive->getSerial());
|
||||
perror(randomsrc);
|
||||
cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// open disk
|
||||
driveFileDiscr = open(cpDrivePath, O_RDWR | O_LARGEFILE);
|
||||
if (driveFileDiscr == -1)
|
||||
{
|
||||
std::string errorMsg(strerror(driveFileDiscr));
|
||||
Logger::logThis()->error("Shred-Task: Open drive failed! " + errorMsg + " - Drive: " + drive->getSerial());
|
||||
perror(cpDrivePath);
|
||||
cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// read key for random generator
|
||||
ssize_t readRet = read(randomSrcFileDiscr, ucKey, sizeof(ucKey));
|
||||
if (readRet <= 0)
|
||||
{
|
||||
std::string errorMsg(strerror(readRet));
|
||||
Logger::logThis()->error("Shred-Task: Read random key failed! " + errorMsg + " - Drive: " + drive->getSerial());
|
||||
perror(randomsrc);
|
||||
cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
tfng_prng_seedkey(ucKey);
|
||||
|
||||
this->ulDriveByteSize = getDriveSizeInBytes(driveFileDiscr);
|
||||
drive->sShredSpeed.chronoShredTimestamp = std::chrono::system_clock::now();
|
||||
; // set inital timestamp for speed metric
|
||||
drive->sShredSpeed.ulSpeedMetricBytesWritten = 0U; // uses to calculate speed metric
|
||||
|
||||
#ifdef LOG_LEVEL_HIGH
|
||||
Logger::logThis()->info("Shred-Task: Bytes-Size of Drive: " + to_string(this->ulDriveByteSize) + " - Drive: " + drive->getSerial());
|
||||
#endif
|
||||
|
||||
for (unsigned int uiShredIterationCounter = 0U; uiShredIterationCounter < SHRED_ITERATIONS; uiShredIterationCounter++)
|
||||
{
|
||||
unsigned long ulDriveByteCounter = 0U; // used for one shred-iteration to keep track of the current drive position
|
||||
|
||||
if (uiShredIterationCounter == (SHRED_ITERATIONS - 1))
|
||||
{
|
||||
// last shred iteration --> overwrite (just the write chunk) bytes with zeros instead with random data
|
||||
memset(caTfngData, 0U, CHUNK_SIZE);
|
||||
}
|
||||
|
||||
while (ulDriveByteCounter < ulDriveByteSize)
|
||||
{
|
||||
int iBytesToShred = 0; // Bytes that will be overwritten in this chunk-iteration
|
||||
|
||||
if (uiShredIterationCounter != (SHRED_ITERATIONS - 1))
|
||||
{
|
||||
// NOT last shred iteration --> generate new random data
|
||||
tfng_prng_genrandom(caTfngData, TFNG_DATA_SIZE);
|
||||
}
|
||||
|
||||
if ((ulDriveByteSize - ulDriveByteCounter) < CHUNK_SIZE)
|
||||
{
|
||||
iBytesToShred = (ulDriveByteSize - ulDriveByteCounter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iBytesToShred = CHUNK_SIZE;
|
||||
}
|
||||
|
||||
int iByteShredded = write(driveFileDiscr, caTfngData, iBytesToShred);
|
||||
|
||||
if (iByteShredded <= 0)
|
||||
{
|
||||
std::string errorMsg(strerror(iByteShredded));
|
||||
Logger::logThis()->error("Shred-Task: Write to drive failed! " + errorMsg + " - Drive: " + drive->getSerial());
|
||||
perror("unable to write random data");
|
||||
cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ulDriveByteCounter += iByteShredded;
|
||||
ulDriveByteOverallCount += iByteShredded;
|
||||
d32Percent = this->calcProgress();
|
||||
drive->sShredSpeed.ulSpeedMetricBytesWritten += iByteShredded;
|
||||
|
||||
#ifdef LOG_LEVEL_HIGH
|
||||
Logger::logThis()->info("Shred-Task: ByteCount: " + to_string(ulDriveByteCounter) + " - iteration: " + to_string((uiShredIterationCounter + 1)) + " - progress: " + to_string(d32Percent) + " - Drive: " + drive->getSerial());
|
||||
#endif
|
||||
if ((d32Percent - d32TmpPercent) >= 0.01)
|
||||
{
|
||||
// set shred percantage
|
||||
drive->setTaskPercentage(d32TmpPercent);
|
||||
d32TmpPercent = d32Percent;
|
||||
// signal process in shreding
|
||||
write(*ipSignalFd, "A", 1);
|
||||
}
|
||||
|
||||
if (drive->state != Drive::SHRED_ACTIVE)
|
||||
{
|
||||
drive->setTaskPercentage(0);
|
||||
d32Percent = 0.00;
|
||||
d32TmpPercent = 0.00;
|
||||
ulDriveByteCounter = 0U;
|
||||
Logger::logThis()->info("Aborted shred for: " + drive->getModelName() + "-" + drive->getSerial());
|
||||
cleanup();
|
||||
return -1;
|
||||
}
|
||||
// end one chunk write
|
||||
}
|
||||
if (0 != iRewindDrive(driveFileDiscr))
|
||||
{
|
||||
Logger::logThis()->error("Shred-Task: Unable to rewind drive! - Drive: " + drive->getSerial());
|
||||
cleanup();
|
||||
return -1;
|
||||
}
|
||||
// end one shred iteration
|
||||
}
|
||||
// end of all shred iteratio
|
||||
|
||||
tfng_prng_seedkey(NULL); // reset random generator
|
||||
|
||||
drive->bWasShredded = true;
|
||||
Logger::logThis()->info("Shred-Task finished - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
|
||||
#ifdef ZERO_CHECK
|
||||
drive->state = Drive::CHECK_ACTIVE;
|
||||
Logger::logThis()->info("Check-Task started - Drive: " + drive->getModelName() + "-" + drive->getSerial() + " @" + address.str());
|
||||
drive->u32DriveChecksumAfterShredding = uiCalcChecksum(driveFileDiscr, drive, ipSignalFd);
|
||||
#ifdef LOG_LEVEL_HIGH
|
||||
if (drive->u32DriveChecksumAferShredding != 0)
|
||||
{
|
||||
Logger::logThis()->info("Shred-Task: Checksum not zero: " + to_string(drive->u32DriveChecksumAfterShredding) + " - Drive: " + drive->getSerial());
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::logThis()->info("Shred-Task: Checksum zero: " + to_string(drive->u32DriveChecksumAfterShredding) + " - Drive: " + drive->getSerial());
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
cleanup();
|
||||
|
||||
if ((drive->state == Drive::SHRED_ACTIVE) || (drive->state == Drive::CHECK_ACTIVE))
|
||||
{
|
||||
drive->state = Drive::NONE;
|
||||
drive->setTaskPercentage(0.0);
|
||||
Printer::getPrinter()->print(drive);
|
||||
Logger::logThis()->info("Finished shred/check for: " + drive->getModelName() + "-" + drive->getSerial());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* \brief calc shredding progress in %
|
||||
* \param current byte index of the drive
|
||||
* \param current shred iteration
|
||||
* \return double percentage
|
||||
*/
|
||||
double Shred::calcProgress()
|
||||
{
|
||||
unsigned int uiMaxShredIteration = SHRED_ITERATIONS;
|
||||
|
||||
#ifdef ZERO_CHECK
|
||||
uiMaxShredIteration++; // increment because we will check after SHRED_ITERATIONS the drive for non-zero bytes
|
||||
#endif
|
||||
return (double)(((double)ulDriveByteOverallCount) / ((double)this->ulDriveByteSize * uiMaxShredIteration)) * 100.0f;
|
||||
}
|
||||
|
||||
int Shred::iRewindDrive(fileDescriptor file)
|
||||
{
|
||||
if (0 != lseek(file, 0L, SEEK_SET))
|
||||
{
|
||||
perror("unable to rewind drive");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long Shred::getDriveSizeInBytes(fileDescriptor file)
|
||||
{
|
||||
unsigned long ulDriveSizeTmp = lseek(file, 0L, SEEK_END);
|
||||
|
||||
if (0 != iRewindDrive(file))
|
||||
{
|
||||
ulDriveSizeTmp = 0U;
|
||||
}
|
||||
|
||||
#ifdef DEMO_DRIVE_SIZE
|
||||
ulDriveSizeTmp = DEMO_DRIVE_SIZE;
|
||||
#endif
|
||||
return ulDriveSizeTmp;
|
||||
}
|
||||
|
||||
unsigned int Shred::uiCalcChecksum(fileDescriptor file, Drive *drive, int *ipSignalFd)
|
||||
{
|
||||
unsigned int uiChecksum = 0;
|
||||
unsigned long ulDriveByteCounter = 0U;
|
||||
while (ulDriveByteCounter < ulDriveByteSize)
|
||||
{
|
||||
int iBytesToCheck = 0;
|
||||
if ((ulDriveByteSize - ulDriveByteCounter) < CHUNK_SIZE)
|
||||
{
|
||||
iBytesToCheck = (ulDriveByteSize - ulDriveByteCounter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iBytesToCheck = CHUNK_SIZE;
|
||||
}
|
||||
int iReadBytes = read(file, caReadBuffer, iBytesToCheck);
|
||||
for (int iReadBytesCounter = 0U; iReadBytesCounter < iReadBytes; iReadBytesCounter++)
|
||||
{
|
||||
uiChecksum += caReadBuffer[iReadBytesCounter];
|
||||
}
|
||||
ulDriveByteCounter += iReadBytes;
|
||||
ulDriveByteOverallCount += iReadBytes;
|
||||
d32Percent = this->calcProgress();
|
||||
drive->sShredSpeed.ulSpeedMetricBytesWritten += iReadBytes;
|
||||
|
||||
#ifdef LOG_LEVEL_HIGH
|
||||
Logger::logThis()->info("Shred-Task (Checksum): ByteCount: " + to_string(ulDriveByteCounter) + " - progress: " + to_string(d32Percent) + " - Drive: " + drive->getSerial());
|
||||
#endif
|
||||
|
||||
if (((d32Percent - d32TmpPercent) >= 0.01) || (d32Percent == 100.0))
|
||||
{
|
||||
drive->setTaskPercentage(d32TmpPercent);
|
||||
d32TmpPercent = d32Percent;
|
||||
#ifdef LOG_LEVEL_HIGH
|
||||
Logger::logThis()->info("send progress signal to main loop (check)");
|
||||
#endif
|
||||
write(*ipSignalFd, "A", 1);
|
||||
}
|
||||
}
|
||||
drive->bWasChecked = true;
|
||||
return uiChecksum;
|
||||
}
|
||||
|
||||
void Shred::cleanup()
|
||||
{
|
||||
close(driveFileDiscr);
|
||||
close(randomSrcFileDiscr);
|
||||
}
|
135
src/smart.cpp
135
src/smart.cpp
|
@ -14,14 +14,13 @@ uint64_t SMART::capacity = 0U;
|
|||
uint32_t SMART::errorCount = 0U;
|
||||
uint32_t SMART::powerOnHours = 0U;
|
||||
uint32_t SMART::powerCycle = 0U;
|
||||
uint32_t SMART::temperature = 0U;
|
||||
|
||||
/**
|
||||
* \brief get and set S.M.A.R.T. values in Drive
|
||||
* \param pointer of Drive instance
|
||||
* \return void
|
||||
*/
|
||||
void SMART::readSMARTData(Drive *drive)
|
||||
void SMART::readSMARTData(Drive* drive)
|
||||
{
|
||||
modelFamily.clear();
|
||||
modelName.clear();
|
||||
|
@ -30,65 +29,30 @@ void SMART::readSMARTData(Drive *drive)
|
|||
errorCount = 0U;
|
||||
powerOnHours = 0U;
|
||||
powerCycle = 0U;
|
||||
temperature = 0U;
|
||||
|
||||
string sSmartctlCommands[] = {" --json -a ", " --json -d sntjmicron -a ", " --json -d sntasmedia -a ", " --json -d sntrealtek -a "};
|
||||
size_t len = 0; //lenght of found line
|
||||
char* cLine = NULL; //found line
|
||||
|
||||
for (string sSmartctlCommand : sSmartctlCommands)
|
||||
string sCMD = ("smartctl --json -a ");
|
||||
sCMD.append(drive->getPath());
|
||||
const char* cpComand = sCMD.c_str();
|
||||
|
||||
FILE* outputfileSmart = popen(cpComand, "r");
|
||||
|
||||
while ((getline(&cLine, &len, outputfileSmart)) != -1)
|
||||
{
|
||||
string sCMD = ("smartctl");
|
||||
sCMD.append(sSmartctlCommand);
|
||||
sCMD.append(drive->getPath());
|
||||
const char *cpComand = sCMD.c_str();
|
||||
string sLine = string(cLine);
|
||||
|
||||
FILE *outputfileSmart = popen(cpComand, "r");
|
||||
size_t len = 0; // length of found line
|
||||
char *cLine = NULL; // found line
|
||||
uint8_t status = 255;
|
||||
|
||||
while ((getline(&cLine, &len, outputfileSmart)) != -1)
|
||||
{
|
||||
string sLine = string(cLine);
|
||||
|
||||
status = SMART::parseExitStatus(sLine);
|
||||
SMART::parseModelFamily(sLine);
|
||||
SMART::parseModelName(sLine);
|
||||
SMART::parseSerial(sLine);
|
||||
SMART::parseCapacity(sLine);
|
||||
SMART::parseErrorCount(sLine);
|
||||
SMART::parsePowerOnHours(sLine);
|
||||
SMART::parsePowerCycle(sLine);
|
||||
SMART::parseTemperature(sLine);
|
||||
}
|
||||
|
||||
pclose(outputfileSmart);
|
||||
|
||||
if (status == 0U)
|
||||
{
|
||||
// Found S.M.A.R.T. data with this command
|
||||
break;
|
||||
}
|
||||
SMART::parseModelFamily(sLine);
|
||||
SMART::parseModelName(sLine);
|
||||
SMART::parseSerial(sLine);
|
||||
SMART::parseCapacity(sLine);
|
||||
SMART::parseErrorCount(sLine);
|
||||
SMART::parsePowerOnHours(sLine);
|
||||
SMART::parsePowerCycle(sLine);
|
||||
}
|
||||
|
||||
drive->setDriveSMARTData(modelFamily, modelName, serial, capacity, errorCount, powerOnHours, powerCycle, temperature); // wirte data in drive
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief parse ExitStatus
|
||||
* \param string output line of smartctl
|
||||
* \return uint_8 exit status
|
||||
*/
|
||||
uint8_t SMART::parseExitStatus(string sLine)
|
||||
{
|
||||
uint8_t exitStatus = -1;
|
||||
string search("\"exit_status\": ");
|
||||
size_t found = sLine.find(search);
|
||||
if (found != string::npos)
|
||||
{
|
||||
sLine.erase(0, sLine.find(": ") + 1);
|
||||
exitStatus = stol(sLine);
|
||||
}
|
||||
return exitStatus;
|
||||
fclose(outputfileSmart);
|
||||
drive->setDriveSMARTData(modelFamily, modelName, serial, capacity, errorCount, powerOnHours, powerCycle); //wirte data in drive
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,10 +64,9 @@ void SMART::parseModelFamily(string sLine)
|
|||
{
|
||||
string search("\"model_family\": ");
|
||||
size_t found = sLine.find(search);
|
||||
if (found != string::npos)
|
||||
{
|
||||
if (found!=string::npos) {
|
||||
sLine.erase(0, sLine.find(": ") + 3);
|
||||
sLine.erase(sLine.length() - 3, 3);
|
||||
sLine.erase(sLine.length()-3, 3);
|
||||
modelFamily = sLine;
|
||||
}
|
||||
}
|
||||
|
@ -117,10 +80,9 @@ void SMART::parseModelName(string sLine)
|
|||
{
|
||||
string search("\"model_name\": ");
|
||||
size_t found = sLine.find(search);
|
||||
if (found != string::npos)
|
||||
{
|
||||
if (found!=string::npos) {
|
||||
sLine.erase(0, sLine.find(": ") + 3);
|
||||
sLine.erase(sLine.length() - 3, 3);
|
||||
sLine.erase(sLine.length()-3, 3);
|
||||
modelName = sLine;
|
||||
}
|
||||
}
|
||||
|
@ -134,10 +96,9 @@ void SMART::parseSerial(string sLine)
|
|||
{
|
||||
string search("\"serial_number\": ");
|
||||
size_t found = sLine.find(search);
|
||||
if (found != string::npos)
|
||||
{
|
||||
if (found!=string::npos) {
|
||||
sLine.erase(0, sLine.find(": ") + 3);
|
||||
sLine.erase(sLine.length() - 3, 3);
|
||||
sLine.erase(sLine.length()-3, 3);
|
||||
serial = sLine;
|
||||
}
|
||||
}
|
||||
|
@ -151,10 +112,9 @@ void SMART::parseCapacity(string sLine)
|
|||
{
|
||||
string search("\"bytes\": ");
|
||||
size_t found = sLine.find(search);
|
||||
if (found != string::npos)
|
||||
{
|
||||
if (found!=string::npos) {
|
||||
sLine.erase(0, sLine.find(": ") + 2);
|
||||
sLine.erase(sLine.length() - 1, 1);
|
||||
sLine.erase(sLine.length()-1, 1);
|
||||
capacity = stol(sLine);
|
||||
}
|
||||
}
|
||||
|
@ -168,10 +128,10 @@ void SMART::parseErrorCount(string sLine)
|
|||
{
|
||||
string search("\"error_count_total\": ");
|
||||
size_t found = sLine.find(search);
|
||||
if (found != string::npos)
|
||||
if (found!=string::npos)
|
||||
{
|
||||
sLine.erase(0, sLine.find(": ") + 2);
|
||||
sLine.erase(sLine.length() - 2, 2);
|
||||
sLine.erase(0, sLine.find(": ")+2);
|
||||
sLine.erase(sLine.length()-2, 2);
|
||||
errorCount = stol(sLine);
|
||||
}
|
||||
}
|
||||
|
@ -185,11 +145,12 @@ void SMART::parsePowerOnHours(string sLine)
|
|||
{
|
||||
string search("\"hours\": ");
|
||||
size_t found = sLine.find(search);
|
||||
if (found != string::npos)
|
||||
if (found!=string::npos)
|
||||
{
|
||||
sLine.erase(0, sLine.find(": ") + 2);
|
||||
sLine.erase(sLine.length() - 1, 1);
|
||||
sLine.erase(sLine.length()-1, 1);
|
||||
powerOnHours = stol(sLine);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,34 +163,12 @@ void SMART::parsePowerCycle(string sLine)
|
|||
{
|
||||
string search("\"power_cycle_count\": ");
|
||||
size_t found = sLine.find(search);
|
||||
if (found != string::npos)
|
||||
if (found!=string::npos)
|
||||
{
|
||||
sLine.erase(0, sLine.find(": ") + 2);
|
||||
sLine.erase(sLine.length() - 2, 2);
|
||||
sLine.erase(sLine.length()-2, 2);
|
||||
powerCycle = stol(sLine);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief parse temperature
|
||||
* \param string output line of smartctl
|
||||
* \return void
|
||||
*/
|
||||
void SMART::parseTemperature(string sLine)
|
||||
{
|
||||
string search("\"current\": ");
|
||||
size_t found = sLine.find(search);
|
||||
if (found != string::npos)
|
||||
{
|
||||
sLine.erase(0, sLine.find(": ") + 2);
|
||||
sLine.erase(sLine.length() - 1, 2);
|
||||
if (sLine == "{")
|
||||
{
|
||||
temperature = 0U; // this drive doesn't support temperature
|
||||
}
|
||||
else
|
||||
{
|
||||
temperature = stol(sLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
708
src/tui.cpp
708
src/tui.cpp
|
@ -1,708 +0,0 @@
|
|||
/**
|
||||
* @file tui.cpp
|
||||
* @brief display user interface
|
||||
* @author hendrik schutter
|
||||
* @date 03.08.2020
|
||||
*/
|
||||
|
||||
#include "../include/reHDD.h"
|
||||
|
||||
static std::mutex mxUIrefresh;
|
||||
|
||||
TUI::TUI(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief wipe drive with shred
|
||||
* \param pointer of Drive instance
|
||||
* \return void
|
||||
*/
|
||||
|
||||
void TUI::initTUI()
|
||||
{
|
||||
initscr();
|
||||
raw();
|
||||
keypad(stdscr, TRUE);
|
||||
if (has_colors() == TRUE)
|
||||
{
|
||||
start_color();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Your terminal does not support color\n");
|
||||
Logger::logThis()->error("Your terminal does not support color");
|
||||
exit(1);
|
||||
}
|
||||
clear();
|
||||
curs_set(0);
|
||||
noecho();
|
||||
cbreak();
|
||||
init_pair(COLOR_AREA_STDSCR, COLOR_WHITE, COLOR_BLUE);
|
||||
wbkgd(stdscr, COLOR_PAIR(COLOR_AREA_STDSCR));
|
||||
|
||||
init_pair(COLOR_AREA_ENTRY_EVEN, COLOR_BLACK, COLOR_WHITE);
|
||||
init_pair(COLOR_AREA_ENTRY_ODD, COLOR_BLUE, COLOR_WHITE);
|
||||
init_pair(COLOR_AREA_ENTRY_SELECTED, COLOR_WHITE, COLOR_RED);
|
||||
init_pair(COLOR_AREA_OVERVIEW, COLOR_BLACK, COLOR_WHITE);
|
||||
init_pair(COLOR_AREA_DETAIL, COLOR_BLACK, COLOR_WHITE);
|
||||
|
||||
mvprintw(0, 2, "reHDD - HDD refurbishing tool - GPL 3.0 ");
|
||||
Logger::logThis()->info("UI successfully initialized");
|
||||
}
|
||||
|
||||
void TUI::updateTUI(list<Drive> *plistDrives, uint8_t u8SelectedEntry)
|
||||
{
|
||||
mxUIrefresh.lock();
|
||||
uint16_t u16StdscrX, u16StdscrY;
|
||||
getmaxyx(stdscr, u16StdscrY, u16StdscrX);
|
||||
|
||||
init_pair(COLOR_AREA_STDSCR, COLOR_WHITE, COLOR_BLUE);
|
||||
wbkgd(stdscr, COLOR_PAIR(COLOR_AREA_STDSCR));
|
||||
|
||||
refresh();
|
||||
|
||||
// overview window is 3/7 of the x-size
|
||||
overview = createOverViewWindow((int)(u16StdscrX * (float)(3.0 / 7.0)), (u16StdscrY - 1));
|
||||
wrefresh(overview);
|
||||
|
||||
// system stat window is 2/7 of the x-size
|
||||
systemview = createSystemStats(((int)(u16StdscrX * (float)(2.0 / 7.0))) - 6, 12, (int)(u16StdscrX * (float)(5.0 / 7.0) + 4), (u16StdscrY - 13));
|
||||
wrefresh(systemview);
|
||||
|
||||
delwin(detailview);
|
||||
|
||||
list<Drive>::iterator it;
|
||||
uint8_t u8Index = 0U;
|
||||
for (it = plistDrives->begin(); it != plistDrives->end(); ++it)
|
||||
{
|
||||
string sModelFamily = it->getModelFamily();
|
||||
string sSerial = "SN: " + it->getSerial();
|
||||
string sCapacity = it->sCapacityToText();
|
||||
string sState = " ";
|
||||
string sSpeed = " ";
|
||||
string sTime = " ";
|
||||
string sTemp = it->sTemperatureToText();
|
||||
|
||||
bool bSelectedEntry = false;
|
||||
|
||||
if (u8SelectedEntry == u8Index)
|
||||
{
|
||||
bSelectedEntry = true; // mark this drive in entries list
|
||||
displaySelectedDrive(*it, u16StdscrX, u16StdscrY);
|
||||
|
||||
if ((it->getPowerOnHours() >= WORSE_HOURS) || (it->getPowerCycles() >= WORSE_POWERUP) || (it->getErrorCount() > 0) || (it->getTemperature() >= WORSE_TEMPERATURE))
|
||||
{
|
||||
// smart values are bad --> show warning
|
||||
smartWarning = createSmartWarning(50, 10, ((u16StdscrX) - (int)(u16StdscrX / 2) + 35), (int)(u16StdscrY / 2) - 5, it->getPath(), it->getPowerOnHours(), it->getPowerCycles(), it->getErrorCount(), it->getTemperature());
|
||||
wrefresh(smartWarning);
|
||||
}
|
||||
}
|
||||
|
||||
stringstream stream;
|
||||
|
||||
switch (it->state)
|
||||
{
|
||||
case Drive::SHRED_ACTIVE:
|
||||
|
||||
stream << fixed << setprecision(3) << (it->getTaskPercentage());
|
||||
sState = "Shredding: " + stream.str() + "%";
|
||||
|
||||
it->calculateTaskDuration();
|
||||
sTime = this->formatTimeDuration(it->getTaskDuration());
|
||||
sSpeed = this->formatSpeed(it->sShredSpeed.u32ShredTimeDelta, it->sShredSpeed.ulWrittenBytes);
|
||||
break;
|
||||
case Drive::CHECK_ACTIVE:
|
||||
stream << fixed << setprecision(3) << (it->getTaskPercentage());
|
||||
sState = "Checking: " + stream.str() + "%";
|
||||
it->calculateTaskDuration();
|
||||
sTime = this->formatTimeDuration(it->getTaskDuration());
|
||||
sSpeed = this->formatSpeed(it->sShredSpeed.u32ShredTimeDelta, it->sShredSpeed.ulWrittenBytes);
|
||||
break;
|
||||
case Drive::DELETE_ACTIVE:
|
||||
sState = "Deleting ...";
|
||||
it->calculateTaskDuration();
|
||||
sTime = this->formatTimeDuration(it->getTaskDuration());
|
||||
break;
|
||||
case Drive::NONE:
|
||||
case Drive::SHRED_SELECTED:
|
||||
case Drive::DELETE_SELECTED:
|
||||
if (it->bWasDeleted)
|
||||
{
|
||||
sState = "DELETED"; // mark drive as deleted previously
|
||||
}
|
||||
if (it->bWasShredded)
|
||||
{
|
||||
if (it->bWasChecked)
|
||||
{
|
||||
// drive was also checked after shredding
|
||||
sState = "SHREDDED & CHECKED"; // mark drive as shredded previously and optional checked
|
||||
}
|
||||
else
|
||||
{
|
||||
// shredded and not checked yet
|
||||
sState = "SHREDDED"; // mark drive as shredded previously
|
||||
}
|
||||
sTime = this->formatTimeDuration(it->getTaskDuration());
|
||||
}
|
||||
|
||||
#ifdef ZERO_CHECK
|
||||
if (bSelectedEntry && it->bWasChecked && (it->u32DriveChecksumAfterShredding != 0U))
|
||||
{
|
||||
dialog = createZeroChecksumWarning(70, 16, ((u16StdscrX) - (int)(u16StdscrX / 2) - 20), (int)(u16StdscrY / 2) - 8, it->getPath(), it->getModelFamily(), it->getModelName(), it->getSerial(), it->u32DriveChecksumAfterShredding);
|
||||
wrefresh(dialog);
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
case Drive::FROZEN:
|
||||
stream << fixed << setprecision(3) << (it->getTaskPercentage());
|
||||
#ifdef FROZEN_ALERT
|
||||
if (bSelectedEntry)
|
||||
{
|
||||
dialog = createFrozenWarning(70, 16, ((u16StdscrX) - (int)(u16StdscrX / 2) - 20), (int)(u16StdscrY / 2) - 8, it->getPath(), it->getModelFamily(), it->getModelName(), it->getSerial(), stream.str() + "%");
|
||||
wrefresh(dialog);
|
||||
}
|
||||
#endif
|
||||
sState = "FROZEN " + stream.str() + "%"; // mark drive as frozen and reached progress
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t u16StartOffsetY = (2 * (u8Index));
|
||||
|
||||
WINDOW *tmp = createEntryWindow((int)(u16StdscrX * (float)(3.0 / 7.0) - 2), 2, 3, u16StartOffsetY + 2, (distance(plistDrives->begin(), it) + 1), sModelFamily, sSerial, sCapacity, sState, sTime, sSpeed, sTemp, bSelectedEntry);
|
||||
wrefresh(tmp);
|
||||
u8Index++;
|
||||
} // end loop though drives
|
||||
|
||||
if (plistDrives->size() == 0)
|
||||
{
|
||||
// no selected drive present
|
||||
Logger::logThis()->warning("no selected drive present");
|
||||
struct MenuState menustate;
|
||||
menustate.bAbort = false;
|
||||
menustate.bConfirmDelete = false;
|
||||
menustate.bConfirmShred = false;
|
||||
menustate.bDelete = false;
|
||||
menustate.bShred = false;
|
||||
|
||||
detailview = overwriteDetailViewWindow((u16StdscrX) - ((int)(u16StdscrX * (float)(3.0 / 7.0))) - 7, (u16StdscrY - 15), (int)(u16StdscrX * (float)(3.0 / 7.0) + 5));
|
||||
wrefresh(detailview);
|
||||
|
||||
menuview = createMenuView(((int)(u16StdscrX * (float)(2.0 / 7.0))) - 3, 12, (int)(u16StdscrX * (float)(3.0 / 7.0) + 5), (u16StdscrY - 13), menustate);
|
||||
wrefresh(menuview);
|
||||
}
|
||||
|
||||
mxUIrefresh.unlock();
|
||||
}
|
||||
|
||||
enum TUI::UserInput TUI::readUserInput()
|
||||
{
|
||||
int ch = wgetch(stdscr);
|
||||
switch (ch)
|
||||
{
|
||||
case KEY_UP:
|
||||
return TUI::UserInput::UpKey;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
return TUI::UserInput::DownKey;
|
||||
break;
|
||||
case 10:
|
||||
return TUI::UserInput::Enter;
|
||||
break;
|
||||
case 27:
|
||||
return TUI::UserInput::ESC;
|
||||
break;
|
||||
case 'a':
|
||||
return TUI::UserInput::Abort;
|
||||
break;
|
||||
case 'd':
|
||||
return TUI::UserInput::Delete;
|
||||
break;
|
||||
case 's':
|
||||
return TUI::UserInput::Shred;
|
||||
break;
|
||||
case 'S':
|
||||
return TUI::UserInput::ShredAll;
|
||||
break;
|
||||
default:
|
||||
return TUI::UserInput::Undefined;
|
||||
break;
|
||||
}
|
||||
return TUI::UserInput::Undefined;
|
||||
}
|
||||
|
||||
void TUI::centerTitle(WINDOW *pwin, const char *title)
|
||||
{
|
||||
int x, maxX, stringSize;
|
||||
getmaxyx(pwin, maxX, maxX);
|
||||
stringSize = 4 + strlen(title);
|
||||
x = (maxX - stringSize) / 2;
|
||||
mvwaddch(pwin, 0, x, ACS_RTEE);
|
||||
waddch(pwin, ' ');
|
||||
waddstr(pwin, title);
|
||||
waddch(pwin, ' ');
|
||||
waddch(pwin, ACS_LTEE);
|
||||
}
|
||||
|
||||
/*
|
||||
left window that contains the drive entries
|
||||
*/
|
||||
WINDOW *TUI::createOverViewWindow(int iXSize, int iYSize)
|
||||
{
|
||||
WINDOW *newWindow;
|
||||
newWindow = newwin(iYSize, iXSize, 1, 2);
|
||||
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_OVERVIEW));
|
||||
box(newWindow, ACS_VLINE, ACS_HLINE);
|
||||
|
||||
centerTitle(newWindow, "Detected Drives");
|
||||
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
WINDOW *TUI::createDetailViewWindow(int iXSize, int iYSize, int iXStart, Drive drive)
|
||||
{
|
||||
WINDOW *newWindow;
|
||||
newWindow = newwin(iYSize, iXSize, 1, iXStart);
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_DETAIL));
|
||||
box(newWindow, ACS_VLINE, ACS_HLINE);
|
||||
|
||||
string title = "Selected Drive: " + drive.getModelName() + " " + drive.sCapacityToText();
|
||||
centerTitle(newWindow, title.c_str());
|
||||
|
||||
string sPath = "Path: " + drive.getPath();
|
||||
string sModelFamily = "ModelFamily: " + drive.getModelFamily();
|
||||
string sModelName = "ModelName: " + drive.getModelName();
|
||||
string sCapacity = "Capacity: " + drive.sCapacityToText();
|
||||
string sSerial = "Serial: " + drive.getSerial();
|
||||
string sPowerOnHours = "PowerOnHours: " + drive.sPowerOnHoursToText();
|
||||
string sPowerCycle = "PowerCycle: " + drive.sPowerCyclesToText();
|
||||
string sErrorCount = "ErrorCount: " + drive.sErrorCountToText();
|
||||
|
||||
uint16_t u16Line = 2;
|
||||
|
||||
mvwaddstr(newWindow, u16Line++, 3, sPath.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sModelFamily.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sModelName.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sCapacity.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sSerial.c_str());
|
||||
|
||||
attroff(COLOR_PAIR(COLOR_AREA_DETAIL));
|
||||
|
||||
mvwaddstr(newWindow, u16Line++, 3, sPowerOnHours.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sPowerCycle.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sErrorCount.c_str());
|
||||
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
WINDOW *TUI::overwriteDetailViewWindow(int iXSize, int iYSize, int iXStart)
|
||||
{
|
||||
WINDOW *newWindow;
|
||||
newWindow = newwin(iYSize, iXSize, 1, iXStart);
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_DETAIL));
|
||||
box(newWindow, ACS_VLINE, ACS_HLINE);
|
||||
|
||||
string title = "About this tool";
|
||||
centerTitle(newWindow, title.c_str());
|
||||
|
||||
string sLine01 = "reHDD - hard drive refurbishing tool";
|
||||
string sLine02 = "Version: " + string(REHDD_VERSION);
|
||||
string sLine03 = "Available under GPL 3.0";
|
||||
string sLine04 = "https://git.mosad.xyz/localhorst/reHDD";
|
||||
string sLine05 = "Delete: Wipe format table - this is NOT secure";
|
||||
string sLine06 = "Shred: Overwrite drive " + to_string(SHRED_ITERATIONS) + " iterations - this is secure";
|
||||
|
||||
uint16_t u16Line = 5;
|
||||
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLine01.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine02.size() / 2), sLine02.c_str());
|
||||
u16Line++;
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine03.size() / 2), sLine03.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine04.size() / 2), sLine04.c_str());
|
||||
u16Line++;
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine05.size() / 2), sLine05.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine06.size() / 2), sLine06.c_str());
|
||||
|
||||
attroff(COLOR_PAIR(COLOR_AREA_DETAIL));
|
||||
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
WINDOW *TUI::createEntryWindow(int iXSize, int iYSize, int iXStart, int iYStart, int iListIndex, string sModelFamily, string sSerial, string sCapacity, string sState, string sTime, string sSpeed, string sTemp, bool bSelected)
|
||||
{
|
||||
WINDOW *newWindow;
|
||||
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
|
||||
|
||||
if (!bSelected)
|
||||
{
|
||||
// entry is NOT selected
|
||||
if (iListIndex % 2 == 0)
|
||||
{
|
||||
// even
|
||||
attron(COLOR_PAIR(COLOR_AREA_ENTRY_EVEN));
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_EVEN));
|
||||
}
|
||||
else
|
||||
{
|
||||
// odd
|
||||
attron(COLOR_PAIR(COLOR_AREA_ENTRY_ODD));
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_ODD));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// entry IS selected
|
||||
attron(COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
|
||||
}
|
||||
|
||||
// box(newWindow, ACS_VLINE, ACS_HLINE);
|
||||
|
||||
// index number
|
||||
mvwaddstr(newWindow, 0, 1, to_string(iListIndex).c_str());
|
||||
|
||||
/*
|
||||
70 chars in x-axis
|
||||
|
||||
line:01
|
||||
0: space
|
||||
1: index number
|
||||
2: space
|
||||
3-35: ModelFamily
|
||||
36: space
|
||||
37-43: Capacity
|
||||
44: space
|
||||
47-49: Temp
|
||||
|
||||
line:02
|
||||
0-2: space
|
||||
3-31: Serial
|
||||
32: space
|
||||
33-45: Speed
|
||||
46: space
|
||||
47-58: Time
|
||||
59: space
|
||||
60-70: State (but right side aligned)
|
||||
*/
|
||||
|
||||
vTruncateText(&sModelFamily, 32);
|
||||
mvwaddstr(newWindow, 0, 3, sModelFamily.c_str());
|
||||
mvwaddstr(newWindow, 0, 37, sCapacity.c_str());
|
||||
mvwaddstr(newWindow, 0, 47, sTemp.c_str());
|
||||
|
||||
vTruncateText(&sSerial, 28);
|
||||
mvwaddstr(newWindow, 1, 3, sSerial.c_str());
|
||||
mvwaddstr(newWindow, 1, 33, sSpeed.c_str());
|
||||
mvwaddstr(newWindow, 1, 47, sTime.c_str());
|
||||
mvwaddstr(newWindow, 1, iXSize - sState.length() - 2, sState.c_str());
|
||||
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
WINDOW *TUI::createSystemStats(int iXSize, int iYSize, int iXStart, int iYStart)
|
||||
{
|
||||
WINDOW *newWindow;
|
||||
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
|
||||
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_OVERVIEW));
|
||||
box(newWindow, ACS_VLINE, ACS_HLINE);
|
||||
|
||||
centerTitle(newWindow, "System");
|
||||
|
||||
time_t rawtime;
|
||||
struct tm *timeinfo;
|
||||
char buffer[80];
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
strftime(buffer, sizeof(buffer), "Date: %d-%m-%Y Time: %H:%M", timeinfo);
|
||||
string time(buffer);
|
||||
|
||||
string sLine01 = "reHDD - hard drive refurbishing tool";
|
||||
string sLine02 = "Version: " + string(REHDD_VERSION);
|
||||
string sLine03 = "Build time: ";
|
||||
sLine03.append(__DATE__);
|
||||
sLine03.append(" ");
|
||||
sLine03.append(__TIME__);
|
||||
string sLine04 = "Available under GPL 3.0";
|
||||
string sLine05 = "https://git.mosad.xyz/localhorst/reHDD";
|
||||
|
||||
uint16_t u16Line = 2;
|
||||
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLine01.c_str());
|
||||
u16Line++;
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLine02.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLine03.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLine04.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLine05.c_str());
|
||||
u16Line++;
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), time.c_str());
|
||||
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
WINDOW *TUI::createMenuView(int iXSize, int iYSize, int iXStart, int iYStart, struct MenuState menustate)
|
||||
{
|
||||
WINDOW *newWindow;
|
||||
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
|
||||
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_OVERVIEW));
|
||||
box(newWindow, ACS_VLINE, ACS_HLINE);
|
||||
|
||||
centerTitle(newWindow, "Controls");
|
||||
|
||||
uint16_t u16Line = 4;
|
||||
|
||||
if (menustate.bAbort)
|
||||
{
|
||||
string sLineTmp = "Press a for Abort";
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLineTmp.size() / 2), sLineTmp.c_str());
|
||||
u16Line++;
|
||||
}
|
||||
if (menustate.bShred)
|
||||
{
|
||||
string sLineTmp = "Press s for Shred (S for all drives)";
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLineTmp.size() / 2), sLineTmp.c_str());
|
||||
u16Line++;
|
||||
}
|
||||
if (menustate.bDelete)
|
||||
{
|
||||
string sLineTmp = "Press d for Delete";
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLineTmp.size() / 2), sLineTmp.c_str());
|
||||
}
|
||||
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
WINDOW *TUI::createDialog(int iXSize, int iYSize, int iXStart, int iYStart, string task, string optionA, string optionB)
|
||||
{
|
||||
WINDOW *newWindow;
|
||||
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
|
||||
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
|
||||
box(newWindow, ACS_VLINE, ACS_HLINE);
|
||||
|
||||
centerTitle(newWindow, task.c_str());
|
||||
|
||||
uint16_t u16Line = 3;
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (optionA.size() / 2), optionA.c_str());
|
||||
u16Line++;
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (optionB.size() / 2), optionB.c_str());
|
||||
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
WINDOW *TUI::createFrozenWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, string sModelFamily, string sModelName, string sSerial, string sProgress)
|
||||
{
|
||||
WINDOW *newWindow;
|
||||
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
|
||||
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
|
||||
box(newWindow, ACS_VLINE, ACS_HLINE);
|
||||
|
||||
string sHeader = "Drive " + sPath + " is frozen";
|
||||
string sLine01 = "Please detach this drive and check it manually:";
|
||||
string sShredState = "Shredding stopped after " + sProgress;
|
||||
string sLinePath = "Path: " + sPath;
|
||||
string sLineModelFamlily = "ModelFamily: " + sModelFamily;
|
||||
string sLineModelName = "ModelName: " + sModelName;
|
||||
string sLineSerial = "Serial: " + sSerial;
|
||||
|
||||
string sLine02 = "reHDD was not able to write data to the drive.";
|
||||
string sLine03 = "This can be caused by an malfunctioning drive.";
|
||||
|
||||
centerTitle(newWindow, sHeader.c_str());
|
||||
|
||||
uint16_t u16Line = 2;
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLine01.c_str());
|
||||
u16Line++;
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLinePath.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLineModelFamlily.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLineModelName.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLineSerial.c_str());
|
||||
u16Line++;
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLine02.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLine03.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sShredState.c_str());
|
||||
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
WINDOW *TUI::createZeroChecksumWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, string sModelFamily, string sModelName, string sSerial, uint32_t u32Checksum)
|
||||
{
|
||||
WINDOW *newWindow;
|
||||
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
|
||||
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
|
||||
box(newWindow, ACS_VLINE, ACS_HLINE);
|
||||
|
||||
string sHeader = "Drive " + sPath + " is NOT successfully shredded!";
|
||||
string sLine01 = "Please detach this drive and check it manually:";
|
||||
string sShredChecksum = "After shredding the checksum was: " + to_string(u32Checksum);
|
||||
string sLinePath = "Path: " + sPath;
|
||||
string sLineModelFamily = "ModelFamily: " + sModelFamily;
|
||||
string sLineModelName = "ModelName: " + sModelName;
|
||||
string sLineSerial = "Serial: " + sSerial;
|
||||
|
||||
string sLine02 = "reHDD was not able to write zero into every byte on the drive.";
|
||||
string sLine03 = "This can be caused by an malfunctioning drive.";
|
||||
|
||||
centerTitle(newWindow, sHeader.c_str());
|
||||
|
||||
uint16_t u16Line = 2;
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLine01.c_str());
|
||||
u16Line++;
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLinePath.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLineModelFamily.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLineModelName.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLineSerial.c_str());
|
||||
u16Line++;
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLine02.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sLine03.c_str());
|
||||
mvwaddstr(newWindow, u16Line++, 3, sShredChecksum.c_str());
|
||||
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
string TUI::formatTimeDuration(time_t u32Duration)
|
||||
{
|
||||
std::ostringstream out;
|
||||
int dy = (int)((u32Duration) / 86400);
|
||||
int hr = (int)(((u32Duration) / 3600) % 24);
|
||||
int min = ((int)((u32Duration) / 60)) % 60;
|
||||
int sec = (int)((u32Duration) % 60);
|
||||
char s[25];
|
||||
sprintf(s, "%02d:%02d:%02d:%02d", dy, hr, min, sec);
|
||||
out << s;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
string TUI::formatSpeed(time_t u32ShredTimeDelta, unsigned long ulWrittenBytes)
|
||||
{
|
||||
std::ostringstream out;
|
||||
double dDeltaSec = ((double)((u32ShredTimeDelta) / 1000000000.0)); // convert nano in sec
|
||||
double speed = ((ulWrittenBytes / 1000000.0) / dDeltaSec);
|
||||
char s[25];
|
||||
sprintf(s, "%0.2lf MB/s", speed);
|
||||
out << s;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void TUI::vTruncateText(string *psText, uint16_t u16MaxLenght)
|
||||
{
|
||||
if (psText->length() > u16MaxLenght)
|
||||
{
|
||||
psText->resize(u16MaxLenght - 3);
|
||||
*psText = *psText + "...";
|
||||
}
|
||||
}
|
||||
|
||||
void TUI::displaySelectedDrive(Drive drive, int stdscrX, int stdscrY)
|
||||
{
|
||||
struct MenuState menustate;
|
||||
menustate.bAbort = false;
|
||||
menustate.bConfirmDelete = false;
|
||||
menustate.bConfirmShred = false;
|
||||
menustate.bDelete = false;
|
||||
menustate.bShred = false;
|
||||
|
||||
// set menustate based on drive state
|
||||
switch (drive.state)
|
||||
{
|
||||
case Drive::NONE: // no task running or selected for this drive
|
||||
menustate.bShred = true;
|
||||
menustate.bDelete = true;
|
||||
break;
|
||||
case Drive::DELETE_ACTIVE: // delete task running for this drive
|
||||
menustate.bAbort = true;
|
||||
break;
|
||||
|
||||
case Drive::SHRED_ACTIVE: // shred task running for this drive
|
||||
menustate.bAbort = true;
|
||||
break;
|
||||
|
||||
case Drive::CHECK_ACTIVE: // check task running for this drive
|
||||
menustate.bAbort = true;
|
||||
break;
|
||||
|
||||
case Drive::DELETE_SELECTED: // delete task selected for this drive
|
||||
menustate.bConfirmDelete = true;
|
||||
break;
|
||||
|
||||
case Drive::SHRED_SELECTED: // shred task selected for this drive
|
||||
menustate.bConfirmShred = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
detailview = createDetailViewWindow((stdscrX) - ((int)(stdscrX * (float)(3.0 / 7.0))) - 7, (stdscrY - 15), (int)(stdscrX * (float)(3.0 / 7.0) + 5), drive);
|
||||
wrefresh(detailview);
|
||||
|
||||
menuview = createMenuView(((int)(stdscrX * (float)(2.0 / 7.0))) - 3, 12, (int)(stdscrX * (float)(3.0 / 7.0) + 5), (stdscrY - 13), menustate);
|
||||
wrefresh(menuview);
|
||||
|
||||
if (menustate.bConfirmShred == true)
|
||||
{
|
||||
dialog = createDialog(40, 10, ((stdscrX) - (int)(stdscrX / 3) - 7) - (int)((stdscrX / 3) + 5) / 2, (int)(stdscrY / 2) - 5, "Confirm SHRED", "Press ENTER for SHRED", "Press ESC for cancel");
|
||||
wrefresh(dialog);
|
||||
}
|
||||
else if (menustate.bConfirmDelete == true)
|
||||
{
|
||||
dialog = createDialog(40, 10, ((stdscrX) - (int)(stdscrX / 3) - 7) - (int)((stdscrX / 3) + 5) / 2, (int)(stdscrY / 2) - 5, "Confirm DELETE", "Press ENTER for DELETE", "Press ESC for cancel");
|
||||
wrefresh(dialog);
|
||||
}
|
||||
else
|
||||
{
|
||||
delwin(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
WINDOW *TUI::createSmartWarning(int iXSize, int iYSize, int iXStart, int iYStart, string sPath, uint32_t u32PowerOnHours, uint32_t u32PowerCycles, uint32_t u32ErrorCount, uint32_t u32Temperature)
|
||||
{
|
||||
WINDOW *newWindow;
|
||||
newWindow = newwin(iYSize, iXSize, iYStart, iXStart);
|
||||
|
||||
wbkgd(newWindow, COLOR_PAIR(COLOR_AREA_ENTRY_SELECTED));
|
||||
box(newWindow, ACS_VLINE, ACS_HLINE);
|
||||
|
||||
string sHeader = "Drive " + sPath + " is suspicious";
|
||||
string sLine01 = "Please evaluate this drive carefully.";
|
||||
|
||||
centerTitle(newWindow, sHeader.c_str());
|
||||
|
||||
uint16_t u16Line = 2;
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLine01.c_str());
|
||||
u16Line++;
|
||||
|
||||
if (u32PowerOnHours > WORSE_HOURS)
|
||||
{
|
||||
string sLineTmp = "Operating hours exceeded " + to_string(WORSE_HOURS) + " hours: " + to_string(u32PowerOnHours);
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLineTmp.c_str());
|
||||
u16Line++;
|
||||
}
|
||||
|
||||
if (u32PowerCycles > WORSE_POWERUP)
|
||||
{
|
||||
string sLineTmp = "Power-on exceeded " + to_string(WORSE_POWERUP) + " cycles: " + to_string(u32PowerCycles);
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLineTmp.c_str());
|
||||
u16Line++;
|
||||
}
|
||||
|
||||
if (u32ErrorCount > 0)
|
||||
{
|
||||
string sLineTmp = "S.M.A.R.T. errors detected: " + to_string(u32ErrorCount);
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLineTmp.c_str());
|
||||
u16Line++;
|
||||
}
|
||||
|
||||
if (u32Temperature >= WORSE_TEMPERATURE)
|
||||
{
|
||||
string sLineTmp = "Drive too hot: " + to_string(u32Temperature) + " C";
|
||||
mvwaddstr(newWindow, u16Line++, (iXSize / 2) - (sLine01.size() / 2), sLineTmp.c_str());
|
||||
}
|
||||
return newWindow;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* @file wipe.cpp
|
||||
* @brief wipe drive
|
||||
* @author hendrik schutter
|
||||
* @date 03.05.2020
|
||||
*/
|
||||
|
||||
#include "../include/reHDD.h"
|
||||
|
||||
//#define DRYRUN //if defined the drive will not be wiped, a ping cmd is attempted instead
|
||||
|
||||
/**
|
||||
* \brief wipe drive with shred
|
||||
* \param pointer of Drive instance
|
||||
* \return void
|
||||
*/
|
||||
void Wipe::wipeDrive(Drive* drive)
|
||||
{
|
||||
size_t len = 0; //lenght of found line
|
||||
char* cLine = NULL; //found line
|
||||
|
||||
#ifndef DRYRUN
|
||||
string sCMD = ("shred -v ");
|
||||
sCMD.append(drive->getPath());
|
||||
#endif
|
||||
#ifdef DRYRUN
|
||||
cout << "dryrun for " << drive->getPath() << endl;
|
||||
string sCMD = ("ping ::1 -c 5");
|
||||
#endif
|
||||
const char* cpComand = sCMD.c_str();
|
||||
|
||||
cout << "wipe: " << cpComand << endl;
|
||||
|
||||
auto t_start = chrono::high_resolution_clock::now();
|
||||
|
||||
FILE* outputfileSmart = popen(cpComand, "r");
|
||||
|
||||
while ((getline(&cLine, &len, outputfileSmart)) != -1)
|
||||
{
|
||||
string sLine = string(cLine);
|
||||
cout << sLine;
|
||||
}
|
||||
fclose(outputfileSmart);
|
||||
|
||||
auto t_end = chrono::high_resolution_clock::now();
|
||||
|
||||
uint64_t u64TimeMS = chrono::duration<double, std::milli>(t_end-t_start).count();
|
||||
|
||||
uint64_t u64hours = 0U;
|
||||
uint64_t u64minutes = 0U;
|
||||
uint64_t u64seconds = 0U;
|
||||
|
||||
while(u64TimeMS >= 1000)
|
||||
{
|
||||
u64seconds++;
|
||||
u64TimeMS = u64TimeMS - 1000;
|
||||
}
|
||||
|
||||
while(u64seconds >= 60)
|
||||
{
|
||||
u64minutes++;
|
||||
u64seconds = u64seconds - 60;
|
||||
}
|
||||
|
||||
while(u64minutes >= 60)
|
||||
{
|
||||
u64hours++;
|
||||
u64minutes = u64minutes - 60;
|
||||
}
|
||||
|
||||
cout << "Elapsed time: " << u64hours << " h - " << u64minutes << " min - " << u64seconds << " sec" << endl;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 488716ef22ac5a1aae235a59bea2997ac7e8e45a
|
|
@ -12,57 +12,7 @@
|
|||
"unordered_map": "cpp",
|
||||
"string_view": "cpp",
|
||||
"ostream": "cpp",
|
||||
"chrono": "cpp",
|
||||
"thread": "cpp",
|
||||
"deque": "cpp",
|
||||
"vector": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"ranges": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"iomanip": "cpp"
|
||||
},
|
||||
"git.ignoreLimitWarning": true
|
||||
"chrono": "cpp"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue