/*  Copyright (C) 1993,1994 by the author(s).
 
 This software is published in the hope that it will be useful, but
 WITHOUT ANY WARRANTY for any part of this software to work correctly
 or as described in the manuals. See the ShapeTools Public License
 for details.

 Permission is granted to use, copy, modify, or distribute any part of
 this software but only under the conditions described in the ShapeTools 
 Public License. A copy of this license is supposed to have been given
 to you along with ShapeTools in a file named LICENSE. Among other
 things, this copyright notice and the Public License must be
 preserved on all copies.
 */
/*
 * AtFS -- Attribute Filesystem
 *
 * aferror.c -- Error handling functions
 *
 * Author: Andreas Lampen (Andreas.Lampen@cs.tu-berlin.de)
 *
 * $Header: aferror.c[7.0] Fri Jun 25 14:31:55 1993 andy@cs.tu-berlin.de frozen $
 */

#include <pwd.h>
#include <ctype.h>
#ifdef SYSLOG
#include <syslog.h>
#endif

#include "atfs.h"

static char logName[USER_MAX] = "";

/*=========================================================================
 *     af_serr -- report error without writing error protocol
 *=========================================================================*/

extern int  errno;
extern char *sys_errlist[];

EXPORT int af_errno, af_nodiag = FALSE;

EXPORT void af_serr (routine, called, errcd)
     char  *routine;
     char  *called;
     int   errcd;
{
  af_nodiag = TRUE;
  af_err (routine, called, errcd);
  af_nodiag = FALSE;
}    

/*=========================================================================
 *     af_err -- write error protocol
 *=========================================================================*/

static char diagstr[265]; /* for diagnistics of AF_EMISC */

static char *errors[] = 
  {
    "", "", "",
    "permission denied",				/*  3 */
    "archive file has changed since last read",		/*  4 */
    "archive file is locked for writing",		/*  5 */
    "no additional space in binary pool",		/*  6 */
    "specified revision must not be a busy version",	/*  7 */
    "specified revision is a derived object",		/*  8 */
    "invalid key",					/*  9 */
    "invalid set",					/* 10 */
    "invalid user",					/* 11 */
    "bad version number",				/* 12 */
    "invalid location of archive",			/* 13 */
    "application exceeds memory limit",                 /* 14 */
    "miscellaneous errors",				/* 15 */
    "invalid mode",					/* 16 */
    "AtFS subdirectory missing or not writable",	/* 17 */
    "key does not exist in set",			/* 18 */
    "invalid position in set",				/* 19 */
    "specified revision does not exist",		/* 20 */
    "specified object is no busy version",		/* 21 */
    "specified object is no derived object",		/* 22 */
    "version is not locked or locked by someone else",	/* 23 */
    "specified object is no regular file",		/* 24 */
    "specified object has no versions",			/* 25 */
    "user defined attribute does not exist",		/* 26 */
    "saved versions cannot be modified",		/* 27 */
    "invalid state transition",				/* 28 */
    "string too long",					/* 29 */
    "too many user defined attributes",			/* 30 */
    "wrong state",					/* 31 */
    "error during delta operation",			/* 32 */
    "Archive file inconsistent",			/* 33 */
    "internal error",					/* 34 */
    "no AtFS file",					/* 35 */
    "cannot build archive name (filename too long)",    /* 36 */
  };


EXPORT void af_err (routine, called, errcd)
     char  *routine;
     char  *called;
     int   errcd;
{
  char *prefix;
#ifndef SYSLOG
  FILE *errfile;
#endif

  if (af_nodiag) {
    af_errno = errcd;
    if (af_errno == AF_EMISC)
      strcpy (diagstr, called);
    return; /* do nothing */
  }

#ifdef SYSLOG
  if (!openlog ("AtFS", LOG_PID, LOG_LOCAL1)) {
#else
  if ((errfile = fopen (AF_ERRLOG, "a")) == NULL) {
#endif
    fprintf (stderr, "AtFS: cannot open Error-logfile\n");
    return;
  }
  chmod (AF_ERRLOG, 0666);

  if (!(*logName)) {
    struct passwd *pwent;
    if ((pwent = getpwuid (geteuid())))
      strcpy (logName, pwent->pw_name);
    else
      strcpy (logName, "--?--");
  }

  if (isupper (routine[0]))
    prefix = "af";
  else
    prefix = "af_";

#ifdef SYSLOG
  switch (errcd) {
  case AF_ESYSERR:
    syslog (LOG_ERR, "%s called %s%s: %s error in %s (%m)", 
	    logName, prefix, routine, errors [abs(errcd)], called);
    break;
  case AF_EINCONSIST:
  case AF_ENOATFSFILE:
  case AF_EINTERNAL:
    syslog (LOG_ERR, "%s called %s%s: %s (%s)", logName, prefix,
	    routine, errors [abs(errcd)], called);
    break;
  case AF_EMISC:
    syslog (LOG_ERR, "%s called %s%s: %s ", logName, prefix, routine, called);
    strcpy (diagstr, called);
    break;
  default:
    syslog (LOG_ERR, "%s called %s%s: %s", logName, prefix, routine, errors [abs(errcd)]);
  }
#else
  fprintf (errfile, "%s pid[%d] %s",af_gethostname(),getpid (), af_asctime ());
  switch (errcd) {
  case AF_ESYSERR:
    fprintf (errfile, "\t%s called %s%s: %s error in %s\n", 
	     logName, prefix, routine, errors [abs(errcd)], called);
    break;
  case AF_EINCONSIST:
  case AF_ENOATFSFILE:
  case AF_EINTERNAL:
    fprintf (errfile, "\t%s called %s%s: %s (%s)\n", logName, prefix, routine, errors [abs(errcd)], called);
    break;
  case AF_EMISC:
    fprintf (errfile, "\t%s called %s%s: %s\n", logName, prefix, routine, called);
    strcpy (diagstr, called);
    break;
  default:
    fprintf (errfile, "\t%s called %s%s: %s\n", logName, prefix, routine, errors [abs(errcd)]);
  }
#endif

#ifdef SYSLOG
  closelog ();
#else
  fclose (errfile);
#endif

  af_errno = errcd;
  return;
}

/*=========================================================================
 *     af_wng -- write warning to error protocol
 *=========================================================================*/

EXPORT void af_wng (routine, comment)
     char  *routine, *comment;
{
  char *prefix;
#ifndef SYSLOG
  FILE *errfile;
#endif

#ifdef SYSLOG
  if (!openlog ("AtFS", LOG_PID, LOG_LOCAL1)) {
#else
  if ((errfile = fopen (AF_ERRLOG, "a")) == NULL) {
#endif
    fprintf (stderr, "AtFS: cannot open Error-logfile\n");
    return;
  }
  chmod (AF_ERRLOG, 0666);

  if (!(*logName)) {
    struct passwd *pwent;
    if ((pwent = getpwuid (geteuid())))
      strcpy (logName, pwent->pw_name);
    else
      strcpy (logName, "--?--");
  }

  if (isupper (routine[0]))
    prefix = "af";
  else
    prefix = "af_";

#ifdef SYSLOG
  syslog (LOG_ERR, "%s called %s%s: Warning - %s", logName, prefix, routine, comment);
#else
  fprintf (errfile, "%s pid[%d] %s", af_gethostname(), getpid (), af_asctime ());
  fprintf (errfile, "\t%s called %s%s: Warning - %s\n", logName, prefix, routine, comment);
#endif

#ifdef SYSLOG
  closelog ();
#else
  fclose (errfile);
#endif
  return;
}


/*=========================================================================
 *     af_perror -- print AtFS-error message
 *=========================================================================*/

EXPORT void af_perror (string)
     char  *string;
{
  switch (af_errno) {
  case AF_ESYSERR:
    perror (string);
    break;
  case AF_EMISC:
    fprintf (stderr, "%s: %s\n", string, diagstr);
    break;
  default:
    fprintf (stderr, "%s: %s\n", string, errors [abs(af_errno)]);
  }
}


/*=========================================================================
 *     af_errmsg -- print AtFS-error message
 *=========================================================================*/

EXPORT char *af_errmsg (string)
     char  *string;
{
  static char errMsg[256];

  switch (af_errno) {
  case AF_ESYSERR:
    sprintf (errMsg, "%s: %s", string, sys_errlist[errno]);
    break;
  case AF_EMISC:
    sprintf (errMsg, "%s: %s", string, diagstr);
    break;
  default:
    sprintf (errMsg, "%s: %s", string, errors [abs(af_errno)]);
  }
  return (errMsg);
}
