aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--avg.c55
-rw-r--r--common.h42
-rw-r--r--deadshred.c235
-rw-r--r--sig.c50
5 files changed, 219 insertions, 166 deletions
diff --git a/Makefile b/Makefile
index bfe5c26..0e2dff4 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,8 @@ OBJ =\
fmt.o\
text.o\
avg.o\
- rnd.o
+ rnd.o\
+ sig.o
HDR =\
common.h
diff --git a/avg.c b/avg.c
index 4078c50..f24b174 100644
--- a/avg.c
+++ b/avg.c
@@ -5,16 +5,11 @@
/* 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 int
-was_write_average_overrun(int i, const struct timespec *now, int seconds)
+was_write_average_overrun(int i, int seconds, const struct status *s)
{
struct timespec diff;
- libsimple_difftimespec(&diff, now, &write_average_begin_times[i]);
+ libsimple_difftimespec(&diff, &s->now, &s->write_average_begin_times[i]);
if (diff.tv_sec >= seconds)
return 1;
if (diff.tv_sec == seconds - 1 && diff.tv_nsec >= DECISECONDS(9))
@@ -24,48 +19,48 @@ was_write_average_overrun(int i, const struct timespec *now, int seconds)
static void
-shift_write_average(void)
+shift_write_average(struct status *s)
{
- 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));
+ s->write_average_i -= 1;
+ memmove(&s->write_average_begin_times[0], &s->write_average_begin_times[1],
+ (size_t)s->write_average_i * sizeof(*s->write_average_begin_times));
+ memmove(&s->write_average_amounts[0], &s->write_average_amounts[1],
+ (size_t)s->write_average_i * sizeof(*s->write_average_amounts));
}
void
-wravg_init(const struct timespec *start_time)
+wravg_init(const struct timespec *start_time, struct status *s)
{
- write_average_begin_times[0] = *start_time;
+ s->write_average_begin_times[0] = *start_time;
}
void
-wravg_update_write(ssize_t amount)
+wravg_update_write(ssize_t amount, struct status *s)
{
if (amount > 0)
- write_average_amounts[write_average_i] += (off_t)amount;
+ s->write_average_amounts[s->write_average_i] += (off_t)amount;
}
void
-wravg_update_time(const struct timespec *now)
+wravg_update_time(struct status *s)
{
- 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;
+ if (was_write_average_overrun(s->write_average_i, 1, s)) {
+ s->write_average_i += 1;
+ if (s->write_average_i == WRAVG_STEPS)
+ shift_write_average(s);
+ s->write_average_begin_times[s->write_average_i] = s->now;
+ s->write_average_amounts[s->write_average_i] = 0;
}
- while (write_average_i && was_write_average_overrun(0, now, (int)ELEMSOF(write_average_amounts)))
- shift_write_average();
+ while (s->write_average_i && was_write_average_overrun(0, WRAVG_STEPS, s))
+ shift_write_average(s);
}
const char *
-wravg_get(const struct timespec *now)
+wravg_get(struct status *s)
{
static char buf[512];
@@ -74,10 +69,10 @@ wravg_get(const struct timespec *now)
double write_average;
int i;
- for (i = 0; i <= write_average_i; i++)
- write_average_sum += write_average_amounts[i];
+ for (i = 0; i <= s->write_average_i; i++)
+ write_average_sum += s->write_average_amounts[i];
- libsimple_difftimespec(&write_average_time, now, &write_average_begin_times[0]);
+ libsimple_difftimespec(&write_average_time, &s->now, &s->write_average_begin_times[0]);
if (write_average_time.tv_sec < 0)
return "-";
diff --git a/common.h b/common.h
index 875375c..c1dbcfc 100644
--- a/common.h
+++ b/common.h
@@ -12,6 +12,9 @@
#define WHOLE_SECOND DECISECONDS(10)
+#define WRAVG_STEPS 5
+
+
enum direction {
FORWARDS = 0,
BACKWARDS = 1
@@ -24,10 +27,32 @@ struct span {
size_t blocksize;
};
+struct status {
+ struct timespec now;
+ off_t shredded;
+ off_t bad_bytes;
+ uintmax_t bad_writes;
+ uintmax_t bad_sections;
+ uintmax_t pass_nr;
+ struct timespec last_success;
+ enum direction direction;
+
+ int write_average_i;
+ struct timespec write_average_begin_times[WRAVG_STEPS];
+ off_t write_average_amounts[WRAVG_STEPS];
+};
+#define STATUS_INIT {.pass_nr = 1, .last_success = {-1, 0}, .direction = FORWARDS}
+
+
+/* deadshred.c */
+extern struct status status;
+extern _Atomic volatile sig_atomic_t exiting;
+
/* io.c */
off_t filesize(int fd, const char *fname);
+
/* fmt.c */
const char *humansize1000(off_t s, char *buf);
const char *humansize1024(off_t s, char *buf);
@@ -38,14 +63,17 @@ off_t unhumansize(const char *s, char flag);
const char *durationstr(const struct timespec *dur, char *buf, int second_decimals);
const char *humanbytespersecond(double bytes_per_second, char *buf);
+
/* text.c */
int have_micro_symbol(void);
+
/* avg.c */
-void wravg_init(const struct timespec *start_time);
-void wravg_update_write(ssize_t amount);
-void wravg_update_time(const struct timespec *now);
-const char *wravg_get(const struct timespec *now);
+void wravg_init(const struct timespec *start_time, struct status *s);
+void wravg_update_write(ssize_t amount, struct status *s);
+void wravg_update_time(struct status *s);
+const char *wravg_get(struct status *s);
+
/* rnd.c */
#if defined(__GNUC__)
@@ -55,3 +83,9 @@ size_t max_blksize(void);
void init_random(int fd, const char *fname);
const char *get_random(size_t needed);
void used_random(ssize_t amount);
+
+
+/* sig.c */
+void setup_sighandler(void);
+void block_sigs(void);
+void unblock_sigs(void);
diff --git a/deadshred.c b/deadshred.c
index 5956115..28a64fe 100644
--- a/deadshred.c
+++ b/deadshred.c
@@ -2,49 +2,30 @@
#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]");
+/* TODO add option (-b) to switch start direction */
-static _Atomic volatile sig_atomic_t exiting = 0;
+struct status status = STATUS_INIT;
+_Atomic volatile sig_atomic_t exiting = 0;
static struct span *spans = NULL;
static size_t nspans = 0;
static size_t spans_size = 0;
-static off_t shredded = 0;
static off_t total_size = 0;
-
static char total_size_1000[256];
static char total_size_1024[256];
-static uintmax_t bad_writes = 0;
-static uintmax_t bad_sections = 0;
-static off_t bad_bytes = 0;
-
static clockid_t clck = CLOCK_MONOTONIC_COARSE;
static const char *clkcstr = "CLOCK_MONOTONIC_COARSE";
-static struct timespec last_success = {-1, 0};
static struct timespec max_success = {-1, 0};
static struct timespec start_time;
-static const struct timespec progress_print_interval = {0, MILLISECONDS(500)};
-static const struct timespec poll_timeout = {0, MILLISECONDS(500)};
-static int progress_print_sig_pipe[2];
-static pthread_mutex_t progress_mutex;
-
-static enum direction direction = FORWARDS; /* TODO add option (-b) to switch start direction */
-static uintmax_t pass_nr = 1;
-
-
-static void
-signal_handler(int signo)
-{
- (void) signo;
- exiting = 1;
-}
+static const struct timespec status_print_interval = {0, MILLISECONDS(500)};
+static const struct timespec poll_timeout = {1, 0};
+static int status_print_pipe[2];
static void
@@ -79,7 +60,7 @@ add_span(off_t off, off_t amount, size_t blocksize, int try_join)
static void
-print_progress(int done, const struct timespec *now)
+print_status(int done, struct status *s)
{
static char buf1[2048] = {0};
static char buf2[2048] = {0};
@@ -95,14 +76,14 @@ print_progress(int done, const struct timespec *now)
struct timespec since_success = {-1, 0};
struct timespec time_spent;
- if (last_success.tv_sec >= 0) {
- libsimple_difftimespec(&since_success, now, &last_success);
+ if (s->last_success.tv_sec >= 0) {
+ libsimple_difftimespec(&since_success, &s->now, &s->last_success);
if (libsimple_cmptimespec(&since_success, &max_success) > 0)
max_success = since_success;
}
/* TODO deal with machine and process suspension */
- libsimple_difftimespec(&time_spent, now, &start_time);
+ libsimple_difftimespec(&time_spent, &s->now, &start_time);
sprintf(bufi == 0 ? buf1 : buf2,
"%ji bytes (%s, %s, %.2lf %%) of %s (%s) shredded\033[K\n"
@@ -113,28 +94,28 @@ print_progress(int done, const struct timespec *now)
"pass: %ju; pass direction: %s\033[K\n"
"%s",
/* line 1 { */
- (intmax_t)shredded,
- humansize1000(shredded, subbuf1),
- humansize1024(shredded, subbuf2),
- 100 * (double)shredded / (double)total_size,
+ (intmax_t)s->shredded,
+ humansize1000(s->shredded, subbuf1),
+ humansize1024(s->shredded, subbuf2),
+ 100 * (double)s->shredded / (double)total_size,
total_size_1000,
total_size_1024,
/* } line 2 { */
- bad_writes,
- bad_sections,
- (intmax_t)bad_bytes,
- humansize1000(bad_bytes, subbuf3),
- humansize1024(bad_bytes, subbuf4),
+ s->bad_writes,
+ s->bad_sections,
+ (intmax_t)s->bad_bytes,
+ humansize1000(s->bad_bytes, subbuf3),
+ humansize1024(s->bad_bytes, subbuf4),
/* } line 3 { */
durationstr(&time_spent, subbuf5, 1),
- wravg_get(now),
+ wravg_get(s),
/* } line 4 { */
durationstr(&since_success, subbuf6, 2),
/* } line 5 { */
durationstr(&max_success, subbuf7, 2),
/* } line 6 { */
- pass_nr,
- direction == FORWARDS ? "forwards" : "backwards",
+ s->pass_nr,
+ s->direction == FORWARDS ? "forwards" : "backwards",
/* } */
done ? "" : "\033[6A");
@@ -148,22 +129,19 @@ print_progress(int done, const struct timespec *now)
static void *
-progress_print_loop(void *user)
+status_print_loop(void *user)
{
- struct pollfd pfd = {.fd = progress_print_sig_pipe[0], .events = POLLOUT};
- struct timespec now;
+ struct pollfd pfd = {.fd = status_print_pipe[0], .events = POLLIN};
ssize_t r;
int terminate = 0;
- sigset_t sigset;
+ struct status s = STATUS_INIT;
+ size_t status_off;
(void) user;
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGTERM);
- sigaddset(&sigset, SIGINT);
- errno = pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
- if (errno)
- eprintf("pthread_sigmask SIG_UNBLOCK {SIGTERM, SIGINT} NULL:");
+ s.last_success = start_time;
+
+ unblock_sigs();
do {
switch (ppoll(&pfd, 1U, &poll_timeout, NULL)) {
@@ -176,29 +154,32 @@ progress_print_loop(void *user)
case 0:
break;
default:
- r = read(progress_print_sig_pipe[0], &now, sizeof(now));
- if (r == (ssize_t)sizeof(now)) {
+ status_off = 0;
+ read_status_again:
+ r = read(status_print_pipe[0], &((char *)&s)[status_off], sizeof(s) - status_off);
+ if (r == (ssize_t)(sizeof(s) - status_off)) {
goto have_time;
} else if (!r) {
terminate = 1;
+ break;
} else if (r < 0) {
if (errno == EINTR)
- continue;
+ goto read_status_again;
eprintf("read <internal pipe>:");
+ } else {
+ status_off += (size_t)r;
+ goto read_status_again;
}
- break;
}
- if (clock_gettime(clck, &now))
+ if (clock_gettime(clck, &s.now))
eprintf("clock_gettime %s:", clkcstr);
have_time:
- pthread_mutex_lock(&progress_mutex);
if (exiting) {
fprintf(stderr, "\033[K\nTermination initialised by user...\033[K\n\033[K\n");
terminate = 1;
}
- print_progress(0, &now);
- wravg_update_time(&now);
- pthread_mutex_unlock(&progress_mutex);
+ print_status(0, &s);
+ wravg_update_time(&s);
} while (!terminate);
return NULL;
@@ -210,33 +191,46 @@ shredspan(int fd, struct span *span, const char *fname)
{
off_t off, n;
ssize_t r;
- struct timespec now, when = {0, 0};
+ size_t status_off;
+ struct timespec when = {0, 0};
int bad = span->bad > 0;
int first_fail = 1;
const char *random_data;
- pthread_mutex_lock(&progress_mutex);
-
- off = (direction == FORWARDS ? span->start : span->end);
- while (direction == FORWARDS ? off < span->end : off > span->start) {
+ off = (status.direction == FORWARDS ? span->start : span->end);
+ while (status.direction == FORWARDS ? off < span->end : off > span->start) {
if (exiting) {
userexit:
- if (direction == FORWARDS)
+ if (status.direction == FORWARDS)
span->start = off;
else
span->end = off;
- close(progress_print_sig_pipe[1]);
- progress_print_sig_pipe[1] = -1;
- goto out;
+ close(status_print_pipe[1]);
+ status_print_pipe[1] = -1;
+ return;
}
- if (clock_gettime(clck, &now))
+ if (clock_gettime(clck, &status.now))
eprintf("clock_gettime %s:", clkcstr);
- if (libsimple_cmptimespec(&now, &when) >= 0) {
- libsimple_sumtimespec(&when, &now, &progress_print_interval);
- write(progress_print_sig_pipe[1], &now, sizeof(now));
+ if (libsimple_cmptimespec(&status.now, &when) >= 0) {
+ libsimple_sumtimespec(&when, &status.now, &status_print_interval);
+ status_off = 0;
+ write_status_again:
+ r = write(status_print_pipe[1], &((const char *)&status)[status_off], sizeof(status) - status_off);
+ if (r != (ssize_t)(sizeof(status) - status_off)) {
+ if (r >= 0) {
+ status_off += (size_t)r;
+ goto write_status_again;
+ } else if (r == EINTR) {
+ if (exiting)
+ goto userexit;
+ goto write_status_again;
+ } else {
+ eprintf("write <internal pipe>:");
+ }
+ }
}
- if (direction == FORWARDS) {
+ if (status.direction == FORWARDS) {
n = MIN((off_t)span->blocksize, span->end - off);
} else {
n = off--;
@@ -248,69 +242,61 @@ shredspan(int fd, struct span *span, const char *fname)
break;
}
random_data = get_random(span->blocksize);
- pthread_mutex_unlock(&progress_mutex);
pwrite_again:
r = pwrite(fd, random_data, (size_t)n, off);
if (r < 0) {
if (errno == EINTR) {
- if (exiting) {
- pthread_mutex_lock(&progress_mutex);
+ if (exiting)
goto userexit;
- }
goto pwrite_again;
}
- pthread_mutex_lock(&progress_mutex);
if (errno != EIO)
weprintf("pwrite %s <buffer> %zu %ji:", fname, (size_t)n, (intmax_t)off);
add_span(off, n, span->blocksize == 1U ? 1U : span->blocksize >> 1, !first_fail);
first_fail = 0;
- if (direction == FORWARDS)
+ if (status.direction == FORWARDS)
off += n;
if (!span->bad)
- bad_bytes += n;
+ status.bad_bytes += n;
if (bad)
bad = 0;
else
- bad_sections += 1U;
+ status.bad_sections += 1U;
when.tv_sec = 0;
when.tv_nsec = 0;
- bad_writes += 1U;
+ status.bad_writes += 1U;
continue;
}
- pthread_mutex_lock(&progress_mutex);
- if (direction == FORWARDS) {
+ if (status.direction == FORWARDS) {
off += (off_t)r;
} else if ((off_t)r < n) {
n -= (off_t)r;
add_span(off + (off_t)r, n, span->blocksize == 1U ? 1U : span->blocksize >> 1, !first_fail);
first_fail = 0;
- if (direction == FORWARDS)
+ if (status.direction == FORWARDS)
off += n;
if (!span->bad)
- bad_bytes += n;
+ status.bad_bytes += n;
if (bad)
bad = 0;
else
- bad_sections += 1U;
+ status.bad_sections += 1U;
when.tv_sec = 0;
when.tv_nsec = 0;
- bad_writes += 1U;
+ status.bad_writes += 1U;
}
- shredded += (off_t)r;
+ status.shredded += (off_t)r;
used_random(r);
- wravg_update_write(r);
- last_success = now;
+ wravg_update_write(r, &status);
+ status.last_success = status.now;
if (span->bad) {
- bad_bytes -= (off_t)r;
+ status.bad_bytes -= (off_t)r;
span->bad -= (off_t)r;
}
}
if (bad && !span->bad)
- bad_sections -= 1U;
-
-out:
- pthread_mutex_unlock(&progress_mutex);
+ status.bad_sections -= 1U;
}
@@ -349,10 +335,7 @@ main(int argc, char *argv[])
off_t off = -1, len = -1, end = -1;
size_t i, j;
int fd;
- struct timespec now;
- struct sigaction sa;
- pthread_t progress_print_thread;
- sigset_t sigset;
+ pthread_t status_print_thread;
ARGBEGIN {
case 'o':
@@ -377,21 +360,6 @@ main(int argc, char *argv[])
if (argc != 1)
usage();
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = &signal_handler;
- sigemptyset(&sa.sa_mask);
- if (sigaction(SIGTERM, &sa, NULL))
- eprintf("sigaction SIGTERM {.sa_handler=<function>, .sa_mask={}, .sa_flags=0} NULL:");
- if (sigaction(SIGINT, &sa, NULL))
- eprintf("sigaction SIGINT {.sa_handler=<function>, .sa_mask={}, .sa_flags=0} NULL:");
-
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGTERM);
- sigaddset(&sigset, SIGINT);
- errno = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
- if (errno)
- eprintf("pthread_sigmask SIG_BLOCK {SIGTERM, SIGINT} NULL:");
-
fd = open(argv[0], O_WRONLY | O_DSYNC);
if (fd < 0)
eprintf("open %s O_WRONLY|O_DSYNC:", argv[0]);
@@ -425,16 +393,22 @@ main(int argc, char *argv[])
}
total_size = spans[0].end - spans[0].start;
+ if (!total_size) {
+ weprintf("attempting to shred 0 bytes");
+ close(fd);
+ return 0;
+ }
+
humansize1000(total_size, total_size_1000);
humansize1024(total_size, total_size_1024);
- if (pipe(progress_print_sig_pipe))
+ if (pipe(status_print_pipe))
eprintf("pipe:");
- errno = pthread_mutex_init(&progress_mutex, NULL);
- if (errno)
- eprintf("pthread_mutex_init NULL:");
- errno = pthread_create(&progress_print_thread, NULL, &progress_print_loop, NULL);
+ setup_sighandler();
+ block_sigs();
+
+ errno = pthread_create(&status_print_thread, NULL, &status_print_loop, NULL);
if (errno)
eprintf("pthread_create NULL:");
@@ -444,8 +418,8 @@ main(int argc, char *argv[])
if (clock_gettime(clck, &start_time))
eprintf("clock_gettime %s:", clkcstr);
}
- wravg_init(&start_time);
- last_success = start_time;
+ wravg_init(&start_time, &status);
+ status.last_success = start_time;
while (nspans) {
size_t old_nspans = nspans;
@@ -458,22 +432,21 @@ main(int argc, char *argv[])
/* 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;
- pass_nr++;
+ status.direction ^= 1;
+ status.pass_nr += 1U;
}
close(fd);
- if (progress_print_sig_pipe[1] >= 0)
- close(progress_print_sig_pipe[1]);
+ if (status_print_pipe[1] >= 0)
+ close(status_print_pipe[1]);
- errno = pthread_join(progress_print_thread, NULL);
+ errno = pthread_join(status_print_thread, NULL);
if (errno)
weprintf("pthread_join:");
- pthread_mutex_destroy(&progress_mutex);
- if (clock_gettime(clck, &now))
+ if (clock_gettime(clck, &status.now))
eprintf("clock_gettime %s:", clkcstr);
- print_progress(1, &now);
+ print_status(1, &status);
if (nspans) {
/* TODO document in man page */
diff --git a/sig.c b/sig.c
new file mode 100644
index 0000000..c7900fd
--- /dev/null
+++ b/sig.c
@@ -0,0 +1,50 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+static void
+sighandler(int signo)
+{
+ (void) signo;
+ exiting = 1;
+}
+
+
+void
+setup_sighandler(void)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = &sighandler;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGTERM, &sa, NULL))
+ eprintf("sigaction SIGTERM {.sa_handler=<function>, .sa_mask={}, .sa_flags=0} NULL:");
+ if (sigaction(SIGINT, &sa, NULL))
+ eprintf("sigaction SIGINT {.sa_handler=<function>, .sa_mask={}, .sa_flags=0} NULL:");
+}
+
+
+void
+block_sigs(void)
+{
+ sigset_t sigset;
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGTERM);
+ sigaddset(&sigset, SIGINT);
+ errno = pthread_sigmask(SIG_BLOCK, &sigset, NULL);
+ if (errno)
+ eprintf("pthread_sigmask SIG_BLOCK {SIGTERM, SIGINT} NULL:");
+}
+
+
+void
+unblock_sigs(void)
+{
+ sigset_t sigset;
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGTERM);
+ sigaddset(&sigset, SIGINT);
+ errno = pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
+ if (errno)
+ eprintf("pthread_sigmask SIG_UNBLOCK {SIGTERM, SIGINT} NULL:");
+}