From 2e55bedc45e836899a18ea7f4a488f50597afad5 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 21 Sep 2024 19:31:16 +0200 Subject: misc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- deadshred.c | 315 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 173 insertions(+), 142 deletions(-) (limited to 'deadshred.c') diff --git a/deadshred.c b/deadshred.c index d7f2f5f..24d02fa 100644 --- a/deadshred.c +++ b/deadshred.c @@ -3,15 +3,17 @@ #include -USAGE("[-b blocksize] [-o offset] [-l length | -e postend] [-r] device [< random-source]"); +USAGE("[-b blocksize] [-o offset] [-l length | -e postend] [-rY] device [map-file] [< random-source]"); -struct status status = STATUS_INIT; -_Atomic volatile sig_atomic_t exiting = 0; +struct auxthread_input { + struct status initial_status; + int map_fd; + const char *map_fname; +}; + -static struct span *spans = NULL; -static size_t nspans = 0; -static size_t spans_size = 0; +static struct status status = STATUS_INIT; static off_t total_size = 0; static char total_size_1000[256]; @@ -24,38 +26,7 @@ static struct timespec start_time; 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 -add_span(off_t off, off_t amount, size_t blocksize, int try_join) -{ - off_t end = off + amount; - - while ((off_t)(blocksize >> 1) >= amount) - blocksize >>= 1; - - if (try_join) { - if (off == spans[nspans - 1U].end || end == spans[nspans - 1U].start) { - spans[nspans - 1U].start = MIN(off, spans[nspans - 1U].start); - spans[nspans - 1U].end = MAX(end, spans[nspans - 1U].end); - spans[nspans - 1U].bad += amount; - spans[nspans - 1U].blocksize = MAX(blocksize, spans[nspans - 1U].blocksize); - return; - } - } - - if (nspans == spans_size) { - spans_size += 1024; - spans = ereallocarray(spans, spans_size, sizeof(*spans)); - } - - spans[nspans].start = off; - spans[nspans].end = end; - spans[nspans].bad = amount; - spans[nspans].blocksize = blocksize; - nspans++; -} +static int auxthread_pipe[2]; static void @@ -127,14 +98,27 @@ print_status(int done, struct status *s) } +static void +preprint(void) +{ + fprintf(stderr, "\n\n\n\n\n\n\033[K"); +} + + static void * -status_print_loop(void *initial_status) +auxthread_loop(void *input) { - struct pollfd pfd = {.fd = status_print_pipe[0], .events = POLLIN}; + struct pollfd pfd = {.fd = auxthread_pipe[0], .events = POLLIN}; ssize_t r; int terminate = 0; - struct status s = *(struct status *)initial_status; - size_t status_off; + int map_fd = ((struct auxthread_input *)input)->map_fd; + const char *map_fname = ((struct auxthread_input *)input)->map_fname; + struct status s = ((struct auxthread_input *)input)->initial_status; + size_t offset, spans_transfer_size; + + s.spans = NULL; + s.spans_size = 0; + s.span_off = 0; unblock_sigs(); @@ -149,22 +133,46 @@ status_print_loop(void *initial_status) case 0: break; default: - status_off = 0; + offset = 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) { + r = read(auxthread_pipe[0], &((char *)&s)[offset], STATUS_TRANSFER_SIZE - offset); + if (!r) { terminate = 1; break; } else if (r < 0) { if (errno == EINTR) goto read_status_again; eprintf("read :"); - } else { - status_off += (size_t)r; + } else if (r != (ssize_t)(STATUS_TRANSFER_SIZE - offset)) { + offset += (size_t)r; goto read_status_again; } + + if (!s.nspans) + goto have_time; + if (s.spans_size != s.nspans) { + s.spans_size = s.nspans; + s.spans = ereallocarray(s.spans, s.spans_size, sizeof(*s.spans)); + } + + offset = 0; + spans_transfer_size = s.nspans * sizeof(*s.spans); + read_spans_again: + r = read(auxthread_pipe[0], &((char *)s.spans)[offset], spans_transfer_size - offset); + if (!r) { + terminate = 1; + break; + } else if (r < 0) { + if (errno == EINTR) + goto read_spans_again; + eprintf("read :"); + } else if (r != (ssize_t)(spans_transfer_size - offset)) { + offset += (size_t)r; + goto read_spans_again; + } + + update_map(map_fd, &s, map_fname); + goto have_time; } if (clock_gettime(clck, &s.now)) eprintf("clock_gettime %s:", clkcstr); @@ -177,16 +185,16 @@ status_print_loop(void *initial_status) wravg_update_time(&s); } while (!terminate); + free(s.spans); return NULL; } static void -shredspan(int fd, struct span *span, const char *fname) +shredspan(int fd, struct span *span, const char *fname, int have_map) { off_t off, n; ssize_t r; - size_t status_off; struct timespec when = {0, 0}; int bad = span->bad > 0; int first_fail = 1; @@ -201,8 +209,8 @@ shredspan(int fd, struct span *span, const char *fname) span->start = off; else span->end = off; - close(status_print_pipe[1]); - status_print_pipe[1] = -1; + close(auxthread_pipe[1]); + auxthread_pipe[1] = -1; return; } @@ -213,22 +221,51 @@ shredspan(int fd, struct span *span, const char *fname) status.last_success = status.now; } if (libsimple_cmptimespec(&status.now, &when) >= 0) { + size_t saved_nspans = status.nspans; + size_t spans_transfer_size; + size_t spans_offset = 0; + size_t status_off = 0; libsimple_sumtimespec(&when, &status.now, &status_print_interval); - status_off = 0; + if (have_map && 0) /* TODO periodically 1 instead 0 */ + status.nspans -= status.span_off; + else + status.nspans = 0; + spans_transfer_size = status.nspans * sizeof(*status.spans); + spans_transfer_size += spans_offset = status.span_off * sizeof(*status.spans); 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)) { + r = write(auxthread_pipe[1], &((const char *)&status)[status_off], STATUS_TRANSFER_SIZE - status_off); + if (r != (ssize_t)(STATUS_TRANSFER_SIZE - status_off)) { if (r >= 0) { status_off += (size_t)r; goto write_status_again; } else if (r == EINTR) { - if (exiting) + if (exiting) { + status.nspans = saved_nspans; goto userexit; + } goto write_status_again; } else { eprintf("write :"); } } + status.nspans = saved_nspans; + if (spans_offset < spans_transfer_size) { + write_spans_again: + r = write(auxthread_pipe[1], &((const char *)status.spans)[spans_offset], + spans_transfer_size - spans_offset); + if (r != (ssize_t)(spans_transfer_size - spans_offset)) { + if (r >= 0) { + spans_offset += (size_t)r; + goto write_spans_again; + } else if (r == EINTR) { + if (exiting) + goto userexit; + goto write_spans_again; + } else { + eprintf("write :"); + } + } + } } if (status.direction == FORWARDS) { n = MIN((off_t)span->blocksize, span->end - off); @@ -252,7 +289,7 @@ shredspan(int fd, struct span *span, const char *fname) } if (errno != EIO) eprintf("pwrite %s %zu %ji:", fname, (size_t)n, (intmax_t)off); - add_span(off, n, span->blocksize == 1U ? 1U : span->blocksize >> 1, !first_fail); + add_span(&status, off, n, span->blocksize == 1U ? 1U : span->blocksize >> 1, !first_fail); first_fail = 0; if (status.direction == FORWARDS) off += n; @@ -271,7 +308,7 @@ shredspan(int fd, struct span *span, const char *fname) 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); + add_span(&status, off + (off_t)r, n, span->blocksize == 1U ? 1U : span->blocksize >> 1, !first_fail); first_fail = 0; if (status.direction == FORWARDS) off += n; @@ -300,43 +337,16 @@ shredspan(int fd, struct span *span, const char *fname) } -static void -dump_map(int fd, const char *fname) -{ - size_t i; - int r; - - if (!nspans) - return; - - for (i = 0; i < nspans; i++) { - r = dprintf(fd, "%s%jx-%jx/%zx", - i ? "," : "0x", - (uintmax_t)spans[i].start, - (uintmax_t)spans[i].end, - spans[i].blocksize); - if (r < 0) - goto fail; - } - r = dprintf(fd, "\n"); - if (r < 0) - goto fail; - - return; - -fail: - eprintf("dprintf %s:", fname); -} - - int main(int argc, char *argv[]) { off_t off = -1, len = -1, end = -1, blk = -1; size_t i, j; int fd, reverse_direction = 0; - pthread_t status_print_thread; - struct status initial_status; + int ask_for_confirmation = 1; + int map_fd = -1; + pthread_t auxthread; + struct auxthread_input auxthread_input; ARGBEGIN { case 'b': @@ -362,21 +372,18 @@ main(int argc, char *argv[]) case 'r': reverse_direction = 1; break; + case 'Y': + ask_for_confirmation = 0; + break; default: usage(); } ARGEND; - if (argc != 1) + if (argc < 1 || argc > 2) usage(); - /* TODO If in foreground, and /dev/tty can be opened, - * use /dev/tty — however if stdin is a tty, use - * stdin instead — to request configuration unless - * bypassed with new option (-Y). The prompt shall - * be identify the device and display it's size, - * also the section the wipe shall be displayed - * if -elo was used. The use shall be required - * to enter 'yes' in upper case. */ + if (ask_for_confirmation && !confirm(argv[0], off, len, end)) + return 1; fd = open(argv[0], O_WRONLY | O_DSYNC); if (fd < 0) @@ -384,52 +391,62 @@ main(int argc, char *argv[]) init_random(STDIN_FILENO, "", blk); - spans = emalloc(sizeof(*spans)); - spans[0].start = 0; - spans[0].end = filesize(fd, argv[0]); - spans[0].bad = 0; - spans[0].blocksize = max_blksize(); - nspans = 1U; - spans_size = 1U; + status.spans = emalloc(sizeof(*status.spans)); + status.spans[0].start = 0; + status.spans[0].end = filesize(fd, argv[0]); + status.spans[0].bad = 0; + status.spans[0].blocksize = max_blksize(); + status.nspans = 1U; + status.spans_size = 1U; if (off >= 0) { - if (off > spans[0].end) - eprintf("value of -o flag is beyond the end of the file"); - spans[0].start = off; + if (off > status.spans[0].end) + eprintf("value of -o option is beyond the end of the file"); + status.spans[0].start = off; } if (len >= 0) { - if (len > OFF_MAX - spans[0].start) - eprintf("the sum of the values of -o and -l flag is too large"); - end = spans[0].start + len; - if (end > spans[0].end) - eprintf("the sum of the values of -o and -l flag is beyond the end of the file"); - spans[0].end = end; + if (len > OFF_MAX - status.spans[0].start) + eprintf("the sum of the values of -o and -l option is too large"); + end = status.spans[0].start + len; + if (end > status.spans[0].end) + eprintf("the sum of the values of -o and -l option is beyond the end of the file"); + status.spans[0].end = end; } else if (end >= 0) { - if (end > spans[0].end) - eprintf("the value of -e flag is beyond the end of the file"); - spans[0].end = end; + if (end > status.spans[0].end) + eprintf("the value of -e option is beyond the end of the file"); + status.spans[0].end = end; } - total_size = spans[0].end - spans[0].start; + total_size = status.spans[0].end - status.spans[0].start; if (!total_size) { weprintf("attempting to shred 0 bytes"); close(fd); return 0; } - while ((off_t)spans[0].blocksize >> 1 > total_size) - spans[0].blocksize >>= 1; + while ((off_t)status.spans[0].blocksize >> 1 > total_size) + status.spans[0].blocksize >>= 1; humansize1000(total_size, total_size_1000); humansize1024(total_size, total_size_1024); - if (pipe(status_print_pipe)) + if (reverse_direction) + status.direction ^= 1; + + if (argv[1]) { + map_fd = open(argv[1], O_RDWR | O_CREAT, 0666); + if (map_fd < 0) + eprintf("open %s O_RDWR|O_CREAT 0666:", argv[1]); + if (lseek(map_fd, 0, SEEK_SET)) + eprintf("lseek %s 0 SEEK_SET:", argv[1]); + status.shredded = load_map(fd, &status, status.direction, argv[1]); + } + + if (pipe(auxthread_pipe)) eprintf("pipe:"); setup_sighandler(); block_sigs(); - if (reverse_direction) - status.direction ^= 1; if (clock_gettime(clck, &start_time)) { clck = CLOCK_MONOTONIC; clkcstr = "CLOCK_MONOTONIC"; @@ -439,33 +456,38 @@ main(int argc, char *argv[]) wravg_init(&start_time, &status); status.last_success = start_time; - initial_status = status; - errno = pthread_create(&status_print_thread, NULL, &status_print_loop, &initial_status); + auxthread_input.initial_status = status; + auxthread_input.map_fd = map_fd; + auxthread_input.map_fname = argv[1]; + errno = pthread_create(&auxthread, NULL, &auxthread_loop, &auxthread_input); if (errno) eprintf("pthread_create NULL:"); + libsimple_eprintf_preprint = &preprint; + for (;;) { - size_t old_nspans = nspans; - for (i = 0; i < old_nspans && !exiting; i++) - shredspan(fd, &spans[i], argv[0]); - if (exiting) { - memmove(&spans[0], &spans[i], (nspans -= i) * sizeof(*spans)); - break; + size_t old_nspans = status.nspans; + for (i = 0; i < old_nspans; i++) { + status.span_off = i; + shredspan(fd, &status.spans[i], argv[0], map_fd >= 0); + if (exiting) + goto out; } - for (i = 0, j = nspans, nspans -= old_nspans; i < nspans;) - spans[i++] = spans[--j]; - if (!nspans) + for (i = 0, j = status.nspans, status.nspans -= old_nspans; i < status.nspans;) + status.spans[i++] = status.spans[--j]; + if (!status.nspans) break; status.direction ^= 1; status.pass_nr += 1U; } +out: close(fd); - if (status_print_pipe[1] >= 0) - close(status_print_pipe[1]); + if (auxthread_pipe[1] >= 0) + close(auxthread_pipe[1]); destroy_random(); - errno = pthread_join(status_print_thread, NULL); + errno = pthread_join(auxthread, NULL); if (errno) weprintf("pthread_join:"); @@ -473,10 +495,19 @@ main(int argc, char *argv[]) eprintf("clock_gettime %s:", clkcstr); print_status(1, &status); - if (nspans) { - dump_map(STDOUT_FILENO, ""); - if (close(STDOUT_FILENO)) - eprintf("write "); + if (status.nspans > status.span_off) { + if (map_fd >= 0) { + update_map(map_fd, &status, argv[0]); + if (close(map_fd)) + eprintf("write %s:", argv[0]); + } else { + dump_map(STDOUT_FILENO, &status, ""); + if (close(STDOUT_FILENO)) + eprintf("write :"); + } + } else if (argv[1]) { + if (unlink(argv[1])) + weprintf("unlink %s:", argv[1]); } return 0; } -- cgit v1.2.3-70-g09d2