/*Last Modified:   6-MAR-1992 14:58:48.87, By: MARK */
/*
* Error handling routines from Stevens: UNIX network programming
* pp 722-731
*/

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

#include "vmsgopherd.h"
#include <varargs.h>

#ifdef CLIENT
#ifdef SERVER
/*no way jose, can't define both! (CLIENT and SERVER)*/
#endif
#endif

#ifndef CLIENT
#ifndef SERVER
#define CLIENT 1
#endif
#endif

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

extern char *pname;

#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.
*
*/

/*VARARGS1*/
err_quit(va_alist)
va_dcl
{
       va_list args;
       char *fmt;

       va_start(args);
       if (pname != NULL)
               fprintf(stderr, "%s: ",pname);
       fmt = va_arg(args, char *);
       vfprintf(stderr, fmt, args);
       fputc('\n', stderr);
       va_end(args);

/*      exit(1);        */

}

/*
* Fatal error related to a system call. Print the message and terminate.
* Don't dump core, but do print the systems errno value and its
* associated message.
*
*      err_sys(str, arg1, arg2, ...)
*
*/

/*VARARGS1*/
err_sys(va_alist)
va_dcl
{
       va_list args;
       char *fmt;

       va_start(args);
       if (pname != NULL)
               fprintf(stderr, "%s: ", pname);
       fmt = va_arg(args, char *);
       vfprintf(stderr, fmt, args);
       va_end(args);

       my_perror();

/*      exit(1);   */

}


/*
* Recoverable error. print a message and return to the caller.
*
*      err_ret(str, arg1, arg2, ...)
*/

/*VARARGS1*/
err_ret(va_alist)
va_dcl
{
       va_list args;
       char    *fmt;

       va_start(args);
       if (pname != NULL)
               fprintf(stderr, "%s: ", pname);
       fmt = va_arg(args, char *);
       vfprintf(stderr, fmt, args);
       va_end(args);

       my_perror();

       fflush(stdout);
       fflush(stderr);
       return;
}


/*
* Fatal error.  Print a message, dump core and terminate.
*
*      err_dump(str, arg1, arg2, ....)
*
*/

/*VARARGS1*/
err_dump(va_alist)
va_dcl
{
       va_list args;
       char *fmt;

       va_start(args);
       if (pname != NULL)
               fprintf(stderr, "%s: ", pname);
       fmt = va_arg(args, char *);
       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);       */
}

/*
* Print the UNIX errno value
*/


my_perror()
{
       char *sys_err_str();

       fprintf(stderr, " %s\n", sys_err_str());
}

#endif /* CLIENT */

#ifdef SERVER

#ifdef BSD
/*
 * Under BSD, these server routines use the syslog(3) facility.
 * They don't append a newline for example.
 */

#include <syslog.h>


#else /* not BSD */
/*
* There really ought to be a better way to handle server logging
* under System V
*/

#define syslog(a,b)     fprintf(stderr, "%s\n", (b))
#define openlog(a,b,c)  fprintf(stderr, "%s\n", (a))

#endif  /* BSD */

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

/*
* Identify ourselves, 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 the console if unable to
* send the message to syslogd.
* LOG_DAEMON is our facility.
*/

err_init(ident)
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, ...)
*/

/*VARARGS1*/
err_quit(va_alist)
va_dcl
{
       va_list args;
       char *fmt;

       va_start(args);
       fmt = va_arg(args, char *);
       vsprintf(emesgstr, fmt, args);
       va_end(args);

       syslog(LOG_ERR, emesgstr);

/*      exit(1)   */

}


/*
* Fatal error related to a system call.  Print the message and terminate.
* Don't dump core, but do print the systems errno value and its associated
* message.
*/

/*VARARGS*/
err_sys(va_alist)
va_dcl
{
       va_list args;
       char *fmt;

       va_start(args);
       fmt = va_arg(args, char *);
       vsprintf(emesgstr, fmt, args);
       va_end(args);

       my_perror();
       syslog(LOG_ERR, emesgstr);

/*      exit(1);   */

}


/*
* Recoverable error.  Print a message, and return to caller.
*/

/*VARARGS1*/
err_ret(va_alist)
va_dcl
{
       va_alist args;
       char *fmt;

       va_start(args);
       fmt = va_arg(args, char *);
       vsprintf(emergstr, fmt, args);
       va_end(args);

       my_perror();
       syslog(LOG_ERR, emergstr);

       return;
}


/*
* Fatal error.  Print a message, dump core and terminate.
*/

/*VARARGS1*/
err_dump(va_alist)
va_dcl
{
       va_list args;
       char *fmt;

       va_start(args);
       fmt = va_arg(args, char *);
       vsprintf(emesgstr, fmt, args);
       va_end(args);

       my_perror();
       syslog(LOG_ERR, emesgstr);

/*      abort();
       exit(1);    */

}

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

void
my_perror()
{
       int len;
       char *sys_err_str();

       len = strlen(emesgstr);
       sprintf(emesgstr + len, " %s", sys_err_str());
}

#endif  /* SERVER */


extern int vmserrno;            /* UNIX error number */
extern int sys_nerr;            /* # of error message strings in sys table */
extern char *sys_errlist[];     /* the system error message table */

#ifdef SYS5
int t_errno;
int t_nerr;
char *t_errlist[1];
#endif

/*
* 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".  This means that if an error
* condition is being sent ot 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()
{
       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';
       }

#ifdef SYS5

       if (t_errno != 0) {
               char tmsgstr[100];

               if (t_errno > 0 && t_errno < sys_nerr)
                       sprintf(tmsgstr, " (%s)", t_errlist[t_errno]);
               else
                       sprintf(tmsgstr, ", (t_errno = %d)", t_errno);

               strcat(msgstr, tmsgstr);
       }
#endif

       return(msgstr);
}