diff options
Diffstat (limited to 'test/pwrite-wrap.c')
-rw-r--r-- | test/pwrite-wrap.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/test/pwrite-wrap.c b/test/pwrite-wrap.c new file mode 100644 index 0000000..7939041 --- /dev/null +++ b/test/pwrite-wrap.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> + * License: GPLv3 or later (see COPYING for details) + */ +/* + * fault injection wrapper for pwrite + */ +#include "cmogstored.h" +#include "iov_str.h" +#include <poll.h> +#include <sys/uio.h> +static sig_atomic_t pwrite_wrap_flags; +static int pwrite_slow_msec = 5000; +#define PWRITE_WRAP_NONE (0) +#define PWRITE_WRAP_SLOW (1) +#define PWRITE_WRAP_PARTIAL (1 << 1) +#define PWRITE_WRAP_ENOSPC (1 << 2) +#define PWRITE_WRAP_MAX 4 +static const char * const pwrite_wrap_names[] = { + "none", "slow", "partial", "enospc" +}; + +#define EMIT(s) write(STDERR_FILENO, (s), sizeof(s)-1) + +/* test/pwrite_wrap.rb depends on the following line */ +static const char msg[] = "pwrite fault injection\n"; + +int __real_pwrite(int fd, void *buf, size_t count, off_t offset); + +int __wrap_pwrite(int fd, void *buf, size_t count, off_t offset) +{ + if (pwrite_wrap_flags & PWRITE_WRAP_SLOW) { + poll(NULL, 0, pwrite_slow_msec); + } + if ((pwrite_wrap_flags & PWRITE_WRAP_PARTIAL) && (count > 0)) + count--; + if (pwrite_wrap_flags & PWRITE_WRAP_ENOSPC) { + errno = ENOSPC; + return -1; + } + + return __real_pwrite(fd, buf, count, offset); +} + +static void set_wrap_pwrite(int signum) +{ + static sig_atomic_t pwrite_wrap_knob = 0; + struct iovec vec[3]; + union { const char *in; void *out; } name; + + switch (signum) { + case SIGVTALRM: + pwrite_wrap_knob = (pwrite_wrap_knob + 1) % PWRITE_WRAP_MAX; + IOV_STR(&vec[0], "knob set: "); + break; + case SIGTTIN: + pwrite_wrap_flags |= pwrite_wrap_knob; + IOV_STR(&vec[0], "flag set: "); + break; + case SIGTTOU: + pwrite_wrap_flags ^= pwrite_wrap_knob; + IOV_STR(&vec[0], "flag clr: "); + break; + default: assert(0 && "unknown signal caught"); + } + + name.in = pwrite_wrap_names[pwrite_wrap_knob]; + vec[1].iov_base = name.out; + vec[1].iov_len = strlen(name.in); + + IOV_STR(&vec[2], "\n"); + writev(STDERR_FILENO, vec, 3); +} + +__attribute__((constructor)) void pwrite_wrap_init(void) +{ + struct sigaction sa; + const char slow_env[] = "PWRITE_WRAP_SLOW_MSEC"; + const char *msec = getenv(slow_env); + + memset(&sa, 0, sizeof(struct sigaction)); + CHECK(int, 0, sigemptyset(&sa.sa_mask) ); + sa.sa_handler = set_wrap_pwrite; + CHECK(int, 0, sigaction(SIGVTALRM, &sa, NULL)); + CHECK(int, 0, sigaction(SIGTTIN, &sa, NULL)); + CHECK(int, 0, sigaction(SIGTTOU, &sa, NULL)); + + if (msec) { + char *end; + unsigned long v = strtoul(msec, &end, 10); + + if (*end || v > INT_MAX) + die("Invalid %s=%s", slow_env, msec); + pwrite_slow_msec = v; + fprintf(stderr, "set %s=%d\n", slow_env, pwrite_slow_msec); + } +} |