about summary refs log tree commit homepage
path: root/test/pwrite-wrap.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/pwrite-wrap.c')
-rw-r--r--test/pwrite-wrap.c97
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);
+        }
+}