commit b40d4d10c8e8ec99f559d828f0d0652ed2df6f5b Author: Andy Beverley Date: Fri Sep 6 23:38:39 2013 +0100 Initial commit diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..45a33d3 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,2 @@ +AUTOMAKE_OPTIONS = foreign +SUBDIRS = src man diff --git a/README b/README new file mode 100644 index 0000000..dd7a24c --- /dev/null +++ b/README @@ -0,0 +1,92 @@ +Installation +============ +Installation should work with the standard: +./configure +make +make install + +The ncurses, pthreads and parted libraries are required for compiling. +For any problems, please use the Sourceforge Help/Bugs forum. + +Andy Beverley + + +RELEASE NOTES +============= + +v0.14 +===== +- Added explicit check for ncurses (required for Fedora). See bug 3604008. + +v0.13 +===== +- Added nowait option (patch 3601259 - thanks David Shaw). +- Added nogui option. +- Updated man page and help command for above options and autonuke. +- Added pkg-config check for ncurses (patch 3603140 - thanks Alon Bar-Lev). + +v0.12 +===== +- Added ability to specify device on command line (patch 3587144). +- Fixed segfault for -p option (patch 3587132). + +v0.11 +===== +- Fixed bug 3568750. Not closing devices after initial scan. + +v0.10 +===== +- Fixed bug 3553851. Not exiting on terminal kill. Fixed for all areas of + program including wiping. + +v0.09 +===== +- Added feature #3545971. Display device name. +- Added feature #3496858. Option to not perform a final blanking pass. + +v0.08 +===== +- Fixed bug #3501746 whereby "wipe finished" was displayed too early + +v0.07 +===== +- Added threading synchronisation for logging +- Fixed bug #3486927 (incorrect Sourceforge URL) + +v0.06 +===== +- Added man page (thanks Michal Ambroz ) +- Updated GPL licence and FSF address (thanks Michal Ambroz ) + +v0.05 +===== +- Added sequence number to disk selection +- Added check for ncurses header files in subdir +- Fixed screen corruption bug introduced in 0.04 +- Fixed occasional seg fault on start +- Introduced dynamic array allocation for devices, with no hard limit +- Minor updates to configure.ac + +v0.04 +===== +- Removed references to DBAN in options.c +- Added log file name option (-l|--logfile) +- If no log file specified all messages go to STDOUT +- Incorrect success message after an interruption fixed +- Improved labelling of disks with no partition table +- Added help command +- Added version command +- Added command 'b' to blank screen during wipe +- Compilation needs to include panel library + +KNOWN BUG - display sometimes becomes corrupted after starting wipe + +v0.03 +===== +- Added quit option label (ctrl-c) +- Removed further references to DWIPE +- Added GPL V2 licence file (COPYING) + +v0.02 +===== +- Fixed segfault that happened during multiple disk wipes diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..d24c7af --- /dev/null +++ b/configure.ac @@ -0,0 +1,59 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.64]) +AC_INIT(nwipe, 0.14, andy@andybev.com) +AM_INIT_AUTOMAKE(nwipe, 0.14) +AC_OUTPUT(Makefile src/Makefile man/Makefile) +AC_CONFIG_SRCDIR([src/nwipe.c]) +AC_CONFIG_HEADERS([config.h]) + +# Checks for programs. +AC_PROG_CC +PKG_PROG_PKG_CONFIG + +# Checks for libraries. + +PKG_CHECK_MODULES( + [PANEL], + [panel], + [ + CFLAGS="${CFLAGS} ${PANEL_CFLAGS}" + LIBS="${LIBS} ${PANEL_LIBS}" + ], + [AC_CHECK_LIB([panel], [main], ,[AC_MSG_ERROR([ncurses panel library not found])])] +) + +PKG_CHECK_MODULES( + [NCURSES], + [ncurses], + [ + CFLAGS="${CFLAGS} ${NCURSES_CFLAGS}" + LIBS="${LIBS} ${NCURSES_LIBS}" + ], + [AC_CHECK_LIB([ncurses], [delscreen], [ + LIBS="-lncurses $LIBS" + AC_CHECK_HEADERS(ncurses.h,, [ + AC_CHECK_HEADERS(ncurses/ncurses.h, [ + AC_DEFINE([NCURSES_IN_SUBDIR], [ncurses/], [Look for ncurses headers in subdir]) + ], [AC_MSG_ERROR([ncurses headers not found])]) + ]) + ], [AC_MSG_ERROR([ncurses development library not found])] + )] +) + +AC_CHECK_LIB([parted], [ped_device_probe_all], ,[AC_MSG_ERROR([parted development library not found])]) +AC_CHECK_LIB([pthread], [main], ,[AC_MSG_ERROR([pthread development library not found])]) + +# Checks for header files. +AC_CHECK_HEADERS([fcntl.h inttypes.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/file.h sys/ioctl.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_SIZE_T +AC_CHECK_MEMBERS([struct stat.st_blksize]) + +# Checks for library functions. +AC_FUNC_MALLOC +AC_CHECK_FUNCS([fdatasync memset regcomp strdup strerror]) + +AC_OUTPUT diff --git a/man/Makefile b/man/Makefile new file mode 100644 index 0000000..b737a7b --- /dev/null +++ b/man/Makefile @@ -0,0 +1,396 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# man/Makefile. Generated from Makefile.in by configure. + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +pkgdatadir = $(datadir)/nwipe +pkgincludedir = $(includedir)/nwipe +pkglibdir = $(libdir)/nwipe +pkglibexecdir = $(libexecdir)/nwipe +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = man +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +man1dir = $(mandir)/man1 +am__installdirs = "$(DESTDIR)$(man1dir)" +NROFF = nroff +MANS = $(man_MANS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = ${SHELL} /home/andrew/nwipe-0.09/missing --run aclocal-1.11 +AMTAR = ${SHELL} /home/andrew/nwipe-0.09/missing --run tar +AUTOCONF = ${SHELL} /home/andrew/nwipe-0.09/missing --run autoconf +AUTOHEADER = ${SHELL} /home/andrew/nwipe-0.09/missing --run autoheader +AUTOMAKE = ${SHELL} /home/andrew/nwipe-0.09/missing --run automake-1.11 +AWK = gawk +CC = gcc +CCDEPMODE = depmode=gcc3 +CFLAGS = -g -O2 +CPP = gcc -E +CPPFLAGS = +CYGPATH_W = echo +DEFS = -DHAVE_CONFIG_H +DEPDIR = .deps +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = /bin/grep -E +EXEEXT = +GREP = /bin/grep +INSTALL = /usr/bin/install -c +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +INSTALL_STRIP_PROGRAM = $(install_sh) -c -s +LDFLAGS = +LIBOBJS = +LIBS = -lpthread -lparted -lpanel -lncurses +LTLIBOBJS = +MAKEINFO = ${SHELL} /home/andrew/nwipe-0.09/missing --run makeinfo +MKDIR_P = /bin/mkdir -p +OBJEXT = o +PACKAGE = nwipe +PACKAGE_BUGREPORT = andy@andybev.com +PACKAGE_NAME = nwipe +PACKAGE_STRING = nwipe 0.09 +PACKAGE_TARNAME = nwipe +PACKAGE_URL = +PACKAGE_VERSION = 0.09 +PATH_SEPARATOR = : +SET_MAKE = +SHELL = /bin/bash +STRIP = +VERSION = 0.09 +abs_builddir = /home/andrew/nwipe-0.09/man +abs_srcdir = /home/andrew/nwipe-0.09/man +abs_top_builddir = /home/andrew/nwipe-0.09 +abs_top_srcdir = /home/andrew/nwipe-0.09 +ac_ct_CC = gcc +am__include = include +am__leading_dot = . +am__quote = +am__tar = ${AMTAR} chof - "$$tardir" +am__untar = ${AMTAR} xf - +bindir = ${exec_prefix}/bin +build_alias = +builddir = . +datadir = ${datarootdir} +datarootdir = ${prefix}/share +docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} +dvidir = ${docdir} +exec_prefix = ${prefix} +host_alias = +htmldir = ${docdir} +includedir = ${prefix}/include +infodir = ${datarootdir}/info +install_sh = ${SHELL} /home/andrew/nwipe-0.09/install-sh +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localedir = ${datarootdir}/locale +localstatedir = ${prefix}/var +mandir = ${datarootdir}/man +mkdir_p = /bin/mkdir -p +oldincludedir = /usr/include +pdfdir = ${docdir} +prefix = /usr/local +program_transform_name = s,x,x, +psdir = ${docdir} +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +srcdir = . +sysconfdir = ${prefix}/etc +target_alias = +top_build_prefix = ../ +top_builddir = .. +top_srcdir = .. +man_MANS = nwipe.1 +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu man/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu man/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-man1: $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" + @list=''; test -n "$(man1dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man1dir)" && rm -f $$files; } +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(MANS) +installdirs: + for dir in "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man1 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-man + +uninstall-man: uninstall-man1 + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-man1 install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \ + uninstall-am uninstall-man uninstall-man1 + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/man/Makefile.am b/man/Makefile.am new file mode 100644 index 0000000..084ab09 --- /dev/null +++ b/man/Makefile.am @@ -0,0 +1 @@ +man_MANS = nwipe.1 diff --git a/man/nwipe.1 b/man/nwipe.1 new file mode 100644 index 0000000..817f8db --- /dev/null +++ b/man/nwipe.1 @@ -0,0 +1,86 @@ +.TH NWIPE "1" "January 2012" "nwipe version 0.14" "User Commands" +.SH NAME +nwipe \- securely erase disks +.SH SYNOPSIS +.B nwipe +[\fIoptions\fR] [\fIdevice1\fR] [\fIdevice2\fR] ... +.SH DESCRIPTION +nwipe is a command that will securely erase disks using a variety of +recognised methods. It is a fork of the dwipe command used by Darik's Boot +and Nuke (dban). nwipe is included with partedmagic if want a quick and +easy bootable CD version. nwipe was created out of a need to run the DBAN +dwipe command outside of DBAN, in order to allow its use with any host +distribution, thus giving better hardware support. It is essentially the +same as dwipe, with a few changes: +.TP +- pthreads is used instead of fork +.TP +- The parted library is used to detect drives +.TP +- The code is designed to be compiled with gcc + +.SH OPTIONS +.TP +\fB\-V\fR, \fB\-\-version\fR +Prints the version number +.TP +\fB\-h\fR, \fB\-\-help\fR +Prints a help summary +.TP +\fB\-\-autonuke\fR +If no devices have been specified on the command line, starts wiping all +devices immediately. If devices have been specified, starts wiping only +those specified devices immediately. +.TP +\fB\-\-sync\fR +Open devices in sync mode +.TP +\fB\-\-nowait\fR +Do not wait for a key before exiting (default is to wait). +.TP +\fB\-\-nogui\fR +Do not show the GUI interface. Can only be used with the autonuke option. +Nowait option is automatically invoked with the nogui option. +.TP +\fB\-\-verify\fR=\fITYPE\fR +Whether to perform verification of erasure (default: last) +off \- Do not verify +last \- Verify after the last pass +all \- Verify every pass +.TP +\fB\-m\fR, \fB\-\-method\fR=\fIMETHOD\fR +The wiping method (default: dodshort). +.IP +dod522022m / dod \- 7 pass DOD 5220.22\-M method +.IP +dodshort / dod3pass \- 3 pass DOD method +.IP +gutmann \- Peter Gutmann's Algorithm +.IP +ops2 \- RCMP TSSIT OPS\-II +.IP +random / prng / stream \- PRNG Stream +.IP +zero / quick \- Overwrite with zeros +.TP +\fB\-l\fR, \fB\-\-logfile\fR=\fIFILE\fR +Filename to log to. Default is STDOUT +.TP +\fB\-p\fR, \fB\-\-prng\fR=\fIMETHOD\fR +PRNG option (mersenne|twister|isaac) +.TP +\fB\-r\fR, \fB\-\-rounds\fR=\fINUM\fR +Number of times to wipe the device using the selected method (default: 1) +.SH BUGS +Please see the sourceforge site for the latest list +(http://nwipe.sourceforge.net) +.SH AUTHOR +Nwipe was released by Andy Beverley +as modified version of dwipe from DBAN by Darik Horn . +.SH "SEE ALSO" +.BR shred (1), +.BR dwipe (1), +.BR dd (1), +.BR dcfldd (1), +.BR dc3dd (1) + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..c123372 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,9 @@ +# what flags you want to pass to the C compiler & linker +#CFLAGS = -lncurses -lparted +AM_CFLAGS = +AM_LDFLAGS = + +# this lists the binaries to produce, the (non-PHONY, binary) targets in +# the previous manual Makefile +bin_PROGRAMS = nwipe +nwipe_SOURCES = context.h isaac_rand.c logging.h options.h prng.h nwipe.c gui.c isaac_rand.h method.h pass.c device.c gui.h isaac_standard.h mt19937ar-cok.c nwipe.h mt19937ar-cok.h pass.h device.h logging.c method.c options.c prng.c version.c version.h diff --git a/src/context.h b/src/context.h new file mode 100644 index 0000000..0249e1e --- /dev/null +++ b/src/context.h @@ -0,0 +1,141 @@ +/* + * context.h: The internal state representation of nwipe. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef CONTEXT_H_ +#define CONTEXT_H_ + +#include "prng.h" + +typedef enum nwipe_device_t_ +{ + NWIPE_DEVICE_UNKNOWN = 0, /* Unknown device. */ + NWIPE_DEVICE_IDE, + NWIPE_DEVICE_SCSI, + NWIPE_DEVICE_COMPAQ, /* Unimplemented. */ + NWIPE_DEVICE_USB, /* Unimplemented. */ + NWIPE_DEVICE_IEEE1394 /* Unimplemented. */ +} nwipe_device_t; + +typedef enum nwipe_pass_t_ +{ + NWIPE_PASS_NONE = 0, /* Not running. */ + NWIPE_PASS_WRITE, /* Writing patterns to the device. */ + NWIPE_PASS_VERIFY, /* Verifying a pass. */ + NWIPE_PASS_FINAL_BLANK, /* Filling the device with zeros. */ + NWIPE_PASS_FINAL_OPS2 /* Special case for nwipe_ops2. */ +} nwipe_pass_t; + +typedef enum nwipe_select_t_ +{ + NWIPE_SELECT_NONE = 0, /* Unused. */ + NWIPE_SELECT_TRUE, /* Wipe this device. */ + NWIPE_SELECT_TRUE_PARENT, /* A parent of this device has been selected, so the wipe is implied. */ + NWIPE_SELECT_FALSE, /* Do not wipe this device. */ + NWIPE_SELECT_FALSE_CHILD, /* A child of this device has been selected, so we can't wipe this device. */ + NWIPE_SELECT_DISABLED /* Do not wipe this device and do not allow it to be selected. */ +} nwipe_select_t; + + +#define NWIPE_KNOB_SPEEDRING_SIZE 30 +#define NWIPE_KNOB_SPEEDRING_GRANULARITY 10 + +typedef struct nwipe_speedring_t_ +{ + u64 bytes[NWIPE_KNOB_SPEEDRING_SIZE]; + u64 bytestotal; + u64 byteslast; + time_t times[NWIPE_KNOB_SPEEDRING_SIZE]; + time_t timestotal; + time_t timeslast; + u32 position; +} nwipe_speedring_t; + + +typedef struct nwipe_context_t_ +{ + int block_size; /* The soft block size reported the device. */ + int device_bus; /* The device bus number. */ + int device_fd; /* The file descriptor of the device file being wiped. */ + int device_host; /* The host number. */ + struct hd_driveid device_id; /* The WIN_IDENTIFY data for IDE drives. */ + int device_lun; /* The device logical unit number. */ + int device_major; /* The major device number. */ + int device_minor; /* The minor device number. */ + int device_part; /* The device partition or slice number. */ + char* device_name; /* The device file name. */ + loff_t device_size; /* The device size in bytes. */ + struct stat device_stat; /* The device file state from fstat(). */ + nwipe_device_t device_type; /* Indicates an IDE, SCSI, or Compaq SMART device. */ + int device_target; /* The device target. */ + u64 eta; /* The estimated number of seconds until method completion. */ + int entropy_fd; /* The entropy source. Usually /dev/urandom. */ + char* label; /* The string that we will show the user. */ + int pass_count; /* The number of passes performed by the working wipe method. */ + u64 pass_done; /* The number of bytes that have already been i/o'd in this pass. */ + u64 pass_errors; /* The number of errors across all passes. */ + u64 pass_size; /* The total number of i/o bytes across all passes. */ + nwipe_pass_t pass_type; /* The type of the current working pass. */ + int pass_working; /* The current working pass. */ + nwipe_prng_t* prng; /* The PRNG implementation. */ + nwipe_entropy_t prng_seed; /* The random data that is used to seed the PRNG. */ + void* prng_state; /* The private internal state of the PRNG. */ + int result; /* The process return value. */ + int round_count; /* The number of rounds performed by the working wipe method. */ + u64 round_done; /* The number of bytes that have already been i/o'd. */ + u64 round_errors; /* The number of errors across all rounds. */ + u64 round_size; /* The total number of i/o bytes across all rounds. */ + double round_percent; /* The percentage complete across all rounds. */ + int round_working; /* The current working round. */ + int sector_size; /* The hard sector size reported by the device. */ + nwipe_select_t select; /* Indicates whether this device should be wiped. */ + int signal; /* Set when the child is killed by a signal. */ + nwipe_speedring_t speedring; /* Ring buffer for computing the rolling throughput average. */ + short sync_status; /* A flag to indicate when the method is syncing. */ + pthread_t thread; /* The ID of the thread. */ + u64 throughput; /* Average throughput in bytes per second. */ + u64 verify_errors; /* The number of verification errors across all passes. */ + struct hd_driveid identity; /* The serial number of the drive (where applicable) */ +} nwipe_context_t; + + +/* We use 2 data structs to pass data between threads. */ + +/* The first contains any required values: */ +/* Values cannot form part of the second array below, hence the need for this. */ +typedef struct +{ + int nwipe_enumerated; /* The number of devices available. */ + int nwipe_selected; /* The number of devices being wiped. */ + pthread_t *gui_thread; /* The ID of GUI thread. */ +} nwipe_misc_thread_data_t; + +/* The second points to the first structure, as well as the structure of all the devices */ +typedef struct +{ + nwipe_context_t **c; /* Pointer to the nwipe context structure. */ + nwipe_misc_thread_data_t *nwipe_misc_thread_data; /* Pointer to the misc structure above. */ +} nwipe_thread_data_ptr_t; + + +#endif /* CONTEXT_H_ */ + +/* eof */ diff --git a/src/device.c b/src/device.c new file mode 100644 index 0000000..7f66a14 --- /dev/null +++ b/src/device.c @@ -0,0 +1,133 @@ +/* + * device.c: Device routines for nwipe. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/* Why is this needed? Segfaults without it */ +#include + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "options.h" +#include "logging.h" + +#include +#include + +int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount ); + +int nwipe_device_scan( nwipe_context_t*** c ) +{ + /** + * Scans the the filesystem for storage device names. + * + * @parameter device_names A reference to a null array pointer. + * @modifies device_names Populates device_names with an array of nwipe_contect_t + * @returns The number of strings in the device_names array. + * + */ + + PedDevice* dev = NULL; + ped_device_probe_all(); + + int dcount = 0; + + while ((dev = ped_device_get_next (dev))) + { + if (check_device(c, dev, dcount)) + dcount++; + } + + /* Return the number of devices that were found. */ + return dcount; + +} /* nwipe_device_scan */ + +int nwipe_device_get( nwipe_context_t*** c, char **devnamelist, int ndevnames ) +{ + /** + * Gets information about devices + * + * @parameter device_names A reference to a null array pointer. + * @parameter devnamelist An array of string pointers to the device names + * @parameter ndevnames Number of elements in devnamelist + * @modifies device_names Populates device_names with an array of nwipe_contect_t + * @returns The number of strings in the device_names array. + * + */ + + PedDevice* dev = NULL; + + int i; + int dcount = 0; + + for(i = 0; i < ndevnames; i++) { + + dev = ped_device_get(devnamelist[i]); + if (!dev) + break; + + if (check_device(c, dev, dcount)) + dcount++; + } + + /* Return the number of devices that were found. */ + return dcount; + +} /* nwipe_device_get */ + +int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount ) +{ + /* Populate this struct, then assign it to overall array of structs. */ + nwipe_context_t* next_device; + + /* Try opening the device to see if it's valid. Close on completion. */ + if (!ped_device_open(dev)) + return 0; + ped_device_close(dev); + + /* New device, reallocate memory for additional struct pointer */ + *c = realloc (*c, (dcount+1) * sizeof(nwipe_context_t *)); + + next_device = malloc (sizeof(nwipe_context_t)); + + /* Check the allocation. */ + if( ! next_device ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to create the array of enumeration contexts." ); + return 0; + } + + /* Zero the allocation. */ + memset( next_device , 0, sizeof( nwipe_context_t ) ); + + /* Get device information */ + next_device->label = dev->model; + next_device->device_name = dev->path; + next_device->device_size = dev->length * dev->sector_size; + + (*c)[dcount] = next_device; + + return 1; +} + +/* eof */ diff --git a/src/device.h b/src/device.h new file mode 100644 index 0000000..b32dd7e --- /dev/null +++ b/src/device.h @@ -0,0 +1,33 @@ +/* + * device.h: Device routines for nwipe. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#ifndef DEVICE_H_ +#define DEVICE_H_ + +void nwipe_device_identify( nwipe_context_t* c ); /* Get hardware information about the device. */ +int nwipe_device_scan( nwipe_context_t*** c ); /* Find devices that we can wipe. */ +int nwipe_device_get( nwipe_context_t*** c, char **devnamelist, int ndevnames ); /* Get info about devices to wipe */ + +#endif /* DEVICE_H_ */ + +/* eof */ diff --git a/src/gui.c b/src/gui.c new file mode 100644 index 0000000..6ea72de --- /dev/null +++ b/src/gui.c @@ -0,0 +1,2089 @@ +/* + * gui.c: An ncurses GUI for nwipe. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +/* RATIONALE: + * + * This entire GUI is a non-portable task-specific thunk. + * + * The alternatives are, however, no better. The CDK is large and clumsy, + * and things like ncurses libmenu are not worth the storage overhead. + * + */ + +/* Why is this needed? Segfaults without it */ +#include + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "gui.h" +#include "pass.h" +#include "logging.h" + +#define NWIPE_GUI_PANE 8 + +/* Header window: width, height, x coordinate, y coordinate. */ +#define NWIPE_GUI_HEADER_W COLS +#define NWIPE_GUI_HEADER_H 1 +#define NWIPE_GUI_HEADER_X 0 +#define NWIPE_GUI_HEADER_Y 0 + +/* Footer window: width, height, x coordinate, y coordinate. */ +#define NWIPE_GUI_FOOTER_W COLS +#define NWIPE_GUI_FOOTER_H 1 +#define NWIPE_GUI_FOOTER_X 0 +#define NWIPE_GUI_FOOTER_Y (LINES -1) + +/* Options window: width, height, x coorindate, y coordinate. */ +#define NWIPE_GUI_OPTIONS_W 44 +#define NWIPE_GUI_OPTIONS_H 7 +#define NWIPE_GUI_OPTIONS_Y 1 +#define NWIPE_GUI_OPTIONS_X 0 + +/* Options fields, relative to their window. */ +#define NWIPE_GUI_OPTIONS_TAB 10 +#define NWIPE_GUI_OPTIONS_ENTROPY_Y 1 +#define NWIPE_GUI_OPTIONS_ENTROPY_X 1 +#define NWIPE_GUI_OPTIONS_PRNG_Y 2 +#define NWIPE_GUI_OPTIONS_PRNG_X 1 +#define NWIPE_GUI_OPTIONS_METHOD_Y 3 +#define NWIPE_GUI_OPTIONS_METHOD_X 1 +#define NWIPE_GUI_OPTIONS_VERIFY_Y 4 +#define NWIPE_GUI_OPTIONS_VERIFY_X 1 +#define NWIPE_GUI_OPTIONS_ROUNDS_Y 5 +#define NWIPE_GUI_OPTIONS_ROUNDS_X 1 + +/* Stats window: width, height, x coordinate, y coordinate. */ +#define NWIPE_GUI_STATS_W 36 +#define NWIPE_GUI_STATS_H 7 +#define NWIPE_GUI_STATS_Y 1 +#define NWIPE_GUI_STATS_X 44 + +/* Stats fields, relative to their window. */ +#define NWIPE_GUI_STATS_RUNTIME_Y 1 +#define NWIPE_GUI_STATS_RUNTIME_X 1 +#define NWIPE_GUI_STATS_ETA_Y 2 +#define NWIPE_GUI_STATS_ETA_X 1 +#define NWIPE_GUI_STATS_LOAD_Y 3 +#define NWIPE_GUI_STATS_LOAD_X 1 +#define NWIPE_GUI_STATS_THROUGHPUT_Y 4 +#define NWIPE_GUI_STATS_THROUGHPUT_X 1 +#define NWIPE_GUI_STATS_ERRORS_Y 5 +#define NWIPE_GUI_STATS_ERRORS_X 1 +#define NWIPE_GUI_STATS_TAB 16 + + +/* Select window: width, height, x coordinate, y coordinate. */ +#define NWIPE_GUI_MAIN_W COLS +#define NWIPE_GUI_MAIN_H ( LINES - NWIPE_GUI_MAIN_Y -1 ) +#define NWIPE_GUI_MAIN_Y 8 +#define NWIPE_GUI_MAIN_X 0 + + +/* Window pointers. */ +WINDOW* footer_window; +WINDOW* header_window; +WINDOW* main_window; +WINDOW* options_window; +WINDOW* stats_window; + +PANEL* footer_panel; +PANEL* header_panel; +PANEL* main_panel; +PANEL* options_panel; +PANEL* stats_panel; + + +/* Options window title. */ +const char* options_title = " Options "; + +/* Statistics window title. */ +const char* stats_title = " Statistics "; + +/* Footer labels. */ +const char* nwipe_buttons1 = " P=PRNG M=Method V=Verify R=Rounds B=Blanking-pass, J=Up K=Down Space=Select, F10=Start, ctrl-c=Quit "; +const char* nwipe_buttons2 = " J=Up K=Down Space=Select"; +const char* nwipe_buttons3 = " B=Blank screen, ctrl-c=Quit"; + + + +void nwipe_gui_title( WINDOW* w, const char* s ) +{ +/** + * Prints the string 's' centered on the first line of the window 'w'. + * + */ + + /* The number of lines in the window. (Not used.) */ + int wy; + + /* The number of columns in the window. */ + int wx; + + /* Get the window dimensions. */ + getmaxyx( w, wy, wx ); + + /* Print the title. */ + mvwprintw( w, 0, ( wx - strlen( s ) ) / 2, "%s", s ); + +} /* nwipe_gui_title */ + + +void nwipe_gui_init( void ) +{ +/** + * Initializes the ncurses gui. + * + */ + + /* Initialize the screen. */ + initscr(); + + /* Disable TTY line buffering. */ + cbreak(); + + /* Disable TTY echo. */ + noecho(); + + /* Enable most special keys. */ + keypad( stdscr, TRUE ); + + if( has_colors() ) + { + /* Initialize color capabilities. */ + start_color(); + + if( can_change_color() ) + { + /* Redefine cyan to gray. */ + init_color( COLOR_CYAN, 128, 128, 128 ); + } + + /* Set white on blue as the emphasis color. */ + init_pair( 1, COLOR_WHITE, COLOR_BLUE ); + + /* Set gray (or cyan) on blue as the normal color. */ + init_pair( 2, COLOR_CYAN, COLOR_BLUE ); + + /* Set red on blue as the hilite color. */ + init_pair( 3, COLOR_RED, COLOR_BLUE ); + + /* Set blue on white as the color for the header and footer windows. */ + init_pair( 4, COLOR_BLUE, COLOR_WHITE ); + + /* Set white on green for success messages. */ + init_pair( 5, COLOR_WHITE, COLOR_GREEN ); + + /* Set white on green for failure messages. */ + init_pair( 6, COLOR_WHITE, COLOR_RED ); + + /* Set black on black for when hiding the display. */ + init_pair( 7, COLOR_BLACK, COLOR_BLACK ); + + /* Set the background style. */ + wbkgdset( stdscr, COLOR_PAIR(1) | ' ' ); + + } + + /* Clear the screen. */ + wclear( stdscr ); + + + /* Create the header window. */ + header_window = newwin( NWIPE_GUI_HEADER_H, NWIPE_GUI_HEADER_W, NWIPE_GUI_HEADER_Y, NWIPE_GUI_HEADER_X ); + header_panel = new_panel( header_window ); + + if( has_colors() ) + { + /* Set the background style of the header window. */ + wbkgdset( header_window, COLOR_PAIR(4) | ' ' ); + } + + /* Clear the header window. */ + wclear( header_window ); + + /* Print the product banner. */ + nwipe_gui_title( header_window, nwipe_options.banner ); + + /* Create the footer window. */ + footer_window = newwin( NWIPE_GUI_FOOTER_H, NWIPE_GUI_FOOTER_W, NWIPE_GUI_FOOTER_Y, NWIPE_GUI_FOOTER_X ); + footer_panel = new_panel( footer_window ); + + if( has_colors() ) + { + /* Set the background style of the footer window. */ + wbkgdset( footer_window, COLOR_PAIR(4) | ' ' ); + } + + /* Clear the footer window. */ + wclear( footer_window ); + + /* Create the options window. */ + options_window = newwin( NWIPE_GUI_OPTIONS_H, NWIPE_GUI_OPTIONS_W, NWIPE_GUI_OPTIONS_Y, NWIPE_GUI_OPTIONS_X ); + options_panel = new_panel( options_window ); + + if( has_colors() ) + { + /* Set the background style of the options window. */ + wbkgdset( options_window, COLOR_PAIR(1) | ' ' ); + + /* Apply the color change to the options window. */ + wattron( options_window, COLOR_PAIR(1) ); + } + + /* Clear the options window. */ + wclear( options_window ); + + /* Add a border. */ + box( options_window, 0, 0 ); + + /* Create the stats window. */ + stats_window = newwin( NWIPE_GUI_STATS_H, NWIPE_GUI_STATS_W, NWIPE_GUI_STATS_Y, NWIPE_GUI_STATS_X ); + stats_panel = new_panel( stats_window ); + + if( has_colors() ) + { + /* Set the background style of the stats window. */ + wbkgdset( stats_window, COLOR_PAIR(1) | ' ' ); + + /* Apply the color change to the stats window. */ + wattron( stats_window, COLOR_PAIR(1) ); + } + + /* Clear the new window. */ + wclear( stats_window ); + + /* Add a border. */ + box( stats_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( stats_window, stats_title ); + + /* Print field labels. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_RUNTIME_Y, NWIPE_GUI_STATS_RUNTIME_X, "Runtime: " ); + mvwprintw( stats_window, NWIPE_GUI_STATS_ETA_Y, NWIPE_GUI_STATS_ETA_X, "Remaining: " ); + mvwprintw( stats_window, NWIPE_GUI_STATS_LOAD_Y, NWIPE_GUI_STATS_LOAD_X, "Load Averages: " ); + mvwprintw( stats_window, NWIPE_GUI_STATS_THROUGHPUT_Y, NWIPE_GUI_STATS_THROUGHPUT_X, "Throughput: " ); + mvwprintw( stats_window, NWIPE_GUI_STATS_ERRORS_Y, NWIPE_GUI_STATS_ERRORS_X, "Errors: " ); + + /* Create the main window. */ + main_window = newwin( NWIPE_GUI_MAIN_H, NWIPE_GUI_MAIN_W, NWIPE_GUI_MAIN_Y, NWIPE_GUI_MAIN_X ); + main_panel = new_panel( main_window ); + + if( has_colors() ) + { + /* Set the background style. */ + wbkgdset( main_window, COLOR_PAIR(1) | ' ' ); + + /* Apply the color change. */ + wattron( main_window, COLOR_PAIR(1) ); + } + + /* Clear the main window. */ + werase( main_window ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Refresh the screen. */ + wrefresh( stdscr ); + wrefresh( header_window ); + wrefresh( footer_window ); + wrefresh( options_window ); + wrefresh( stats_window ); + wrefresh( main_window ); + + update_panels(); + doupdate(); + + /* Hide the cursor. */ + curs_set( 0 ); + +} /* nwipe_gui_init */ + + +void nwipe_gui_free( void ) +{ +/** + * Releases the ncurses gui. + * + */ + + /* Free ncurses resources. */ + del_panel( footer_panel ); + del_panel( header_panel ); + del_panel( main_panel ); + del_panel( options_panel ); + del_panel( stats_panel ); + delwin( footer_window ); + delwin( header_window ); + delwin( main_window ); + delwin( options_window ); + delwin( stats_window ); + endwin(); + +} /* nwipe_gui_free */ + + +void nwipe_gui_select( int count, nwipe_context_t** c ) +{ +/** + * The primary user interface. Allows the user to + * change options and specify the devices to be wiped. + * + * @parameter count The number of contexts in the array. + * @parameter c An array of device contexts. + * + * @modifies c[].select Sets the select flag according to user input. + * @modifies options Sets program options according to to user input. + * + */ + + /* Widget labels. */ + const char* select_title = " Disks and Partitions "; + + /* The number of lines available in the window. */ + int wlines; + + /* The number of columns available in the window. */ + int wcols; + + /* The number of selection elements that we can show in the window. */ + int slots; + + /* The index of the element that is visible in the first slot. */ + int offset = 0; + + /* The selection focus. */ + int focus = 0; + + /* A generic loop variable. */ + int i; + + /* User input buffer. */ + int keystroke; + + /* The current working line. */ + int yy; + + /* There is one slot per line. */ + getmaxyx( main_window, wlines, wcols ); + + /* Less two lines for the box and two lines for padding. */ + slots = wlines - 4; + + + do + { + /* Clear the main window. */ + werase( main_window ); + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, nwipe_buttons1 ); + wrefresh( footer_window ); + + /* Update the options window. */ + nwipe_gui_options(); + + /* Initialize the line offset. */ + yy = 2; + + for( i = 0; i < slots && i < count ; i++ ) + { + + /* Move to the next line. */ + mvwprintw( main_window, yy++, 1, " " ); + + if( i + offset == focus ) + { + if( c[focus]->select == NWIPE_SELECT_TRUE || c[focus]->select == NWIPE_SELECT_FALSE ) + { + /* Print the 'enabled' cursor. */ + waddch( main_window, ACS_RARROW ); + } + + else + { + /* Print the 'disabled' cursor. */ + waddch( main_window, ACS_DIAMOND ); + } + } + + else + { + /* Print whitespace. */ + waddch( main_window, ' ' ); + } + + switch( c[i+offset]->select ) + { + case NWIPE_SELECT_TRUE: + + wprintw( main_window, " [wipe] %i. %s - %s (%lld bytes)", (i + offset + 1), + c[i+offset]->device_name, + c[i+offset]->label, + c[i+offset]->device_size ); + break; + + case NWIPE_SELECT_FALSE: + /* Print an element that is not selected. */ + wprintw( main_window, " [ ] %i. %s - %s (%lld bytes)", (i + offset +1), + c[i+offset]->device_name, + c[i+offset]->label, + c[i+offset]->device_size ); + break; + + case NWIPE_SELECT_TRUE_PARENT: + + /* This element will be wiped when its parent is wiped. */ + wprintw( main_window, " [****] %i. %s - %s (%lld bytes)", (i + offset +1), + c[i+offset]->device_name, + c[i+offset]->label, + c[i+offset]->device_size ); + break; + + case NWIPE_SELECT_FALSE_CHILD: + + /* We can't wipe this element because it has a child that is being wiped. */ + wprintw( main_window, " [----] %i. %s - %s (%lld bytes)", (i + offset +1), + c[i+offset]->device_name, + c[i+offset]->label, + c[i+offset]->device_size ); + break; + + case NWIPE_SELECT_DISABLED: + + /* We don't know how to wipe this device. (Iomega Zip drives.) */ + wprintw( main_window, " [????] %s", "Unrecognized Device" ); + break; + + default: + + /* TODO: Handle the sanity error. */ + break; + + + } /* switch select */ + + } /* for */ + + if( offset > 0 ) + { + mvwprintw( main_window, 1, wcols -8, " More " ); + waddch( main_window, ACS_UARROW ); + } + + if( count - offset > slots ) + { + mvwprintw( main_window, wlines -2, wcols -8, " More " ); + waddch( main_window, ACS_DARROW ); + } + + /* Draw a border around the menu window. */ + box( main_window, 0, 0 ); + + /* Print a title. */ + nwipe_gui_title( main_window, select_title ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Get user input. */ + keystroke = getch(); + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + /* Increment the focus. */ + focus += 1; + + if( focus >= count ) + { + /* The focus is already at the last element. */ + focus = count -1; + break; + } + + if( focus - offset >= slots ) + { + /* The next element is offscreen. Scroll down. */ + offset += 1; + break; + } + + break; + + case KEY_UP: + case 'k': + case 'K': + + /* Decrement the focus. */ + focus -= 1; + + if( focus < 0 ) + { + /* The focus is already at the last element. */ + focus = 0; + break; + } + + if( focus < offset ) + { + /* The next element is offscreen. Scroll up. */ + offset -= 1; + break; + } + + break; + + case KEY_ENTER: + case 10: + case ' ': + + /* TODO: This block should be made into a function. */ + + if( c[focus]->select == NWIPE_SELECT_TRUE ) + { + /* Reverse the selection of this element. */ + c[focus]->select = NWIPE_SELECT_FALSE; + + if( c[focus]->device_part == 0 ) + { + /* Sub-deselect all partitions and slices within this disk. */ + for( i = 0 ; i < count ; i++ ) + { + if + ( + c[i]->device_type == c[focus]->device_type + && c[i]->device_host == c[focus]->device_host + && c[i]->device_bus == c[focus]->device_bus + && c[i]->device_target == c[focus]->device_target + && c[i]->device_lun == c[focus]->device_lun + && c[i]->device_part > 0 + ) + { + c[i]->select = NWIPE_SELECT_FALSE; + } + + } /* for all contexts */ + + } /* if sub-deselect */ + + else + { + /* The number of selected partitions or slices within this disk. */ + int j = 0; + + for( i = 0 ; i < count ; i++ ) + { + if + ( + c[i]->device_type == c[focus]->device_type + && c[i]->device_host == c[focus]->device_host + && c[i]->device_bus == c[focus]->device_bus + && c[i]->device_target == c[focus]->device_target + && c[i]->device_lun == c[focus]->device_lun + && c[i]->device_part > 0 + && c[i]->select == NWIPE_SELECT_TRUE + ) + { + /* Increment the counter. */ + j += 1; + } + + } /* for all contexts */ + + if( j == 0 ) + { + /* Find the parent disk of this partition or slice. */ + for( i = 0 ; i < count ; i++ ) + { + if + ( + c[i]->device_type == c[focus]->device_type + && c[i]->device_host == c[focus]->device_host + && c[i]->device_bus == c[focus]->device_bus + && c[i]->device_target == c[focus]->device_target + && c[i]->device_lun == c[focus]->device_lun + && c[i]->device_part == 0 + ) + { + /* Enable the disk element. */ + c[i]->select = NWIPE_SELECT_FALSE; + } + + } /* for all contexts */ + + } /* if */ + + } /* else super-enable */ + + break; + + } /* if NWIPE_SELECT_TRUE */ + + if( c[focus]->select == NWIPE_SELECT_FALSE ) + { + /* Reverse the selection. */ + c[focus]->select = NWIPE_SELECT_TRUE; + + if( c[focus]->device_part == 0 ) + { + /* Sub-select all partitions and slices within this disk. */ + for( i = 0 ; i < count ; i++ ) + { + if + ( + c[i]->device_type == c[focus]->device_type + && c[i]->device_host == c[focus]->device_host + && c[i]->device_bus == c[focus]->device_bus + && c[i]->device_target == c[focus]->device_target + && c[i]->device_lun == c[focus]->device_lun + && c[i]->device_part > 0 + ) + { + c[i]->select = NWIPE_SELECT_TRUE_PARENT; + } + + } /* for */ + + } /* if sub-select */ + + else + { + /* ASSERT: ( c[focus]->device_part > 0 ) */ + + /* Super-deselect the disk that contains this device. */ + for( i = 0 ; i < count ; i++ ) + { + if + ( + c[i]->device_type == c[focus]->device_type + && c[i]->device_host == c[focus]->device_host + && c[i]->device_bus == c[focus]->device_bus + && c[i]->device_target == c[focus]->device_target + && c[i]->device_lun == c[focus]->device_lun + && c[i]->device_part == 0 + ) + { + c[i]->select = NWIPE_SELECT_FALSE_CHILD; + } + } + + } /* else super-deselect */ + + break; + + } /* if NWIPE_SELECT_FALSE */ + + /* TODO: Explain to the user why they can't change this. */ + break; + + case 'm': + case 'M': + + /* Run the method dialog. */ + nwipe_gui_method(); + break; + + case 'p': + case 'P': + + /* Run the PRNG dialog. */ + nwipe_gui_prng(); + break; + + case 'r': + case 'R': + + /* Run the rounds dialog. */ + nwipe_gui_rounds(); + break; + + case 'v': + case 'V': + + /* Run the option dialog. */ + nwipe_gui_verify(); + break; + + case 'b': + case 'B': + + /* Run the noblank dialog. */ + nwipe_gui_noblank(); + break; + + } /* keystroke switch */ + + } while( keystroke != KEY_F(10) && keystroke != ERR ); + + /* Clear the main window. */ + werase( main_window ); + + /* Refresh the main window. */ + wrefresh( main_window ); + + /* Clear the footer. */ + werase( footer_window ); + + /* Refresh the footer window. */ + wrefresh( footer_window ); + +} /* nwipe_gui_select */ + + + +void nwipe_gui_options( void ) +{ +/** + * Updates the options window. + * + * @modifies options_window + * + */ + + /* Erase the window. */ + werase( options_window ); + + mvwprintw( options_window, NWIPE_GUI_OPTIONS_ENTROPY_Y, NWIPE_GUI_OPTIONS_ENTROPY_X, \ + "Entropy: Linux Kernel (urandom)" ); + + mvwprintw( options_window, NWIPE_GUI_OPTIONS_PRNG_Y, NWIPE_GUI_OPTIONS_PRNG_X, \ + "PRNG: %s", nwipe_options.prng->label ); + + mvwprintw( options_window, NWIPE_GUI_OPTIONS_METHOD_Y, NWIPE_GUI_OPTIONS_METHOD_X, \ + "Method: %s", nwipe_method_label( nwipe_options.method) ); + + mvwprintw( options_window, NWIPE_GUI_OPTIONS_VERIFY_Y, NWIPE_GUI_OPTIONS_VERIFY_X, "Verify: " ); + + switch( nwipe_options.verify ) + { + case NWIPE_VERIFY_NONE: + wprintw( options_window, "Off" ); + break; + + case NWIPE_VERIFY_LAST: + wprintw( options_window, "Last Pass" ); + break; + + case NWIPE_VERIFY_ALL: + wprintw( options_window, "All Passes" ); + break; + + default: + wprintw( options_window, "Unknown %i", nwipe_options.verify ); + + } /* switch verify */ + + + mvwprintw( options_window, NWIPE_GUI_OPTIONS_ROUNDS_Y, NWIPE_GUI_OPTIONS_ROUNDS_X, "Rounds: " ); + if ( nwipe_options.noblank ) + { + wprintw( options_window, "%i (no final blanking pass)", nwipe_options.rounds); + } else + { + wprintw( options_window, "%i (plus blanking pass)", nwipe_options.rounds); + } + + /* Add a border. */ + box( options_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( options_window, options_title ); + + /* Refresh the window. */ + wrefresh( options_window ); + +} /* nwipe_gui_options */ + + + +void nwipe_gui_rounds( void ) +{ +/** + * Allows the user to change the rounds option. + * + * @modifies nwipe_options.rounds + * @modifies main_window + * + */ + + /* Set the initial focus. */ + int focus = nwipe_options.rounds; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* Erase the footer window. */ + werase( footer_window ); + wrefresh( footer_window ); + + + do + { + /* Erase the main window. */ + werase( main_window ); + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Rounds " ); + + /* Initialize the working row. */ + yy = 4; + + /* 0 1 2 3 4 5 6 7 */ + mvwprintw( main_window, yy++, tab1, "This is the number of times to run the wipe method on each device." ); + mvwprintw( main_window, yy++, tab1, "" ); + + if( focus > 0 ) + { + /* Print the syslinux configuration hint. */ + mvwprintw( main_window, yy++, tab1, "syslinux.cfg: nuke=\"nwipe --rounds %i\"", focus ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, "> %i", focus ); + } + + else + { + mvwprintw( main_window, yy++, tab1, "The number of rounds must be a non-negative integer." ); + + /* Print this line last so that the cursor is in the right place. */ + mvwprintw( main_window, 2, tab1, "> " ); + } + + /* Reveal the cursor. */ + curs_set( 1 ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Get a keystroke. */ + keystroke = getch(); + + switch( keystroke ) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + + if( focus < 100000000 ) + { + /* Left shift, base ten. */ + focus *= 10; + + /* This assumes ASCII input, where the zero character is 0x30. */ + focus += keystroke - 48; + } + + break; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + /* Right shift, base ten. */ + focus /= 10; + + break; + + } /* switch keystroke */ + + /* Hide the cursor. */ + curs_set( 0 ); + + } while( keystroke != 10 && keystroke != ERR ); + + if( focus > 0 ) + { + /* Set the number of rounds. */ + nwipe_options.rounds = focus; + } + +} /* nwipe_guid_rounds */ + + + +void nwipe_gui_prng( void ) +{ +/** + * Allows the user to change the PRNG. + * + * @modifies nwipe_options.prng + * @modifies main_window + * + */ + + extern nwipe_prng_t nwipe_twister; + extern nwipe_prng_t nwipe_isaac; + + /* The number of implemented PRNGs. */ + const int count = 2; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 30; + + /* Set the initial focus. */ + int focus = 0; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, nwipe_buttons2 ); + wrefresh( footer_window ); + + if( nwipe_options.prng == &nwipe_twister ) { focus = 0; } + if( nwipe_options.prng == &nwipe_isaac ) { focus = 1; } + + + while( keystroke != ERR ) + { + /* Clear the main window. */ + werase( main_window ); + + /* Initialize the working row. */ + yy = 2; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, "" ); + mvwprintw( main_window, yy++, tab1, "" ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_twister.label ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_isaac.label ); + mvwprintw( main_window, yy++, tab1, "" ); + + /* Print the cursor. */ + mvwaddch( main_window, 4 + focus, tab1, ACS_RARROW ); + + + switch( focus ) + { + case 0: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe --prng twister\"" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "The Mersenne Twister, by Makoto Matsumoto and Takuji Nishimura, is a " ); + mvwprintw( main_window, yy++, tab1, "generalized feedback shift register PRNG that is uniform and " ); + mvwprintw( main_window, yy++, tab1, "equidistributed in 623-dimensions with a proven period of 2^19937-1. " ); + mvwprintw( main_window, yy++, tab1, " " ); + mvwprintw( main_window, yy++, tab1, "This implementation passes the Marsaglia Diehard test suite. " ); + mvwprintw( main_window, yy++, tab1, " " ); + break; + + case 1: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe --prng isaac\"" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "ISAAC, by Bob Jenkins, is a PRNG derived from RC4 with a minimum period of " ); + mvwprintw( main_window, yy++, tab1, "2^40 and an expected period of 2^8295. It is difficult to recover the " ); + mvwprintw( main_window, yy++, tab1, "initial PRNG state by cryptanalysis of the ISAAC stream. " ); + mvwprintw( main_window, yy++, tab1, " " ); + break; + + } /* switch */ + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Pseudo Random Number Generator " ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Get a keystroke. */ + keystroke = getch(); + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count -1 ) { focus += 1; } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) { focus -= 1; } + break; + + case KEY_ENTER: + case ' ': + case 10: + + if( focus == 0 ) { nwipe_options.prng = &nwipe_twister; } + if( focus == 1 ) { nwipe_options.prng = &nwipe_isaac; } + return; + + case KEY_BACKSPACE: + case KEY_BREAK: + + return; + + } /* switch */ + + } /* while */ + +} /* nwipe_gui_prng */ + + + +void nwipe_gui_verify( void ) +{ +/** + * Allows the user to change the verification option. + * + * @modifies nwipe_options.verify + * @modifies main_window + * + */ + + /* The number of definitions in the nwipe_verify_t enumeration. */ + const int count = 3; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 30; + + /* Set the initial focus. */ + int focus = nwipe_options.verify; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, nwipe_buttons2 ); + wrefresh( footer_window ); + + while( keystroke != ERR ) + { + /* Clear the main window. */ + werase( main_window ); + + /* Initialize the working row. */ + yy = 2; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " Verification Off " ); + mvwprintw( main_window, yy++, tab1, " Verify Last Pass " ); + mvwprintw( main_window, yy++, tab1, " Verify All Passes " ); + mvwprintw( main_window, yy++, tab1, " " ); + + /* Print the cursor. */ + mvwaddch( main_window, 2 + focus, tab1, ACS_RARROW ); + + + switch( focus ) + { + case 0: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe --verify off\"" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "Do not verify passes. The wipe will be a write-only operation. " ); + mvwprintw( main_window, yy++, tab1, " " ); + break; + + case 1: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe --verify last\"" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "Check whether the device is actually empty after the last pass fills the " ); + mvwprintw( main_window, yy++, tab1, "device with zeros. " ); + break; + + case 2: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe --verify all\"" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "After every pass, read back the pattern and check whether it is correct. " ); + mvwprintw( main_window, yy++, tab1, " " ); + mvwprintw( main_window, yy++, tab1, "This program writes the entire length of the device before it reads back " ); + mvwprintw( main_window, yy++, tab1, "for verification, even for random pattern passes, to better ensure that " ); + mvwprintw( main_window, yy++, tab1, "hardware caches are actually flushed. " ); + break; + + } /* switch */ + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Verification Mode " ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Get a keystroke. */ + keystroke = getch(); + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count -1 ) { focus += 1; } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) { focus -= 1; } + break; + + case KEY_ENTER: + case ' ': + case 10: + + if( focus >= 0 && focus < count ) { nwipe_options.verify = focus; } + if( nwipe_options.verify != NWIPE_VERIFY_NONE ) { nwipe_options.noblank = 0; } + return; + + case KEY_BACKSPACE: + case KEY_BREAK: + + return; + + } /* switch */ + + } /* while */ + +} /* nwipe_gui_verify */ + + +void nwipe_gui_noblank( void ) +{ +/** + * Allows the user to change the verification option. + * + * @modifies nwipe_options.noblank + * @modifies main_window + * + */ + + /* The number of options available. */ + const int count = 2; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 40; + + /* Set the initial focus. */ + int focus = nwipe_options.noblank; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, nwipe_buttons2 ); + wrefresh( footer_window ); + + while( keystroke != ERR ) + { + /* Clear the main window. */ + werase( main_window ); + + /* Initialize the working row. */ + yy = 2; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " Perform a final blanking pass " ); + mvwprintw( main_window, yy++, tab1, " Do not perform final blanking pass " ); + mvwprintw( main_window, yy++, tab1, " " ); + + /* Print the cursor. */ + mvwaddch( main_window, 2 + focus, tab1, ACS_RARROW ); + + + switch( focus ) + { + case 0: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe\"" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "Perform a final blanking pass after the wipe, leaving disk with only zeros. " ); + mvwprintw( main_window, yy++, tab1, " " ); + break; + + case 1: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe -b\"" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "Do not perform a final blanking pass. Leave data as per final wiping pass. " ); + mvwprintw( main_window, yy++, tab1, "Any verification options will be ignored. Not compatible with Quick Erase. " ); + break; + + } /* switch */ + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Final Blanking Pass " ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Get a keystroke. */ + keystroke = getch(); + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count -1 ) { focus += 1; } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) { focus -= 1; } + break; + + case KEY_ENTER: + case ' ': + case 10: + + if( focus >= 0 && focus < count ){ nwipe_options.noblank = focus; } + if ( nwipe_options.noblank ) { nwipe_options.verify = NWIPE_VERIFY_NONE; } + return; + + case KEY_BACKSPACE: + case KEY_BREAK: + + return; + + } /* switch */ + + } /* while */ + +} /* nwipe_gui_noblank */ + + +void nwipe_gui_method( void ) +{ +/** + * Allows the user to change the wipe method. + * + * @modifies nwipe_options.method + * @modifies main_window + * + */ + + /* The number of implemented methods. */ + const int count = 6; + + /* The first tabstop. */ + const int tab1 = 2; + + /* The second tabstop. */ + const int tab2 = 30; + + /* The currently selected method. */ + int focus = 0; + + /* The current working row. */ + int yy; + + /* Input buffer. */ + int keystroke; + + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, nwipe_buttons2 ); + wrefresh( footer_window ); + + if( nwipe_options.method == &nwipe_zero ) { focus = 0; } + if( nwipe_options.method == &nwipe_ops2 ) { focus = 1; } + if( nwipe_options.method == &nwipe_dodshort ) { focus = 2; } + if( nwipe_options.method == &nwipe_dod522022m ) { focus = 3; } + if( nwipe_options.method == &nwipe_gutmann ) { focus = 4; } + if( nwipe_options.method == &nwipe_random ) { focus = 5; } + + + do + { + /* Clear the main window. */ + werase( main_window ); + + /* Initialize the working row. */ + yy = 2; + + /* Print the options. */ + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_zero ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_ops2 ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_dodshort ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_dod522022m ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_gutmann ) ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_method_label( &nwipe_random ) ); + mvwprintw( main_window, yy++, tab1, " " ); + + /* Print the cursor. */ + mvwaddch( main_window, 2 + focus, tab1, ACS_RARROW ); + + switch( focus ) + { + case 0: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe --method zero\"" ); + mvwprintw( main_window, 3, tab2, "Security Level: Low (1 pass)" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "This method fills the device with zeros. Note that the rounds option does " ); + mvwprintw( main_window, yy++, tab1, "not apply to this method. This method always runs one round. " ); + mvwprintw( main_window, yy++, tab1, " " ); + mvwprintw( main_window, yy++, tab1, "Use this method to blank disks before internal redeployment, or before " ); + mvwprintw( main_window, yy++, tab1, "reinstalling Microsoft Windows to remove the data areas that the format " ); + mvwprintw( main_window, yy++, tab1, "utility preserves. " ); + break; + + case 1: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe --method ops2\"" ); + mvwprintw( main_window, 3, tab2, "Security Level: Medium (8 passes)" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "The Royal Canadian Mounted Police Technical Security Standard for " ); + mvwprintw( main_window, yy++, tab1, "Information Technology, Appendix OPS-II: Media Sanitization. " ); + mvwprintw( main_window, yy++, tab1, " " ); + mvwprintw( main_window, yy++, tab1, "This implementation, with regards to paragraph 2 section A of the standard, " ); + mvwprintw( main_window, yy++, tab1, "uses a pattern that is one random byte and that is changed each round. " ); + break; + + case 2: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe --method dodshort\"" ); + mvwprintw( main_window, 3, tab2, "Security Level: Medium (3 passes)" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "The American Department of Defense 5220.22-M short wipe. " ); + mvwprintw( main_window, yy++, tab1, "This method is composed of passes 1,2,7 from the standard wipe. " ); + break; + + case 3: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe --method dod522022m\"" ); + mvwprintw( main_window, 3, tab2, "Security Level: Medium (7 passes)" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "The American Department of Defense 5220.22-M standard wipe. " ); + mvwprintw( main_window, yy++, tab1, "This implementation uses the same algorithm as the Heidi Eraser product. " ); + break; + + case 4: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe --method gutmann\"" ); + mvwprintw( main_window, 3, tab2, "Security Level: High (35 passes)" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "This is the method described by Peter Gutmann in the paper entitled " ); + mvwprintw( main_window, yy++, tab1, "\"Secure Deletion of Data from Magnetic and Solid-State Memory\". " ); + break; + + case 5: + + mvwprintw( main_window, 2, tab2, "syslinux.cfg: nuke=\"nwipe --method random\"" ); + mvwprintw( main_window, 3, tab2, "Security Level: Depends on Rounds" ); + + /* 0 1 2 3 4 5 6 7 8 */ + mvwprintw( main_window, yy++, tab1, "This method fills the device with a stream from the PRNG. It is probably the " ); + mvwprintw( main_window, yy++, tab1, "best method to use on modern hard disk drives because encoding schemes vary. " ); + mvwprintw( main_window, yy++, tab1, " " ); + mvwprintw( main_window, yy++, tab1, "This method has a medium security level with 4 rounds, and a high security " ); + mvwprintw( main_window, yy++, tab1, "level with 8 rounds. " ); + break; + + } /* switch */ + + /* Add a border. */ + box( main_window, 0, 0 ); + + /* Add a title. */ + nwipe_gui_title( main_window, " Wipe Method " ); + + /* Refresh the window. */ + wrefresh( main_window ); + + /* Get a keystroke. */ + keystroke = getch(); + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + if( focus < count -1 ) { focus += 1; } + break; + + case KEY_UP: + case 'k': + case 'K': + + if( focus > 0 ) { focus -= 1; } + break; + + case KEY_BACKSPACE: + case KEY_BREAK: + + return; + + } /* switch */ + + } while( keystroke != KEY_ENTER && keystroke != ' ' && keystroke != 10 && keystroke != ERR ); + + + switch( focus ) + { + case 0: + nwipe_options.method = &nwipe_zero; + break; + + case 1: + nwipe_options.method = &nwipe_ops2; + break; + + case 2: + nwipe_options.method = &nwipe_dodshort; + break; + + case 3: + nwipe_options.method = &nwipe_dod522022m; + break; + + case 4: + nwipe_options.method = &nwipe_gutmann; + break; + + case 5: + nwipe_options.method = &nwipe_random; + break; + } + + +} /* nwipe_gui_method */ + + +void nwipe_gui_load( void ) +{ +/** + * Prints the system load average to the statistics window. + * + * @modifies stat_window Prints the system load average to the statistics window. + * + */ + + /* A file handle for the stat file. */ + FILE* nwipe_fp; + + /* The one, five, and fifteen minute load averages. */ + float load_01; + float load_05; + float load_15; + + + /* Open the loadavg file. */ + nwipe_fp = fopen( NWIPE_KNOB_LOADAVG, "r" ); + + /* Print the label. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_LOAD_Y, NWIPE_GUI_STATS_LOAD_X, "Load Averages:" ); + + if( nwipe_fp ) + { + /* The load averages are the first three numbers in the file. */ + if( 3 == fscanf( nwipe_fp, "%f %f %f", &load_01, &load_05, &load_15 ) ) + { + /* Print the load average. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_LOAD_Y, NWIPE_GUI_STATS_TAB, + "%04.2f %04.2f %04.2f", load_01, load_05, load_15 ); + } + + else + { + /* Print an error. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_LOAD_Y, NWIPE_GUI_STATS_TAB, "(fscanf error %i)", errno ); + } + + /* Close the loadavg file. */ + fclose( nwipe_fp ); + } + + else + { + mvwprintw( stats_window, NWIPE_GUI_STATS_LOAD_Y, NWIPE_GUI_STATS_TAB, "(fopen error %i)", errno ); + } + +} /* nwipe_gui_load */ + + + +void *nwipe_gui_status( void *ptr ) +{ +/** + * Shows runtime statistics and overall progress. + * + * @parameter count The number of contexts in the array. + * @parameter c An array of device contexts. + * + * @modifies main_window Prints information into the main window. + * @modifies c[].throughput Updates the i/o throughput value. + * + */ + + nwipe_thread_data_ptr_t *nwipe_thread_data_ptr; + nwipe_thread_data_ptr = (nwipe_thread_data_ptr_t *) ptr; + + nwipe_context_t **c; + nwipe_misc_thread_data_t *nwipe_misc_thread_data; + int count; + + c = nwipe_thread_data_ptr->c; + nwipe_misc_thread_data = nwipe_thread_data_ptr->nwipe_misc_thread_data; + count = nwipe_misc_thread_data->nwipe_selected; + + /* Throughput print formats. */ + char* nwipe_tera = "%llu TB/s"; + char* nwipe_giga = "%llu GB/s"; + char* nwipe_mega = "%llu MB/s"; + char* nwipe_kilo = "%llu KB/s"; + char* nwipe_unit = "%llu B/s"; + + /* The throughput format pointer. */ + char* nwipe_format; + + /* We count time from when this function is first called. */ + static time_t nwipe_time_start = 0; + + /* Whether the screen has been blanked by the user. */ + static int nwipe_gui_blank = 0; + + /* The current time. */ + time_t nwipe_time_now; + + /* The index of the element that is visible in the first slot. */ + static int offset; + + /* The number of elements that we can show in the window. */ + int slots; + + /* Window dimensions. */ + int wlines; + int wcols; + + /* Generic loop variable. */ + int i; + + /* The current working line in the main window. */ + int yy; + + /* User input buffer. */ + int keystroke; + + /* The combined througput of all processes. */ + u64 nwipe_throughput = 0; + + /* The estimated runtime of the slowest device. */ + time_t nwipe_maxeta = 0; + + /* The combined number of errors of all processes. */ + u64 nwipe_errors = 0; + + /* Time values. */ + int nwipe_hh; + int nwipe_mm; + int nwipe_ss; + + /* The number of active wipe processes. */ + /* Set to 1 initially to start loop. */ + int nwipe_active = 1; + + if( nwipe_time_start == 0 ) + { + /* This is the first time that we have been called. */ + nwipe_time_start = time( NULL ) -1; + } + + /* Get the window dimensions. */ + getmaxyx( main_window, wlines, wcols ); + + /* Less four lines for the box and padding. */ + slots = wlines - 4; + + /* Each element prints three lines. */ + slots /= 3; + + /* Add text to footer window */ + nwipe_gui_title( footer_window, nwipe_buttons3 ); + wrefresh( footer_window ); + + while ( nwipe_active ) { + + /* Get the current time. */ + nwipe_time_now = time( NULL ); + + /* Erase the main window. */ + werase( main_window ); + + /* Erase the stats window. */ + werase( stats_window ); + + /* Initialize our working offset to the third line. */ + yy = 2; + + /* Try to get a keystroke. */ + keystroke = getch(); + + if ( keystroke > 0 && nwipe_gui_blank == 1 ) + { + /* Show screen */ + nwipe_gui_blank = 0; + + /* Set background */ + wbkgdset( stdscr, COLOR_PAIR(1) ); + wclear( stdscr ); + + /* Unhide panels */ + show_panel(header_panel); + show_panel(footer_panel); + show_panel(stats_panel); + show_panel(options_panel); + show_panel(main_panel); + + /* Update panels */ + update_panels(); + doupdate(); + + } + else if ( keystroke > 0 ) { + + switch( keystroke ) + { + + case 'b': + case 'B': + + /* Blank screen. */ + nwipe_gui_blank = 1; + hide_panel(header_panel); + hide_panel(footer_panel); + hide_panel(stats_panel); + hide_panel(options_panel); + hide_panel(main_panel); + + /* Set the background style. */ + wbkgdset( stdscr, COLOR_PAIR(7) ); + wclear( stdscr ); + + break; + + case KEY_DOWN: + case 'j': + case 'J': + + /* Scroll down. */ + offset += 1; + + if( count < slots ) + { + offset = 0; + } + + else if( offset + slots > count ) + { + offset = count - slots; + } + + break; + + case KEY_UP: + case 'k': + case 'K': + + /* Scroll up. */ + offset -= 1; + + if( offset < 0 ) + { + offset = 0; + } + + break; + + default: + + /* Do nothing. */ + break; + } + + } /* keystroke */ + + + /* Update screen if not blanked. */ + if ( nwipe_gui_blank == 0 ) + { + + nwipe_active = 0; // Number of active wipe threads + /* Enumerate all contexts to compute statistics. */ + for( i = 0 ; i < count ; i++ ) + { + /* Check whether the child process is still running the wipe. */ + if( c[i]->thread > 0 ) + { + /* Increment the child counter. */ + nwipe_active += 1; + + /* Maintain a rolling average of throughput. */ + nwipe_update_speedring( &c[i]->speedring, c[i]->round_done, nwipe_time_now ); + + if( c[i]->speedring.timestotal > 0 ) + { + /* Update the current average throughput in bytes-per-second. */ + c[i]->throughput = c[i]->speedring.bytestotal / c[i]->speedring.timestotal; + + /* Update the estimated remaining runtime. */ + /* Check that throughput is not zero (sometimes caused during a sync) */ + if (c[i]->throughput == 0) + { + c[i]->throughput = 1; + } + + c[i]->eta = ( c[i]->round_size - c[i]->round_done ) / c[i]->throughput; + + if( c[i]->eta > nwipe_maxeta ) + { + nwipe_maxeta = c[i]->eta; + } + } + + /* Update the percentage value. */ + c[i]->round_percent = (double) c[i]->round_done / (double) c[i]->round_size * 100; + + /* Accumulate combined throughput. */ + nwipe_throughput += c[i]->throughput; + + } /* child running */ + + /* Accumulate the error count. */ + nwipe_errors += c[i]->pass_errors; + nwipe_errors += c[i]->verify_errors; + + } /* for statistics */ + + + /* Print information for the user. */ + for( i = offset ; i < offset + slots && i < count ; i++ ) + { + /* Print the context label. */ + mvwprintw( main_window, yy++, 2, "%s", c[i]->label ); + + /* Check whether the child process is still running the wipe. */ + if( c[i]->thread > 0 ) + { + /* Print percentage and pass information. */ + mvwprintw( main_window, yy++, 4, "[%05.2f%%, round %i of %i, pass %i of %i] ", \ + c[i]->round_percent, c[i]->round_working, c[i]->round_count, c[i]->pass_working, c[i]->pass_count ); + + } /* child running */ + + else + { + if( c[i]->result == 0 ) { mvwprintw( main_window, yy++, 4, "(success) " ); } + else if( c[i]->signal ) { mvwprintw( main_window, yy++, 4, "(failure, signal %i) ", c[i]->signal ); } + else { mvwprintw( main_window, yy++, 4, "(failure, code %i) ", c[i]->result ); } + + } /* child returned */ + + if( c[i]->verify_errors ) { wprintw( main_window, "[verify errors: %llu] ", c[i]->verify_errors ); } + if( c[i]->pass_errors ) { wprintw( main_window, "[pass errors: %llu] ", c[i]->pass_errors ); } + + + switch( c[i]->pass_type ) + { + case NWIPE_PASS_FINAL_BLANK: + wprintw( main_window, "[blanking] " ); + break; + + case NWIPE_PASS_FINAL_OPS2: + wprintw( main_window, "[OPS-II final] " ); + break; + + case NWIPE_PASS_WRITE: + wprintw( main_window, "[writing] " ); + break; + + case NWIPE_PASS_VERIFY: + wprintw( main_window, "[verifying] " ); + break; + + case NWIPE_PASS_NONE: + break; + } + + if( c[i]->sync_status ) { wprintw( main_window, "[syncing] " ); } + + if( c[i]->throughput >= INT64_C( 1000000000000000 ) ) + { wprintw( main_window, "[%llu TB/s] ", c[i]->throughput / INT64_C( 1000000000000 ) ); } + else if( c[i]->throughput >= INT64_C( 1000000000000 ) ) + { wprintw( main_window, "[%llu GB/s] ", c[i]->throughput / INT64_C( 1000000000 ) ); } + else if( c[i]->throughput >= INT64_C( 1000000000 ) ) + { wprintw( main_window, "[%llu MB/s] ", c[i]->throughput / INT64_C( 1000000 ) ); } + else if( c[i]->throughput >= INT64_C( 1000000 ) ) + { wprintw( main_window, "[%llu KB/s] ", c[i]->throughput / INT64_C( 1000 ) ); } + else + { wprintw( main_window, "[%llu B/s] ", c[i]->throughput / INT64_C( 1 ) ); } + + /* Insert whitespace. */ + yy += 1; + + } /* for */ + + + if( offset > 0 ) + { + mvwprintw( main_window, 1, wcols -8, " More " ); + waddch( main_window, ACS_UARROW ); + } + + if( count - offset > slots ) + { + mvwprintw( main_window, wlines -2, wcols -8, " More " ); + waddch( main_window, ACS_DARROW ); + } + + + /* Box the main window. */ + box( main_window, 0, 0 ); + + /* Refresh the main window. */ + wrefresh( main_window ); + + /* Update the load average field. */ + nwipe_gui_load(); + + + if( nwipe_throughput >= INT64_C( 1000000000000000 ) ) + { nwipe_throughput /= INT64_C( 1000000000000 ); nwipe_format = nwipe_tera; } + else if( nwipe_throughput >= INT64_C( 1000000000000 ) ) + { nwipe_throughput /= INT64_C( 1000000000 ); nwipe_format = nwipe_giga; } + else if( nwipe_throughput >= INT64_C( 1000000000 ) ) + { nwipe_throughput /= INT64_C( 1000000 ); nwipe_format = nwipe_mega; } + else if( nwipe_throughput >= INT64_C( 1000000 ) ) + { nwipe_throughput /= INT64_C( 1000 ); nwipe_format = nwipe_kilo; } + else + { nwipe_throughput /= INT64_C( 1 ); nwipe_format = nwipe_unit; } + + /* Print the combined throughput. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_THROUGHPUT_Y, NWIPE_GUI_STATS_THROUGHPUT_X, "Throughput:" ); + + if( nwipe_throughput > 0 ) + { + mvwprintw( stats_window, NWIPE_GUI_STATS_THROUGHPUT_Y, NWIPE_GUI_STATS_TAB, nwipe_format, nwipe_throughput ); + } + + /* Change the current time into a delta. */ + nwipe_time_now -= nwipe_time_start; + + /* Put the delta into HH:mm:ss form. */ + nwipe_hh = nwipe_time_now / 3600; + nwipe_time_now %= 3600; + nwipe_mm = nwipe_time_now / 60; + nwipe_time_now %= 60; + nwipe_ss = nwipe_time_now; + + /* Print the runtime. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_RUNTIME_Y, 1, "Runtime:" ); + mvwprintw( stats_window, NWIPE_GUI_STATS_RUNTIME_Y, NWIPE_GUI_STATS_TAB, "%02i:%02i:%02i", nwipe_hh, nwipe_mm, nwipe_ss ); + + mvwprintw( stats_window, NWIPE_GUI_STATS_ETA_Y, 1, "Remaining:" ); + + if( nwipe_maxeta > 0 ) + { + /* Do it again for the estimated runtime remaining. */ + nwipe_hh = nwipe_maxeta / 3600; + nwipe_maxeta %= 3600; + nwipe_mm = nwipe_maxeta / 60; + nwipe_maxeta %= 60; + nwipe_ss = nwipe_maxeta; + + /* Print the estimated runtime remaining. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_ETA_Y, NWIPE_GUI_STATS_TAB, "%02i:%02i:%02i", nwipe_hh, nwipe_mm, nwipe_ss ); + } + + /* Print the error count. */ + mvwprintw( stats_window, NWIPE_GUI_STATS_ERRORS_Y, NWIPE_GUI_STATS_ERRORS_X, "Errors:" ); + mvwprintw( stats_window, NWIPE_GUI_STATS_ERRORS_Y, NWIPE_GUI_STATS_TAB, "%llu", nwipe_errors ); + + /* Add a border. */ + box( stats_window, 0, 0 ); + + /* Add a title. */ + mvwprintw( stats_window, 0, ( NWIPE_GUI_STATS_W - strlen( stats_title ) ) /2, "%s", stats_title ); + + /* Refresh the stats window. */ + wrefresh( stats_window ); + + } // end blank screen if + + if (nwipe_options.logfile[0] == '\0') { + + // Logging to STDOUT. Flush log. + + def_prog_mode(); /* Save the tty modes */ + endwin(); /* End curses mode temporarily */ + + /* Flush stdout and disable buffering, otherwise output missed new lines. */ + fflush(stdout); + setbuf(stdout, NULL); + + pthread_mutex_lock( &mutex1 ); + + for (i=0; i < log_current_element; i++) + { + printf("%s\n", log_lines[i]); + } + log_current_element = 0; + + pthread_mutex_unlock( &mutex1 ); + + reset_prog_mode(); /* Return to the previous tty mode*/ + /* stored by def_prog_mode() */ + refresh(); /* Do refresh() to restore the */ + /* Screen contents */ + } + + /* Test for a thread cancellation request */ + pthread_testcancel(); + + } // while + + if (nwipe_options.logfile[0] == '\0') + { + nwipe_gui_title( footer_window, "Wipe finished - press enter to exit. Logged to STDOUT" ); + } + else { + char finish_message[NWIPE_GUI_FOOTER_W]; + snprintf(finish_message, sizeof(finish_message), "Wipe finished - press enter to exit. Logged to %s", + nwipe_options.logfile); + nwipe_gui_title( footer_window, finish_message ); + } + wrefresh( footer_window ); + nwipe_misc_thread_data->gui_thread = 0; + +} /* nwipe_gui_status */ + + +void nwipe_update_speedring( nwipe_speedring_t* speedring, u64 speedring_bytes, time_t speedring_now ) +{ + + if( speedring->timeslast == 0 ) + { + /* Ignore the first sample and initialize. */ + speedring->timeslast = speedring_now; + return; + } + + if( speedring_now - speedring->timeslast < NWIPE_KNOB_SPEEDRING_GRANULARITY ) + { + /* Avoid jitter caused by frequent updates. */ + return; + } + + /* Subtract the oldest speed sample from the accumulator. */ + speedring->bytestotal -= speedring->bytes[ speedring->position ]; + speedring->timestotal -= speedring->times[ speedring->position ]; + + /* Put the lastest bytes-per-second sample into the ring buffer. */ + speedring->bytes[ speedring->position ] = speedring_bytes - speedring->byteslast; + speedring->times[ speedring->position ] = speedring_now - speedring->timeslast; + + /* Add the newest speed sample to the accumulator. */ + speedring->bytestotal += speedring->bytes[ speedring->position ]; + speedring->timestotal += speedring->times[ speedring->position ]; + + /* Remember the last sample. */ + speedring->byteslast = speedring_bytes; + speedring->timeslast = speedring_now; + + if( ++speedring->position >= NWIPE_KNOB_SPEEDRING_SIZE ) + { + speedring->position = 0; + } +} + +/* eof */ + diff --git a/src/gui.h b/src/gui.h new file mode 100644 index 0000000..1727a3c --- /dev/null +++ b/src/gui.h @@ -0,0 +1,43 @@ +/* + * gui.h: An ncurses GUI for nwipe. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#ifndef GUI_H_ +#define GUI_H_ + +void nwipe_gui_free( void ); /* Stop the GUI. */ +void nwipe_gui_init( void ); /* Start the GUI. */ +void nwipe_gui_select( int count, nwipe_context_t** c ); /* Select devices to wipe. */ +void *nwipe_gui_status( void *ptr ); /* Update operation progress. */ +void nwipe_gui_method( void ); /* Change the method option. */ +void nwipe_gui_options( void ); /* Update the options window. */ +void nwipe_gui_prng( void ); /* Change the prng option. */ +void nwipe_gui_rounds( void ); /* Change the rounds option. */ +void nwipe_gui_verify( void ); /* Change the verify option. */ +void nwipe_gui_noblank( void ); /* Change the noblank option. */ + +void nwipe_update_speedring( nwipe_speedring_t* speedring, u64 speedring_done, time_t speedring_now ); + + +#endif /* GUI_H_ */ + +/* eof */ diff --git a/src/isaac_rand.c b/src/isaac_rand.c new file mode 100644 index 0000000..34d172e --- /dev/null +++ b/src/isaac_rand.c @@ -0,0 +1,137 @@ +/* +------------------------------------------------------------------------------ +rand.c: By Bob Jenkins. My random number generator, ISAAC. Public Domain. +MODIFIED: + 960327: Creation (addition of randinit, really) + 970719: use context, not global variables, for internal state + 980324: added main (ifdef'ed out), also rearranged randinit() + 010626: Note that this is public domain +------------------------------------------------------------------------------ +*/ +#ifndef STANDARD +#include "isaac_standard.h" +#endif +#ifndef RAND +#include "isaac_rand.h" +#endif + + +#define ind(mm,x) (*(ub4 *)((ub1 *)(mm) + ((x) & ((RANDSIZ-1)<<2)))) +#define rngstep(mix,a,b,mm,m,m2,r,x) \ +{ \ + x = *m; \ + a = (a^(mix)) + *(m2++); \ + *(m++) = y = ind(mm,x) + a + b; \ + *(r++) = b = ind(mm,y>>RANDSIZL) + x; \ +} + +void isaac(ctx) +randctx *ctx; +{ + register ub4 a,b,x,y,*m,*mm,*m2,*r,*mend; + mm=ctx->randmem; r=ctx->randrsl; + a = ctx->randa; b = ctx->randb + (++ctx->randc); + for (m = mm, mend = m2 = m+(RANDSIZ/2); m>6 , a, b, mm, m, m2, r, x); + rngstep( a<<2 , a, b, mm, m, m2, r, x); + rngstep( a>>16, a, b, mm, m, m2, r, x); + } + for (m2 = mm; m2>6 , a, b, mm, m, m2, r, x); + rngstep( a<<2 , a, b, mm, m, m2, r, x); + rngstep( a>>16, a, b, mm, m, m2, r, x); + } + ctx->randb = b; ctx->randa = a; +} + + +#define mix(a,b,c,d,e,f,g,h) \ +{ \ + a^=b<<11; d+=a; b+=c; \ + b^=c>>2; e+=b; c+=d; \ + c^=d<<8; f+=c; d+=e; \ + d^=e>>16; g+=d; e+=f; \ + e^=f<<10; h+=e; f+=g; \ + f^=g>>4; a+=f; g+=h; \ + g^=h<<8; b+=g; h+=a; \ + h^=a>>9; c+=h; a+=b; \ +} + +/* if (flag==TRUE), then use the contents of randrsl[] to initialize mm[]. */ +void randinit(ctx, flag) +randctx *ctx; +word flag; +{ + word i; + ub4 a,b,c,d,e,f,g,h; + ub4 *m,*r; + ctx->randa = ctx->randb = ctx->randc = 0; + m=ctx->randmem; + r=ctx->randrsl; + a=b=c=d=e=f=g=h=0x9e3779b9; /* the golden ratio */ + + for (i=0; i<4; ++i) /* scramble it */ + { + mix(a,b,c,d,e,f,g,h); + } + + if (flag) + { + /* initialize using the contents of r[] as the seed */ + for (i=0; irandcnt=RANDSIZ; /* prepare to use the first set of results */ +} + + +#ifdef NEVER +int main() +{ + ub4 i,j; + randctx ctx; + ctx.randa=ctx.randb=ctx.randc=(ub4)0; + for (i=0; i<256; ++i) ctx.randrsl[i]=(ub4)0; + randinit(&ctx, TRUE); + for (i=0; i<2; ++i) + { + isaac(&ctx); + for (j=0; j<256; ++j) + { + printf("%.8lx",ctx.randrsl[j]); + if ((j&7)==7) printf("\n"); + } + } +} +#endif diff --git a/src/isaac_rand.h b/src/isaac_rand.h new file mode 100644 index 0000000..4931bea --- /dev/null +++ b/src/isaac_rand.h @@ -0,0 +1,56 @@ +/* +------------------------------------------------------------------------------ +rand.h: definitions for a random number generator +By Bob Jenkins, 1996, Public Domain +MODIFIED: + 960327: Creation (addition of randinit, really) + 970719: use context, not global variables, for internal state + 980324: renamed seed to flag + 980605: recommend RANDSIZL=4 for noncryptography. + 010626: note this is public domain +------------------------------------------------------------------------------ +*/ +#ifndef STANDARD +#include "isaac_standard.h" +#endif + +#ifndef RAND +#define RAND +#define RANDSIZL (8) /* I recommend 8 for crypto, 4 for simulations */ +#define RANDSIZ (1<randcnt-- ? \ + (isaac(r), (r)->randcnt=RANDSIZ-1, (r)->randrsl[(r)->randcnt]) : \ + (r)->randrsl[(r)->randcnt]) + +#endif /* RAND */ + + diff --git a/src/isaac_standard.h b/src/isaac_standard.h new file mode 100644 index 0000000..202a5d6 --- /dev/null +++ b/src/isaac_standard.h @@ -0,0 +1,57 @@ +/* +------------------------------------------------------------------------------ +Standard definitions and types, Bob Jenkins +------------------------------------------------------------------------------ +*/ +#ifndef STANDARD +# define STANDARD +# ifndef STDIO +# include +# define STDIO +# endif +# ifndef STDDEF +# include +# define STDDEF +# endif +typedef unsigned long long ub8; +#define UB8MAXVAL 0xffffffffffffffffLL +#define UB8BITS 64 +typedef signed long long sb8; +#define SB8MAXVAL 0x7fffffffffffffffLL +typedef unsigned long int ub4; /* unsigned 4-byte quantities */ +#define UB4MAXVAL 0xffffffff +typedef signed long int sb4; +#define UB4BITS 32 +#define SB4MAXVAL 0x7fffffff +typedef unsigned short int ub2; +#define UB2MAXVAL 0xffff +#define UB2BITS 16 +typedef signed short int sb2; +#define SB2MAXVAL 0x7fff +typedef unsigned char ub1; +#define UB1MAXVAL 0xff +#define UB1BITS 8 +typedef signed char sb1; /* signed 1-byte quantities */ +#define SB1MAXVAL 0x7f +typedef int word; /* fastest type available */ + +#define bis(target,mask) ((target) |= (mask)) +#define bic(target,mask) ((target) &= ~(mask)) +#define bit(target,mask) ((target) & (mask)) +#ifndef min +# define min(a,b) (((a)<(b)) ? (a) : (b)) +#endif /* min */ +#ifndef max +# define max(a,b) (((a)<(b)) ? (b) : (a)) +#endif /* max */ +#ifndef align +# define align(a) (((ub4)a+(sizeof(void *)-1))&(~(sizeof(void *)-1))) +#endif /* align */ +#ifndef abs +# define abs(a) (((a)>0) ? (a) : -(a)) +#endif +#define TRUE 1 +#define FALSE 0 +#define SUCCESS 0 /* 1 on VAX */ + +#endif /* STANDARD */ diff --git a/src/logging.c b/src/logging.c new file mode 100644 index 0000000..eba15e1 --- /dev/null +++ b/src/logging.c @@ -0,0 +1,222 @@ +/* + * logging.c: Logging facilities for nwipe. + * + * Copyright Darik Horn . + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "logging.h" + +int const MAX_LOG_LINE_CHARS = 512; + +/* Global array to hold log values to print when logging to STDOUT */ +char **log_lines; +int log_current_element = 0; +int log_elements_allocated = 0; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +void nwipe_log( nwipe_log_t level, const char* format, ... ) +{ +/** + * Writes a message to the program log file. + * + */ + + + /* A time buffer. */ + time_t t; + + /* A pointer to the system time struct. */ + struct tm* p; + + /* Get the current time. */ + t = time( NULL ); + p = gmtime( &t ); + + pthread_mutex_lock( &mutex1 ); + + /* Increase the current log element pointer - we will write here */ + if (log_current_element == log_elements_allocated) { + log_elements_allocated++; + log_lines = (char **) realloc (log_lines, (log_elements_allocated) * sizeof(char *)); + log_lines[log_current_element] = malloc(MAX_LOG_LINE_CHARS * sizeof(char)); + } + + /* Position of writing to current log string */ + int line_current_pos = 0; + + /* Print the date. The rc script uses the same format. */ + line_current_pos = snprintf( log_lines[log_current_element], MAX_LOG_LINE_CHARS, "[%i/%02i/%02i %02i:%02i:%02i] nwipe: ", \ + 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec ); + + switch( level ) + { + + case NWIPE_LOG_NONE: + /* Do nothing. */ + break; + + case NWIPE_LOG_DEBUG: + line_current_pos += snprintf( log_lines[log_current_element] + line_current_pos, MAX_LOG_LINE_CHARS, "debug: " ); + break; + + case NWIPE_LOG_INFO: + line_current_pos += snprintf( log_lines[log_current_element] + line_current_pos, MAX_LOG_LINE_CHARS, "info: " ); + break; + + case NWIPE_LOG_NOTICE: + line_current_pos += snprintf( log_lines[log_current_element] + line_current_pos, MAX_LOG_LINE_CHARS, "notice: " ); + break; + + case NWIPE_LOG_WARNING: + line_current_pos += snprintf( log_lines[log_current_element] + line_current_pos, MAX_LOG_LINE_CHARS, "warning: " ); + break; + + case NWIPE_LOG_ERROR: + line_current_pos += snprintf( log_lines[log_current_element] + line_current_pos, MAX_LOG_LINE_CHARS, "error: " ); + break; + + case NWIPE_LOG_FATAL: + line_current_pos += snprintf( log_lines[log_current_element] + line_current_pos, MAX_LOG_LINE_CHARS, "fatal: " ); + break; + + case NWIPE_LOG_SANITY: + /* TODO: Request that the user report the log. */ + line_current_pos += snprintf( log_lines[log_current_element] + line_current_pos, MAX_LOG_LINE_CHARS, "sanity: " ); + break; + + default: + line_current_pos += snprintf( log_lines[log_current_element] + line_current_pos, MAX_LOG_LINE_CHARS, "level %i: ", level ); + + } + + /* The variable argument pointer. */ + va_list ap; + + /* Fetch the argument list. */ + va_start( ap, format ); + + /* Print the event. */ + line_current_pos += vsnprintf( log_lines[log_current_element] + line_current_pos, MAX_LOG_LINE_CHARS, format, ap ); + +/* + if( level >= NWIPE_LOG_WARNING ) + { + vfprintf( stderr, format, ap ); + } +*/ + + /* Release the argument list. */ + va_end( ap ); + +/* + if( level >= NWIPE_LOG_WARNING ) + { + fprintf( stderr, "\n" ); + } +*/ + + /* A result buffer. */ + int r; + + /* The log file pointer. */ + FILE* fp; + + /* The log file descriptor. */ + int fd; + + + if (nwipe_options.logfile[0] == '\0') + { + if (nwipe_options.nogui) + { + printf( "%s\n", log_lines[log_current_element] ); + } + else + { + log_current_element++; + } + } else + { + /* Open the log file for appending. */ + fp = fopen( nwipe_options.logfile, "a" ); + + if( fp == NULL ) + { + fprintf( stderr, "nwipe_log: Unable to open '%s' for logging.\n", nwipe_options.logfile ); + return; + } + + /* Get the file descriptor of the log file. */ + fd = fileno( fp ); + + /* Block and lock. */ + r = flock( fd, LOCK_EX ); + + if( r != 0 ) + { + perror( "nwipe_log: flock:" ); + fprintf( stderr, "nwipe_log: Unable to lock '%s' for logging.\n", nwipe_options.logfile ); + return; + } + + fprintf( fp, "%s\n", log_lines[log_current_element] ); + + /* Unlock the file. */ + r = flock( fd, LOCK_UN ); + + if( r != 0 ) + { + perror( "nwipe_log: flock:" ); + fprintf( stderr, "Error: Unable to unlock '%s' after logging.\n", nwipe_options.logfile ); + } + + /* Close the stream. */ + r = fclose( fp ); + + if( r != 0 ) + { + perror( "nwipe_log: fclose:" ); + fprintf( stderr, "Error: Unable to close '%s' after logging.\n", nwipe_options.logfile ); + } + } + + pthread_mutex_unlock( &mutex1 ); + + +} /* nwipe_log */ + + +void nwipe_perror( int nwipe_errno, const char* f, const char* s ) +{ +/** + * Wrapper for perror(). + * + * We may wish to tweak or squelch this later. + * + */ + + nwipe_log( NWIPE_LOG_ERROR, "%s: %s: %s", f, s, strerror( nwipe_errno ) ); + +} /* nwipe_perror */ + +/* eof */ diff --git a/src/logging.h b/src/logging.h new file mode 100644 index 0000000..f855dcd --- /dev/null +++ b/src/logging.h @@ -0,0 +1,47 @@ +/* + * logging.c: Logging facilities for nwipe. + * + * Copyright Darik Horn . + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#ifndef LOGGING_H_ +#define LOGGING_H_ + +typedef enum nwipe_log_t_ +{ + NWIPE_LOG_NONE = 0, + NWIPE_LOG_DEBUG, /* TODO: Very verbose logging. */ + NWIPE_LOG_INFO, /* TODO: Verbose logging. */ + NWIPE_LOG_NOTICE, /* Most logging happens at this level. */ + NWIPE_LOG_WARNING, /* Things that the user should know about. */ + NWIPE_LOG_ERROR, /* Non-fatal errors that result in failure. */ + NWIPE_LOG_FATAL, /* Errors that cause the program to exit. */ + NWIPE_LOG_SANITY /* Programming errors. */ +} nwipe_log_t; + +void nwipe_log( nwipe_log_t level, const char* format, ... ); +void nwipe_perror( int nwipe_errno, const char* f, const char* s ); + +/* Global array to hold log values to print when logging to STDOUT */ +//extern char **log_lines; +//extern int log_current_element; +//extern int log_elements_allocated; + +#endif /* LOGGING_H_ */ + +/* eof */ diff --git a/src/method.c b/src/method.c new file mode 100644 index 0000000..11e27fd --- /dev/null +++ b/src/method.c @@ -0,0 +1,858 @@ +/* + * method.c: Method implementations for nwipe. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +/* HOWTO: Add another wipe method. + * + * 1. Create a new function here and add the prototype to the 'nwipe.h' file. + * 2. Update nwipe_method_label() appropriately. + * 3. Put the passes that you wish to run into a nwipe_patterns_t array. + * 4. Call nwipe_runmethod() with your array of patterns. + * 5. Cut-and-paste within the 'options.c' file so that the new method can be invoked. + * 6. Optionally try to plug your function into 'gui.c'. + * + * + * WARNING: Remember to pad all pattern arrays with { 0, NULL }. + * + * WARNING: Never change nwipe_options after calling a method. + * + * NOTE: The nwipe_runmethod function appends a final pass to all methods. + * + */ + +/* Why is this needed? Segfaults without it */ +#include + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "pass.h" +#include "logging.h" + + +/* + * Comment Legend + * + * "method" An ordered set of patterns. + * "pattern" The magic bits that will be written to a device. + * "pass" Reading or writing one pattern to an entire device. + * "rounds" The number of times that a method will be applied to a device. + * + */ + +const char* nwipe_dod522022m_label = "DoD 5220.22-M"; +const char* nwipe_dodshort_label = "DoD Short"; +const char* nwipe_gutmann_label = "Gutmann Wipe"; +const char* nwipe_ops2_label = "RCMP TSSIT OPS-II"; +const char* nwipe_random_label = "PRNG Stream"; +const char* nwipe_zero_label = "Quick Erase"; + +const char* nwipe_unknown_label = "Unknown Method (FIXME)"; + +const char* nwipe_method_label( void* method ) +{ +/** + * Returns a pointer to the name of the method function. + * + */ + + if( method == &nwipe_dod522022m ) { return nwipe_dod522022m_label; } + if( method == &nwipe_dodshort ) { return nwipe_dodshort_label; } + if( method == &nwipe_gutmann ) { return nwipe_gutmann_label; } + if( method == &nwipe_ops2 ) { return nwipe_ops2_label; } + if( method == &nwipe_random ) { return nwipe_random_label; } + if( method == &nwipe_zero ) { return nwipe_zero_label; } + + /* else */ + return nwipe_unknown_label; + +} /* nwipe_method_label */ + + +void *nwipe_zero( void *ptr ) +{ +/** + * Fill the device with zeroes. + * + */ + + nwipe_context_t *c; + c = (nwipe_context_t *) ptr; + + /* Do nothing because nwipe_runmethod appends a zero-fill. */ + nwipe_pattern_t patterns [] = + { + { 0, NULL } + }; + + /* Run the method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Finished. Set the thread ID to 0 so that the GUI knows */ + c->thread = 0; + +} /* nwipe_zero */ + + + +void *nwipe_dod522022m( void *ptr ) +{ +/** + * United States Department of Defense 5220.22-M standard wipe. + * + */ + + nwipe_context_t *c; + c = (nwipe_context_t *) ptr; + + /* A result holder. */ + int r; + + /* Random characters. (Elements 2 and 6 are unused.) */ + char dod [7]; + + nwipe_pattern_t patterns [] = + { + { 1, &dod[0] }, /* Pass 1: A random character. */ + { 1, &dod[1] }, /* Pass 2: The bitwise complement of pass 1. */ + { -1, "" }, /* Pass 3: A random stream. */ + { 1, &dod[3] }, /* Pass 4: A random character. */ + { 1, &dod[4] }, /* Pass 5: A random character. */ + { 1, &dod[5] }, /* Pass 6: The bitwise complement of pass 5. */ + { -1, "" }, /* Pass 7: A random stream. */ + { 0, NULL } + }; + + /* Load the array with random characters. */ + r = read( c->entropy_fd, &dod, sizeof( dod ) ); + + /* NOTE: Only the random data in dod[0], dod[3], and dod[4] is actually used. */ + + /* Check the result. */ + if( r != sizeof( dod ) ) + { + r = errno; + nwipe_perror( r, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the %s method.", nwipe_dod522022m_label ); + + /* Ensure a negative return. */ + if( r < 0 ) { c->result = r; return; } + else { c->result = -1; return; } + + } + + /* Pass 2 is the bitwise complement of Pass 1. */ + dod[1] = ~ dod[0]; + + /* Pass 4 is the bitwise complement of Pass 3. */ + dod[5] = ~ dod[4]; + + /* Run the DoD 5220.22-M method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Finished. Set the thread ID to 0 so that the GUI knows */ + c->thread = 0; + +} /* nwipe_dod522022m */ + + + +void *nwipe_dodshort( void *ptr ) +{ +/** + * United States Department of Defense 5220.22-M short wipe. + * This method is comprised of passes 1,2,7 from the standard wipe. + * + */ + + nwipe_context_t *c; + c = (nwipe_context_t *) ptr; + + /* A result holder. */ + int r; + + /* Random characters. (Element 3 is unused.) */ + char dod [3]; + + nwipe_pattern_t patterns [] = + { + { 1, &dod[0] }, /* Pass 1: A random character. */ + { 1, &dod[1] }, /* Pass 2: The bitwise complement of pass 1. */ + { -1, "" }, /* Pass 3: A random stream. */ + { 0, NULL } + }; + + /* Load the array with random characters. */ + r = read( c->entropy_fd, &dod, sizeof( dod ) ); + + /* NOTE: Only the random data in dod[0] is actually used. */ + + /* Check the result. */ + if( r != sizeof( dod ) ) + { + r = errno; + nwipe_perror( r, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the %s method.", nwipe_dodshort_label ); + + /* Ensure a negative return. */ + if( r < 0 ) { c->result = r; return; } + else { c->result = -1; return; } + + } + + /* Pass 2 is the bitwise complement of Pass 1. */ + dod[1] = ~ dod[0]; + + /* Run the DoD 5220.022-M short method. */ + c->result = nwipe_runmethod( c, patterns ); + + /* Finished. Set the thread ID to 0 so that the GUI knows */ + c->thread = 0; + +} /* nwipe_dodshort */ + + + +void *nwipe_gutmann( void *ptr ) +{ +/** + * Peter Gutmann's wipe. + * + */ + + nwipe_context_t *c; + c = (nwipe_context_t *) ptr; + + /* A result buffer. */ + int r; + + /* The number of patterns in the Guttman Wipe, also used to index the 'patterns' array. */ + int i = 35; + + /* An index into the 'book' array. */ + int j; + + /* The N-th element that has not been used. */ + int n; + + /* Define the Gutmann method. */ + nwipe_pattern_t book [] = + { + { -1, "" }, /* Random pass. */ + { -1, "" }, /* Random pass. */ + { -1, "" }, /* Random pass. */ + { -1, "" }, /* Random pass. */ + { 3, "\x55\x55\x55" }, /* Static pass: 0x555555 01010101 01010101 01010101 */ + { 3, "\xAA\xAA\xAA" }, /* Static pass: 0XAAAAAA 10101010 10101010 10101010 */ + { 3, "\x92\x49\x24" }, /* Static pass: 0x924924 10010010 01001001 00100100 */ + { 3, "\x49\x24\x92" }, /* Static pass: 0x492492 01001001 00100100 10010010 */ + { 3, "\x24\x92\x49" }, /* Static pass: 0x249249 00100100 10010010 01001001 */ + { 3, "\x00\x00\x00" }, /* Static pass: 0x000000 00000000 00000000 00000000 */ + { 3, "\x11\x11\x11" }, /* Static pass: 0x111111 00010001 00010001 00010001 */ + { 3, "\x22\x22\x22" }, /* Static pass: 0x222222 00100010 00100010 00100010 */ + { 3, "\x33\x33\x33" }, /* Static pass: 0x333333 00110011 00110011 00110011 */ + { 3, "\x44\x44\x44" }, /* Static pass: 0x444444 01000100 01000100 01000100 */ + { 3, "\x55\x55\x55" }, /* Static pass: 0x555555 01010101 01010101 01010101 */ + { 3, "\x66\x66\x66" }, /* Static pass: 0x666666 01100110 01100110 01100110 */ + { 3, "\x77\x77\x77" }, /* Static pass: 0x777777 01110111 01110111 01110111 */ + { 3, "\x88\x88\x88" }, /* Static pass: 0x888888 10001000 10001000 10001000 */ + { 3, "\x99\x99\x99" }, /* Static pass: 0x999999 10011001 10011001 10011001 */ + { 3, "\xAA\xAA\xAA" }, /* Static pass: 0xAAAAAA 10101010 10101010 10101010 */ + { 3, "\xBB\xBB\xBB" }, /* Static pass: 0xBBBBBB 10111011 10111011 10111011 */ + { 3, "\xCC\xCC\xCC" }, /* Static pass: 0xCCCCCC 11001100 11001100 11001100 */ + { 3, "\xDD\xDD\xDD" }, /* Static pass: 0xDDDDDD 11011101 11011101 11011101 */ + { 3, "\xEE\xEE\xEE" }, /* Static pass: 0xEEEEEE 11101110 11101110 11101110 */ + { 3, "\xFF\xFF\xFF" }, /* Static pass: 0xFFFFFF 11111111 11111111 11111111 */ + { 3, "\x92\x49\x24" }, /* Static pass: 0x924924 10010010 01001001 00100100 */ + { 3, "\x49\x24\x92" }, /* Static pass: 0x492492 01001001 00100100 10010010 */ + { 3, "\x24\x92\x49" }, /* Static pass: 0x249249 00100100 10010010 01001001 */ + { 3, "\x6D\xB6\xDB" }, /* Static pass: 0x6DB6DB 01101101 10110110 11011011 */ + { 3, "\xB6\xDB\x6D" }, /* Static pass: 0xB6DB6D 10110110 11011011 01101101 */ + { 3, "\xDB\x6D\xB6" }, /* Static pass: 0XDB6DB6 11011011 01101101 10110110 */ + { -1, "" }, /* Random pass. */ + { -1, "" }, /* Random pass. */ + { -1, "" }, /* Random pass. */ + { -1, "" }, /* Random pass. */ + { 0, NULL } + }; + + /* Put the book array into this array in random order. */ + nwipe_pattern_t patterns [36]; + + /* An entropy buffer. */ + u16 s [i]; + + /* Load the array with random characters. */ + r = read( c->entropy_fd, &s, sizeof( s ) ); + + if( r != sizeof( s ) ) + { + r = errno; + nwipe_perror( r, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the %s method.", nwipe_gutmann_label ); + + /* Ensure a negative return. */ + if( r < 0 ) { c->result = r; return; } + else { c->result = -1; return; } + } + + + while( --i >= 0 ) + { + + /* Get a random integer that is less than the first index 'i'. */ + n = (int)( (double)( s[i] ) / (double)( 0x0000FFFF + 1 ) * (double)( i + 1 ) ); + + /* Initialize the secondary index. */ + j = -1; + + while( n-- >= 0 ) + { + /* Advance 'j' by 'n' positions... */ + j += 1; + + /* ... but don't count 'book' elements that have already been copied. */ + while( book[j].length == 0 ) { j += 1; } + } + + /* Copy the element. */ + patterns[i] = book[j]; + + /* Mark this element as having been used. */ + book[j].length = 0; + + nwipe_log( NWIPE_LOG_DEBUG, "nwipe_gutmann: Set patterns[%i] = book[%i].", i, j ); + } + + /* Ensure that the array is terminated. */ + patterns[35].length = 0; + patterns[35].s = NULL; + + /* Run the Gutmann method. */ + c->result = nwipe_runmethod( c, patterns ); + + + /* Finished. Set the thread ID to 0 so that the GUI knows */ + c->thread = 0; + +} /* nwipe_gutmann */ + + + +void *nwipe_ops2( void *ptr ) +{ +/** + * Royal Canadian Mounted Police + * Technical Security Standard for Information Technology + * Appendix OPS-II: Media Sanitization + * + * NOTE: The last pass of this method is specially handled by nwipe_runmethod. + * + */ + + nwipe_context_t *c; + c = (nwipe_context_t *) ptr; + + /* A generic array index. */ + int i; + + /* A generic result buffer. */ + int r; + + /* A buffer for random characters. */ + char* s; + + /* A buffer for the bitwise complements of 's'. */ + char* t; + + /* The element count of 's' and 't'. */ + u32 u; + + /* The pattern array for this method is dynamically allocated. */ + nwipe_pattern_t* patterns; + + /* The element count of 'patterns'. */ + u32 q; + + + /* We need one random character per round. */ + u = 1 * nwipe_options.rounds; + + /* Allocate the array of random characters. */ + s = malloc( sizeof( char ) * u ); + + if( s == NULL ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate the random character array." ); + c->result = -1; + return; + } + + /* Allocate the array of complement characters. */ + t = malloc( sizeof( char ) * u ); + + if( s == NULL ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate the complement character array." ); + c->result = -1; + return; + } + + + /* We need eight pattern elements per round, plus one for padding. */ + q = 8 * u + 1; + + /* Allocate the pattern array. */ + patterns = malloc( sizeof( nwipe_pattern_t ) * q ); + + if( patterns == NULL ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate the pattern array." ); + c->result = -1; + return; + } + + + /* Load the array of random characters. */ + r = read( c->entropy_fd, s, u ); + + if( r != u ) + { + r = errno; + nwipe_perror( r, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the %s method.", nwipe_ops2_label ); + + /* Ensure a negative return. */ + if( r < 0 ) { c->result = r; return; } + else { c->result = -1; return; } + } + + + for( i = 0 ; i < u ; i += 1 ) + { + /* Populate the array of complements. */ + t[i] = ~s[i]; + } + + + for( i = 0 ; i < u ; i += 8 ) + { + /* Populate the array of patterns. */ + + /* Even elements point to the random characters. */ + patterns[i*4 +0].length = 1; + patterns[i*4 +0].s = &s[i]; + patterns[i*4 +2].length = 1; + patterns[i*4 +2].s = &s[i]; + patterns[i*4 +4].length = 1; + patterns[i*4 +4].s = &s[i]; + patterns[i*4 +6].length = 1; + patterns[i*4 +6].s = &s[i]; + + /* Odd elements point to the complement characters. */ + patterns[i*4 +1].length = 1; + patterns[i*4 +1].s = &t[i]; + patterns[i*4 +3].length = 1; + patterns[i*4 +3].s = &t[i]; + patterns[i*4 +5].length = 1; + patterns[i*4 +5].s = &t[i]; + patterns[i*4 +7].length = 1; + patterns[i*4 +7].s = &t[i]; + } + + /* Ensure that the array is terminated. */ + patterns[q-1].length = 0; + patterns[q-1].s = NULL; + + /* Run the TSSIT OPS-II method. */ + r = nwipe_runmethod( c, patterns ); + + /* Release the random character buffer. */ + free( s ); + + /* Release the complement character buffer */ + free( t ); + + /* Release the pattern buffer. */ + free( patterns ); + + /* We're done. */ + c->result = nwipe_runmethod( c, patterns ); + + + /* Finished. Set the thread ID to 0 so that the GUI knows */ + c->thread = 0; + +} /* nwipe_ops2 */ + + + +void *nwipe_random( void *ptr ) +{ +/** + * Fill the device with a stream from the PRNG. + * + */ + + nwipe_context_t *c; + c = (nwipe_context_t *) ptr; + + /* Define the random method. */ + nwipe_pattern_t patterns [] = + { + { -1, "" }, + { 0, NULL } + }; + + /* Run the method. */ + c->result = nwipe_runmethod( c, patterns ); + + + /* Finished. Set the thread ID to 0 so that the GUI knows */ + c->thread = 0; + +} /* nwipe_random */ + + + +int nwipe_runmethod( nwipe_context_t* c, nwipe_pattern_t* patterns ) +{ +/** + * Writes patterns to the device. + * + */ + + /* The result holder. */ + int r; + + /* An index variable. */ + int i = 0; + + /* The zero-fill pattern for the final pass of most methods. */ + nwipe_pattern_t pattern_zero = { 1, "\x00" }; + + + /* Create the PRNG state buffer. */ + c->prng_seed.length = NWIPE_KNOB_PRNG_STATE_LENGTH; + c->prng_seed.s = malloc( c->prng_seed.length ); + + /* Check the memory allocation. */ + if( ! c->prng_seed.s ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the prng seed buffer." ); + return -1; + } + + /* Count the number of patterns in the array. */ + while( patterns[i].length ) { i += 1; } + + /* Tell the parent the number of device passes that will be run in one round. */ + c->pass_count = i; + + /* Set the number of bytes that will be written across all passes in one round. */ + c->pass_size = c->pass_count * c->device_size; + + if( nwipe_options.verify == NWIPE_VERIFY_ALL ) + { + /* We must read back all passes, so double the byte count. */ + c->pass_size *= 2; + } + + + /* Tell the parent the number of rounds that will be run. */ + c->round_count = nwipe_options.rounds; + + /* Set the number of bytes that will be written across all rounds. */ + c->round_size = c->round_count * c->pass_size; + + /* The final pass is always a zero fill, except ops2 which is random. */ + /* Do not add if there is no blanking pass. */ + if ( nwipe_options.noblank == 0 ) + { + c->round_size += c->device_size; + } + + /* Set the round total count down */ + c->result = c->round_size; + + if((nwipe_options.verify == NWIPE_VERIFY_LAST || nwipe_options.verify == NWIPE_VERIFY_ALL) + && nwipe_options.noblank == 0 ) + { + /* We must read back the last pass to verify it. */ + c->round_size += c->device_size; + } + + + /* Initialize the working round counter. */ + c->round_working = 0; + + nwipe_log( NWIPE_LOG_NOTICE, "Invoking method '%s' on device '%s'.", \ + nwipe_method_label( nwipe_options.method ), c->device_name ); + + while( c->round_working < c->round_count ) + { + /* Increment the round counter. */ + c->round_working += 1; + + nwipe_log( NWIPE_LOG_NOTICE, "Starting round %i of %i on device '%s'.", \ + c->round_working, c->round_count, c->device_name ); + + /* Initialize the working pass counter. */ + c->pass_working = 0; + + for( i = 0 ; i < c->pass_count ; i++ ) + { + /* Increment the working pass. */ + c->pass_working += 1; + + nwipe_log( NWIPE_LOG_NOTICE, "Starting pass %i of %i, round %i of %i, on device '%s'.", \ + c->pass_working, c->pass_count, c->round_working, c->round_count, c->device_name ); + + if( patterns[i].length == 0 ) + { + /* Caught insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "nwipe_runmethod: A non-terminating pattern element has zero length." ); + return -1; + } + + if( patterns[i].length > 0 ) + { + + /* Write a static pass. */ + c->pass_type = NWIPE_PASS_WRITE; + r = nwipe_static_pass( c, &patterns[i] ); + c->pass_type = NWIPE_PASS_NONE; + + /* Log number of bytes written to disk */ + nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes written to device '%s'.", \ + c->pass_done, c->device_name ); + + /* Check for a fatal error. */ + if( r < 0 ) { return r; } + + if( nwipe_options.verify == NWIPE_VERIFY_ALL ) + { + + nwipe_log( NWIPE_LOG_NOTICE, "Verifying pass %i of %i, round %i of %i, on device '%s'.", \ + c->pass_working, c->pass_count, c->round_working, c->round_count, c->device_name ); + + /* Verify this pass. */ + c->pass_type = NWIPE_PASS_VERIFY; + r = nwipe_static_verify( c, &patterns[i] ); + c->pass_type = NWIPE_PASS_NONE; + + /* Check for a fatal error. */ + if( r < 0 ) { return r; } + + nwipe_log( NWIPE_LOG_NOTICE, "Verified pass %i of %i, round %i of %i, on device '%s'.", \ + c->pass_working, c->pass_count, c->round_working, c->round_count, c->device_name ); + } + + } /* static pass */ + + else + { + c->pass_type = NWIPE_PASS_WRITE; + + /* Seed the PRNG. */ + r = read( c->entropy_fd, c->prng_seed.s, c->prng_seed.length ); + + /* Check the result. */ + if( r < 0 ) + { + c->pass_type = NWIPE_PASS_NONE; + nwipe_perror( errno, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the PRNG." ); + return -1; + } + + /* Check for a partial read. */ + if( r != c->prng_seed.length ) + { + /* TODO: Handle partial reads. */ + nwipe_log( NWIPE_LOG_FATAL, "Insufficient entropy is available." ); + return -1; + } + + /* Write the random pass. */ + r = nwipe_random_pass( c ); + c->pass_type = NWIPE_PASS_NONE; + + /* Log number of bytes written to disk */ + nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes written to device '%s'.", \ + c->pass_done, c->device_name ); + + /* Check for a fatal error. */ + if( r < 0 ) { return r; } + + if( nwipe_options.verify == NWIPE_VERIFY_ALL ) + { + nwipe_log( NWIPE_LOG_NOTICE, "Verifying pass %i of %i, round %i of %i, on device '%s'.", \ + c->pass_working, c->pass_count, c->round_working, c->round_count, c->device_name ); + + /* Verify this pass. */ + c->pass_type = NWIPE_PASS_VERIFY; + r = nwipe_random_verify( c ); + c->pass_type = NWIPE_PASS_NONE; + + /* Check for a fatal error. */ + if( r < 0 ) { return r; } + + nwipe_log( NWIPE_LOG_NOTICE, "Verified pass %i of %i, round %i of %i, on device '%s'.", \ + c->pass_working, c->pass_count, c->round_working, c->round_count, nwipe_method_label( nwipe_options.method ) ); + } + + } /* random pass */ + + nwipe_log( NWIPE_LOG_NOTICE, "Finished pass %i of %i, round %i of %i, on device '%s'.", \ + c->pass_working, c->pass_count, c->round_working, c->round_count, c->device_name ); + + } /* for passes */ + + nwipe_log( NWIPE_LOG_NOTICE, "Finished round %i of %i on device '%s'.", \ + c->round_working, c->round_count, c->device_name ); + + } /* while rounds */ + + + if( nwipe_options.method == &nwipe_ops2 ) + { + /* NOTE: The OPS-II method specifically requires that a random pattern be left on the device. */ + + /* Tell the parent that we are running the final pass. */ + c->pass_type = NWIPE_PASS_FINAL_OPS2; + + /* Seed the PRNG. */ + r = read( c->entropy_fd, c->prng_seed.s, c->prng_seed.length ); + + /* Check the result. */ + if( r < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the PRNG." ); + return -1; + } + + /* Check for a partial read. */ + if( r != c->prng_seed.length ) + { + /* TODO: Handle partial reads. */ + nwipe_log( NWIPE_LOG_FATAL, "Insufficient entropy is available." ); + return -1; + } + + nwipe_log( NWIPE_LOG_NOTICE, "Writing final random pattern to '%s'.", c->device_name ); + + /* The final ops2 pass. */ + r = nwipe_random_pass( c ); + + /* Check for a fatal error. */ + if( r < 0 ) { return r; } + + if( nwipe_options.verify == NWIPE_VERIFY_LAST || nwipe_options.verify == NWIPE_VERIFY_ALL ) + { + nwipe_log( NWIPE_LOG_NOTICE, "Verifying the final random pattern on '%s' is empty.", c->device_name ); + + /* Verify the final zero pass. */ + r = nwipe_random_verify( c ); + + /* Check for a fatal error. */ + if( r < 0 ) { return r; } + + nwipe_log( NWIPE_LOG_NOTICE, "Verified the final random pattern on '%s' is empty.", c->device_name ); + } + + nwipe_log( NWIPE_LOG_NOTICE, "Wrote final random pattern to '%s'.", c->device_name ); + + } /* final ops2 */ + + + else if (nwipe_options.noblank == 0) + { + /* Tell the user that we are on the final pass. */ + c->pass_type = NWIPE_PASS_FINAL_BLANK; + + nwipe_log( NWIPE_LOG_NOTICE, "Blanking device '%s'.", c->device_name ); + + /* The final zero pass. */ + r = nwipe_static_pass( c, &pattern_zero ); + + /* Check for a fatal error. */ + if( r < 0 ) { return r; } + + + if( nwipe_options.verify == NWIPE_VERIFY_LAST || nwipe_options.verify == NWIPE_VERIFY_ALL ) + { + nwipe_log( NWIPE_LOG_NOTICE, "Verifying that '%s' is empty.", c->device_name ); + + /* Verify the final zero pass. */ + r = nwipe_static_verify( c, &pattern_zero ); + + /* Check for a fatal error. */ + if( r < 0 ) { return r; } + + nwipe_log( NWIPE_LOG_NOTICE, "Verified that '%s' is empty.", c->device_name ); + } + + nwipe_log( NWIPE_LOG_NOTICE, "Blanked device '%s'.", c->device_name ); + + } /* final blank */ + + /* Release the state buffer. */ + c->prng_seed.length = 0; + free( c->prng_seed.s ); + + /* Tell the parent that we have fininshed the final pass. */ + c->pass_type = NWIPE_PASS_NONE; + + if( c->verify_errors > 0 ) + { + /* We finished, but with non-fatal verification errors. */ + nwipe_log( NWIPE_LOG_ERROR, "%llu verification errors on device '%s'.", c->verify_errors, c->device_name ); + } + + if( c->pass_errors > 0 ) + { + /* We finished, but with non-fatal wipe errors. */ + nwipe_log( NWIPE_LOG_ERROR, "%llu wipe errors on device '%s'.", c->pass_errors, c->device_name ); + } + + /* FIXME: The 'round_errors' context member is not being used. */ + + if( c->pass_errors > 0 || c->round_errors > 0 || c->verify_errors > 0 ) + { + /* We finished, but with non-fatal errors. */ + return 1; + } + + /* We finished successfully. */ + return 0; + +} /* nwipe_runmethod */ + + +/* eof */ diff --git a/src/method.h b/src/method.h new file mode 100644 index 0000000..9661651 --- /dev/null +++ b/src/method.h @@ -0,0 +1,58 @@ +/* + * methods.c: Method implementations for nwipe. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#ifndef METHOD_H_ +#define METHOD_H_ + +/* The argument list for nwipe methods. */ +#define NWIPE_METHOD_SIGNATURE nwipe_context_t* c + +typedef enum nwipe_verify_t_ +{ + NWIPE_VERIFY_NONE = 0, /* Do not read anything back from the device. */ + NWIPE_VERIFY_LAST, /* Check the last pass. */ + NWIPE_VERIFY_ALL, /* Check all passes. */ +} nwipe_verify_t; + +/* The typedef of the function that will do the wipe. */ +typedef int(*nwipe_method_t)( void *ptr ); + +typedef struct /* nwipe_pattern_t */ +{ + int length; /* Length of the pattern in bytes, -1 means random. */ + char* s; /* The actual bytes of the pattern. */ +} nwipe_pattern_t; + +const char* nwipe_method_label( void* method ); +int nwipe_runmethod( NWIPE_METHOD_SIGNATURE, nwipe_pattern_t* patterns ); + +void *nwipe_dod522022m( void *ptr ); +void *nwipe_dodshort( void *ptr ); +void *nwipe_gutmann( void *ptr ); +void *nwipe_ops2( void *ptr ); +void *nwipe_random( void *ptr ); +void *nwipe_zero( void *ptr ); + +#endif /* METHOD_H_ */ + +/* eof */ diff --git a/src/mt19937ar-cok.c b/src/mt19937ar-cok.c new file mode 100644 index 0000000..63ef659 --- /dev/null +++ b/src/mt19937ar-cok.c @@ -0,0 +1,139 @@ +/* + This code is modified for use in nwipe. + + A C-program for MT19937, with initialization improved 2002/2/10. + Coded by Takuji Nishimura and Makoto Matsumoto. + This is a faster version by taking Shawn Cokus's optimization, + Matthe Bellew's simplification, Isaku Wada's real version. + + Before using, initialize the state by using init_genrand(seed) + or init_by_array(init_key, key_length). + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Any feedback is very welcome. + http://www.math.keio.ac.jp/matumoto/emt.html + email: matumoto@math.keio.ac.jp +*/ + +#include +#include "mt19937ar-cok.h" + +/* initializes state[N] with a seed */ +void init_genrand( twister_state_t* state, unsigned long s) +{ + int j; + state->array[0]= s & 0xffffffffUL; + for( j = 1; j < N; j++ ) + { + state->array[j] = (1812433253UL * (state->array[j-1] ^ (state->array[j-1] >> 30)) + j); + state->array[j] &= 0xffffffffUL; /* for >32 bit machines */ + } + state->left = 1; + state->initf = 1; +} + + +void twister_init( twister_state_t* state, unsigned long init_key[], unsigned long key_length ) +{ + int i = 1; + int j = 0; + int k = ( N > key_length ? N : key_length ); + + init_genrand( state, 19650218UL ); + + for( ; k; k-- ) + { + state->array[i] = (state->array[i] ^ ((state->array[i-1] ^ (state->array[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; + state->array[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + ++i; + ++j; + + if ( i >= N ) + { + state->array[0] = state->array[N-1]; + i = 1; + } + + if ( j >= key_length ) + { + j = 0; + } + } + + for( k = N -1; k; k-- ) + { + state->array[i] = (state->array[i] ^ ((state->array[i-1] ^ (state->array[i-1] >> 30)) * 1566083941UL)) - i; + state->array[i] &= 0xffffffffUL; + ++i; + + if ( i >= N ) + { + state->array[0] = state->array[N-1]; + i = 1; + } + } + + state->array[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ + state->left = 1; + state->initf = 1; +} + +static void next_state( twister_state_t* state ) +{ + unsigned long *p = state->array; + int j; + + if( state->initf == 0) { init_genrand( state, 5489UL ); } + state->left = N; + state->next = state->array; + for( j = N - M + 1; --j; p++ ) { *p = p[M] ^ TWIST(p[0], p[1]); } + for( j = M; --j; p++ ) { *p = p[M-N] ^ TWIST(p[0], p[1]); } + *p = p[M-N] ^ TWIST(p[0], state->array[0]); +} + +/* generates a random number on [0,0xffffffff]-interval */ +unsigned long twister_genrand_int32( twister_state_t* state ) +{ + unsigned long y; + + if ( --state->left == 0 ) { next_state( state ); } + y = *state->next++; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} diff --git a/src/mt19937ar-cok.h b/src/mt19937ar-cok.h new file mode 100644 index 0000000..afcc873 --- /dev/null +++ b/src/mt19937ar-cok.h @@ -0,0 +1,32 @@ +/* + * mt19937ar-cok.h: The Mersenne Twister PRNG implementation for nwipe. + * + */ + +#ifndef MT19937AR_H_ +#define MT19937AR_H_ + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UMASK 0x80000000UL /* most significant w-r bits */ +#define LMASK 0x7fffffffUL /* least significant r bits */ +#define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) ) +#define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL)) + +typedef struct twister_state_t_ +{ + unsigned long array[N]; + int left; + int initf; + unsigned long *next; +} twister_state_t; + +/* Initialize the MT state. ( 0 < key_length <= 624 ). */ +void twister_init( twister_state_t* state, unsigned long init_key[], unsigned long key_length); + +/* Generate a random integer on the [0,0xffffffff] interval. */ +unsigned long twister_genrand_int32( twister_state_t* state ); + +#endif /* MT19937AR_H_ */ diff --git a/src/nwipe.c b/src/nwipe.c new file mode 100644 index 0000000..83f1de8 --- /dev/null +++ b/src/nwipe.c @@ -0,0 +1,573 @@ +/* vi: tabstop=3 + * + * nwipe.c: Darik's Wipe. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "device.h" +#include "logging.h" +#include "gui.h" + + +#include /* FIXME: Twice Included */ +#include +#include + +#include +#include + +int main( int argc, char** argv ) +{ + int nwipe_optind; /* The result of nwipe_options(). */ + int nwipe_enumerated; /* The number of contexts that have been enumerated. */ + int nwipe_error = 0; /* An error counter. */ + int nwipe_selected = 0; /* The number of contexts that have been selected. */ + int nwipe_shmid; /* A shared memory handle for the context array. */ + int nwipe_wait = 0; /* The number of child processes that have returned. */ + pthread_t nwipe_gui_thread; /* The thread ID of the GUI thread. */ + pthread_t nwipe_sigint_thread; /* The thread ID of the sigint handler. */ + + /* The list of device filenames. */ + char** nwipe_names = NULL; + + /* Used to write-out the result file. */ + char nwipe_result_file [FILENAME_MAX]; + FILE* nwipe_result_fp; + + /* The entropy source file handle. */ + int nwipe_entropy; + + /* The generic index variables. */ + int i; + int j; + + /* The generic result buffer. */ + int r; + + /* Two arrays are used, containing pointers to the the typedef for each disk */ + /* The first array (c1) points to all devices, the second points to only */ + /* the disks selected for wiping. */ + + /* The array of pointers to enumerated contexts. */ + /* Initialised and populated in device scan. */ + nwipe_context_t **c1 = 0; + + /* Parse command line options. */ + nwipe_optind = nwipe_options_parse( argc, argv ); + + if( nwipe_optind == argc ) + { + /* File names were not given by the user. Scan for devices. */ + + nwipe_enumerated = nwipe_device_scan( &c1 ); + + if( nwipe_enumerated == 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "Storage devices not found." ); + return -1; + } + + else + { + nwipe_log( NWIPE_LOG_INFO, "Automatically enumerated %i devices.", nwipe_enumerated ); + } + } + + else + { + + argv += nwipe_optind; + argc -= nwipe_optind; + + nwipe_enumerated = nwipe_device_get( &c1, argv, argc ); + } + + + /* Open the entropy source. */ + nwipe_entropy = open( NWIPE_KNOB_ENTROPY, O_RDONLY ); + + /* Check the result. */ + if( nwipe_entropy < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "open" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to open entropy source %s.", NWIPE_KNOB_ENTROPY ); + return errno; + } + + nwipe_log( NWIPE_LOG_NOTICE, "Opened entropy source '%s'.", NWIPE_KNOB_ENTROPY ); + + /* Block relevant signals in main thread. Any other threads that are */ + /* created after this will also block those signals. */ + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGHUP); + sigaddset(&sigset, SIGTERM); + sigaddset(&sigset, SIGQUIT); + sigaddset(&sigset, SIGINT); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + + /* Create a signal handler thread. This thread will catch all */ + /* signals and decide what to do with them. This will only */ + /* catch nondirected signals. (I.e., if a thread causes a SIGFPE */ + /* then that thread will get that signal. */ + + /* Pass a pointer to a struct containing all data to the signal handler. */ + nwipe_misc_thread_data_t nwipe_misc_thread_data; + nwipe_thread_data_ptr_t nwipe_thread_data_ptr; + + nwipe_thread_data_ptr.c = c1; + nwipe_misc_thread_data.nwipe_enumerated = nwipe_enumerated; + if( !nwipe_options.nogui ) + nwipe_misc_thread_data.gui_thread = &nwipe_gui_thread; + nwipe_thread_data_ptr.nwipe_misc_thread_data = &nwipe_misc_thread_data; + + pthread_attr_t pthread_attr; + pthread_attr_init(&pthread_attr); + pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_DETACHED); + + pthread_create( &nwipe_sigint_thread, &pthread_attr, signal_hand, &nwipe_thread_data_ptr); + + + /* A context struct for each device has already been created. */ + /* Now set specific nwipe options */ + for( i = 0; i < nwipe_enumerated; i++ ) + { + + /* Set the entropy source. */ + c1[i]->entropy_fd = nwipe_entropy; + + if( nwipe_options.autonuke ) + { + /* When the autonuke option is set, select all disks. */ + //TODO - partitions + //if( c1[i].device_part == 0 ) { c1[i].select = NWIPE_SELECT_TRUE; } + //else { c1[i].select = NWIPE_SELECT_TRUE_PARENT; } + c1[i]->select = NWIPE_SELECT_TRUE; + } + + else + { + /* The user must manually select devices. */ + c1[i]->select = NWIPE_SELECT_FALSE; + } + + /* Set the PRNG implementation. */ + c1[i]->prng = nwipe_options.prng; + c1[i]->prng_seed.length = 0; + c1[i]->prng_seed.s = 0; + c1[i]->prng_state = 0; + + } /* file arguments */ + + /* Check for initialization errors. */ + if( nwipe_error ) { return -1; } + + /* Start the ncurses interface. */ + if( !nwipe_options.nogui ) + nwipe_gui_init(); + + if( nwipe_options.autonuke == 1 ) + { + /* Print the options window. */ + if( !nwipe_options.nogui ) + nwipe_gui_options(); + } + else + { + /* Get device selections from the user. */ + if( nwipe_options.nogui ) + { + printf("--nogui option must be used with autonuke option\n"); + exit(1); + } + else + { + nwipe_gui_select( nwipe_enumerated, c1 ); + } + } + + + /* Count the number of selected contexts. */ + for( i = 0 ; i < nwipe_enumerated ; i++ ) + { + if( c1[i]->select == NWIPE_SELECT_TRUE ) + { + nwipe_selected += 1; + } + } + + /* Pass the number selected to the struct for other threads */ + nwipe_misc_thread_data.nwipe_selected = nwipe_selected; + + /* The array of pointers to contexts that will actually be wiped. */ + nwipe_context_t **c2 = (nwipe_context_t **)malloc(nwipe_enumerated * sizeof(nwipe_context_t *)); + + /* Populate the array of selected contexts. */ + for( i = 0, j = 0 ; i < nwipe_enumerated ; i++ ) + { + if( c1[i]->select == NWIPE_SELECT_TRUE ) + { + /* Copy the context. */ + c2[j++] = c1[i]; + } + + } /* for */ + + /* TODO: free c1 and c2 memory. */ + + for( i = 0 ; i < nwipe_selected ; i++ ) + { + + /* A result buffer for the BLKGETSIZE64 ioctl. */ + u64 size64; + + /* Open the file for reads and writes. */ + c2[i]->device_fd = open( c2[i]->device_name, O_RDWR ); + + /* Check the open() result. */ + if( c2[i]->device_fd < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "open" ); + nwipe_log( NWIPE_LOG_WARNING, "Unable to open device '%s'.", c2[i]->device_name ); + c2[i]->select = NWIPE_SELECT_DISABLED; + continue; + } + + /* Stat the file. */ + if( fstat( c2[i]->device_fd, &c2[i]->device_stat ) != 0 ) + { + nwipe_perror( errno, __FUNCTION__, "fstat"); + nwipe_log( NWIPE_LOG_ERROR, "Unable to stat file '%s'.", c2[i]->device_name ); + nwipe_error++; + continue; + } + + /* Check that the file is a block device. */ + if( ! S_ISBLK( c2[i]->device_stat.st_mode ) ) + { + nwipe_log( NWIPE_LOG_ERROR, "'%s' is not a block device.", c2[i]->device_name ); + nwipe_error++; + continue; + } + + /* TODO: Lock the file for exclusive access. */ + /* + if( flock( c2[i]->device_fd, LOCK_EX | LOCK_NB ) != 0 ) + { + nwipe_perror( errno, __FUNCTION__, "flock" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to lock the '%s' file.", c2[i]->device_name ); + nwipe_error++; + continue; + } + */ + + /* Attempt to get serial number of device. */ + + ioctl(c2[i]->device_fd, HDIO_GET_IDENTITY, &c2[i]->identity); + if ( c2[i]->identity.serial_no ) { + nwipe_log( NWIPE_LOG_INFO, "Device %s has serial number %s", c2[i]->device_name, c2[i]->identity.serial_no); + } + + + /* Do sector size and block size checking. */ + + if( ioctl( c2[i]->device_fd, BLKSSZGET, &c2[i]->sector_size ) == 0 ) + { + nwipe_log( NWIPE_LOG_INFO, "Device '%s' has sector size %i.", c2[i]->device_name, c2[i]->sector_size ); + + if( ioctl( c2[i]->device_fd, BLKBSZGET, &c2[i]->block_size ) == 0 ) + { + if( c2[i]->block_size != c2[i]->sector_size ) + { + nwipe_log( NWIPE_LOG_WARNING, "Changing '%s' block size from %i to %i.", c2[i]->device_name, c2[i]->block_size, c2[i]->sector_size ); + if( ioctl( c2[i]->device_fd, BLKBSZSET, &c2[i]->sector_size ) == 0 ) + { + c2[i]->block_size = c2[i]->sector_size; + } + + else + { + nwipe_log( NWIPE_LOG_WARNING, "Device '%s' failed BLKBSZSET ioctl.", c2[i]->device_name ); + } + } + } + else + { + nwipe_log( NWIPE_LOG_WARNING, "Device '%s' failed BLKBSZGET ioctl.", c2[i]->device_name ); + c2[i]->block_size = 0; + } + } + + else + { + nwipe_log( NWIPE_LOG_WARNING, "Device '%s' failed BLKSSZGET ioctl.", c2[i]->device_name ); + c2[i]->sector_size = 0; + c2[i]->block_size = 0; + } + + + /* The st_size field is zero for block devices. */ + /* ioctl( c2[i]->device_fd, BLKGETSIZE64, &c2[i]->device_size ); */ + + /* Seek to the end of the device to determine its size. */ + c2[i]->device_size = lseek( c2[i]->device_fd, 0, SEEK_END ); + + /* Also ask the driver for the device size. */ + /* if( ioctl( c2[i]->device_fd, BLKGETSIZE64, &size64 ) ) */ + if( ioctl( c2[i]->device_fd, _IOR(0x12,114,size_t), &size64 ) ) + { + /* The ioctl failed. */ + fprintf( stderr, "Error: BLKGETSIZE64 failed on '%s'.\n", c2[i]->device_name ); + nwipe_log( NWIPE_LOG_ERROR, "BLKGETSIZE64 failed on '%s'.\n", c2[i]->device_name ); + nwipe_error++; + } + c2[i]->device_size = size64; + + /* Check whether the two size values agree. */ + if( c2[i]->device_size != size64 ) + { + /* This could be caused by the linux last-odd-block problem. */ + fprintf( stderr, "Error: Last-odd-block detected on '%s'.\n", c2[i]->device_name ); + nwipe_log( NWIPE_LOG_ERROR, "Last-odd-block detected on '%s'.", c2[i]->device_name ); + nwipe_error++; + } + + + if( c2[i]->device_size == (loff_t)-1 ) + { + /* We cannot determine the size of this device. */ + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to determine the size of '%s'.", c2[i]->device_name ); + nwipe_error++; + } + + else + { + /* Reset the file pointer. */ + r = lseek( c2[i]->device_fd, 0, SEEK_SET ); + + if( r == (loff_t)-1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to reset the '%s' file offset.", c2[i]->device_name ); + nwipe_error++; + } + } + + + if( c2[i]->device_size == 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, "Device '%s' is size %llu.", c2[i]->device_name, c2[i]->device_size ); + nwipe_error++; + continue; + } + + else + { + nwipe_log( NWIPE_LOG_INFO, "Device '%s' is size %llu.", c2[i]->device_name, c2[i]->device_size ); + } + + + /* Fork a child process. */ + errno = pthread_create( &c2[i]->thread, NULL, nwipe_options.method, (void*) c2[i]); + if ( errno ) { + nwipe_perror( errno, __FUNCTION__, "pthread_create" ); + if( !nwipe_options.nogui ) + nwipe_gui_free(); + return errno; + } + + } /* new thread */ + + + /* Change the terminal mode to non-blocking input. */ + nodelay( stdscr, 0 ); + + /* Set getch to delay in order to slow screen updates. */ + halfdelay( NWIPE_KNOB_SLEEP * 10 ); + + /* Set up data structs to pass the GUI thread the data it needs. */ + nwipe_thread_data_ptr_t nwipe_gui_data; + if( !nwipe_options.nogui ) + { + nwipe_gui_data.c = c2; + nwipe_gui_data.nwipe_misc_thread_data = &nwipe_misc_thread_data; + /* Fork the GUI thread. */ + errno = pthread_create( &nwipe_gui_thread, NULL, nwipe_gui_status, &nwipe_gui_data); + } + + + /* Wait for all the wiping threads to finish. */ + for( i = 0 ; i < nwipe_selected ; i++ ) + { + + if ( c2[i]->thread ) + { + pthread_join( c2[i]->thread, NULL); + + /* Close the device file descriptor. */ + close( c2[i]->device_fd ); + } + + } + + + /* Kill the GUI thread */ + /* It may not be running if the program was interrupted */ + if ( nwipe_gui_thread ) + { + pthread_join( nwipe_gui_thread, NULL ); + + nocbreak(); + // timeout(-1); + /* Wait for enter key to be pressed unless --nowait + was specified. */ + if( !nwipe_options.nowait ) + getch(); + + /* Release the gui. */ + nwipe_gui_free(); + + } + + nwipe_log( NWIPE_LOG_NOTICE, "Nwipe exited." ); + + for( i = 0 ; i < nwipe_selected ; i++ ) + { + + /* Check for fatal errors. */ + if( c2[i]->result < 0 ){ return -1; } + + } + + for( i = 0 ; i < nwipe_selected ; i++ ) + { + + /* Check for non-fatal errors. */ + if( c2[i]->result > 0 ){ return 1; } + + } + + /* Flush any remaining logs. */ + for (i=0; i < log_current_element; i++) + { + printf("%s\n", log_lines[i]); + } + + /* Success. */ + return 0; + +} /* main */ + + +void *signal_hand(void *ptr) +{ + int sig; + // Define signals that this handler should react to + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGHUP); + sigaddset(&sigset, SIGTERM); + sigaddset(&sigset, SIGQUIT); + sigaddset(&sigset, SIGINT); + + int i; + + /* Set up the structs we will use for the data required. */ + nwipe_thread_data_ptr_t *nwipe_thread_data_ptr; + nwipe_context_t **c; + nwipe_misc_thread_data_t *nwipe_misc_thread_data; + + /* Retrieve from the pointer passed to the function. */ + nwipe_thread_data_ptr = (nwipe_thread_data_ptr_t *) ptr; + c = nwipe_thread_data_ptr->c; + nwipe_misc_thread_data = nwipe_thread_data_ptr->nwipe_misc_thread_data; + + + while (1) { + /* wait for a signal to arrive */ + + sigwait(&sigset,&sig); + + switch ( sig ) { + + case SIGHUP : + case SIGINT : + case SIGQUIT : + case SIGTERM : + { + + for( i = 0; i < nwipe_misc_thread_data->nwipe_enumerated; i++ ) + { + + if ( c[i]->thread ) + { + pthread_cancel( c[i]->thread ); + } + } + + // Kill the GUI thread + if( !nwipe_options.nogui ) + { + if ( nwipe_misc_thread_data->gui_thread ) + { + pthread_cancel( *nwipe_misc_thread_data->gui_thread ); + *nwipe_misc_thread_data->gui_thread = 0; + } + } + + if( !nwipe_options.nogui ) + nwipe_gui_free(); + + /* Flush any remaining logs. */ + for (i=0; i < log_current_element; i++) + { + printf("%s\n", log_lines[i]); + } + + + printf("Program interrupted (caught signal %d)\n", sig); + + // Cleanup + // TODO: All other cleanup required + + exit(0); + + } /* end case */ + + } /* end switch */ + + } /* end of while */ + + return((void *)0); + +} /* end of signal_hand */ + + +/* eof */ diff --git a/src/nwipe.h b/src/nwipe.h new file mode 100644 index 0000000..600c6e6 --- /dev/null +++ b/src/nwipe.h @@ -0,0 +1,102 @@ +/* + * nwipe.h: The header file of the nwipe program. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef NWIPE_H_ +#define NWIPE_H_ + +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif + +/* Busybox headers. */ +#ifdef BB_VER +#include "busybox.h" +#endif + +/* System headers. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +/* System errors. */ +extern int errno; + +/* Global array to hold log values to print when logging to STDOUT */ +extern char **log_lines; +extern int log_current_element; +extern int log_elements_allocated; +extern pthread_mutex_t mutex1; + +/* Ncurses headers. Assume panel.h is in same place.*/ +#ifdef NCURSES_IN_SUBDIR + #include + #include +#else + #include + #include +#endif + +/* Kernel device headers. */ +#include + +/* These types are usually defined in for __KERNEL__ code. */ +typedef unsigned long long u64; +typedef unsigned long u32; +typedef unsigned short u16; +typedef unsigned char u8; + +/* This is required for ioctl BLKGETSIZE64, but it conflicts with . */ +/* #include */ + +/* Define ioctls that cannot be included. */ +#define BLKSSZGET _IO(0x12,104) +#define BLKBSZGET _IOR(0x12,112,size_t) +#define BLKBSZSET _IOW(0x12,113,size_t) +#define BLKGETSIZE64 _IOR(0x12,114,sizeof(u64)) + +/* This is required for ioctl FDFLUSH. */ +#include + +void *signal_hand(void *); + +#endif /* NWIPE_H_ */ + +/* eof */ diff --git a/src/options.c b/src/options.c new file mode 100644 index 0000000..96b9a31 --- /dev/null +++ b/src/options.c @@ -0,0 +1,403 @@ +/* + * options.c: Command line processing routines for nwipe. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "logging.h" +#include "version.h" + +/* The global options struct. */ +nwipe_options_t nwipe_options; + +int nwipe_options_parse( int argc, char** argv ) +{ + extern char* optarg; /* The working getopt option argument. */ + extern int optind; /* The working getopt index into argv. */ + extern int optopt; /* The last unhandled getopt option. */ + extern int opterr; /* The last getopt error number. */ + + extern nwipe_prng_t nwipe_twister; + extern nwipe_prng_t nwipe_isaac; + + /* The maximum banner size, including the null. */ + const int nwipe_banner_size = 81; + + /* The getopt() result holder. */ + int nwipe_opt; + + /* Array index variable. */ + int i; + + /* The list of acceptable short options. */ + char nwipe_options_short [] = "Vhl:hm:p:r:"; + + /* The list of acceptable long options. */ + static struct option nwipe_options_long [] = + { + /* Set when the user wants to wipe without a confirmation prompt. */ + { "autonuke", no_argument, 0, 0 }, + + /* A GNU standard option. Corresponds to the 'h' short option. */ + { "help", no_argument, 0, 'h' }, + + /* The wipe method. Corresponds to the 'm' short option. */ + { "method", required_argument, 0, 'm' }, + + /* Log file. Corresponds to the 'l' short option. */ + { "logfile", required_argument, 0, 'l' }, + + /* The Pseudo Random Number Generator. */ + { "prng", required_argument, 0, 'p' }, + + /* The number of times to run the method. */ + { "rounds", required_argument, 0, 'r' }, + + /* Whether to blank the disk after wiping. */ + { "noblank", no_argument, 0, 0 }, + + /* Whether to exit after wiping or wait for a keypress. */ + { "nowait", no_argument, 0, 0 }, + + /* Whether to exit after wiping or wait for a keypress. */ + { "nogui", no_argument, 0, 0 }, + + /* A flag to indicate whether the devices whould be opened in sync mode. */ + { "sync", no_argument, 0, 0 }, + + /* Verify that wipe patterns are being written to the device. */ + { "verify", required_argument, 0, 0 }, + + /* Display program version. */ + { "version", no_argument, 0, 'V' }, + + /* Requisite padding for getopt(). */ + { 0, 0, 0, 0 } + }; + + /* Note that COLS isn't available until ncurses is initialized. */ + nwipe_options.banner = malloc( nwipe_banner_size ); + + /* Set the default product banner. */ + /* TODO: Add version constant. */ + strncpy ( nwipe_options.banner, program_name, nwipe_banner_size); + strncat ( nwipe_options.banner, " ", nwipe_banner_size - strlen (nwipe_options.banner) - 1); + strncat ( nwipe_options.banner, version_string, nwipe_banner_size - strlen (nwipe_options.banner) - 1); + strncat ( nwipe_options.banner, " (based on DBAN's dwipe - Darik's Wipe)", nwipe_banner_size - strlen (nwipe_options.banner) - 1); + + /* Set default options. */ + nwipe_options.autonuke = 0; + nwipe_options.method = &nwipe_dodshort; + nwipe_options.prng = &nwipe_twister; + nwipe_options.rounds = 1; + nwipe_options.noblank = 0; + nwipe_options.nowait = 0; + nwipe_options.nogui = 0; + nwipe_options.sync = 0; + nwipe_options.verify = NWIPE_VERIFY_LAST; + memset( nwipe_options.logfile, '\0', sizeof(nwipe_options.logfile) ); + + + /* Parse command line options. */ + while( 1 ) + { + /* Get the next command line option with (3)getopt. */ + nwipe_opt = getopt_long( argc, argv, nwipe_options_short, nwipe_options_long, &i ); + + /* Break when we have processed all of the given options. */ + if( nwipe_opt < 0 ) { break; } + + switch( nwipe_opt ) + { + case 0: /* Long options without short counterparts. */ + + if( strcmp( nwipe_options_long[i].name, "autonuke" ) == 0 ) + { + nwipe_options.autonuke = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "noblank" ) == 0 ) + { + nwipe_options.noblank = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "nowait" ) == 0 ) + { + nwipe_options.nowait = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "nogui" ) == 0 ) + { + nwipe_options.nogui = 1; + nwipe_options.nowait = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "sync" ) == 0 ) + { + nwipe_options.sync = 1; + break; + } + + if( strcmp( nwipe_options_long[i].name, "verify" ) == 0 ) + { + + if( strcmp( optarg, "0" ) == 0 || strcmp( optarg, "off" ) == 0 ) + { + nwipe_options.verify = NWIPE_VERIFY_NONE; + break; + } + + if( strcmp( optarg, "1" ) == 0 || strcmp( optarg, "last" ) == 0 ) + { + nwipe_options.verify = NWIPE_VERIFY_LAST; + break; + } + + if( strcmp( optarg, "2" ) == 0 || strcmp( optarg, "all" ) == 0 ) + { + nwipe_options.verify = NWIPE_VERIFY_ALL; + break; + } + + /* Else we do not know this verification level. */ + fprintf( stderr, "Error: Unknown verification level '%s'.\n", optarg ); + exit( EINVAL ); + + } + + + case 'm': /* Method option. */ + + if( strcmp( optarg, "dod522022m" ) == 0 || strcmp( optarg, "dod" ) == 0 ) + { + nwipe_options.method = &nwipe_dod522022m; + break; + } + + if( strcmp( optarg, "dodshort" ) == 0 || strcmp( optarg, "dod3pass" ) == 0 ) + { + nwipe_options.method = &nwipe_dodshort; + break; + } + + if( strcmp( optarg, "gutmann" ) == 0 ) + { + nwipe_options.method = &nwipe_gutmann; + break; + } + + if( strcmp( optarg, "ops2" ) == 0 ) + { + nwipe_options.method = &nwipe_ops2; + break; + } + + if( strcmp( optarg, "random" ) == 0 + || strcmp( optarg, "prng" ) == 0 + || strcmp( optarg, "stream" ) == 0 + ) + { + nwipe_options.method= &nwipe_random; + break; + } + + if( strcmp( optarg, "zero" ) == 0 || strcmp( optarg, "quick" ) == 0 ) + { + nwipe_options.method = &nwipe_zero; + break; + } + + /* Else we do not know this wipe method. */ + fprintf( stderr, "Error: Unknown wipe method '%s'.\n", optarg ); + exit( EINVAL ); + + + case 'l': /* Log file option. */ + + nwipe_options.logfile[strlen(optarg)] = '\0'; + strncpy(nwipe_options.logfile, optarg, sizeof(nwipe_options.logfile)); + break; + + case 'h': /* Display help. */ + + display_help(); + break; + + case 'p': /* PRNG option. */ + + if( strcmp( optarg, "mersenne" ) == 0 + || strcmp( optarg, "twister" ) == 0 + ) + { + nwipe_options.prng = &nwipe_twister; + break; + } + + if( strcmp( optarg, "isaac" ) == 0 ) + { + nwipe_options.prng = &nwipe_isaac; + break; + } + + /* Else we do not know this PRNG. */ + fprintf( stderr, "Error: Unknown prng '%s'.\n", optarg ); + exit( EINVAL ); + + + case 'r': /* Rounds option. */ + + if( sscanf( optarg, " %i", &nwipe_options.rounds ) != 1 \ + || nwipe_options.rounds < 1 + ) + { + fprintf( stderr, "Error: The rounds argument must be a postive integer.\n" ); + exit( EINVAL ); + } + + break; + + case 'V': /* Rounds option. */ + + printf ( "%s version %s\n", program_name, version_string ); + exit( EXIT_SUCCESS ); + + default: + + /* Bogus command line argument. */ + display_help(); + exit( EINVAL ); + + } /* method */ + + } /* command line options */ + + /* Return the number of options that were processed. */ + return optind; + +} /* nwipe_options_parse */ + + +void nwipe_options_log( void ) +{ +/** + * Prints a manifest of options to the log. + * + */ + + nwipe_log( NWIPE_LOG_NOTICE, "Program options are set as follows..." ); + + if( nwipe_options.autonuke ) + { + nwipe_log( NWIPE_LOG_NOTICE, " autonuke = %i (on)", nwipe_options.autonuke ); + } + + else + { + nwipe_log( NWIPE_LOG_NOTICE, " autonuke = %i (off)", nwipe_options.autonuke ); + } + + if( nwipe_options.noblank ) + { + nwipe_log( NWIPE_LOG_NOTICE, " do not perform a final blank pass" ); + } + + if( nwipe_options.nowait ) + { + nwipe_log( NWIPE_LOG_NOTICE, " do not wait for a key before exiting" ); + } + + if( nwipe_options.nogui ) + { + nwipe_log( NWIPE_LOG_NOTICE, " do not show GUI interface" ); + } + + nwipe_log( NWIPE_LOG_NOTICE, " banner = %s", nwipe_options.banner ); + nwipe_log( NWIPE_LOG_NOTICE, " method = %s", nwipe_method_label( nwipe_options.method ) ); + nwipe_log( NWIPE_LOG_NOTICE, " rounds = %i", nwipe_options.rounds ); + nwipe_log( NWIPE_LOG_NOTICE, " sync = %i", nwipe_options.sync ); + + switch( nwipe_options.verify ) + { + case NWIPE_VERIFY_NONE: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i (off)", nwipe_options.verify ); + break; + + case NWIPE_VERIFY_LAST: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i (last pass)", nwipe_options.verify ); + break; + + case NWIPE_VERIFY_ALL: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i (all passes)", nwipe_options.verify ); + break; + + default: + nwipe_log( NWIPE_LOG_NOTICE, " verify = %i", nwipe_options.verify ); + break; + } + +} /* nwipe_options_log */ + +/** + * display_help + * displays the help section to STDOUT and exits + */ +void +display_help() +{ + printf("Usage: %s [options] [device1] [device2] ...\n", program_name); + printf("Options:\n" ); + puts(" -V, --version Prints the version number"); + puts(" -h, --help Prints this help"); + puts(" --autonuke If no devices have been specified on the command line, starts wiping all"); + puts(" devices immediately. If devices have been specified, starts wiping only"); + puts(" those specified devices immediately."); + puts(" --sync Open devices in sync mode"); + puts(" --verify=TYPE Whether to perform verification of erasure (default: last)"); + puts(" off - Do not verify"); + puts(" last - Verify after the last pass"); + puts(" all - Verify every pass"); + puts(" -m, --method=METHOD The wiping method (default: dodshort). See man page for more details."); + puts(" dod522022m / dod - 7 pass DOD 5220.22-M method"); + puts(" dodshort / dod3pass - 3 pass DOD method"); + puts(" gutmann - Peter Gutmann's Algorithm"); + puts(" ops2 - RCMP TSSIT OPS-II"); + puts(" random / prng / stream - PRNG Stream"); + puts(" zero / quick - Overwrite with zeros"); + puts(" -l, --logfile=FILE Filename to log to. Default is STDOUT"); + puts(" -p, --prng=METHOD PRNG option (mersenne|twister|isaac)" ); + puts(" -r, --rounds=NUM Number of times to wipe the device using the selected method (default: 1)" ); + puts(" --noblank Do not blank disk after wipe (default is to complete a final blank pass)" ); + puts(" --nowait Do not wait for a key before exiting (default is to wait)" ); + puts(" --nogui Do not show the GUI interface. Automatically invokes the nowait option" ); + puts(" Must be used with --autonuke option"); + puts(""); + exit( EXIT_SUCCESS ); +} + +/* eof */ diff --git a/src/options.h b/src/options.h new file mode 100644 index 0000000..b555e00 --- /dev/null +++ b/src/options.h @@ -0,0 +1,67 @@ +/* + * options.h: Command line processing routines for nwipe. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#ifndef OPTIONS_H_ +#define OPTIONS_H_ + +/* Program knobs. */ +#define NWIPE_KNOB_ENTROPY "/dev/urandom" +#define NWIPE_KNOB_IDENTITY_SIZE 512 +#define NWIPE_KNOB_LABEL_SIZE 128 +#define NWIPE_KNOB_LOADAVG "/proc/loadavg" +#define NWIPE_KNOB_LOG_BUFFERSIZE 1024 /* Maximum length of a log event. */ +#define NWIPE_KNOB_PARTITIONS "/proc/partitions" +#define NWIPE_KNOB_PARTITIONS_PREFIX "/dev/" +#define NWIPE_KNOB_PRNG_STATE_LENGTH 512 /* 128 words */ +#define NWIPE_KNOB_SCSI "/proc/scsi/scsi" +#define NWIPE_KNOB_SLEEP 1 +#define NWIPE_KNOB_STAT "/proc/stat" + +/* Function prototypes for loading options from the environment and command line. */ +int nwipe_options_parse( int argc, char** argv ); +void nwipe_options_log( void ); + +/* Function to display help text */ +void display_help(); + +typedef struct /* nwipe_options_t */ +{ + int autonuke; /* Do not prompt the user for confirmation when set. */ + int noblank; /* Do not perform a final blanking pass. */ + int nowait; /* Do not wait for a final key before exiting. */ + int nogui ; /* Do not show the GUI. */ + char* banner; /* The product banner shown on the top line of the screen. */ +// nwipe_method_t method; /* A function pointer to the wipe method that will be used. */ + void* method; /* A function pointer to the wipe method that will be used. */ + char logfile[FILENAME_MAX]; /* The filename to log the output to */ + nwipe_prng_t* prng; /* The pseudo random number generator implementation. */ + int rounds; /* The number of times that the wipe method should be called. */ + int sync; /* A flag to indicate whether writes should be sync'd. */ + nwipe_verify_t verify; /* A flag to indicate whether writes should be verified. */ +} nwipe_options_t; + +extern nwipe_options_t nwipe_options; + +#endif /* OPTIONS_H_ */ + +/* eof */ diff --git a/src/pass.c b/src/pass.c new file mode 100644 index 0000000..1cf5c74 --- /dev/null +++ b/src/pass.c @@ -0,0 +1,755 @@ +/* + * pass.c: Routines that read and write patterns to block devices. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/* Why is this needed? Segfaults without it */ +#include + +#include "nwipe.h" +#include "context.h" +#include "method.h" +#include "prng.h" +#include "options.h" +#include "pass.h" +#include "logging.h" + + +int nwipe_random_verify( nwipe_context_t* c ) +{ +/** + * Verifies that a random pass was correctly written to the device. + * + */ + + /* The result holder. */ + int r; + + /* The IO size. */ + size_t blocksize; + + /* The result buffer for calls to lseek. */ + loff_t offset; + + /* The input buffer. */ + char* b; + + /* The pattern buffer that is used to check the input buffer. */ + char* d; + + /* The number of bytes remaining in the pass. */ + u64 z = c->device_size; + + + if( c->prng_seed.s == NULL ) + { + nwipe_log( NWIPE_LOG_SANITY, "Null seed pointer." ); + return -1; + } + + if( c->prng_seed.length <= 0 ) + { + nwipe_log( NWIPE_LOG_SANITY, "The entropy length member is %i.", c->prng_seed.length ); + return -1; + } + + /* Create the input buffer. */ + b = malloc( c->device_stat.st_blksize ); + + /* Check the memory allocation. */ + if( ! b ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the input buffer." ); + return -1; + } + + /* Create the pattern buffer */ + d = malloc( c->device_stat.st_blksize ); + + /* Check the memory allocation. */ + if( ! d ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the pattern buffer." ); + return -1; + } + + /* Reset the file pointer. */ + offset = lseek( c->device_fd, 0, SEEK_SET ); + + /* Reset the pass byte counter. */ + c->pass_done = 0; + + if( offset == (loff_t)-1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to reset the '%s' file offset.", c->device_name ); + return -1; + } + + if( offset != 0 ) + { + /* This is system insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "lseek() returned a bogus offset on '%s'.", c->device_name ); + return -1; + } + + /* Tell our parent that we are syncing the device. */ + c->sync_status = 1; + + /* Sync the device. */ + r = fdatasync( c->device_fd ); + + /* Tell our parent that we have finished syncing the device. */ + c->sync_status = 0; + + if( r != 0 ) + { + /* FIXME: Is there a better way to handle this? */ + nwipe_perror( errno, __FUNCTION__, "fdatasync" ); + nwipe_log( NWIPE_LOG_WARNING, "Buffer flush failure on '%s'.", c->device_name ); + } + + /* Reseed the PRNG. */ + c->prng->init( &c->prng_state, &c->prng_seed ); + + while( z > 0 ) + { + if( c->device_stat.st_blksize <= z ) + { + blocksize = c->device_stat.st_blksize; + } + else + { + /* This is a seatbelt for buggy drivers and programming errors because */ + /* the device size should always be an even multiple of its blocksize. */ + blocksize = z; + nwipe_log( NWIPE_LOG_WARNING, + "%s: The size of '%s' is not a multiple of its block size %i.", + __FUNCTION__, c->device_name, c->device_stat.st_blksize ); + } + + /* Fill the output buffer with the random pattern. */ + c->prng->read( &c->prng_state, d, blocksize ); + + /* Read the buffer in from the device. */ + r = read( c->device_fd, b, blocksize ); + + /* Check the result. */ + if( r < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to read from '%s'.", c->device_name ); + return -1; + } + + /* Check for a partial read. */ + if( r != blocksize ) + { + /* TODO: Handle a partial read. */ + + /* The number of bytes that were not read. */ + int s = blocksize - r; + + nwipe_log( NWIPE_LOG_WARNING, "%s: Partial read from '%s', %i bytes short.", __FUNCTION__, c->device_name, s ); + + /* Increment the error count. */ + c->verify_errors += 1; + + /* Bump the file pointer to the next block. */ + offset = lseek( c->device_fd, s, SEEK_CUR ); + + if( offset == (loff_t)-1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to bump the '%s' file offset after a partial read.", c->device_name ); + return -1; + } + + } /* partial read */ + + /* Compare buffer contents. */ + if( memcmp( b, d, blocksize ) != 0 ) { c->verify_errors += 1; } + + /* Decrement the bytes remaining in this pass. */ + z -= r; + + /* Increment the total progress counters. */ + c->pass_done += r; + c->round_done += r; + + pthread_testcancel(); + + } /* while bytes remaining */ + + /* Release the buffers. */ + free( b ); + free( d ); + + /* We're done. */ + return 0; + +} /* nwipe_random_verify */ + + + +int nwipe_random_pass( NWIPE_METHOD_SIGNATURE ) +{ +/** + * Writes a random pattern to the device. + * + */ + + /* The result holder. */ + int r; + + /* The IO size. */ + size_t blocksize; + + /* The result buffer for calls to lseek. */ + loff_t offset; + + /* The output buffer. */ + char* b; + + /* The number of bytes remaining in the pass. */ + u64 z = c->device_size; + + + if( c->prng_seed.s == NULL ) + { + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: Null seed pointer." ); + return -1; + } + + if( c->prng_seed.length <= 0 ) + { + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: The entropy length member is %i.", c->prng_seed.length ); + return -1; + } + + + /* Create the output buffer. */ + b = malloc( c->device_stat.st_blksize ); + + /* Check the memory allocation. */ + if( ! b ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the output buffer." ); + return -1; + } + + /* Seed the PRNG. */ + c->prng->init( &c->prng_state, &c->prng_seed ); + + /* Reset the file pointer. */ + offset = lseek( c->device_fd, 0, SEEK_SET ); + + /* Reset the pass byte counter. */ + c->pass_done = 0; + + if( offset == (loff_t)-1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to reset the '%s' file offset.", c->device_name ); + return -1; + } + + if( offset != 0 ) + { + /* This is system insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: lseek() returned a bogus offset on '%s'.", c->device_name ); + return -1; + } + + + while( z > 0 ) + { + if( c->device_stat.st_blksize <= z ) + { + blocksize = c->device_stat.st_blksize; + } + else + { + /* This is a seatbelt for buggy drivers and programming errors because */ + /* the device size should always be an even multiple of its blocksize. */ + blocksize = z; + nwipe_log( NWIPE_LOG_WARNING, + "%s: The size of '%s' is not a multiple of its block size %i.", + __FUNCTION__, c->device_name, c->device_stat.st_blksize ); + } + + /* Fill the output buffer with the random pattern. */ + c->prng->read( &c->prng_state, b, blocksize ); + + /* Write the next block out to the device. */ + r = write( c->device_fd, b, blocksize ); + + /* Check the result for a fatal error. */ + if( r < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "write" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to read from '%s'.", c->device_name ); + return -1; + } + + /* Check for a partial write. */ + if( r != blocksize ) + { + /* TODO: Handle a partial write. */ + + /* The number of bytes that were not written. */ + int s = blocksize - r; + + /* Increment the error count by the number of bytes that were not written. */ + c->pass_errors += s; + + nwipe_log( NWIPE_LOG_WARNING, "Partial write on '%s', %i bytes short.", c->device_name, s ); + + /* Bump the file pointer to the next block. */ + offset = lseek( c->device_fd, s, SEEK_CUR ); + + if( offset == (loff_t)-1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to bump the '%s' file offset after a partial write.", c->device_name ); + return -1; + } + + } /* partial write */ + + /* Decrement the bytes remaining in this pass. */ + z -= r; + + /* Increment the total progress counters. */ + c->pass_done += r; + c->round_done += r; + + pthread_testcancel(); + + } /* remaining bytes */ + + /* Release the output buffer. */ + free( b ); + + /* Tell our parent that we are syncing the device. */ + c->sync_status = 1; + + /* Sync the device. */ + r = fdatasync( c->device_fd ); + + /* Tell our parent that we have finished syncing the device. */ + c->sync_status = 0; + + if( r != 0 ) + { + /* FIXME: Is there a better way to handle this? */ + nwipe_perror( errno, __FUNCTION__, "fdatasync" ); + nwipe_log( NWIPE_LOG_WARNING, "Buffer flush failure on '%s'.", c->device_name ); + } + + /* We're done. */ + return 0; + +} /* nwipe_random_pass */ + + + +int nwipe_static_verify( NWIPE_METHOD_SIGNATURE, nwipe_pattern_t* pattern ) +{ +/** + * Verifies that a static pass was correctly written to the device. + * + */ + + /* The result holder. */ + int r; + + /* The IO size. */ + size_t blocksize; + + /* The result buffer for calls to lseek. */ + loff_t offset; + + /* The input buffer. */ + char* b; + + /* The pattern buffer that is used to check the input buffer. */ + char* d; + + /* A pointer into the pattern buffer. */ + char* q; + + /* The pattern buffer window offset. */ + int w = 0; + + /* The number of bytes remaining in the pass. */ + u64 z = c->device_size; + + if( pattern == NULL ) + { + /* Caught insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "nwipe_static_verify: Null entropy pointer." ); + return -1; + } + + if( pattern->length <= 0 ) + { + /* Caught insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "nwipe_static_verify: The pattern length member is %i.", pattern->length ); + return -1; + } + + /* Create the input buffer. */ + b = malloc( c->device_stat.st_blksize ); + + /* Check the memory allocation. */ + if( ! b ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the input buffer." ); + return -1; + } + + /* Create the pattern buffer */ + d = malloc( c->device_stat.st_blksize + pattern->length * 2 ); + + /* Check the memory allocation. */ + if( ! d ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the pattern buffer." ); + return -1; + } + + for( q = d ; q < d + c->device_stat.st_blksize + pattern->length ; q += pattern->length ) + { + /* Fill the pattern buffer with the pattern. */ + memcpy( q, pattern->s, pattern->length ); + } + + /* Tell our parent that we are syncing the device. */ + c->sync_status = 1; + + /* Sync the device. */ + r = fdatasync( c->device_fd ); + + /* Tell our parent that we have finished syncing the device. */ + c->sync_status = 0; + + if( r != 0 ) + { + /* FIXME: Is there a better way to handle this? */ + nwipe_perror( errno, __FUNCTION__, "fdatasync" ); + nwipe_log( NWIPE_LOG_WARNING, "Buffer flush failure on '%s'.", c->device_name ); + } + + + /* Reset the file pointer. */ + offset = lseek( c->device_fd, 0, SEEK_SET ); + + /* Reset the pass byte counter. */ + c->pass_done = 0; + + if( offset == (loff_t)-1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to reset the '%s' file offset.", c->device_name ); + return -1; + } + + if( offset != 0 ) + { + /* This is system insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "nwipe_static_verify: lseek() returned a bogus offset on '%s'.", c->device_name ); + return -1; + } + + + while( z > 0 ) + { + if( c->device_stat.st_blksize <= z ) + { + blocksize = c->device_stat.st_blksize ; + } + else + { + /* This is a seatbelt for buggy drivers and programming errors because */ + /* the device size should always be an even multiple of its blocksize. */ + blocksize = z; + nwipe_log( NWIPE_LOG_WARNING, + "%s: The size of '%s' is not a multiple of its block size %i.", + __FUNCTION__, c->device_name, c->device_stat.st_blksize ); + } + + /* Fill the output buffer with the random pattern. */ + /* Read the buffer in from the device. */ + r = read( c->device_fd, b, blocksize ); + + /* Check the result. */ + if( r < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "read" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to read from '%s'.", c->device_name ); + return -1; + } + + /* Check for a partial read. */ + if( r == blocksize ) + { + /* Check every byte in the buffer. */ + if( memcmp( b, &d[w], r ) != 0 ) { c->verify_errors += 1; } + } + else + { + /* The number of bytes that were not read. */ + int s = blocksize - r; + + /* TODO: Handle a partial read. */ + + /* Increment the error count. */ + c->verify_errors += 1; + + nwipe_log( NWIPE_LOG_WARNING, "Partial read on '%s', %i bytes short.", c->device_name, s ); + + /* Bump the file pointer to the next block. */ + offset = lseek( c->device_fd, s, SEEK_CUR ); + + if( offset == (loff_t)-1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to bump the '%s' file offset after a partial read.", c->device_name ); + return -1; + } + + } /* partial read */ + + /* Adjust the window. */ + w = ( c->device_stat.st_blksize + w ) % pattern->length; + + /* Intuition check: + * If the pattern length evenly divides the block size + * then ( w == 0 ) always. + */ + + /* Decrement the bytes remaining in this pass. */ + z -= r; + + /* Increment the total progress counters. */ + c->pass_done += r; + c->round_done += r; + + pthread_testcancel(); + + } /* while bytes remaining */ + + /* Release the buffers. */ + free( b ); + free( d ); + + /* We're done. */ + return 0; + +} /* nwipe_static_verify */ + + + +int nwipe_static_pass( NWIPE_METHOD_SIGNATURE, nwipe_pattern_t* pattern ) +{ +/** + * Writes a static pattern to the device. + * + */ + + /* The result holder. */ + int r; + + /* The IO size. */ + size_t blocksize; + + /* The result buffer for calls to lseek. */ + loff_t offset; + + /* The output buffer. */ + char* b; + + /* A pointer into the output buffer. */ + char* p; + + /* The output buffer window offset. */ + int w = 0; + + /* The number of bytes remaining in the pass. */ + u64 z = c->device_size; + + if( pattern == NULL ) + { + /* Caught insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: Null pattern pointer." ); + return -1; + } + + if( pattern->length <= 0 ) + { + /* Caught insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: The pattern length member is %i.", pattern->length ); + return -1; + } + + /* Create the output buffer. */ + b = malloc( c->device_stat.st_blksize + pattern->length * 2 ); + + /* Check the memory allocation. */ + if( ! b ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the pattern buffer." ); + return -1; + } + + for( p = b ; p < b + c->device_stat.st_blksize + pattern->length ; p += pattern->length ) + { + /* Fill the output buffer with the pattern. */ + memcpy( p, pattern->s, pattern->length ); + } +/// + /* Reset the file pointer. */ + offset = lseek( c->device_fd, 0, SEEK_SET ); + + /* Reset the pass byte counter. */ + c->pass_done = 0; + + if( offset == (loff_t)-1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to reset the '%s' file offset.", c->device_name ); + return -1; + } + + if( offset != 0 ) + { + /* This is system insanity. */ + nwipe_log( NWIPE_LOG_SANITY, "__FUNCTION__: lseek() returned a bogus offset on '%s'.", c->device_name ); + return -1; + } + + + while( z > 0 ) + { + if( c->device_stat.st_blksize <= z ) + { + blocksize = c->device_stat.st_blksize ; + } + else + { + /* This is a seatbelt for buggy drivers and programming errors because */ + /* the device size should always be an even multiple of its blocksize. */ + blocksize = z; + nwipe_log( NWIPE_LOG_WARNING, + "%s: The size of '%s' is not a multiple of its block size %i.", + __FUNCTION__, c->device_name, c->device_stat.st_blksize ); + } + + /* Fill the output buffer with the random pattern. */ + /* Write the next block out to the device. */ + r = write( c->device_fd, &b[w], blocksize ); + + /* Check the result for a fatal error. */ + if( r < 0 ) + { + nwipe_perror( errno, __FUNCTION__, "write" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to write to '%s'.", c->device_name ); + return -1; + } + + /* Check for a partial write. */ + if( r != blocksize ) + { + /* TODO: Handle a partial write. */ + + /* The number of bytes that were not written. */ + int s = blocksize - r; + + /* Increment the error count. */ + c->pass_errors += s; + + nwipe_log( NWIPE_LOG_WARNING, "Partial write on '%s', %i bytes short.", c->device_name, s ); + + /* Bump the file pointer to the next block. */ + offset = lseek( c->device_fd, s, SEEK_CUR ); + + if( offset == (loff_t)-1 ) + { + nwipe_perror( errno, __FUNCTION__, "lseek" ); + nwipe_log( NWIPE_LOG_ERROR, "Unable to bump the '%s' file offset after a partial write.", c->device_name ); + return -1; + } + + } /* partial write */ + + + /* Adjust the window. */ + w = ( c->device_stat.st_blksize + w ) % pattern->length; + + /* Intuition check: + * + * If the pattern length evenly divides the block size + * then ( w == 0 ) always. + */ + + /* Decrement the bytes remaining in this pass. */ + z -= r; + + /* Increment the total progress counterr. */ + c->pass_done += r; + c->round_done += r; + + pthread_testcancel(); + + } /* remaining bytes */ + + /* Tell our parent that we are syncing the device. */ + c->sync_status = 1; + + /* Sync the device. */ + r = fdatasync( c->device_fd ); + + /* Tell our parent that we have finished syncing the device. */ + c->sync_status = 0; + + if( r != 0 ) + { + /* FIXME: Is there a better way to handle this? */ + nwipe_perror( errno, __FUNCTION__, "fdatasync" ); + nwipe_log( NWIPE_LOG_WARNING, "Buffer flush failure on '%s'.", c->device_name ); + } + + /* Release the output buffer. */ + free( b ); + + /* We're done. */ + return 0; + +} /* nwipe_static_pass */ + +/* eof */ + diff --git a/src/pass.h b/src/pass.h new file mode 100644 index 0000000..dcda129 --- /dev/null +++ b/src/pass.h @@ -0,0 +1,35 @@ +/* + * pass.h: Routines that read and write patterns to block devices. + * + * Copyright Darik Horn . + * + * Modifications to original dwipe Copyright Andy Beverley + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef PASS_H_ +#define PASS_H_ + +int nwipe_random_pass ( nwipe_context_t* c ); +int nwipe_random_verify( nwipe_context_t* c ); +int nwipe_static_pass ( nwipe_context_t* c, nwipe_pattern_t* pattern ); +int nwipe_static_verify( nwipe_context_t* c, nwipe_pattern_t* pattern ); + +void test_functionn( int count, nwipe_context_t** c ); + +#endif /* PASS_H_ */ + +/* eof */ diff --git a/src/prng.c b/src/prng.c new file mode 100644 index 0000000..79e34ab --- /dev/null +++ b/src/prng.c @@ -0,0 +1,133 @@ +/* + * prng.c: Pseudo Random Number Generator abstractions for nwipe. + * + * Copyright Darik Horn . + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#include "nwipe.h" +#include "prng.h" +#include "logging.h" + +#include "mt19937ar-cok.h" +#include "isaac_rand.h" + +nwipe_prng_t nwipe_twister = +{ + "Mersenne Twister (mt19937ar-cok)", + nwipe_twister_init, + nwipe_twister_read +}; + +nwipe_prng_t nwipe_isaac = +{ + "ISAAC (rand.c 20010626)", + nwipe_isaac_init, + nwipe_isaac_read +}; + + + +int nwipe_twister_init( NWIPE_PRNG_INIT_SIGNATURE ) +{ + if( *state == NULL ) + { + /* This is the first time that we have been called. */ + *state = malloc( sizeof( twister_state_t ) ); + } + twister_init( (twister_state_t*)*state, (u32*)( seed->s ), seed->length / sizeof( u32 ) ); + return 0; +} + +int nwipe_twister_read( NWIPE_PRNG_READ_SIGNATURE ) +{ + u32 ii; + u32 words = count / sizeof( u32 ); + u32 remain = count % sizeof( u32 ); + + /* Twister returns 4-bytes per call, so cast the buffer into words. */ + for( ii = 0; ii < words; ++ii ) + { + ((u32*)buffer)[ii] = twister_genrand_int32( (twister_state_t*)*state ); + } + + /* Fill the buffer tail if the count is not evenly divided by the size of u32. */ + for( ii = 1; ii <= remain; ++ii ) + { + /* Notice how three bytes are discarded by doing this. */ + ((u8*)buffer)[count-ii] = twister_genrand_int32( (twister_state_t*)*state ); + } + + return 0; +} + + + +int nwipe_isaac_init( NWIPE_PRNG_INIT_SIGNATURE ) +{ + int count; + randctx* isaac_state = *state; + + if( *state == NULL ) + { + /* This is the first time that we have been called. */ + *state = malloc( sizeof( randctx ) ); + isaac_state = *state; + + /* Check the memory allocation. */ + if( isaac_state == 0 ) + { + nwipe_perror( errno, __FUNCTION__, "malloc" ); + nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the isaac state." ); + return -1; + } + } + + + /* Take the minimum of the isaac seed size and available entropy. */ + if( sizeof( isaac_state->randrsl ) < seed->length ) + { + count = sizeof( isaac_state->randrsl ); + } + else + { + memset( isaac_state->randrsl, 0, sizeof( isaac_state->randrsl ) ); + count = seed->length; + } + + if( count == 0 ) + { + /* Start ISACC without a seed. */ + randinit( isaac_state, 0 ); + } + else + { + /* Seed the ISAAC state with entropy. */ + memcpy( isaac_state->randrsl, seed->s, count ); + + /* The second parameter indicates that randrsl is non-empty. */ + randinit( isaac_state, 1 ); + } + + return 0; +} + +int nwipe_isaac_read( NWIPE_PRNG_READ_SIGNATURE ) +{ + return 0; +} + +/* eof */ diff --git a/src/prng.h b/src/prng.h new file mode 100644 index 0000000..fc75865 --- /dev/null +++ b/src/prng.h @@ -0,0 +1,56 @@ +/* + * prng.h: Pseudo Random Number Generator abstractions for nwipe. + * + * Copyright Darik Horn . + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef PRNG_H_ +#define PRNG_H_ + +/* A chunk of random data. */ +typedef struct /* nwipe_entropy_t */ +{ + size_t length; /* Length of the entropy string in bytes. */ + u8* s; /* The actual bytes of the entropy string. */ +} nwipe_entropy_t; + +#define NWIPE_PRNG_INIT_SIGNATURE void** state, nwipe_entropy_t* seed +#define NWIPE_PRNG_READ_SIGNATURE void** state, void* buffer, size_t count + +/* Function pointers for PRNG actions. */ +typedef int(*nwipe_prng_init_t)( NWIPE_PRNG_INIT_SIGNATURE ); +typedef int(*nwipe_prng_read_t)( NWIPE_PRNG_READ_SIGNATURE ); + +/* The generic PRNG definition. */ +typedef struct /* nwipe_prng_t */ +{ + const char* label; /* The name of the pseudo random number generator. */ + nwipe_prng_init_t init; /* Inialize the prng state with the seed. */ + nwipe_prng_read_t read; /* Read data from the prng. */ +} nwipe_prng_t; + +/* Mersenne Twister prototypes. */ +int nwipe_twister_init( NWIPE_PRNG_INIT_SIGNATURE ); +int nwipe_twister_read( NWIPE_PRNG_READ_SIGNATURE ); + +/* ISAAC prototypes. */ +int nwipe_isaac_init( NWIPE_PRNG_INIT_SIGNATURE ); +int nwipe_isaac_read( NWIPE_PRNG_READ_SIGNATURE ); + +#endif /* PRNG_H_ */ + +/* eof */ diff --git a/src/version.c b/src/version.c new file mode 100644 index 0000000..0be3915 --- /dev/null +++ b/src/version.c @@ -0,0 +1,16 @@ +/** + * version_string and program_name are used by siege + * and configure; author_name and email_address are + * used by configure to dynamically assign those values + * to documentation files. + */ +const char *version_string = "0.14"; +const char *program_name = "nwipe"; +const char *author_name = "Andy Beverley"; +const char *email_address = "andy@andybev.com"; +const char *years = "2012"; +const char *copyright = "Copyright Darik Horn \n\ +Modifications to original dwipe Copyright Andy Beverley \n\ +This is free software; see the source for copying conditions.\n\ +There is NO warranty; not even for MERCHANTABILITY or FITNESS\n\ +FOR A PARTICULAR PURPOSE.\n"; diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000..0653610 --- /dev/null +++ b/src/version.h @@ -0,0 +1,10 @@ +#ifndef __VERSION_H +#define __VERSION_H + +extern char *version_string; +extern char *program_name; +extern char *author_name; +extern char *email_address; +extern char *copyright; + +#endif/*__VERSION_H*/