From 1b4db814ead1a5f3fcebba6c6e408ee25d1e71c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Fran=C3=A7ois?= Date: Sat, 20 Sep 2014 16:15:32 +0200 Subject: [PATCH] Add support for syscall failure tests --- tests/common/Makefile | 14 ++++++++ tests/common/link_failure.c | 51 +++++++++++++++++++++++++++ tests/common/unlinkat_failure.c | 62 +++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 tests/common/Makefile create mode 100644 tests/common/link_failure.c create mode 100644 tests/common/unlinkat_failure.c diff --git a/tests/common/Makefile b/tests/common/Makefile new file mode 100644 index 00000000..4ee04dd7 --- /dev/null +++ b/tests/common/Makefile @@ -0,0 +1,14 @@ +all: \ + fopen_failure.so \ + link_failure.so \ + open_RDONLY_failure.so \ + open_RDWR_failure.so \ + rename_failure.so \ + rmdir_failure.so \ + time_0.so \ + time_past.so \ + unlink_failure.so \ + unlinkat_failure.so + +%.so: %.c + gcc -W -Wall -pedantic -g $< -shared -ldl -o $@ diff --git a/tests/common/link_failure.c b/tests/common/link_failure.c new file mode 100644 index 00000000..8cf460a6 --- /dev/null +++ b/tests/common/link_failure.c @@ -0,0 +1,51 @@ +/* + * gcc link_failure.c -o link_failure.so -shared -ldl + * LD_PRELOAD=./link_failure.so FAILURE_PATH=/etc/shadow ./test /etc/shadow + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +typedef int (*link_type) (const char *oldpath, const char *newpath); +static link_type next_link; + +static const char *failure_path = NULL; + +int link (const char *oldpath, const char *newpath) +{ + if (NULL == next_link) + { + next_link = dlsym (RTLD_NEXT, "link"); + assert (NULL != next_link); + } + if (NULL == failure_path) { + failure_path = getenv ("FAILURE_PATH"); + if (NULL == failure_path) { + fputs ("No FAILURE_PATH defined\n", stderr); + } + } + + if ( (NULL != newpath) + && (NULL != failure_path) + && (strcmp (newpath, failure_path) == 0)) + { + fprintf (stderr, "link FAILURE %s %s\n", oldpath, newpath); + errno = EIO; + return -1; + } + + return next_link (oldpath, newpath); +} + diff --git a/tests/common/unlinkat_failure.c b/tests/common/unlinkat_failure.c new file mode 100644 index 00000000..5b8bf958 --- /dev/null +++ b/tests/common/unlinkat_failure.c @@ -0,0 +1,62 @@ +/* + * gcc unlinkat_failure.c -o unlinkat_failure.so -shared -ldl + * LD_PRELOAD=./unlinkat_failure.so FAILURE_PATH=/etc/shadow ./test /etc/shadow + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +typedef int (*unlinkat_type) (int dirfd, const char *pathname, int flags); +static unlinkat_type next_unlinkat; + +static const char *failure_path = NULL; +static dev_t failure_dev = -1; +static ino_t failure_ino = -1; + +int unlinkat (int dirfd, const char *pathname, int flags) +{ + if (NULL == next_unlinkat) + { + next_unlinkat = dlsym (RTLD_NEXT, "unlinkat"); + assert (NULL != next_unlinkat); + } + if (NULL == failure_path) { + struct stat sb; + failure_path = getenv ("FAILURE_PATH"); + if (NULL == failure_path) { + fputs ("No FAILURE_PATH defined\n", stderr); + } + if (lstat (failure_path, &sb) != 0) { + fputs ("Can't lstat FAILURE_PATH\n", stderr); + } + failure_dev = sb.st_dev; + failure_ino = sb.st_ino; + } + + if ( (NULL != pathname) + && (NULL != failure_path)) { + struct stat sb; + if ( (fstatat (dirfd, pathname, &sb, flags) == 0) + && (sb.st_dev == failure_dev) + && (sb.st_ino == failure_ino)) { + fprintf (stderr, "unlinkat FAILURE %s\n", failure_path); + errno = EBUSY; + return -1; + } + } + + return next_unlinkat (dirfd, pathname, flags); +} +