/*
 * LD_PRELOAD library to ERADICATE *sync().
 *
 * Compile on Linux with:
 * gcc -nostartfiles -fpic -shared -D_GNU_SOURCE=1 nosync.c -o nosync.so -ldl
 *
 * To test:
 * env LD_PRELOAD=`pwd`/nosync.so <normal command>
 *
 * To install, add this path to /etc/ld.so.preload; HOWEVER, note that
 * udev and early boot programs will also try to load it and may fail
 * if it cannot be found (eg: if it is not on the root file system).
 *
 * Change 2010-07-29: Also disable sync() unless called by a program
 * containing "sync" in the name.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <stdarg.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>
#define sync __noclobber_sync
#define fsync __noclobber_fsync
#define fdatasync __noclobber_fdatasync
#define open __noclobber_open
#define open64 __noclobber_open64
#include <unistd.h>
#undef open64
#undef open
#undef fdatasync
#undef fsync
#undef sync
#include <string.h>

static int (*real_open)(const char *, int, ...);
static int (*real_open64)(const char *, int, ...);
static void (*real_sync)(void);

void _init(void)
{
	const char *err;
	int save_errno;

	save_errno = errno;
	unlink("/-/nosync-init/-/");
	errno = save_errno;
	real_sync = dlsym(RTLD_NEXT, "sync");
	if ((err = dlerror()) != NULL)
		fprintf(stderr, "dlsym(open): %s\n", err);
	real_open = dlsym(RTLD_NEXT, "open");
	if ((err = dlerror()) != NULL)
		fprintf(stderr, "dlsym(open): %s\n", err);
	real_open64 = dlsym(RTLD_NEXT, "open64");
	err = dlerror();
}

void _fini(void)
{
}

int open(const char *pathname, int flags, ...)
{
	va_list args;
	mode_t mode;

	va_start(args, flags);
	flags&= ~O_SYNC;
	mode = va_arg(args,int);
	va_end(args);
	if (real_open)
		return real_open(pathname,flags,mode);
	return syscall(SYS_open,pathname,flags,mode);
}

int open64(const char *pathname, int flags, ...)
{
	va_list args;
	mode_t mode;

	va_start(args, flags);
	flags&= ~O_SYNC;
	mode = va_arg(args,int);
	va_end(args);
	if (real_open64)
		return real_open64(pathname,flags,mode);
	return syscall(SYS_open,pathname,flags | O_LARGEFILE,mode);
}

int sync()
{
	ssize_t r;
	int save_errno = errno;
	char buf[256];
	unlink("/-/sync/-/");
	r = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
	errno = save_errno;
	if (r > 0) {
		buf[r] = '\0';
		if (strstr(buf,"sync"))
			real_sync();
	}
}

int fsync()
{
	int save_errno = errno;
	unlink("/-/fsync/-/");
	errno = save_errno;
	return 0;
}

int fdatasync()
{
	int save_errno = errno;
	unlink("/-/fdatasync/-/");
	errno = save_errno;
	return 0;
}
