From 44cff01e5bbe04ff991ede843e96f0c2d83d20c6 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Thu, 19 Sep 2024 18:03:17 +0200 Subject: Split into multiple C files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- deadshred.c | 400 +++--------------------------------------------------------- 1 file changed, 16 insertions(+), 384 deletions(-) (limited to 'deadshred.c') 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 -#include -#include +#include "common.h" #include +/* 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 :"); - } - 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 -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 :"); - } 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, ""); 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; -- cgit v1.2.3-70-g09d2