/* log.c -- Logging routines, for a single, program-wide logging facility * Created: Mon Mar 10 09:37:21 1997 by faith@dict.org * Revised: Sun Mar 31 11:54:19 2002 by faith@dict.org * Copyright 1997-1999, 2001-2002 Rickard E. Faith (faith@dict.org) * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * $Id: log.c,v 1.19 2005/11/21 18:57:05 cheusov Exp $ * */ #include "maaP.h" #ifdef HAVE_SYSLOG_NAMES #define SYSLOG_NAMES #endif #include #include #include #if HAVE_SYS_PARAM_H # include #endif #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif static int logFd = -1; static FILE *logUserStream; static int logSyslog; static int inhibitFull = 0; static int logOpen; static int logFacility = LOG_USER; static const char *logIdent; static const char *logFilenameOrig; static char *logFilename; static char *logFilenameTmp; static int logFilenameLen; static char logHostname[MAXHOSTNAMELEN]; #ifndef HAVE_SYSLOG_NAMES typedef struct _code { const char *c_name; int c_val; } CODE; CODE facilitynames[] = { #if LOG_AUTH { "auth", LOG_AUTH }, #endif #if LOG_AUTHPRIV { "authpriv", LOG_AUTHPRIV }, #endif #if LOG_CRON { "cron", LOG_CRON }, #endif #if LOG_DAEMON { "daemon", LOG_DAEMON }, #endif #if LOG_FTP { "ftp", LOG_FTP }, #endif #if LOG_KERN { "kern", LOG_KERN }, #endif #if LOG_LPR { "lpr", LOG_LPR }, #endif #if LOG_MAIL { "mail", LOG_MAIL }, #endif #if LOG_NEWS { "news", LOG_NEWS }, #endif #if LOG_SYSLOG { "syslog", LOG_SYSLOG }, #endif #if LOG_USER { "user", LOG_USER }, #endif #if LOG_UUCP { "uucp", LOG_UUCP }, #endif #if LOG_LOCAL0 { "local0", LOG_LOCAL0 }, #endif #if LOG_LOCAL1 { "local1", LOG_LOCAL1 }, #endif #if LOG_LOCAL2 { "local2", LOG_LOCAL2 }, #endif #if LOG_LOCAL3 { "local3", LOG_LOCAL3 }, #endif #if LOG_LOCAL4 { "local4", LOG_LOCAL4 }, #endif #if LOG_LOCAL5 { "local5", LOG_LOCAL5 }, #endif #if LOG_LOCAL6 { "local6", LOG_LOCAL6 }, #endif #if LOG_LOCAL7 { "local7", LOG_LOCAL7 }, #endif { NULL, -1 }, }; #endif static void _log_set_hostname( void ) { static int hostnameSet = 0; char *pt; if (!hostnameSet) { memset( logHostname, 0, sizeof(logHostname) ); gethostname( logHostname, sizeof(logHostname)-1 ); if ((pt = strchr(logHostname, '.'))) *pt = '\0'; ++hostnameSet; } } void log_set_facility(const char *facility) { CODE *pt; for (pt = facilitynames; pt->c_name; pt++) { if (!strcmp(pt->c_name, facility)) { logFacility = pt->c_val; return; } } err_fatal(__FUNCTION__, "%s is not a valid facility name\n", facility); } const char *log_get_facility(void) { CODE *pt; for (pt = facilitynames; pt->c_name; pt++) if (pt->c_val == logFacility) return pt->c_name; return NULL; } void log_option( int option ) { if (option == LOG_OPTION_NO_FULL) inhibitFull = 1; else inhibitFull = 0; } void log_syslog( const char *ident ) { if (ident){ if (logSyslog) err_internal( __FUNCTION__, "Syslog facility already open\n" ); openlog( ident, LOG_PID|LOG_NOWAIT, logFacility ); ++logOpen; ++logSyslog; }else{ if (!logSyslog) return; closelog (); --logOpen; --logSyslog; } } static void log_mkpath(const char *filename) { char *tmp = alloca(strlen(filename) + 1); char *pt; strcpy(tmp, filename); for (pt = tmp; *pt; pt++) { if (*pt == '/' && pt != tmp) { *pt = '\0'; mkdir(tmp, 0755); *pt = '/'; } } } static void _log_check_filename(void) { time_t t; struct tm *tm; if (!logFilename || !logFilenameTmp || !logFilenameLen) return; time(&t); tm = localtime(&t); strftime(logFilenameTmp, logFilenameLen, logFilenameOrig, tm); if (strcmp(logFilenameTmp, logFilename)) { strcpy(logFilename, logFilenameTmp); if (logFd >= 0) close(logFd); log_mkpath(logFilename); if ((logFd = open( logFilename, O_WRONLY|O_CREAT|O_APPEND, 0644 )) < 0) err_fatal_errno( __FUNCTION__, "Cannot open \"%s\" for append\n", logFilename ); } } void log_file( const char *ident, const char *filename ) { if (ident && filename){ if (logFd >= 0) err_internal( __FUNCTION__, "Log file \"%s\" open when trying to open \"%s\"\n", logFilename, filename ); logIdent = str_find( ident ); logFilenameOrig = str_find(filename); logFilenameLen = strlen(filename)*3+1024; logFilename = xmalloc(logFilenameLen + 1); logFilenameTmp = xmalloc(logFilenameLen + 1); logFilename[0] = '\0'; _log_check_filename(); _log_set_hostname(); ++logOpen; }else{ if (logFd < 0) return; close (logFd); logFd = -1; if (logFilename) xfree (logFilename); logFilename = NULL; if (logFilenameTmp) xfree (logFilenameTmp); logFilenameTmp = NULL; logFilenameLen = 0; --logOpen; } } void log_stream( const char *ident, FILE *stream ) { if (ident && stream){ if (logUserStream) err_internal( __FUNCTION__, "User stream already open\n" ); logUserStream = stream; logIdent = str_find( ident ); _log_set_hostname(); ++logOpen; }else{ if (!logUserStream) return; if (logUserStream != stdout && logUserStream != stderr) { fclose (logUserStream); } logUserStream = NULL; --logOpen; } } void log_close( void ) { log_file (NULL, NULL); log_stream (NULL, NULL); log_syslog (NULL); } static void _log_base_va( const char *routine, int log_facility, const char *format, va_list ap ) { time_t t; static char buf [4096] = ""; static char buf_main [4096] = ""; static char buf_preamble [256] = ""; if (!logOpen) return; time(&t); if (logFd >= 0 || logUserStream) { /* preamble */ if (inhibitFull) { buf_preamble [0] = 0; } else { snprintf (buf_preamble, sizeof (buf_preamble), "%24.24s %s %s[%ld]: ", ctime(&t), logHostname, logIdent, (long int) getpid()); } /* main part of log message */ vsnprintf (buf_main, sizeof (buf_main), format, ap ); /* full log message */ if (routine){ snprintf (buf, sizeof (buf), "%s(%s) %s\n", buf_preamble, routine, buf_main); }else{ snprintf (buf, sizeof (buf), "%s%s\n", buf_preamble, buf_main); } /* writing */ if (logFd >= 0) { _log_check_filename(); write( logFd, buf, strlen(buf) ); } if (logUserStream) { fseek( logUserStream, 0L, SEEK_END ); /* might help if luser didn't open stream with "a" */ if (logUserStream == stdout || logUserStream == stderr) fprintf( logUserStream, "%s", buf_main ); else fprintf( logUserStream, "%s", buf ); fflush( logUserStream ); } } #if HAVE_VSYSLOG if (logSyslog) { vsyslog( log_facility, format, ap ); } #endif } void log_error_va( const char *routine, const char *format, va_list ap ) { _log_base_va (routine, LOG_ERR, format, ap); } void log_error( const char *routine, const char *format, ... ) { va_list ap; va_start( ap, format ); log_error_va( routine, format, ap ); va_end( ap ); } void log_info_va( const char *format, va_list ap ) { _log_base_va (NULL, LOG_INFO, format, ap); } void log_info( const char *format, ... ) { va_list ap; va_start( ap, format ); log_info_va( format, ap ); va_end( ap ); }