/* $Header: sysdep.c,v 2.9 90/05/03 10:13:06 chip Exp $
 *
 * Routines which are (or might well be) system-dependant.
 * I've put the message routines here since you may need to use
 * the ANSI <stdarg.h> instead of <varargs.h>.
 *
 * $Log:	sysdep.c,v $
 * Revision 2.9  90/05/03  10:13:06  chip
 * Support nap() call in ABCenix.  (Huh?)
 * 
 * Revision 2.8  90/03/06  12:21:16  chip
 * Move logging into log.c and address parsing into addr.c.
 * New: error delivery file for messages that fail.
 * Major rearrangement of delivery file code.
 * 
 * Revision 2.7  90/02/23  14:16:52  chip
 * Support "#!" in delivery files.
 * Support "user|program" and "user?error" from delivery files.
 * Improve debugging and error message formatting.
 * Rearrange code for clarity.
 * 
 * Revision 2.6  90/02/06  11:56:43  chip
 * Enforce MBX_MODE regardless of UMASK.
 * Enforce ordered logging with a log lockfile.
 * Revise log format.
 * 
 * Revision 2.5  89/12/19  16:29:47  network
 * Make timezone handling portable to System V.
 * 
 * Revision 2.4  89/11/10  12:23:58  network
 * Log recursion depth, undelivered mail and failed headers.
 * 
 * Revision 2.3  89/11/01  12:19:06  network
 * Delintify.
 * 
 * Revision 2.2  89/11/01  11:51:51  network
 * Add logging.
 * 
 * Revision 2.1  89/06/09  12:25:40  network
 * Update RCS revisions.
 * 
 * Revision 1.8  89/06/09  12:23:59  network
 * Baseline for 2.0 release.
 * 
 */

#include "deliver.h"
#include <errno.h>
#ifdef HAS_STDARG
#include <stdarg.h>
#else
#ifdef HAS_VARARGS
#include <varargs.h>
#else
/*
 * Non-portable home-grown varargs.  Use at your own risk.
 * Especially note that if sizeof(int) > sizeof(short), then
 * "va_arg(..,short)" is broken.
 */
typedef char *va_list;
#define va_dcl          int va_alist;
#define va_start(ap)    ap = (char *) &va_alist
#define va_arg(ap,type) *(type *)(ap += sizeof(type), ap - sizeof(type))
#define va_end(ap)      /* nothing */
#endif
#endif

#ifdef UNAME
#include <sys/utsname.h>
#endif

/*
 * External functions.
 */

#if defined(M_XENIX) || defined(ABCenix)
#define CALL_NAP
#endif

#ifdef CALL_NAP
extern  long    nap();
#else
extern  unsigned sleep();
#endif

/*
 * External data.
 */

extern  int     errno;
extern  int     sys_nerr;
/* extern  char    *sys_errlist[]; */

/*
 * Locally useful macros.
 */

/* Wrapper macros to hide stdarg/vararg differences. */

#ifdef HAS_STDARG
#define FMT_PARAM       (char *fmt, ...)
#define FMT_VARS        va_list ap;
#define FMT_START       va_start(ap, fmt);
#define FMT_END         va_end(ap);
#else
#define FMT_PARAM       (va_alist) va_dcl
#define FMT_VARS        va_list ap; char *fmt;
#define FMT_START       va_start(ap); fmt = va_arg(ap, char *);
#define FMT_END         va_end(ap);
#endif

/*----------------------------------------------------------------------
 * Print a message.
 */

/* VARARGS */
message
FMT_PARAM
{
	FMT_VARS

	FMT_START
	(void) vfprintf(stderr, fmt, ap);
	FMT_END

	if (errlog)
	{
		errstart();
		FMT_START
		(void) vfprintf(errlog, fmt, ap);
		FMT_END
	}
}

/*----------------------------------------------------------------------
 * Print an error message.
 */

/* VARARGS */
error
FMT_PARAM
{
	FMT_VARS

	FMT_START
	(void) fprintf(stderr, "%s: ", progname);
	(void) vfprintf(stderr, fmt, ap);
	FMT_END

	if (errlog)
	{
		errstart();
		FMT_START
		(void) fprintf(errlog, "%s: ", progname);
		(void) vfprintf(errlog, fmt, ap);
		FMT_END
	}
}

/*----------------------------------------------------------------------
 * Report an error returned from a system call.
 */

/* VARARGS */
syserr
FMT_PARAM
{
	int     e = errno;
	FMT_VARS

	FMT_START
	(void) fprintf(stderr, "%s: ", progname);
	vsyserr(stderr, fmt, ap, e);
	FMT_END

	if (errlog)
	{
		errstart();
		FMT_START
		(void) fprintf(errlog, "%s: ", progname);
		vsyserr(errlog, fmt, ap, e);
		FMT_END
	}
}

vsyserr(fp, fmt, ap, e)
FILE    *fp;
char    *fmt;
va_list ap;
int     e;
{
	(void) vfprintf(fp, fmt, ap);
	if (e <= sys_nerr)
		(void) fprintf(fp, ": %s\n", sys_errlist[e]);
	else
		(void) fprintf(fp, ": unknown system error %d\n", e);
}

/*----------------------------------------------------------------------
 * Sleep for the given number of seconds.
 */

snooze(n)
int     n;
{
#ifdef CALL_NAP
	(void) nap(n * 1000L);
#else
	(void) sleep(n);
#endif
}

/*----------------------------------------------------------------------
 * Get the host name from HOSTFILE.
 */

#ifdef HOSTFILE

char *
gethost()
{
	int     fd, rd;
	char    *p;
	static char name[32];

	if ((fd = open(HOSTFILE, O_RDONLY)) == -1)
		return NULL;
	rd = read(fd, name, sizeof(name) - 1);
	(void) close(fd);

	if (rd < 1)
		return NULL;
	name[rd] = 0;
	if ((p = strchr(name, '\n')) != NULL)
		*p = 0;

	return (name[0] ? name : NULL);
}

#endif /* HOSTFILE */

/*----------------------------------------------------------------------
 * Get the host name via the uname() system call.
 */

#ifdef UNAME

char *
gethost()
{
	static struct utsname u;

	uname(&u);
	return (u.nodename[0] ? u.nodename : NULL);
}

#endif /* UNAME */

/*----------------------------------------------------------------------
 * Get the host name via the gethostname() system call.
 */

#ifdef GETHOSTNAME

char *
gethost()
{
	static char hostname[64];

	if (gethostname(hostname, sizeof(hostname)) == -1)
		return NULL;

	return hostname;
}

#endif /* GETHOSTNAME */

/*----------------------------------------------------------------------
 * Return a pre-defined HOSTNAME.
 */

#ifdef HOSTNAME

char *
gethost()
{
	return HOSTNAME;
}

#endif /* HOSTNAME */

/*----------------------------------------------------------------------
 * Variable-argument-list output, System V style.
 */

#ifndef HAS_VPRINTF

vprintf(fmt, ap)
char    *fmt;
va_list ap;
{
	int     a,b,c,d,e,f,g,h;

	a = va_arg(ap, int);
	b = va_arg(ap, int);
	c = va_arg(ap, int);
	d = va_arg(ap, int);
	e = va_arg(ap, int);
	f = va_arg(ap, int);
	g = va_arg(ap, int);
	h = va_arg(ap, int);

	(void) printf(fmt, a,b,c,d,e,f,g,h);
}

vfprintf(fp, fmt, ap)
FILE    *fp;
char    *fmt;
va_list ap;
{
	int     a,b,c,d,e,f,g,h;

	a = va_arg(ap, int);
	b = va_arg(ap, int);
	c = va_arg(ap, int);
	d = va_arg(ap, int);
	e = va_arg(ap, int);
	f = va_arg(ap, int);
	g = va_arg(ap, int);
	h = va_arg(ap, int);

	(void) fprintf(fp, fmt, a,b,c,d,e,f,g,h);
}

vsprintf(s, fmt, ap)
char    *s;
char    *fmt;
va_list ap;
{
	int     a,b,c,d,e,f,g,h;

	a = va_arg(ap, int);
	b = va_arg(ap, int);
	c = va_arg(ap, int);
	d = va_arg(ap, int);
	e = va_arg(ap, int);
	f = va_arg(ap, int);
	g = va_arg(ap, int);
	h = va_arg(ap, int);

	(void) sprintf(s, fmt, a,b,c,d,e,f,g,h);
}

#endif  /* !HAS_VPRINTF */

/*----------------------------------------------------------------------
 * Add a new environment variable.
 */

#ifndef HAS_PUTENV

int
putenv(s)
char *s;
{
	static  char    **env_array;
	static  int     env_size;
	char    *e;
	int     i, j;

	if (env_array == NULL)
	{
		for (i = 0; environ[i]; ++i)
			{}
		env_size = i + 10;      /* arbitrary */
		env_array = (char **) zalloc(env_size * sizeof(char *));
		Copy((char *)env_array, (char *)environ,
		     (int) ((i + 1) * sizeof(char *)));
		environ = env_array;
	}
	else if (environ != env_array)
		message("putenv: warning: someone moved environ!\n");

	if ((e = strchr(s, '=')) != NULL)
		++e;
	else
		e = s + strlen(s);

	j = 0;
	for (i = 0; env_array[i]; ++i)
	{
		if (strncmp(env_array[i], s, e - s) != 0)
			env_array[j++] = env_array[i];
	}

	if ((j + 1) >= env_size)
	{
		env_size += 10;                 /* arbitrary */
		env_array = (char **) srealloc((char *)env_array,
					env_size * sizeof(char **));
	}

	env_array[j++] = s;
	env_array[j] = NULL;

	environ = env_array;
	return 0;
}

#endif  /* !HAS_PUTENV */

/*----------------------------------------------------------------------
 * Memory copy.
 */

#ifdef MEMFUNCS

Copy(dest, src, len)
char    *dest;
char    *src;
int     len;
{
	while (len-- > 0)
		*dest++ = *src++;
}

#endif

/*----------------------------------------------------------------------
 * Memory clear.
 */

#ifdef MEMFUNCS

Zero(dest, len)
char    *dest;
int     len;
{
	while (len-- > 0)
		*dest++ = 0;
}

#endif
