/*
 * dloverlay.c - dynamic library system call pre-emption
 * brian.s.walden	mcmxciii
 *
 * for Solaris 1.x
 * 
 * cc -O -PIC -c dloverlay.c;ld dloverlay.o -assert pure-text -o dloverlay.so
 * LD_PRELOAD=dloverlay.so
 *
 * currently only overlays gettimeofday(2), hostid(2),
 *  gethostname(2), getdomainname(2), uname(2), and open(2)
 *
 * set any of these envrinment variables:
 *	TIMEOFDAY	set clock offest in seconds: +/- or absolute
 *	HOSTID		hex hostid (0x prefix is OK, non-hex will make it 0)
 *	HOSTNAME	hostname
 *	DOMAINNAME	domainname
 *	SYSNAME		system os type (eg. SunOS)
 *	RELEASE		system os release (eg. 4.1.3)
 *	VERSION		system os version (eg. 5)
 *	MACHINE		machine type (eg. sun4c)
 *	OPEN_DEBUG	setting it in env prints opens on stderr
 *
 * Note: the env vars must be unset and not just nulled out to get back
 * the real syscall operations.
 *
 */

#include <string.h>
#include <sys/syscall.h>

extern char *getenv();

#include <sys/time.h>

gettimeofday(tp, tzp)
struct timeval *tp;
struct timezone *tzp;
{
	int rc;
	if((rc = syscall(SYS_gettimeofday, tp, tzp)) == 0) {
		char *tmmod = getenv("TIMEOFDAY");
		if(tmmod) {
			long delta = atol(tmmod);
			switch (*tmmod) {
			case '-':
			case '+':
				tp->tv_sec += delta;
				break;
			default:
				tp->tv_sec = delta;
				break;
			}
		}
	}
	return rc;
}

gethostid()
{
	char *strhostid = getenv("HOSTID");
	long hostid = strhostid ?
		 strtol(strhostid, (char **)0, 16) : syscall(SYS_gethostid);
	return hostid;
}

gethostname(name, len)
char *name;
{
	char *hostname = getenv("HOSTNAME");
	if(hostname && name) {
		strncpy(name, hostname, len);
		return 0;
	}
	return syscall(SYS_gethostname, name, len);
}

getdomainname(name, len)
char *name;
{
	char *domainname = getenv("DOMAINNAME");
	if(domainname && name) {
		strncpy(name, domainname, len);
		return 0;
	}
	return syscall(SYS_getdomainname, name, len);
}

#include <sys/utsname.h>

uname(name)
struct utsname *name;
{
	int rc;
	char *env;

	if( (rc = syscall(SYS_uname, name)) == 0) {
		/* you have to "know" the utsname structure sizes */
		if(env=getenv("SYSNAME")) strncpy(name->sysname, env, 8);
		if(env=getenv("HOSTNAME")) strncpy(name->nodename, env, 64);
		if(env=getenv("RELEASE")) strncpy(name->release, env, 8);
		if(env=getenv("VERSION")) strncpy(name->version, env, 8);
		if(env=getenv("MACHINE")) strncpy(name->machine, env, 8);
	}
	return rc;
}

#include <stdio.h> /* for stderr */
extern errno;

/* WARNING1: this open does not implement the system v
 * style error if given a null path name, see open(2)
 * WARNING2: this does I/O, caveat if you overlay write(2).
 * NB: this should be expanded to decode the flags and errno
 */
open(path, flags, mode)
char *path;
{	
	char *odebug = getenv("OPEN_DEBUG");
	int fd;

	if(odebug) fprintf(stderr, "[pid=%d/uid=%d] open(\"%s\", %o, %o) = ",
			getpid(), getuid(), path, flags, mode);
	fd = syscall(SYS_open, path, flags, mode);
	if(odebug) fprintf(stderr, fd==(-1)?"[errno %d]\n":"%d\n",
			fd==(-1)?errno:fd);
	return fd;
}
