diff options
author | Joseph Hunkeler <jhunk@stsci.edu> | 2009-09-08 19:02:23 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunk@stsci.edu> | 2009-09-08 19:02:23 -0400 |
commit | ce8f41c0d1f56169dc19696b6baf77307748d0b0 (patch) | |
tree | 3f64426a907895312d65b1c8b2e44a9d6e5ac91d | |
parent | 905e3fef88682aa74e0f3fc7ad3201907725e4b9 (diff) | |
download | NetNuke-ce8f41c0d1f56169dc19696b6baf77307748d0b0.tar.gz |
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | Makefile.linux | 6 | ||||
-rw-r--r-- | human_readable.c | 152 | ||||
-rw-r--r-- | human_readable.h | 14 | ||||
-rw-r--r-- | netnuke.c | 332 |
5 files changed, 510 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4b9be8a --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +CFLAGS=-Wall -pipe -O2 -funroll-loops +OUTPUT=netnuke + +all: + gcc -o ${OUTPUT} -lutil ${CFLAGS} netnuke.c + diff --git a/Makefile.linux b/Makefile.linux new file mode 100644 index 0000000..6f53f9c --- /dev/null +++ b/Makefile.linux @@ -0,0 +1,6 @@ +CFLAGS=-Wall -pipe -O2 -funroll-loops +OUTPUT=netnuke + +all: + gcc -o ${OUTPUT} -lutil ${CFLAGS} netnuke.c human_readable.c + diff --git a/human_readable.c b/human_readable.c new file mode 100644 index 0000000..0a95c31 --- /dev/null +++ b/human_readable.c @@ -0,0 +1,152 @@ +#ifndef __FreeBSD__ + +/* $NetBSD: humanize_number.c,v 1.8 2004/07/27 01:56:24 enami Exp $ */ + +/* + * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <locale.h> +#include <fts.h> + +#include "human_readable.h" + +int +humanize_number(char *buf, size_t len, int64_t bytes, + const char *suffix, int scale, int flags) +{ + const char *prefixes, *sep; + int b, i, r, maxscale, s1, s2, sign; + int64_t divisor, max; + size_t baselen; + + assert(buf != NULL); + assert(suffix != NULL); + assert(scale >= 0); + + if (flags & HN_DIVISOR_1000) { + /* SI for decimal multiplies */ + divisor = 1000; + if (flags & HN_B) + prefixes = "B\0k\0M\0G\0T\0P\0E"; + else + prefixes = "\0\0k\0M\0G\0T\0P\0E"; + } else { + /* + * binary multiplies + * XXX IEC 60027-2 recommends Ki, Mi, Gi... + */ + divisor = 1024; + if (flags & HN_B) + prefixes = "B\0K\0M\0G\0T\0P\0E"; + else + prefixes = "\0\0K\0M\0G\0T\0P\0E"; + } + +#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1]) + maxscale = 7; + + if (scale >= maxscale && + (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0) + return (-1); + + if (buf == NULL || suffix == NULL) + return (-1); + + if (len > 0) + buf[0] = '\0'; + if (bytes < 0) { + sign = -1; + bytes *= -100; + baselen = 3; /* sign, digit, prefix */ + } else { + sign = 1; + bytes *= 100; + baselen = 2; /* digit, prefix */ + } + if (flags & HN_NOSPACE) + sep = ""; + else { + sep = " "; + baselen++; + } + baselen += strlen(suffix); + + /* Check if enough room for `x y' + suffix + `\0' */ + if (len < baselen + 1) + return (-1); + + if (scale & (HN_AUTOSCALE | HN_GETSCALE)) { + /* See if there is additional columns can be used. */ + for (max = 100, i = len - baselen; i-- > 0;) + max *= 10; + + for (i = 0; bytes >= max && i < maxscale; i++) + bytes /= divisor; + + if (scale & HN_GETSCALE) + return (i); + } else + for (i = 0; i < scale && i < maxscale; i++) + bytes /= divisor; + + /* If a value <= 9.9 after rounding and ... */ + if (bytes < 995 && i > 0 && flags & HN_DECIMAL) { + /* baselen + \0 + .N */ + if (len < baselen + 1 + 2) + return (-1); + b = ((int)bytes + 5) / 10; + s1 = b / 10; + s2 = b % 10; + r = snprintf(buf, len, "%d%s%d%s%s%s", + sign * s1, localeconv()->decimal_point, s2, + sep, SCALE2PREFIX(i), suffix); + } else + r = snprintf(buf, len, "%lld%s%s%s", + /* LONGLONG */ + (long long)(sign * ((bytes + 50) / 100)), + sep, SCALE2PREFIX(i), suffix); + + return (r); +} + +#endif diff --git a/human_readable.h b/human_readable.h new file mode 100644 index 0000000..4055bfe --- /dev/null +++ b/human_readable.h @@ -0,0 +1,14 @@ +#ifndef HUMAN_READABLE_H +#define HUMAN_READABLE_H + +#define NO_PRINT 1 + +#define HN_DECIMAL 0x01 +#define HN_NOSPACE 0x02 +#define HN_B 0x04 +#define HN_DIVISOR_1000 0x08 + +#define HN_GETSCALE 0x10 +#define HN_AUTOSCALE 0x20 + +#endif diff --git a/netnuke.c b/netnuke.c new file mode 100644 index 0000000..783f0b5 --- /dev/null +++ b/netnuke.c @@ -0,0 +1,332 @@ +/** + * NetNuke - Erases all storage media deteced by the system + * Copyright (C) 2009 Joseph Hunkeler <jhunkeler@gmail.com, jhunk@stsci.edu> + * + * This file is part of NetNuke. + * + * NetNuke 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 3 of the License, or + * (at your option) any later version. + * + * NetNuke 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 NetNuke. If not, see <http://www.gnu.org/licenses/>. + **/ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <err.h> +#include <time.h> +#ifdef __FreeBSD__ + #include <libutil.h> + #include <sys/disk.h> +#else + #include "human_readable.h" + #include <sys/ioctl.h> + #include <linux/fs.h> +#endif + +/* Global variables */ +int32_t error; +/* List of media types that we can nuke */ +#ifdef __FreeBSD__ + const char* mediaList[17] = { + "ad", //ATAPI + "da", //SCSI + "adv", //AdvanSys Narrow + "adw", //AdvanSys Wide + "amd", //AMD 53C974 (Tekram DC390(T)) + "ncr", //NCR PCI + "bt", //BusLogic + "aha", //Adaptec 154x/1535 + "ahb", //Adaptec 174x + "ahc", //Adaptec 274x/284x/294x + "aic", //Adaptec 152x/AIC-6360/AIC-6260 + "isp", //QLogic + "dpt", //DPT RAID + "amr", //AMI MegaRAID + "mlx", //Mylex DAC960 RAID + "wt", //Wangtek and Archive QIC-02/QIC-36 + }; +#else + const char* mediaList[3] = { + "hd", //ATAPI + "sd", //SCSI + }; +#endif + +/* Prototypes */ +void fillRandom(int32_t buffer[], uint64_t length); +int32_t nuke(const char* media, uint64_t size); +uint64_t getSize(const char* media); +void echoList(void); +int humanize_number(char *buf, size_t len, int64_t bytes, + const char *suffix, int scale, int flags); + + +void fillRandom(int32_t buffer[], uint64_t length) +{ + uint32_t random, random_count; + + /* Initialize random seed */ + srand(time(NULL) * time(NULL) / 3 + 6201985 * 3.14159); + /* Fills the write buffer with random garbage */ + int32_t linebreak = 0; + + for(random_count = 0; random_count < length; random_count++) + { + random = rand() % RAND_MAX; + buffer[random_count] = random; + /* + printf("0x%0.8X ", (char)random); + + if(linebreak == 5) + { + printf("\n"); + linebreak = -1; + } + */ + linebreak++; + } + //printf("\n"); +} + +int nuke(const char* media, uint64_t size) +{ + /* test with 1G worth of data */ + size = (1024 * 1024) * 1000; + + char mediaSize[BUFSIZ]; + char writeSize[BUFSIZ]; + char writePerSecond[BUFSIZ]; + uint64_t byteSize = 1024; + uint64_t times, block; + int32_t wTable[byteSize]; + uint32_t startTime, currentTime, endTime; + int32_t retainer = 0; + + int fd = open("/dev/null", O_WRONLY | O_ASYNC); + if(!fd) + { + perror("nuke"); + exit(1); + } + + /* Generate a size string based on the media size. example: 256M */ + humanize_number(mediaSize, 5, (uint64_t)size, "", + HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); + + printf("Wiping %s: %ju (%s)\n", media, (intmax_t)size, mediaSize); + /* Determine how many writes and at what byte size */ + times = size / byteSize; + /* Dump random garbage to the write table */ + fillRandom(&wTable, byteSize); + + startTime = time(NULL); + for( block = 0 ; block <= times ; block++) + { + currentTime = time(NULL); + long double bytes = (float)(size / times * block); + + error = write(fd, (char*)wTable, sizeof(wTable)); + + switch(error) + { + case EIO: + { + int64_t blockPosition = (int64_t)lseek(fd, -1, SEEK_CUR); + printf("I/O Error: Unable to write to block \"%jd\"\n", blockPosition); + } + break; + + default: + break; + }; + + /* Generate a size string based on bytes written. example: 256M */ + humanize_number(writeSize, 5, + bytes, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); + + /* Generate a size string based on writes per second. example: 256M */ + humanize_number(writePerSecond, 5, + (intmax_t)((long double)bytes / ((long double)currentTime - (long double)startTime)), "", + HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); + + /* Save I/O by printing our progress every X iterations with a retainer*/ + if(retainer > 128 || block == times) + { + /* Output our progress */ + printf("\t%jd of %jd blocks [ %s / %3.1Lf%% / %s/s ]\r", + block, + times, + writeSize, + (bytes / (long double)size) * 100L, + writePerSecond + ); + retainer = -1; + + /* Recycle the write table with random garbage */ + fillRandom(&wTable, byteSize); + } + ++retainer; + } + endTime = time(NULL); + + printf("\n"); + close(fd); + return 0; +} + +void echoList() +{ + int i = 0; + int mt = 0; + int mediaFound = 0; + + do + { + /* Media size */ + uint64_t size; + /* Holds the media type, and number. example: ad0 */ + char media[BUFSIZ]; + char mediaShort[BUFSIZ]; + + /* Generate a device string based on the current interation*/ +#ifdef __FreeBSD__ + sprintf(media, "/dev/%s%d", mediaList[mt], i); +#else + sprintf(media, "/dev/%s%c", mediaList[mt], 'a' + i); +#endif + + /* Set media size */ + size = getSize(media); + + /* We MUST use the int64_t cast. Unsigned integers cannot have a negative value. + * Otherwise this loop would never end. */ + if((int64_t)size > 0L) + { + strncpy(mediaShort, &media[5], strlen(&media[5])); + printf("%s: %jd\n", mediaShort , (intmax_t)size); + mediaFound++; + } + else + { + /* To prevent overrunning */ + if(mediaList[mt] == NULL || mediaList[mt] == '\0') + break; + + /* mediaList iteration */ + mt++; + /* Reset iteratior so that the next increment is zero */ + i = -1; + } + + i++; + + } while( 1 ); + + printf("%d device%c detected\n", mediaFound, mediaFound < 1 || mediaFound > 1 ? 's' : 0 ); + putchar('\n'); +} + + +/* Function: getSize + * Argument 1: Fully qualified path to device + * Return: Media size, or -1 on failure + */ +uint64_t getSize(const char* media) +{ + /* Media size */ + uint64_t size; + /* Attempt to open the media read-only */ + int fd = open(media, O_RDONLY); + + if(fd) + { + /* Set media size */ +#ifdef __FreeBSD__ + error = ioctl(fd, DIOCGMEDIASIZE, &size); +#else + error = ioctl(fd, BLKGETSIZE, &size); + /* For Linux we must adjust the size returned, because we want bytes, not blocks */ + size *= 512; +#endif + } + else + exit(1); + + if(error != 0) + { + /* Errors will be completely ambiguous due to the nature of this + * program. */ + return -1; + } + + /* Close the media file descriptor */ + close(fd); + + /* Return the size of the media */ + return size; +} + +int main(int argc, char* argv[]) +{ + + int i = 0; + int mt = 0; + + echoList(); + + do + { + /* Media size */ + uint64_t size; + /* Holds the media type, and number. example: ad0 */ + char media[BUFSIZ]; + + /* Generate a device string based on the current interation*/ +#ifdef __FreeBSD__ + sprintf(media, "/dev/%s%d", mediaList[mt], i); +#else + sprintf(media, "/dev/%s%c", mediaList[mt], 'a' + i); +#endif + /* Set media size */ + size = getSize(media); + + /* We MUST use the int64_t cast. Unsigned integers cannot have a negative value. + * Otherwise this loop would never end. */ + if((int64_t)size > 0L) + { + //printf("%s: %jd (%s)\n", media, (intmax_t)size, buf); + nuke(media, size); + } + else + { + /* To prevent overrunning */ + if(mediaList[mt] == NULL || mediaList[mt] == '\0') + break; + + /* mediaList iteration */ + mt++; + /* Reset iteratior so that the next increment is zero */ + i = -1; + } + + i++; + + } while( 1 ); + + /* End */ + return 0; +} + |