aboutsummaryrefslogtreecommitdiffstats
path: root/deadshred.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2024-09-19 18:03:17 +0200
committerMattias Andrée <maandree@kth.se>2024-09-19 18:03:17 +0200
commit44cff01e5bbe04ff991ede843e96f0c2d83d20c6 (patch)
treef889f60eca251d716489e3b30994c435c00dbfa2 /deadshred.c
parentm fixes (diff)
downloaddeadshred-44cff01e5bbe04ff991ede843e96f0c2d83d20c6.tar.gz
deadshred-44cff01e5bbe04ff991ede843e96f0c2d83d20c6.tar.bz2
deadshred-44cff01e5bbe04ff991ede843e96f0c2d83d20c6.tar.xz
Split into multiple C files
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
-rw-r--r--deadshred.c400
1 files changed, 16 insertions, 384 deletions
diff --git a/deadshred.c b/deadshred.c
index 50528c4..5956115 100644
--- a/deadshred.c
+++ b/deadshred.c
@@ -1,30 +1,11 @@
/* See LICENSE file for copyright and license details. */
-#include <sys/mount.h>
-#include <pthread.h>
-#include <libsimple.h>
+#include "common.h"
#include <libsimple-arg.h>
+/* TODO why has the program started to freeze (since multithreading?)*/
-USAGE("[-o offset] [-l length | -e postend] device [< random-source]");
-
-#define NANOSECONDS(X) X##L
-#define MICROSECONDS(X) NANOSECONDS(X##000)
-#define MILLISECONDS(X) MICROSECONDS(X##000)
-#define CENTISECONDS(X) MILLISECONDS(X##0)
-#define DECISECONDS(X) CENTISECONDS(X##0)
-#define WHOLE_SECOND DECISECONDS(10)
-enum direction {
- FORWARDS = 0,
- BACKWARDS = 1
-};
-
-struct span {
- off_t start;
- off_t end;
- off_t bad;
- size_t blocksize;
-};
+USAGE("[-o offset] [-l length | -e postend] device [< random-source]");
static _Atomic volatile sig_atomic_t exiting = 0;
@@ -36,10 +17,6 @@ static size_t spans_size = 0;
static off_t shredded = 0;
static off_t total_size = 0;
-static char reservoir[128U << 10];
-static size_t reservoir_off = sizeof(reservoir);
-static int use_stdin;
-
static char total_size_1000[256];
static char total_size_1024[256];
@@ -58,12 +35,7 @@ static const struct timespec poll_timeout = {0, MILLISECONDS(500)};
static int progress_print_sig_pipe[2];
static pthread_mutex_t progress_mutex;
-/* TODO deal with machine and process suspension */
-static struct timespec write_average_begin_times[5];
-static off_t write_average_amounts[ELEMSOF(write_average_begin_times)] = {0};
-static int write_average_i = 0;
-
-static enum direction direction = FORWARDS;
+static enum direction direction = FORWARDS; /* TODO add option (-b) to switch start direction */
static uintmax_t pass_nr = 1;
@@ -75,60 +47,6 @@ signal_handler(int signo)
}
-static off_t
-filesize(int fd, const char *fname)
-{
- struct stat st;
-
- if (fstat(fd, &st))
- eprintf("fstat %s:", fname);
-
- switch (st.st_mode & S_IFMT) {
- case S_IFREG:
- break;
- case S_IFBLK:
- if (ioctl(fd, BLKGETSIZE64, &st.st_size) < 0)
- eprintf("ioctl %s BLKGETSIZE64:", fname);
- break;
- default:
- eprintf("%s: not a regular file or block device", fname);
- }
-
- return st.st_size;
-}
-
-
-static void
-ensure_random(size_t needed)
-{
- size_t off;
- ssize_t r;
-
- if (sizeof(reservoir) - reservoir_off >= needed)
- return;
-
- if (!use_stdin) {
- libsimple_random_bytes(&libsimple_random_bits, NULL, reservoir, reservoir_off);
- reservoir_off = 0;
- return;
- }
-
- for (off = 0; off < reservoir_off;) {
- r = read(STDIN_FILENO, &reservoir[off], reservoir_off - off);
- if (r <= 0) {
- if (!r)
- eprintf("random source depleted");
- if (errno == EINTR)
- continue;
- eprintf("read <stdin>:");
- }
- off += (size_t)r;
- }
-
- reservoir_off = 0;
-}
-
-
static void
add_span(off_t off, off_t amount, size_t blocksize, int try_join)
{
@@ -160,222 +78,6 @@ add_span(off_t off, off_t amount, size_t blocksize, int try_join)
}
-static char *
-humansize1000(off_t s, char *buf)
-{
- const char *units = "kMGTPEZYRQ";
- size_t unit = 0;
- if (s < 1000) {
- sprintf(buf, "%u B", (unsigned)s);
- return buf;
- }
- s /= 100;
- while (units[unit + 1U] && s >= 10000) {
- s /= 1000;
- unit++;
- }
- sprintf(buf, "%u.%u %cB", (unsigned)s / 10U, (unsigned)s % 10U, units[unit]);
- return buf;
-}
-
-
-static char *
-humansize1024(off_t s, char *buf)
-{
- const char *units = "KMGTPEZYRQ";
- size_t unit = 0;
- if (s < 1024) {
- sprintf(buf, "%u B", (unsigned)s);
- return buf;
- }
- while (units[unit + 1U] && s >= 1024 * 1024) {
- s /= 1024;
- unit++;
- }
- sprintf(buf, "%lu.%lu %ciB", (unsigned long int)s / 1024UL, (unsigned long int)(s * 10 % 10240) / 1024UL, units[unit]);
- return buf;
-}
-
-
-#if defined(__GNUC__)
-__attribute__((__pure__))
-#endif
-static off_t
-unhumansize(const char *s, char flag)
-{
- off_t sum = 0, term, digit, divisor, power, base;
-
- if (!isdigit(s[0]) && !(s[0] == '-' && isdigit(s[1])))
- usage();
-
- do {
- divisor = 1;
- term = 0;
- while (isdigit(*s)) {
- digit = (*s++ & 15);
- if (term > (OFF_MAX - digit) / 10)
- eprintf("value of -%c flag is too large", flag);
- term = term * 10 + digit;
- }
- if (*s == '.') {
- s++;
- while (isdigit(*s)) {
- digit = (*s++ & 15);
- if (term > (OFF_MAX - digit) / 10)
- eprintf("value of -%c flag is too large", flag);
- term = term * 10 + digit;
- divisor *= 10;
- }
- }
-
- power = 0;
- switch (*s) {
- case 'Q': power++; /* fall through */
- case 'R': power++; /* fall through */
- case 'Y': power++; /* fall through */
- case 'Z': power++; /* fall through */
- case 'E': power++; /* fall through */
- case 'P': power++; /* fall through */
- case 'T': power++; /* fall through */
- case 'G': power++; /* fall through */
- case 'M': power++; /* fall through */
- case 'k': case 'K': power++;
- if (s[1] == 'i' || s[2] == 'B') {
- base = 1024;
- s = &s[3];
- } else if (s[1] == 'B') {
- base = 1000;
- s = &s[2];
- } else {
- base = 1024;
- s = &s[1];
- }
- while (power) {
- term *= base;
- power--;
- }
- break;
- case 'B':
- if (!power && divisor > 1)
- usage();
- s++;
- break;
- default:
- break;
- }
- sum += term /= divisor;
-
- while (*s == ' ' || *s == ',' || *s == '+')
- s++;
-
- } while (isdigit(s[0]) || (s[0] == '.' && isdigit(s[1])));
-
- return sum;
-}
-
-
-static const char *
-durationstr(const struct timespec *dur, char *buf, int second_decimals)
-{
- uintmax_t ss, s, m, h, d, ss_div = (uintmax_t)WHOLE_SECOND;
- char *p;
- const char *unit;
- int i;
-
- if (dur->tv_sec < 0 || dur->tv_nsec < 0)
- return "-";
-
- if (second_decimals < 0)
- second_decimals = 0;
- else if (second_decimals > 9)
- second_decimals = 9;
-
- for (i = 0; i < second_decimals; i++)
- ss_div /= 10U;
- ss = (uintmax_t)dur->tv_nsec / ss_div;
- s = (uintmax_t)dur->tv_sec % 60U;
- m = (uintmax_t)dur->tv_sec / 60U % 60U;
- h = (uintmax_t)dur->tv_sec / 60U / 60U % 24U;
- d = (uintmax_t)dur->tv_sec / 60U / 60U / 24U;
-
- p = buf;
- if (d)
- p += sprintf(p, "%ju days, ", d);
- if (h) {
- p += sprintf(p, "%ju:%02ju:%02ju", h, m, s);
- unit = "hours";
- } else if (m) {
- p += sprintf(p, "%ju:%02ju", m, s);
- unit = "minutes";
- } else {
- p += sprintf(p, "%ju", s);
- unit = "seconds";
- }
- if (second_decimals)
- p += sprintf(p, ".%0*ju", second_decimals, ss);
- p += sprintf(p, " %s", unit);
-
- return buf;
-}
-
-
-#if defined(__linux__)
-#include <linux/kd.h>
-static int
-have_micro_symbol(void)
-{
- static int ret = -1;
- if (ret < 0) {
- struct unimapdesc desc;
- struct unipair *pairs = NULL;
- size_t i;
- ret = 1;
- desc.entry_ct = 0;
- desc.entries = NULL;
- if (ioctl(STDIN_FILENO, GIO_UNIMAP, &desc))
- if (!desc.entry_ct)
- goto out;
- desc.entries = pairs = ecalloc(desc.entry_ct, sizeof(*pairs));
- if (ioctl(STDIN_FILENO, GIO_UNIMAP, &desc))
- goto out;
- for (i = 0; i < desc.entry_ct; i++)
- if (desc.entries[i++].unicode == 0xB5U)
- goto out;
- ret = 0;
- out:
- free(pairs);
- }
- return ret;
-}
-#else
-# define have_micro_symbol() 1
-#endif
-
-
-static int
-was_write_average_overrun(int i, const struct timespec *now, int seconds)
-{
- struct timespec diff;
- libsimple_difftimespec(&diff, now, &write_average_begin_times[i]);
- if (diff.tv_sec >= seconds)
- return 1;
- if (diff.tv_sec == seconds - 1 && diff.tv_nsec >= DECISECONDS(9))
- return 1;
- return 0;
-}
-
-
-static void
-shift_write_average(void)
-{
- write_average_i--;
- memmove(&write_average_begin_times[0], &write_average_begin_times[1],
- (size_t)write_average_i * sizeof(*write_average_begin_times));
- memmove(&write_average_amounts[0], &write_average_amounts[1],
- (size_t)write_average_i * sizeof(*write_average_amounts));
-}
-
-
static void
print_progress(int done, const struct timespec *now)
{
@@ -390,48 +92,8 @@ print_progress(int done, const struct timespec *now)
char subbuf5[256];
char subbuf6[256];
char subbuf7[256];
- char write_average_buf[512];
struct timespec since_success = {-1, 0};
- struct timespec time_spent, write_average_time;
- int i;
- off_t write_average_sum = 0;
- double write_average;
-
- for (i = 0; i <= write_average_i; i++)
- write_average_sum += write_average_amounts[i];
- libsimple_difftimespec(&write_average_time, now, &write_average_begin_times[0]);
- if (write_average_time.tv_sec < 0 || (write_average_time.tv_sec == 0 && write_average_time.tv_nsec < CENTISECONDS(10))) {
- stpcpy(write_average_buf, "-");
- } else if (write_average_sum == 0) {
- stpcpy(write_average_buf, "0");
- } else {
- const char *units_big = "kMGTPEZYRQ";
- const char *units_small = "munpfazyrq";
- int unit = -1;
- write_average = (double)write_average_time.tv_nsec;
- write_average /= WHOLE_SECOND;
- write_average += (double)write_average_time.tv_sec;
- write_average = (double)write_average_sum / write_average;
- if (write_average < (double)0.01f) {
- do {
- write_average *= 1000;
- unit++;
- } while (units_small[unit + 1] && write_average < (double)0.01f);
- if (units_small[unit] == 'u' && have_micro_symbol())
- sprintf(write_average_buf, "%.02lf µB/s", write_average);
- else
- sprintf(write_average_buf, "%.02lf %cB/s", write_average, units_small[unit]);
- } else {
- while (units_big[unit + 1] && write_average >= 1000) {
- write_average /= 1000;
- unit++;
- }
- if (unit < 0)
- sprintf(write_average_buf, "%.02lf B/s", write_average);
- else
- sprintf(write_average_buf, "%.02lf %cB/s", write_average, units_big[unit]);
- }
- }
+ struct timespec time_spent;
if (last_success.tv_sec >= 0) {
libsimple_difftimespec(&since_success, now, &last_success);
@@ -465,7 +127,7 @@ print_progress(int done, const struct timespec *now)
humansize1024(bad_bytes, subbuf4),
/* } line 3 { */
durationstr(&time_spent, subbuf5, 1),
- write_average_buf,
+ wravg_get(now),
/* } line 4 { */
durationstr(&since_success, subbuf6, 2),
/* } line 5 { */
@@ -485,21 +147,6 @@ print_progress(int done, const struct timespec *now)
}
-static void
-update_progress(const struct timespec *now)
-{
- if (was_write_average_overrun(write_average_i, now, 1)) {
- write_average_i++;
- if (write_average_i == ELEMSOF(write_average_amounts))
- shift_write_average();
- write_average_begin_times[write_average_i] = *now;
- write_average_amounts[write_average_i] = 0;
- }
- while (write_average_i && was_write_average_overrun(0, now, (int)ELEMSOF(write_average_amounts)))
- shift_write_average();
-}
-
-
static void *
progress_print_loop(void *user)
{
@@ -550,7 +197,7 @@ progress_print_loop(void *user)
terminate = 1;
}
print_progress(0, &now);
- update_progress(&now);
+ wravg_update_time(&now);
pthread_mutex_unlock(&progress_mutex);
} while (!terminate);
@@ -566,6 +213,7 @@ shredspan(int fd, struct span *span, const char *fname)
struct timespec now, when = {0, 0};
int bad = span->bad > 0;
int first_fail = 1;
+ const char *random_data;
pthread_mutex_lock(&progress_mutex);
@@ -588,7 +236,6 @@ shredspan(int fd, struct span *span, const char *fname)
libsimple_sumtimespec(&when, &now, &progress_print_interval);
write(progress_print_sig_pipe[1], &now, sizeof(now));
}
- ensure_random(span->blocksize);
if (direction == FORWARDS) {
n = MIN((off_t)span->blocksize, span->end - off);
} else {
@@ -600,9 +247,10 @@ shredspan(int fd, struct span *span, const char *fname)
if (!n)
break;
}
+ random_data = get_random(span->blocksize);
pthread_mutex_unlock(&progress_mutex);
pwrite_again:
- r = pwrite(fd, &reservoir[reservoir_off], (size_t)n, off);
+ r = pwrite(fd, random_data, (size_t)n, off);
if (r < 0) {
if (errno == EINTR) {
if (exiting) {
@@ -649,8 +297,8 @@ shredspan(int fd, struct span *span, const char *fname)
bad_writes += 1U;
}
shredded += (off_t)r;
- reservoir_off += (size_t)r;
- write_average_amounts[write_average_i] += (off_t)r;
+ used_random(r);
+ wravg_update_write(r);
last_success = now;
if (span->bad) {
bad_bytes -= (off_t)r;
@@ -748,30 +396,13 @@ main(int argc, char *argv[])
if (fd < 0)
eprintf("open %s O_WRONLY|O_DSYNC:", argv[0]);
- use_stdin = !isatty(STDIN_FILENO);
- if (use_stdin) {
- struct stat st;
- if (fstat(STDIN_FILENO, &st)) {
- if (errno == EBADF)
- use_stdin = 0;
- else
- eprintf("fstat <stdin>:");
- } else {
- if (S_ISFIFO(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
- weprintf("stdin is open but is not a TTY, character device, FIFO, or socket");
- }
- }
- if (!use_stdin) {
- libsimple_srand();
- }
+ init_random(STDIN_FILENO, "<stdin>");
spans = emalloc(sizeof(*spans));
spans[0].start = 0;
spans[0].end = filesize(fd, argv[0]);
spans[0].bad = 0;
- spans[0].blocksize = sizeof(reservoir);
- while (spans[0].blocksize & (spans[0].blocksize - 1U))
- spans[0].blocksize &= (spans[0].blocksize - 1U);
+ spans[0].blocksize = max_blksize();
nspans = 1U;
spans_size = 1U;
@@ -813,7 +444,7 @@ main(int argc, char *argv[])
if (clock_gettime(clck, &start_time))
eprintf("clock_gettime %s:", clkcstr);
}
- write_average_begin_times[0] = start_time;
+ wravg_init(&start_time);
last_success = start_time;
while (nspans) {
@@ -824,6 +455,7 @@ main(int argc, char *argv[])
memmove(&spans[0], &spans[i], (nspans -= i) * sizeof(*spans));
break;
}
+ /* TODO bug: this is sometimes reached immediately on write failure */
for (i = 0, j = nspans, nspans -= old_nspans; i < nspans;)
spans[i++] = spans[--j];
direction ^= 1;