/*
 * Error handling routines.
 *
 * The functions in this file are independent of any application
 * variables, and may be used with any C program.
 * Either of the names CLIENT or SERVER may be defined when compiling
 * this function.  If neither are defined, we assume CLIENT.
 */

#include	<stdio.h>
#include	<stdarg.h>

#ifdef	CLIENT
#ifdef	SERVER
#error cant define both CLIENT and SERVER
#endif
#endif

#ifndef	CLIENT
#ifndef	SERVER
#define	CLIENT	1		/* default to client */
#endif
#endif

#ifndef	NULL
#define	NULL	((void *) 0)
#endif

char	*pname = NULL;
static void my_perror(void);

#ifdef	CLIENT			/* these all output to stderr */

/*
 * Fatal error.  Print a message and terminate.
 * Don't dump core and don't print the system's errno value.
 *
 *	err_quit(str, arg1, arg2, ...)
 *
 * The string "str" must specify the conversion specification for any args.
 */

void
err_quit(char *fmt, ...)
{
  va_list		args;
  
  va_start(args, fmt);
  if (pname != NULL)
    fprintf(stderr, "%s: ", pname);
  vfprintf(stderr, fmt, args);
  fputc('\n', stderr);
  va_end(args);
  
  exit(1);
}

/*
 * Fatal error related to a system call.  Print a message and terminate.
 * Don't dump core, but do print the system's errno value and its
 * associated message.
 *
 *	err_sys(str, arg1, arg2, ...)
 *
 * The string "str" must specify the conversion specification for any args.
 */

void
err_sys(char *fmt, ...)
{
  va_list		args;
  
  va_start(args, fmt);
  if (pname != NULL)
    fprintf(stderr, "%s: ", pname);
  vfprintf(stderr, fmt, args);
  va_end(args);
  
  my_perror();
  
  exit(1);
}

/*
 * Recoverable error.  Print a message, and return to caller.
 *
 *	err_ret(str, arg1, arg2, ...)
 *
 * The string "str" must specify the conversion specification for any args.
 */

void
err_ret(char *fmt, ...)
{
  va_list		args;
  
  va_start(args, fmt);
  if (pname != NULL)
    fprintf(stderr, "%s: ", pname);
  vfprintf(stderr, fmt, args);
  va_end(args);
  
  my_perror();
  
  fflush(stdout);
  fflush(stderr);
  
  return;
}

/*
 * Fatal error.  Print a message, dump core (for debugging) and terminate.
 *
 *	err_dump(str, arg1, arg2, ...)
 *
 * The string "str" must specify the conversion specification for any args.
 */

void
err_dump(char *fmt, ...)
{
  va_list		args;
  
  va_start(args, fmt);
  if (pname != NULL)
    fprintf(stderr, "%s: ", pname);
  vfprintf(stderr, fmt, args);
  va_end(args);
  
  my_perror();
  
  fflush(stdout);		/* abort doesn't flush stdio buffers */
  fflush(stderr);
  
  abort();		/* dump core and terminate */
  exit(1);		/* shouldn't get here */
}

/*
 * Print the UNIX errno value.
 */

void
my_perror(void)
{
  char	*sys_err_str(void);
  
  fprintf(stderr, " %s\n", sys_err_str());
}

#endif	/* CLIENT */

#ifdef	SERVER

#include	<syslog.h>

char	emesgstr[255] = {0};	/* used by all server routines */

/*
 * Identify ourself, for syslog() messages.
 *
 * LOG_PID is an option that says prepend each message with our pid.
 * LOG_CONS is an option that says write to console if unable to send
 * the message to syslogd.
 * LOG_DAEMON is our facility.
 */

void
err_init(char *ident)
{
  openlog(ident, (LOG_PID | LOG_CONS), LOG_DAEMON);
}

/*
 * Fatal error.  Print a message and terminate.
 * Don't print the system's errno value.
 *
 *	err_quit(str, arg1, arg2, ...)
 *
 * The string "str" must specify the conversion specification for any args.
 */

void
err_quit(char *fmt, ...)
{
  va_list		args;
  
  va_start(args, fmt);
  vsprintf(emesgstr, fmt, args);
  va_end(args);
  
  syslog(LOG_ERR, emesgstr);
  
  exit(1);
}

/*
 * Fatal error related to a system call.  Print a message and terminate.
 * Don't dump core, but do print the system's errno value and its
 * associated message.
 *
 *	err_sys(str, arg1, arg2, ...)
 *
 * The string "str" must specify the conversion specification for any args.
 */

void
err_sys(char *fmt, ...)
{
  va_list		args;
  
  va_start(args, fmt);
  vsprintf(emesgstr, fmt, args);
  va_end(args);
  
  my_perror();
  syslog(LOG_ERR, emesgstr);
  
  exit(1);
}

/*
 * Recoverable error.  Print a message, and return to caller.
 *
 *	err_ret(str, arg1, arg2, ...)
 *
 * The string "str" must specify the conversion specification for any args.
 */

void
err_ret(char *fmt, ...)
{
  va_list		args;
  
  va_start(args, fmt);
  vsprintf(emesgstr, fmt, args);
  va_end(args);
  
  my_perror();
  syslog(LOG_ERR, emesgstr);
  
  return;
}

/*
 * Fatal error.  Print a message, dump core (for debugging) and terminate.
 *
 *	err_dump(str, arg1, arg2, ...)
 *
 * The string "str" must specify the conversion specification for any args.
 */

void
err_dump(char *fmt, ...)
{
  va_list		args;
  
  va_start(args, fmt);
  vsprintf(emesgstr, fmt, args);
  va_end(args);
  
  my_perror();
  syslog(LOG_ERR, emesgstr);
  
  abort();		/* dump core and terminate */
  exit(1);		/* shouldn't get here */
}

/*
 * Print the UNIX errno value.
 * We just append it to the end of the emesgstr[] array.
 */

void
my_perror(void)
{
  register int	len;
  char		*sys_err_str(void);
  
  len = strlen(emesgstr);
  sprintf(emesgstr + len, " %s", sys_err_str());
}

#endif	/* SERVER */

    /* remainder is for both CLIENT and SERVER */
extern int	errno;		/* Unix error number */
extern int	sys_nerr;	/* # of error message strings in sys table */
extern char	*sys_errlist[];	/* the system error message table */

/*
 * Return a string containing some additional operating-system
 * dependent information.
 * Note that different versions of UNIX assign different meanings
 * to the same value of "errno" (compare errno's starting with 35
 * between System V and BSD, for example).  This means that if an error
 * condition is being sent to another UNIX system, we must interpret
 * the errno value on the system that generated the error, and not
 * just send the decimal value of errno to the other system.
 */

char *
sys_err_str(void)
{
  static char	msgstr[200];
  
  if (errno != 0)
    {
      if (errno > 0 && errno < sys_nerr)
        sprintf(msgstr, "(%s)", sys_errlist[errno]);
      else
        sprintf(msgstr, "(errno = %d)", errno);
    }
  else
    {
      msgstr[0] = '\0';
    }
  
  return(msgstr);
}
