* tests/fault_injection.c: New file.
* tests/fault_injection.test: New test.
* tests/fault_syntax.test: Likewise.
* tests/.gitignore: Add fault_injection.
* tests/Makefile.am (check_PROGRAMS): Likewise.
(MISC_TESTS): Add fault_injection.test and fault_syntax.test.
fallocate
fanotify_init
fanotify_mark
+fault_injection
fchdir
fchmod
fchmodat
fallocate \
fanotify_init \
fanotify_mark \
+ fault_injection \
fchdir \
fchmod \
fchmodat \
detach-running.test \
detach-sleeping.test \
detach-stopped.test \
+ fault_injection.test \
+ fault_syntax.test \
filter-unavailable.test \
fork-f.test \
ksysent.test \
--- /dev/null
+/*
+ * Check that fault injection works properly.
+ *
+ * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+static const int expfd = 4;
+static const int gotfd = 5;
+
+#ifndef __s390__
+# define DEFAULT_ERRNO ENOSYS
+#else /* __s390__ */
+/* Invalid syscall number causes EPERM instead of traditional ENOSYS. */
+# define DEFAULT_ERRNO EPERM
+#endif
+
+static const char *errstr;
+static int is_raw, err, first, step, iter, try;
+
+static void
+invoke(int fail)
+{
+ static char buf[sizeof(int) * 3 + 3];
+ const struct iovec io = {
+ .iov_base = buf,
+ .iov_len = sprintf(buf, "%d.", ++try)
+ };
+ int rc;
+
+ if (!fail) {
+ rc = write(expfd, io.iov_base, io.iov_len);
+ if (rc != (int) io.iov_len)
+ perror_msg_and_fail("write");
+ }
+
+ errno = 0;
+ rc = writev(gotfd, &io, 1);
+
+ if (fail) {
+ if (!(rc == -1 && errno == err))
+ perror_msg_and_fail("expected errno %d"
+ ", got rc == %d, errno == %d",
+ err, rc, errno);
+
+ if (is_raw)
+ tprintf("writev(%#x, %p, 0x1) = -1 (errno %d)"
+ " (INJECTED)\n", gotfd, &io, err);
+ else
+ tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%d}], 1)"
+ " = -1 %s (%m) (INJECTED)\n",
+ gotfd, buf, (int) io.iov_len, errstr);
+ } else {
+ if (rc != (int) io.iov_len)
+ perror_msg_and_fail("expected %d"
+ ", got rc == %d, errno == %d",
+ (int) io.iov_len, rc, errno);
+
+ if (is_raw)
+ tprintf("writev(%#x, %p, 0x1) = %#x\n", gotfd, &io, rc);
+ else
+ tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%d}], 1)"
+ " = %d\n",
+ gotfd, buf, (int) io.iov_len, (int) io.iov_len);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct stat st;
+
+ assert(fstat(expfd, &st) == 0);
+ assert(fstat(gotfd, &st) == 0);
+
+ assert(argc == 6);
+
+ is_raw = !strcmp("raw", argv[1]);
+
+ errstr = argv[2];
+ err = atoi(errstr);
+ assert(err >= 0);
+
+ if (!err) {
+ if (!*errstr)
+ err = DEFAULT_ERRNO;
+ else if (!strcmp(errstr, "EINVAL"))
+ err = EINVAL;
+ else
+ err = ENOSYS;
+ }
+
+ errno = err;
+ errstr = errno2name();
+
+ first = atoi(argv[3]);
+ step = atoi(argv[4]);
+ iter = atoi(argv[5]);
+
+ assert(first > 0);
+ assert(step >= 0);
+
+ tprintf("%s", "");
+
+ int i;
+ for (i = 1; i <= iter; ++i) {
+ int fail = 0;
+ if (first > 0) {
+ --first;
+ if (first == 0) {
+ fail = 1;
+ first = step;
+ }
+ }
+ invoke(fail);
+ }
+
+ tprintf("%s\n", "+++ exited with 0 +++");
+ return 0;
+}
--- /dev/null
+#!/bin/sh
+#
+# Check that fault injection works properly.
+#
+# Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+. "${srcdir=.}/init.sh"
+
+#
+# F
+# F+
+# F+S
+
+N=16
+
+check_fault_injection()
+{
+ local trace fault err first step
+ trace=$1; shift
+ fault=$1; shift
+ err=$1; shift
+ first=$1; shift
+ step=$1; shift
+
+ local when=
+ if [ -z "$first$step" ]; then
+ first=1
+ step=1
+ else
+ case "$step" in
+ '') when=":when=$first"; step=0 ;;
+ +) when=":when=$first+"; step=1 ;;
+ *) when=":when=$first+$step" ;;
+ esac
+ fi
+
+ local error=
+ local raw=reg
+ set --
+ case "$err" in
+ '') ;;
+ [123456789]*)
+ error=":error=$err"
+ raw=raw
+ set -- -e raw=all
+ ;;
+ *) error=":error=$err" ;;
+ esac
+
+ outexp="$NAME.out.exp"
+ outgot="$NAME.out.got"
+
+ run_strace -a11 -e trace=$trace \
+ -e fault=$fault$when$error "$@" \
+ ./$NAME $raw "$err" "$first" "$step" $N \
+ > "$EXP" 4> "$outexp" 5> "$outgot"
+
+ match_diff "$EXP" "$LOG"
+ match_diff "$outexp" "$outgot"
+ rm -f "$EXP" "$outexp" "$outgot"
+}
+
+for err in '' ENOSYS 22 EINVAL; do
+ for fault in writev 51,desc; do
+ check_fault_injection \
+ writev $fault "$err" '' ''
+ for F in 1 2 3 5 7 11; do
+ check_fault_injection \
+ writev $fault "$err" $F ''
+ check_fault_injection \
+ writev $fault "$err" $F +
+ for S in 1 2 3 5 7 11; do
+ check_fault_injection \
+ writev $fault "$err" $F $S
+ done
+ done
+ done
+done
--- /dev/null
+#!/bin/sh
+#
+# Check -e fault= syntax.
+#
+# Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+. "${srcdir=.}/init.sh"
+
+#
+# F
+# F+
+# F+S
+
+fail_with()
+{
+ dump_log_and_fail_with \
+ "strace -e fault=$* failed to handle an argument error properly"
+}
+
+for arg in invalid_syscall_name \
+ invalid_syscall_name:when=3 \
+ -1 \
+ -1:when=4 \
+ -2 \
+ -2:when=5 \
+ 32767 \
+ 32767:when=6 \
+ chdir:42 \
+ chdir:42:when=7 \
+ chdir:invalid \
+ chdir:invalid:when=8 \
+ chdir:error= \
+ chdir:error=:when=10 \
+ chdir:error=invalid_error_name \
+ chdir:error=invalid_error_name:when=11 \
+ chdir:error=-1 \
+ chdir:error=-1:when=12 \
+ chdir:error=-2 \
+ chdir:error=-2:when=13 \
+ chdir:error=3+ \
+ chdir:error=3+:when=14 \
+ chdir:error=4096 \
+ chdir:error=4096:when=15 \
+ chdir:when=7:error=invalid_error_name \
+ chdir:when= \
+ chdir:when=:error=19 \
+ chdir:when=0 \
+ chdir:when=0:error=20 \
+ chdir:when=-1 \
+ chdir:when=-1:error=21 \
+ chdir:when=-2+ \
+ chdir:when=-2+:error=22 \
+ chdir:when=-3+0 \
+ chdir:when=-3+0:error=23 \
+ chdir:when=4- \
+ chdir:when=4-:error=24 \
+ chdir:when=5+- \
+ chdir:when=5+-:error=25 \
+ chdir:when=6++ \
+ chdir:when=6++:error=26 \
+ chdir:when=7+0 \
+ chdir:when=7+0:error=27 \
+ chdir:when=8+-1 \
+ chdir:when=8+-1:error=28 \
+ chdir:when=9+1+ \
+ chdir:when=9+1+:error=29 \
+ chdir:when=65536 \
+ chdir:when=65536:error=30 \
+ chdir:when=1+65536 \
+ chdir:when=1+65536:error=31 \
+ ; do
+ $STRACE -e fault="$arg" true 2> "$LOG" &&
+ fail_with "$arg"
+ LC_ALL=C grep -F 'invalid fault argument' < "$LOG" > /dev/null ||
+ fail_with "$arg"
+done
+
+exit 0