summaryrefslogtreecommitdiffstats
path: root/contrib/zkt/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/zkt/log.c')
-rw-r--r--contrib/zkt/log.c443
1 files changed, 443 insertions, 0 deletions
diff --git a/contrib/zkt/log.c b/contrib/zkt/log.c
new file mode 100644
index 0000000..021be98
--- /dev/null
+++ b/contrib/zkt/log.c
@@ -0,0 +1,443 @@
+/*****************************************************************
+**
+** @(#) log.c -- The ZKT error logging module
+**
+** Copyright (c) June 2008, Holger Zuleger HZnet. All rights reserved.
+**
+** This software is open source.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** Redistributions in binary form must reproduce the above copyright notice,
+** this list of conditions and the following disclaimer in the documentation
+** and/or other materials provided with the distribution.
+**
+** Neither the name of Holger Zuleger HZnet nor the names of its contributors may
+** be used to endorse or promote products derived from this software without
+** specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+** POSSIBILITY OF SUCH DAMAGE.
+**
+**
+*****************************************************************/
+# include <stdio.h>
+# include <string.h>
+# include <stdlib.h>
+# include <ctype.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/time.h>
+# include <time.h>
+# include <assert.h>
+# include <errno.h>
+# include <syslog.h>
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+# include "config_zkt.h"
+# include "misc.h"
+# include "debug.h"
+#define extern
+# include "log.h"
+#undef extern
+
+/*****************************************************************
+** module internal vars & declarations
+*****************************************************************/
+static FILE *lg_fp;
+static int lg_minfilelevel;
+static int lg_syslogging;
+static int lg_minsyslevel;
+static long lg_errcnt;
+static const char *lg_progname;
+
+typedef struct {
+ lg_lvl_t level;
+ const char *str;
+ int syslog_level;
+} lg_symtbl_t;
+
+static lg_symtbl_t symtbl[] = {
+ { LG_NONE, "none", -1 },
+ { LG_DEBUG, "debug", LOG_DEBUG },
+ { LG_INFO, "info", LOG_INFO },
+ { LG_NOTICE, "notice", LOG_NOTICE },
+ { LG_WARNING, "warning", LOG_WARNING },
+ { LG_ERROR, "error", LOG_ERR },
+ { LG_FATAL, "fatal", LOG_CRIT },
+
+ { LG_NONE, "user", LOG_USER },
+ { LG_NONE, "daemon", LOG_DAEMON },
+ { LG_NONE, "local0", LOG_LOCAL0 },
+ { LG_NONE, "local1", LOG_LOCAL1 },
+ { LG_NONE, "local2", LOG_LOCAL2 },
+ { LG_NONE, "local3", LOG_LOCAL3 },
+ { LG_NONE, "local4", LOG_LOCAL4 },
+ { LG_NONE, "local5", LOG_LOCAL5 },
+ { LG_NONE, "local6", LOG_LOCAL6 },
+ { LG_NONE, "local7", LOG_LOCAL7 },
+ { LG_NONE, NULL, -1 }
+};
+
+# define MAXFNAME (1023)
+/*****************************************************************
+** function definitions (for function declarations see log.h)
+*****************************************************************/
+
+/*****************************************************************
+** lg_fileopen (path, name) -- open the log file
+** Name is a (absolute or relative) file or directory name.
+** If path is given and name is a relative path name then path
+** is prepended to name.
+** returns the open file pointer or NULL on error
+*****************************************************************/
+static FILE *lg_fileopen (const char *path, const char *name)
+{
+ int len;
+ FILE *fp;
+ struct tm *t;
+ time_t sec;
+ char fname[MAXFNAME+1];
+
+ if ( name == NULL || *name == '\0' )
+ return NULL;
+ else if ( *name == '/' || path == NULL )
+ snprintf (fname, MAXFNAME, "%s", name);
+ else
+ snprintf (fname, MAXFNAME, "%s/%s", path, name);
+
+# ifdef LOG_TEST
+ fprintf (stderr, "\t ==> \"%s\"", fname);
+# endif
+ if ( is_directory (fname) )
+ {
+ len = strlen (fname);
+
+ time (&sec);
+ t = gmtime (&sec);
+ snprintf (fname+len, MAXFNAME-len, LOG_FNAMETMPL,
+ t->tm_year + 1900, t->tm_mon+1, t->tm_mday,
+ t->tm_hour, t->tm_min, t->tm_sec);
+# ifdef LOG_TEST
+ fprintf (stderr, " isdir \"%s\"", fname);
+# endif
+ }
+
+# ifdef LOG_TEST
+ fprintf (stderr, "\n");
+# endif
+
+ if ( (fp = fopen (fname, "a")) == NULL )
+ return NULL;
+
+ return fp;
+}
+
+/*****************************************************************
+** lg_str2lvl (level_name)
+*****************************************************************/
+lg_lvl_t lg_str2lvl (const char *name)
+{
+ lg_symtbl_t *p;
+
+ if ( !name )
+ return LG_NONE;
+
+ for ( p = symtbl; p->str; p++ )
+ if ( strcasecmp (name, p->str) == 0 )
+ return p->level;
+
+ return LG_NONE;
+}
+
+/*****************************************************************
+** lg_lvl2syslog (level)
+*****************************************************************/
+lg_lvl_t lg_lvl2syslog (lg_lvl_t level)
+{
+ lg_symtbl_t *p;
+
+ for ( p = symtbl; p->str; p++ )
+ if ( level == p->level )
+ return p->syslog_level;
+
+ assert ( p->str != NULL ); /* we assume not to reach this! */
+
+ return LOG_DEBUG; /* if not found, return DEBUG as default */
+}
+
+/*****************************************************************
+** lg_str2syslog (facility_name)
+*****************************************************************/
+int lg_str2syslog (const char *facility)
+{
+ lg_symtbl_t *p;
+
+ dbg_val1 ("lg_str2syslog (%s)\n", facility);
+ if ( !facility )
+ return LG_NONE;
+
+ for ( p = symtbl; p->str; p++ )
+ if ( strcasecmp (facility, p->str) == 0 )
+ return p->syslog_level;
+
+ return LG_NONE;
+}
+
+/*****************************************************************
+** lg_lvl2str (level)
+*****************************************************************/
+const char *lg_lvl2str (lg_lvl_t level)
+{
+ lg_symtbl_t *p;
+
+ if ( level < LG_DEBUG )
+ return "none";
+
+ for ( p = symtbl; p->str; p++ )
+ if ( level == p->level )
+ return p->str;
+ return "fatal";
+}
+
+/*****************************************************************
+** lg_geterrcnt () -- returns the current value of the internal
+** error counter
+*****************************************************************/
+long lg_geterrcnt ()
+{
+ return lg_errcnt;
+}
+
+/*****************************************************************
+** lg_seterrcnt () -- sets the internal error counter
+** returns the current value
+*****************************************************************/
+long lg_seterrcnt (long value)
+{
+ return lg_errcnt = value;
+}
+
+/*****************************************************************
+** lg_reseterrcnt () -- resets the internal error counter to 0
+** returns the current value
+*****************************************************************/
+long lg_reseterrcnt ()
+{
+ return lg_seterrcnt (0L);
+}
+
+
+/*****************************************************************
+** lg_open (prog, facility, syslevel, path, file, filelevel)
+** -- open the log channel
+** return values:
+** 0 on success
+** -1 on file open error
+*****************************************************************/
+int lg_open (const char *progname, const char *facility, const char *syslevel, const char *path, const char *file, const char *filelevel)
+{
+ int sysfacility;
+
+ dbg_val6 ("lg_open (%s, %s, %s, %s, %s, %s)\n", progname, facility, syslevel, path, file, filelevel);
+
+ lg_minsyslevel = lg_str2lvl (syslevel);
+ lg_minfilelevel = lg_str2lvl (filelevel);
+
+ sysfacility = lg_str2syslog (facility);
+ if ( sysfacility >= 0 )
+ {
+ lg_syslogging = 1;
+ dbg_val2 ("lg_open: openlog (%s, LOG_NDELAY, %d)\n", progname, lg_str2syslog (facility));
+ openlog (progname, LOG_NDELAY, lg_str2syslog (facility));
+ }
+ if ( file && * file )
+ {
+ if ( (lg_fp = lg_fileopen (path, file)) == NULL )
+ return -1;
+ lg_progname = progname;
+ }
+
+ return 0;
+}
+
+/*****************************************************************
+** lg_close () -- close the open filepointer for error logging
+** return 0 if no error log file is currently open,
+** otherwise the return code of fclose is returned.
+*****************************************************************/
+int lg_close ()
+{
+ int ret = 0;
+
+ if ( lg_syslogging )
+ {
+ closelog ();
+ lg_syslogging = 0;
+ }
+ if ( lg_fp )
+ {
+ ret = fclose (lg_fp);
+ lg_fp = NULL;
+ }
+
+ return ret;
+}
+
+/*****************************************************************
+**
+** lg_args (level, argc, argv[])
+** log all command line arguments (up to a length of 511 chars)
+** with priority level
+**
+*****************************************************************/
+void lg_args (lg_lvl_t level, int argc, char * const argv[])
+{
+ char cmdline[511+1];
+ int len;
+ int i;
+
+ len = 0;
+ for ( i = 0; i < argc && len < sizeof (cmdline); i++ )
+ len += snprintf (cmdline+len, sizeof (cmdline) - len, " %s", argv[i]);
+
+#if 1
+ lg_mesg (level, "------------------------------------------------------------");
+#else
+ lg_mesg (level, "");
+#endif
+ lg_mesg (level, "running%s ", cmdline);
+}
+
+/*****************************************************************
+**
+** lg_mesg (level, fmt, ...)
+**
+** Write a given message to the error log file and counts
+** all messages written with an level greater than LOG_ERR.
+**
+** All messages will be on one line in the logfile, so it's
+** not necessary to add an '\n' to the message.
+**
+** To call this function before an elog_open() is called is
+** useless!
+**
+*****************************************************************/
+void lg_mesg (int priority, char *fmt, ...)
+{
+ va_list ap;
+ struct timeval tv;
+ struct tm *t;
+ char format[256];
+
+ assert (fmt != NULL);
+ assert (priority >= LG_DEBUG && priority <= LG_FATAL);
+
+ format[0] ='\0';
+
+ dbg_val3 ("syslog = %d prio = %d >= sysmin = %d\n", lg_syslogging, priority, lg_minsyslevel);
+ if ( lg_syslogging && priority >= lg_minsyslevel )
+ {
+#if defined (LOG_WITH_LEVEL) && LOG_WITH_LEVEL
+ snprintf (format, sizeof (format), "%s: %s", lg_lvl2str(priority), fmt);
+ fmt = format;
+#endif
+ va_start(ap, fmt);
+ vsyslog (lg_lvl2syslog (priority), fmt, ap);
+ va_end(ap);
+ }
+
+ dbg_val3 ("filelg = %d prio = %d >= filmin = %d\n", lg_fp!=NULL, priority, lg_minfilelevel);
+ if ( lg_fp && priority >= lg_minfilelevel )
+ {
+#if defined (LOG_WITH_TIMESTAMP) && LOG_WITH_TIMESTAMP
+ gettimeofday (&tv, NULL);
+ t = localtime ((time_t *) &tv.tv_sec);
+ fprintf (lg_fp, "%04d-%02d-%02d ",
+ t->tm_year+1900, t->tm_mon+1, t->tm_mday);
+ fprintf (lg_fp, "%02d:%02d:%02d.%03ld: ",
+ t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec / 1000);
+#endif
+#if defined (LOG_WITH_PROGNAME) && LOG_WITH_PROGNAME
+ if ( lg_progname )
+ fprintf (lg_fp, "%s: ", lg_progname);
+#endif
+#if defined (LOG_WITH_LEVEL) && LOG_WITH_LEVEL
+ if ( fmt != format ) /* level is not in fmt string */
+ fprintf (lg_fp, "%s: ", lg_lvl2str(priority));
+#endif
+ va_start(ap, fmt);
+ vfprintf (lg_fp, fmt, ap);
+ va_end(ap);
+ fprintf (lg_fp, "\n");
+ }
+
+ if ( priority >= LG_ERROR )
+ lg_errcnt++;
+}
+
+
+#ifdef LOG_TEST
+const char *progname;
+int main (int argc, char *argv[])
+{
+ const char *levelstr;
+ const char *newlevelstr;
+ int level;
+ int err;
+
+ progname = *argv;
+
+ if ( --argc )
+ levelstr = *++argv;
+ else
+ levelstr = "fatal";
+
+ level = lg_str2lvl (levelstr);
+ newlevelstr = lg_lvl2str (level+1);
+ dbg_val4 ("base level = %s(%d) newlevel = %s(%d)\n", levelstr, level, newlevelstr, level+1);
+ if ( (err = lg_open (progname,
+#if 1
+ "user",
+#else
+ "none",
+#endif
+ levelstr, ".",
+#if 1
+ "test.log",
+#else
+ NULL,
+#endif
+ newlevelstr)) )
+ fprintf (stderr, "\topen error %d\n", err);
+ else
+ {
+ lg_mesg (LG_DEBUG, "debug message");
+ lg_mesg (LG_INFO, "INFO message");
+ lg_mesg (LG_NOTICE, "Notice message");
+ lg_mesg (LG_WARNING, "Warning message");
+ lg_mesg (LG_ERROR, "Error message");
+ lg_mesg (LG_FATAL, "Fatal message ");
+ }
+
+ if ( (err = lg_close ()) < 0 )
+ fprintf (stderr, "\tclose error %d\n", err);
+
+ return 0;
+}
+#endif