summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/log.c
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/slapd/log.c
downloadds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.gz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.xz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.zip
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/slapd/log.c')
-rw-r--r--ldap/servers/slapd/log.c3664
1 files changed, 3664 insertions, 0 deletions
diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c
new file mode 100644
index 00000000..32c0fa2f
--- /dev/null
+++ b/ldap/servers/slapd/log.c
@@ -0,0 +1,3664 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+**
+** log.c
+**
+** Routines for writing access and error/debug logs
+**
+**
+** History:
+** As of DS 4.0, we support log rotation for the ACCESS/ERROR/AUDIT log.
+*/
+
+#include "log.h"
+#include "fe.h"
+
+#if defined( XP_WIN32 )
+#include <fcntl.h>
+#include "ntslapdmessages.h"
+#include "proto-ntutil.h"
+extern HANDLE hSlapdEventSource;
+extern LPTSTR pszServerName;
+#endif
+/**************************************************************************
+ * GLOBALS, defines, and ...
+ *************************************************************************/
+/* main struct which contains all the information about logging */
+PRUintn logbuf_tsdindex;
+struct logbufinfo *logbuf_accum;
+static struct logging_opts loginfo;
+static int detached=0;
+
+/* used to lock the timestamp info used by vslapd_log_access */
+static PRLock *ts_time_lock = NULL;
+
+/*
+ * Note: the order of the values in the slapi_log_map array must exactly
+ * match that of the SLAPI_LOG_XXX #defines found in slapi-plugin.h (this is
+ * so we can use the SLAPI_LOG_XXX values to index directly into the array).
+ */
+static int slapi_log_map[] = {
+ LDAP_DEBUG_ANY, /* SLAPI_LOG_FATAL */
+ LDAP_DEBUG_TRACE, /* SLAPI_LOG_TRACE */
+ LDAP_DEBUG_PACKETS, /* SLAPI_LOG_PACKETS */
+ LDAP_DEBUG_ARGS, /* SLAPI_LOG_ARGS */
+ LDAP_DEBUG_CONNS, /* SLAPI_LOG_CONNS */
+ LDAP_DEBUG_BER, /* SLAPI_LOG_BER */
+ LDAP_DEBUG_FILTER, /* SLAPI_LOG_FILTER */
+ LDAP_DEBUG_CONFIG, /* SLAPI_LOG_CONFIG */
+ LDAP_DEBUG_ACL, /* SLAPI_LOG_ACL */
+ LDAP_DEBUG_SHELL, /* SLAPI_LOG_SHELL */
+ LDAP_DEBUG_PARSE, /* SLAPI_LOG_PARSE */
+ LDAP_DEBUG_HOUSE, /* SLAPI_LOG_HOUSE */
+ LDAP_DEBUG_REPL, /* SLAPI_LOG_REPL */
+ LDAP_DEBUG_CACHE, /* SLAPI_LOG_CACHE */
+ LDAP_DEBUG_PLUGIN, /* SLAPI_LOG_PLUGIN */
+ LDAP_DEBUG_TIMING, /* SLAPI_LOG_TIMING */
+ LDAP_DEBUG_ACLSUMMARY, /* SLAPI_LOG_ACLSUMMARY */
+};
+
+#define SLAPI_LOG_MIN SLAPI_LOG_FATAL /* from slapi-plugin.h */
+#define SLAPI_LOG_MAX SLAPI_LOG_ACLSUMMARY /* from slapi-plugin.h */
+#define TBUFSIZE 50 /* size for time buffers */
+#define SLAPI_LOG_BUFSIZ 2048 /* size for data buffers */
+/**************************************************************************
+ * PROTOTYPES
+ *************************************************************************/
+static int log__open_accesslogfile(int logfile_type, int locked);
+static int log__open_errorlogfile(int logfile_type, int locked);
+static int log__open_auditlogfile(int logfile_type, int locked);
+static int log__needrotation(LOGFD fp, int logtype);
+static int log__delete_access_logfile();
+static int log__delete_error_logfile();
+static int log__delete_audit_logfile();
+static int log__access_rotationinfof(char *pathname);
+static int log__error_rotationinfof(char *pathname);
+static int log__audit_rotationinfof(char *pathname);
+static int log__extract_logheader (FILE *fp, long *f_ctime, int *f_size);
+static int log__getfilesize(LOGFD fp);
+static int log__enough_freespace(char *path);
+
+static int vslapd_log_error(LOGFD fp, char *subsystem, char *fmt, va_list ap );
+static int vslapd_log_access(char *fmt, va_list ap );
+static void log_convert_time (time_t ctime, char *tbuf, int type);
+static LogBufferInfo *log_create_buffer(size_t sz);
+static void log_append_buffer2(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, char *msg2, size_t size2);
+static void log_flush_buffer(LogBufferInfo *lbi, int type, int sync_now);
+static void log_write_title(LOGFD fp);
+
+
+static int
+slapd_log_error_proc_internal(
+ char *subsystem, /* omitted if NULL */
+ char *fmt,
+ va_list ap_err,
+ va_list ap_file);
+
+/*
+ * these macros are used for opening a log file, closing a log file, and
+ * writing out to a log file. we have to do this because currently NSPR
+ * is extremely under-performant on NT, while fopen/fwrite fail on several
+ * unix platforms if there are more than 128 files open.
+ *
+ * LOG_OPEN_APPEND(fd, filename, mode) returns true if successful. 'fd' should
+ * be of type LOGFD (check log.h). the file is open for appending to.
+ * LOG_OPEN_WRITE(fd, filename, mode) is the same but truncates the file and
+ * starts writing at the beginning of the file.
+ * LOG_WRITE(fd, buffer, size, headersize) writes into a LOGFD
+ * LOG_WRITE_NOW(fd, buffer, size, headersize) writes into a LOGFD and flushes the
+ * buffer if necessary
+ * LOG_CLOSE(fd) closes the logfile
+ */
+#ifdef XP_WIN32
+#define LOG_OPEN_APPEND(fd, filename, mode) \
+ (((fd) = fopen((filename), "a")) != NULL)
+#define LOG_OPEN_WRITE(fd, filename, mode) \
+ (((fd) = fopen((filename), "w")) != NULL)
+#define LOG_WRITE(fd, buffer, size, headersize) \
+ if ( fwrite((buffer), (size), 1, (fd)) != 1 ) \
+ {\
+ ReportSlapdEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVER_FAILED_TO_WRITE_LOG, 1, (buffer)); \
+ }
+#define LOG_WRITE_NOW(fd, buffer, size, headersize) do {\
+ if ( fwrite((buffer), (size), 1, (fd)) != 1 ) \
+ { \
+ ReportSlapdEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVER_FAILED_TO_WRITE_LOG, 1, (buffer)); \
+ }; \
+ fflush((fd)); \
+ } while (0)
+#define LOG_CLOSE(fd) \
+ fclose((fd))
+#else /* xp_win32 */
+#define LOG_OPEN_APPEND(fd, filename, mode) \
+ (((fd) = PR_Open((filename), PR_WRONLY | PR_APPEND | PR_CREATE_FILE , \
+ mode)) != NULL)
+#define LOG_OPEN_WRITE(fd, filename, mode) \
+ (((fd) = PR_Open((filename), PR_WRONLY | PR_TRUNCATE | \
+ PR_CREATE_FILE, mode)) != NULL)
+#define LOG_WRITE(fd, buffer, size, headersize) \
+ if ( slapi_write_buffer((fd), (buffer), (size)) != (size) ) \
+ { \
+ PRErrorCode prerr = PR_GetError(); \
+ syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer)+(headersize) ); \
+ }
+#define LOG_WRITE_NOW(fd, buffer, size, headersize) do {\
+ if ( slapi_write_buffer((fd), (buffer), (size)) != (size) ) \
+ { \
+ PRErrorCode prerr = PR_GetError(); \
+ syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer)+(headersize) ); \
+ } \
+ /* Should be a flush in here ?? Yes because PR_SYNC doesn't work ! */ \
+ PR_Sync(fd); \
+ } while (0)
+#define LOG_CLOSE(fd) \
+ PR_Close((fd))
+#endif
+
+
+/******************************************************************************
+* Set the access level
+******************************************************************************/
+void g_set_accesslog_level(int val)
+{
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_level = val;
+ LOG_ACCESS_UNLOCK_WRITE();
+}
+
+/******************************************************************************
+* Set whether the process is alive or dead
+* If it is detached, then we write the error in 'stderr'
+******************************************************************************/
+void g_set_detached(int val)
+{
+ detached = val;
+}
+
+/******************************************************************************
+* Tell me whether logging begins or not
+******************************************************************************/
+void g_log_init(int log_enabled)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char * instancedir = NULL;
+
+ ts_time_lock = PR_NewLock();
+ if (! ts_time_lock)
+ exit(-1);
+
+#if defined( XP_WIN32 )
+ pszServerName = slapi_ch_malloc( MAX_SERVICE_NAME );
+ instancedir = config_get_instancedir();
+ unixtodospath(instancedir);
+ if( !SlapdGetServerNameFromCmdline(pszServerName, instancedir, 1) )
+ {
+ MessageBox(GetDesktopWindow(), "Failed to get the Directory"
+ " Server name from the command-line argument.",
+ " ", MB_ICONEXCLAMATION | MB_OK);
+ exit( 1 );
+ }
+ slapi_ch_free((void **)&instancedir);
+
+ /* Register with the NT EventLog */
+ hSlapdEventSource = RegisterEventSource(NULL, pszServerName );
+ if( !hSlapdEventSource )
+ {
+ char szMessage[256];
+ sprintf( szMessage, "Directory Server %s is terminating. Failed "
+ "to set the EventLog source.", pszServerName);
+ MessageBox(GetDesktopWindow(), szMessage, " ",
+ MB_ICONEXCLAMATION | MB_OK);
+ exit( 1 );
+ }
+#endif
+
+ /* ACCESS LOG */
+ loginfo.log_access_state = 0;
+ loginfo.log_access_mode = SLAPD_DEFAULT_FILE_MODE;
+ loginfo.log_access_maxnumlogs = 1;
+ loginfo.log_access_maxlogsize = -1;
+ loginfo.log_access_rotationsync_enabled = 0;
+ loginfo.log_access_rotationsynchour = -1;
+ loginfo.log_access_rotationsyncmin = -1;
+ loginfo.log_access_rotationsyncclock = -1;
+ loginfo.log_access_rotationtime = -1;
+ loginfo.log_access_rotationunit = -1;
+ loginfo.log_access_rotationtime_secs = -1;
+ loginfo.log_access_maxdiskspace = -1;
+ loginfo.log_access_minfreespace = -1;
+ loginfo.log_access_exptime = -1;
+ loginfo.log_access_exptimeunit = -1;
+ loginfo.log_access_exptime_secs = -1;
+ loginfo.log_access_level = LDAP_DEBUG_STATS;
+ loginfo.log_access_ctime = 0L;
+ loginfo.log_access_fdes = NULL;
+ loginfo.log_access_file = NULL;
+ loginfo.log_numof_access_logs = 1;
+ loginfo.log_access_logchain = NULL;
+ loginfo.log_access_buffer = log_create_buffer(LOG_BUFFER_MAXSIZE);
+ if (loginfo.log_access_buffer == NULL)
+ exit(-1);
+ if ((loginfo.log_access_buffer->lock = PR_NewLock())== NULL )
+ exit (-1);
+ slapdFrontendConfig->accessloglevel = LDAP_DEBUG_STATS;
+
+ /* ERROR LOG */
+ loginfo.log_error_state = 0;
+ loginfo.log_error_mode = SLAPD_DEFAULT_FILE_MODE;
+ loginfo.log_error_maxnumlogs = 1;
+ loginfo.log_error_maxlogsize = -1;
+ loginfo.log_error_rotationsync_enabled = 0;
+ loginfo.log_error_rotationsynchour = -1;
+ loginfo.log_error_rotationsyncmin = -1;
+ loginfo.log_error_rotationsyncclock = -1;
+ loginfo.log_error_rotationtime = -1;
+ loginfo.log_error_rotationunit = -1;
+ loginfo.log_error_rotationtime_secs = -1;
+ loginfo.log_error_maxdiskspace = -1;
+ loginfo.log_error_minfreespace = -1;
+ loginfo.log_error_exptime = -1;
+ loginfo.log_error_exptimeunit = -1;
+ loginfo.log_error_exptime_secs = -1;
+ loginfo.log_error_ctime = 0L;
+ loginfo.log_error_file = NULL;
+ loginfo.log_error_fdes = NULL;
+ loginfo.log_numof_error_logs = 1;
+ loginfo.log_error_logchain = NULL;
+ if ((loginfo.log_error_rwlock =rwl_new())== NULL ) {
+ exit (-1);
+ }
+
+ /* AUDIT LOG */
+ loginfo.log_audit_state = 0;
+ loginfo.log_audit_mode = SLAPD_DEFAULT_FILE_MODE;
+ loginfo.log_audit_maxnumlogs = 1;
+ loginfo.log_audit_maxlogsize = -1;
+ loginfo.log_audit_rotationsync_enabled = 0;
+ loginfo.log_audit_rotationsynchour = -1;
+ loginfo.log_audit_rotationsyncmin = -1;
+ loginfo.log_audit_rotationsyncclock = -1;
+ loginfo.log_audit_rotationtime = -1;
+ loginfo.log_audit_rotationunit = -1;
+ loginfo.log_audit_rotationtime_secs = -1;
+ loginfo.log_audit_maxdiskspace = -1;
+ loginfo.log_audit_minfreespace = -1;
+ loginfo.log_audit_exptime = -1;
+ loginfo.log_audit_exptimeunit = -1;
+ loginfo.log_audit_exptime_secs = -1;
+ loginfo.log_audit_ctime = 0L;
+ loginfo.log_audit_file = NULL;
+ loginfo.log_numof_audit_logs = 1;
+ loginfo.log_audit_fdes = NULL;
+ loginfo.log_audit_logchain = NULL;
+ if ((loginfo.log_audit_rwlock =rwl_new())== NULL ) {
+ exit (-1);
+ }
+}
+
+/******************************************************************************
+* Tell me if log is enabled or disabled
+******************************************************************************/
+int
+log_set_logging(const char *attrname, char *value, int logtype, char *errorbuf, int apply)
+{
+ int v;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( NULL == value ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: NULL value; valid values "
+ "are \"on\" or \"off\"", attrname );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (strcasecmp(value, "on") == 0) {
+ v = LOGGING_ENABLED;
+ }
+ else if (strcasecmp(value, "off") == 0 ) {
+ v = 0;
+ }
+ else {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid value \"%s\", valid values "
+ "are \"on\" or \"off\"", attrname, value );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( !apply ){
+ return LDAP_SUCCESS;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ fe_cfg->accesslog_logging_enabled = v;
+ if(v) {
+ loginfo.log_access_state |= LOGGING_ENABLED;
+ }
+ else {
+ loginfo.log_access_state &= ~LOGGING_ENABLED;
+ }
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ fe_cfg->errorlog_logging_enabled = v;
+ if (v) {
+ loginfo.log_error_state |= LOGGING_ENABLED;
+ }
+ else {
+ loginfo.log_error_state &= ~LOGGING_ENABLED;
+ }
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ fe_cfg->auditlog_logging_enabled = v;
+ if (v) {
+ loginfo.log_audit_state |= LOGGING_ENABLED;
+ }
+ else {
+ loginfo.log_audit_state &= ~LOGGING_ENABLED;
+ }
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ }
+
+ return LDAP_SUCCESS;
+
+}
+/******************************************************************************
+* Tell me the access log file name inc path
+******************************************************************************/
+char *
+g_get_access_log () {
+ char *logfile = NULL;
+
+ LOG_ACCESS_LOCK_READ();
+ if ( loginfo.log_access_file)
+ logfile = slapi_ch_strdup (loginfo.log_access_file);
+ LOG_ACCESS_UNLOCK_READ();
+
+ return logfile;
+
+}
+/******************************************************************************
+* Point to a new access logdir
+*
+* Returns:
+* LDAP_SUCCESS -- success
+* LDAP_UNWILLING_TO_PERFORM -- when trying to open a invalid log file
+* LDAP_LOCAL_ERRO -- some error
+******************************************************************************/
+int
+log_update_accesslogdir(char *pathname, int apply)
+{
+ int rv = LDAP_SUCCESS;
+ LOGFD fp;
+
+ /* try to open the file, we may have a incorrect path */
+ if (! LOG_OPEN_APPEND(fp, pathname, loginfo.log_access_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ pathname, errno, slapd_system_strerror(errno));
+ /* stay with the current log file */
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ LOG_CLOSE(fp);
+
+ /* skip the rest if we aren't doing this for real */
+ if ( !apply ) {
+ return LDAP_SUCCESS;
+ }
+
+ /*
+ ** The user has changed the access log directory. That means we
+ ** need to start fresh.
+ */
+ LOG_ACCESS_LOCK_WRITE ();
+ if (loginfo.log_access_fdes) {
+ LogFileInfo *logp, *d_logp;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Closing the access log file. "
+ "Moving to a new access log file (%s)\n", pathname,0,0);
+
+ LOG_CLOSE(loginfo.log_access_fdes);
+ loginfo.log_access_fdes = 0;
+ loginfo.log_access_ctime = 0;
+ logp = loginfo.log_access_logchain;
+ while (logp) {
+ d_logp = logp;
+ logp = logp->l_next;
+ slapi_ch_free((void**)&d_logp);
+ }
+ loginfo.log_access_logchain = NULL;
+ slapi_ch_free((void**)&loginfo.log_access_file);
+ loginfo.log_access_file = NULL;
+ loginfo.log_numof_access_logs = 1;
+ }
+
+ /* Now open the new access log file */
+ if ( access_log_openf (pathname, 1 /* locked */)) {
+ rv = LDAP_LOCAL_ERROR; /* error Unable to use the new dir */
+ }
+ LOG_ACCESS_UNLOCK_WRITE();
+ return rv;
+}
+/******************************************************************************
+* Tell me the error log file name inc path
+******************************************************************************/
+char *
+g_get_error_log() {
+ char *logfile = NULL;
+
+ LOG_ERROR_LOCK_READ();
+ if ( loginfo.log_error_file)
+ logfile = slapi_ch_strdup (loginfo.log_error_file);
+ LOG_ERROR_UNLOCK_READ();
+
+ return logfile;
+}
+/******************************************************************************
+* Point to a new error logdir
+*
+* Returns:
+* LDAP_SUCCESS -- success
+* LDAP_UNWILLING_TO_PERFORM -- when trying to open a invalid log file
+* LDAP_LOCAL_ERRO -- some error
+******************************************************************************/
+int
+log_update_errorlogdir(char *pathname, int apply)
+{
+
+ int rv = LDAP_SUCCESS;
+ LOGFD fp;
+
+ /* try to open the file, we may have a incorrect path */
+ if (! LOG_OPEN_APPEND(fp, pathname, loginfo.log_error_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ pathname, errno, slapd_system_strerror(errno));
+ /* stay with the current log file */
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ /* skip the rest if we aren't doing this for real */
+ if ( !apply ) {
+ return LDAP_SUCCESS;
+ }
+ LOG_CLOSE(fp);
+
+ /*
+ ** The user has changed the error log directory. That means we
+ ** need to start fresh.
+ */
+ LOG_ERROR_LOCK_WRITE ();
+ if (loginfo.log_error_fdes) {
+ LogFileInfo *logp, *d_logp;
+
+ LOG_CLOSE(loginfo.log_error_fdes);
+ loginfo.log_error_fdes = 0;
+ loginfo.log_error_ctime = 0;
+ logp = loginfo.log_error_logchain;
+ while (logp) {
+ d_logp = logp;
+ logp = logp->l_next;
+ slapi_ch_free((void**)&d_logp);
+ }
+ loginfo.log_error_logchain = NULL;
+ slapi_ch_free((void**)&loginfo.log_error_file);
+ loginfo.log_error_file = NULL;
+ loginfo.log_numof_error_logs = 1;
+ }
+
+ /* Now open the new errorlog */
+ if ( error_log_openf (pathname, 1 /* obtained lock */)) {
+ rv = LDAP_LOCAL_ERROR; /* error: Unable to use the new dir */
+ }
+
+ LOG_ERROR_UNLOCK_WRITE();
+ return rv;
+}
+/******************************************************************************
+* Tell me the audit log file name inc path
+******************************************************************************/
+char *
+g_get_audit_log() {
+ char *logfile = NULL;
+
+ LOG_AUDIT_LOCK_READ();
+ if ( loginfo.log_audit_file)
+ logfile = slapi_ch_strdup (loginfo.log_audit_file);
+ LOG_AUDIT_UNLOCK_READ();
+
+ return logfile;
+}
+/******************************************************************************
+* Point to a new audit logdir
+*
+* Returns:
+* LDAP_SUCCESS -- success
+* LDAP_UNWILLING_TO_PERFORM -- when trying to open a invalid log file
+* LDAP_LOCAL_ERRO -- some error
+******************************************************************************/
+int
+log_update_auditlogdir(char *pathname, int apply)
+{
+ int rv = LDAP_SUCCESS;
+ LOGFD fp;
+
+ /* try to open the file, we may have a incorrect path */
+ if (! LOG_OPEN_APPEND(fp, pathname, loginfo.log_audit_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ pathname, errno, slapd_system_strerror(errno));
+ /* stay with the current log file */
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ /* skip the rest if we aren't doing this for real */
+ if ( !apply ) {
+ return LDAP_SUCCESS;
+ }
+ LOG_CLOSE(fp);
+
+ /*
+ ** The user has changed the audit log directory. That means we
+ ** need to start fresh.
+ */
+ LOG_AUDIT_LOCK_WRITE ();
+ if (loginfo.log_audit_fdes) {
+ LogFileInfo *logp, *d_logp;
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Closing the audit log file. "
+ "Moving to a new audit file (%s)\n", pathname,0,0);
+
+ LOG_CLOSE(loginfo.log_audit_fdes);
+ loginfo.log_audit_fdes = 0;
+ loginfo.log_audit_ctime = 0;
+ logp = loginfo.log_audit_logchain;
+ while (logp) {
+ d_logp = logp;
+ logp = logp->l_next;
+ slapi_ch_free((void**)&d_logp);
+ }
+ loginfo.log_audit_logchain = NULL;
+ slapi_ch_free((void**)&loginfo.log_audit_file);
+ loginfo.log_audit_file = NULL;
+ loginfo.log_numof_audit_logs = 1;
+ }
+
+ /* Now open the new errorlog */
+ if ( audit_log_openf (pathname, 1 /* locked */)) {
+ rv = LDAP_LOCAL_ERROR; /* error: Unable to use the new dir */
+ }
+ LOG_AUDIT_UNLOCK_WRITE();
+ return rv;
+}
+
+int
+log_set_mode (const char *attrname, char *value, int logtype, char *errorbuf, int apply)
+{
+ int v = 0;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( NULL == value ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: null value; valid values "
+ "are are of the format \"yz-yz-yz-\" where y could be 'r' or '-',"
+ " and z could be 'w' or '-'", attrname );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( !apply ){
+ return LDAP_SUCCESS;
+ }
+
+ v = strtol (value, NULL, 8);
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ slapi_ch_free ( (void **) &fe_cfg->accesslog_mode );
+ fe_cfg->accesslog_mode = slapi_ch_strdup (value);
+ loginfo.log_access_mode = v;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ slapi_ch_free ( (void **) &fe_cfg->errorlog_mode );
+ fe_cfg->errorlog_mode = slapi_ch_strdup (value);
+ loginfo.log_error_mode = v;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ slapi_ch_free ( (void **) &fe_cfg->auditlog_mode );
+ fe_cfg->auditlog_mode = slapi_ch_strdup (value);
+ loginfo.log_audit_mode = v;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ }
+ return LDAP_SUCCESS;
+}
+
+/******************************************************************************
+* MAX NUMBER OF LOGS
+******************************************************************************/
+int
+log_set_numlogsperdir(const char *attrname, char *numlogs_str, int logtype, char *returntext, int apply)
+{
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ int rv = LDAP_SUCCESS;
+ int numlogs;
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ rv = LDAP_OPERATIONS_ERROR;
+ PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type %d", attrname, logtype );
+ }
+ if ( !apply || !numlogs_str || !*numlogs_str) {
+ return rv;
+ }
+
+ numlogs = atoi(numlogs_str);
+
+ if (numlogs >= 1) {
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_maxnumlogs = numlogs;
+ fe_cfg->accesslog_maxnumlogs = numlogs;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_maxnumlogs = numlogs;
+ fe_cfg->errorlog_maxnumlogs = numlogs;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_maxnumlogs = numlogs;
+ fe_cfg->auditlog_maxnumlogs = numlogs;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = LDAP_OPERATIONS_ERROR;
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "log_set_numlogsperdir: invalid log type %d", logtype,0,0 );
+ }
+ }
+ return rv;
+}
+
+/******************************************************************************
+* LOG SIZE
+* Return Values:
+* LDAP_OPERATIONS_ERROR -- fail
+* LDAP_SUCCESS -- success
+*
+* NOTE: The config struct should contain the maxlogsize in MB and not in bytes.
+******************************************************************************/
+int
+log_set_logsize(const char *attrname, char *logsize_str, int logtype, char *returntext, int apply)
+{
+ int rv = LDAP_SUCCESS;
+ int mdiskspace= 0;
+ int max_logsize;
+ int logsize;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if (!apply || !logsize_str || !*logsize_str)
+ return rv;
+
+ logsize = atoi(logsize_str);
+
+ /* convert it to bytes */
+ max_logsize = logsize * LOG_MB_IN_BYTES;
+
+ if (max_logsize <= 0) {
+ max_logsize = -1;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ mdiskspace = loginfo.log_access_maxdiskspace;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ mdiskspace = loginfo.log_error_maxdiskspace;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ mdiskspace = loginfo.log_audit_maxdiskspace;
+ break;
+ default:
+ PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid logtype %d", attrname, logtype );
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+
+ if ((max_logsize > mdiskspace) && (mdiskspace != -1))
+ rv = 2;
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ if (!rv && apply) {
+ loginfo.log_access_maxlogsize = max_logsize;
+ fe_cfg->accesslog_maxlogsize = logsize;
+ }
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ if (!rv && apply) {
+ loginfo.log_error_maxlogsize = max_logsize;
+ fe_cfg->errorlog_maxlogsize = logsize;
+ }
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ if (!rv && apply) {
+ loginfo.log_audit_maxlogsize = max_logsize;
+ fe_cfg->auditlog_maxlogsize = logsize;
+ }
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+ /* logsize will be in n MB. Convert it to bytes */
+ if (rv == 2) {
+ LDAPDebug (LDAP_DEBUG_ANY,
+ "Invalid value for Maximum log size:"
+ "Maxlogsize:%d MB Maxdisksize:%d MB\n",
+ logsize, mdiskspace/LOG_MB_IN_BYTES,0);
+
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+ return rv;
+}
+
+time_t
+log_get_rotationsyncclock(int synchour, int syncmin)
+{
+ struct tm *currtm;
+ time_t currclock;
+ time_t syncclock;
+ int hours, minutes;
+
+ time( &currclock);
+ currtm = localtime( &currclock );
+
+ if ( syncmin < currtm->tm_min ) {
+ minutes = syncmin + 60 - currtm->tm_min;
+ hours = synchour - 1 - currtm->tm_hour;
+ } else {
+ minutes = syncmin - currtm->tm_min;
+ hours = synchour - currtm->tm_hour;
+ }
+ if ( hours < 0 ) hours += 24;
+
+ syncclock = currclock + hours * 3600 + minutes * 60;
+ return syncclock;
+}
+
+int
+log_set_rotationsync_enabled(const char *attrname, char *value, int logtype, char *errorbuf, int apply)
+{
+ int v;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( NULL == value ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: NULL value; valid values "
+ "are \"on\" or \"off\"", attrname );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (strcasecmp(value, "on") == 0) {
+ v = LDAP_ON;
+ }
+ else if (strcasecmp(value, "off") == 0 ) {
+ v = LDAP_OFF;
+ }
+ else {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid value \"%s\", valid values "
+ "are \"on\" or \"off\"", attrname, value );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( !apply ){
+ return LDAP_SUCCESS;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ fe_cfg->accesslog_rotationsync_enabled = v;
+ loginfo.log_access_rotationsync_enabled = v;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ fe_cfg->errorlog_rotationsync_enabled = v;
+ loginfo.log_error_rotationsync_enabled = v;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ fe_cfg->auditlog_rotationsync_enabled = v;
+ loginfo.log_audit_rotationsync_enabled = v;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ }
+ return LDAP_SUCCESS;
+}
+
+int
+log_set_rotationsynchour(const char *attrname, char *rhour_str, int logtype, char *returntext, int apply)
+{
+ int rhour = -1;
+ int rv = LDAP_SUCCESS;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply ) {
+ return rv;
+ }
+
+ if ( rhour_str && *rhour_str != '\0' )
+ rhour = atol( rhour_str );
+ if ( rhour > 23 )
+ rhour = rhour % 24;
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_rotationsynchour = rhour;
+ loginfo.log_access_rotationsyncclock = log_get_rotationsyncclock( rhour, loginfo.log_access_rotationsyncmin );
+ fe_cfg->accesslog_rotationsynchour = rhour;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_rotationsynchour = rhour;
+ loginfo.log_error_rotationsyncclock = log_get_rotationsyncclock( rhour, loginfo.log_error_rotationsyncmin );
+ fe_cfg->errorlog_rotationsynchour = rhour;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_rotationsynchour = rhour;
+ loginfo.log_audit_rotationsyncclock = log_get_rotationsyncclock( rhour, loginfo.log_audit_rotationsyncmin );
+ fe_cfg->auditlog_rotationsynchour = rhour;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+
+ return rv;
+}
+
+int
+log_set_rotationsyncmin(const char *attrname, char *rmin_str, int logtype, char *returntext, int apply)
+{
+ int rmin = -1;
+ int rv = LDAP_SUCCESS;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply ) {
+ return rv;
+ }
+
+ if ( rmin_str && *rmin_str != '\0' )
+ rmin = atol( rmin_str );
+ if ( rmin > 59 )
+ rmin = rmin % 60;
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_rotationsyncmin = rmin;
+ fe_cfg->accesslog_rotationsyncmin = rmin;
+ loginfo.log_access_rotationsyncclock = log_get_rotationsyncclock( loginfo.log_access_rotationsynchour, rmin );
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_rotationsyncmin = rmin;
+ loginfo.log_error_rotationsyncclock = log_get_rotationsyncclock( loginfo.log_error_rotationsynchour, rmin );
+ fe_cfg->errorlog_rotationsyncmin = rmin;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_rotationsyncmin = rmin;
+ fe_cfg->auditlog_rotationsyncmin = rmin;
+ loginfo.log_audit_rotationsyncclock = log_get_rotationsyncclock( loginfo.log_audit_rotationsynchour, rmin );
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+
+ return rv;
+}
+
+/******************************************************************************
+* ROTATION TIME
+* Return Values:
+* 1 -- fail
+* 0 -- success
+******************************************************************************/
+int
+log_set_rotationtime(const char *attrname, char *rtime_str, int logtype, char *returntext, int apply)
+{
+
+ int runit= 0;
+ int value, rtime;
+ int rv = LDAP_SUCCESS;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply || !rtime_str || !*rtime_str) {
+ return rv;
+ }
+
+ rtime = atoi(rtime_str);
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_rotationtime = rtime;
+ runit = loginfo.log_access_rotationunit;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_rotationtime = rtime;
+ runit = loginfo.log_error_rotationunit;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_rotationtime = rtime;
+ runit = loginfo.log_audit_rotationunit;
+ break;
+ default:
+ rv = 1;
+ }
+
+ /* find out the rotation unit we have se right now */
+ if (runit == LOG_UNIT_MONTHS) {
+ value = 31 * 24 * 60 * 60 * rtime;
+ } else if (runit == LOG_UNIT_WEEKS) {
+ value = 7 * 24 * 60 * 60 * rtime;
+ } else if (runit == LOG_UNIT_DAYS ) {
+ value = 24 * 60 * 60 * rtime;
+ } else if (runit == LOG_UNIT_HOURS) {
+ value = 3600 * rtime;
+ } else if (runit == LOG_UNIT_MINS) {
+ value = 60 * rtime;
+ } else {
+ /* In this case we don't rotate */
+ value = -1;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ fe_cfg->accesslog_rotationtime = rtime;
+ loginfo.log_access_rotationtime_secs = value;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ fe_cfg->errorlog_rotationtime = rtime;
+ loginfo.log_error_rotationtime_secs = value;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ fe_cfg->auditlog_rotationtime = rtime;
+ loginfo.log_audit_rotationtime_secs = value;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+ return rv;
+}
+/******************************************************************************
+* ROTATION TIME UNIT
+* Return Values:
+* 1 -- fail
+* 0 -- success
+******************************************************************************/
+int log_set_rotationtimeunit(const char *attrname, char *runit, int logtype, char *errorbuf, int apply)
+{
+ int value= 0;
+ int runitType;
+ int rv = 0;
+
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( (strcasecmp(runit, "month") == 0) ||
+ (strcasecmp(runit, "week") == 0) ||
+ (strcasecmp(runit, "day") == 0) ||
+ (strcasecmp(runit, "hour") == 0) ||
+ (strcasecmp(runit, "minute") == 0)) {
+ /* all good values */
+ } else {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: unknown unit \"%s\"", attrname, runit );
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply ) {
+ return rv;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ value = loginfo.log_access_rotationtime;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ value = loginfo.log_error_rotationtime;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ value = loginfo.log_audit_rotationtime;
+ break;
+ default:
+ rv = 1;
+ }
+
+ if (strcasecmp(runit, "month") == 0) {
+ runitType = LOG_UNIT_MONTHS;
+ value *= 31 * 24 * 60 * 60;
+ } else if (strcasecmp(runit, "week") == 0) {
+ runitType = LOG_UNIT_WEEKS;
+ value *= 7 * 24 * 60 * 60;
+ } else if (strcasecmp(runit, "day") == 0) {
+ runitType = LOG_UNIT_DAYS;
+ value *= 24 * 60 * 60;
+ } else if (strcasecmp(runit, "hour") == 0) {
+ runitType = LOG_UNIT_HOURS;
+ value *= 3600;
+ } else if (strcasecmp(runit, "minute") == 0) {
+ runitType = LOG_UNIT_MINS;
+ value *= 60;
+ } else {
+ /* In this case we don't rotate */
+ runitType = LOG_UNIT_UNKNOWN;
+ value = -1;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ loginfo.log_access_rotationtime_secs = value;
+ loginfo.log_access_rotationunit = runitType;
+ slapi_ch_free ( (void **) &fe_cfg->accesslog_rotationunit);
+ fe_cfg->accesslog_rotationunit = slapi_ch_strdup ( runit );
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ loginfo.log_error_rotationtime_secs = value;
+ loginfo.log_error_rotationunit = runitType;
+ slapi_ch_free ( (void **) &fe_cfg->errorlog_rotationunit) ;
+ fe_cfg->errorlog_rotationunit = slapi_ch_strdup ( runit );
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ loginfo.log_audit_rotationtime_secs = value;
+ loginfo.log_audit_rotationunit = runitType;
+ slapi_ch_free ( (void **) &fe_cfg->auditlog_rotationunit);
+ fe_cfg->auditlog_rotationunit = slapi_ch_strdup ( runit );
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+ return rv;
+}
+/******************************************************************************
+* MAXIMUM DISK SPACE
+* Return Values:
+* 1 -- fail
+* 0 -- success
+*
+* NOTE:
+* The config struct should contain the value in MB and not in bytes.
+******************************************************************************/
+int
+log_set_maxdiskspace(const char *attrname, char *maxdiskspace_str, int logtype, char *errorbuf, int apply)
+{
+ int rv = 0;
+ int mlogsize;
+ int maxdiskspace;
+ int s_maxdiskspace;
+
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (!apply || !maxdiskspace_str || !*maxdiskspace_str)
+ return rv;
+
+ maxdiskspace = atoi(maxdiskspace_str);
+ s_maxdiskspace = maxdiskspace;
+
+ /* Disk space are in MB but store in bytes */
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ mlogsize = loginfo.log_access_maxlogsize;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ mlogsize = loginfo.log_error_maxlogsize;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ mlogsize = loginfo.log_audit_maxlogsize;
+ break;
+ default:
+ rv = 1;
+ mlogsize = -1;
+ }
+ maxdiskspace *= LOG_MB_IN_BYTES;
+ if (maxdiskspace < 0) {
+ maxdiskspace = -1;
+ }
+ else if (maxdiskspace < mlogsize) {
+ rv = LDAP_OPERATIONS_ERROR;
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: maxdiskspace \"%d\" is less than max log size \"%d\"",
+ attrname, maxdiskspace, mlogsize );
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ if (rv== 0 && apply) {
+ loginfo.log_access_maxdiskspace = maxdiskspace;
+ fe_cfg->accesslog_maxdiskspace = s_maxdiskspace ;
+ }
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ if (rv== 0 && apply) {
+ loginfo.log_error_maxdiskspace = maxdiskspace;
+ fe_cfg->errorlog_maxdiskspace = s_maxdiskspace;
+ }
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ if (rv== 0 && apply) {
+ loginfo.log_audit_maxdiskspace = maxdiskspace;
+ fe_cfg->auditlog_maxdiskspace = s_maxdiskspace;
+ }
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid maximum log disk size:"
+ "Maxdiskspace:%d MB Maxlogsize:%d MB \n",
+ attrname, maxdiskspace, mlogsize);
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+ return rv;
+
+}
+/******************************************************************************
+* MINIMUM FREE SPACE
+* Return Values:
+* 1 -- fail
+* 0 -- success
+******************************************************************************/
+int
+log_set_mindiskspace(const char *attrname, char *minfreespace_str, int logtype, char *errorbuf, int apply)
+{
+ int rv=LDAP_SUCCESS;
+ int minfreespaceB;
+ int minfreespace;
+
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply || !minfreespace_str || !*minfreespace_str) {
+ return rv;
+ }
+
+ minfreespace = atoi(minfreespace_str);
+
+ /* Disk space are in MB but store in bytes */
+ if (minfreespace >= 1 ) {
+ minfreespaceB = minfreespace * LOG_MB_IN_BYTES;
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_minfreespace = minfreespaceB;
+ fe_cfg->accesslog_minfreespace = minfreespace;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_minfreespace = minfreespaceB;
+ fe_cfg->errorlog_minfreespace = minfreespace;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_minfreespace = minfreespaceB;
+ fe_cfg->auditlog_minfreespace = minfreespace;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+ }
+ return rv;
+}
+/******************************************************************************
+* LOG EXPIRATION TIME
+* Return Values:
+* 1 -- fail
+* 0 -- success
+******************************************************************************/
+int
+log_set_expirationtime(const char *attrname, char *exptime_str, int logtype, char *errorbuf, int apply)
+{
+
+ int eunit, value, exptime;
+ int rsec=0;
+ int rv = 0;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply || !exptime_str || !*exptime_str) {
+ return rv;
+ }
+
+ exptime = atoi(exptime_str);
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_exptime = exptime;
+ eunit = loginfo.log_access_exptimeunit;
+ rsec = loginfo.log_access_rotationtime_secs;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_exptime = exptime;
+ eunit = loginfo.log_error_exptimeunit;
+ rsec = loginfo.log_error_rotationtime_secs;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_exptime = exptime;
+ eunit = loginfo.log_audit_exptimeunit;
+ rsec = loginfo.log_audit_rotationtime_secs;
+ break;
+ default:
+ rv = 1;
+ eunit = -1;
+ }
+
+ if (eunit == LOG_UNIT_MONTHS) {
+ value = 31 * 24 * 60 * 60 * exptime;
+ } else if (eunit == LOG_UNIT_WEEKS) {
+ value = 7 * 24 * 60 * 60 * exptime;
+ } else if (eunit == LOG_UNIT_DAYS) {
+ value = 24 * 60 * 60 * exptime;
+ } else {
+ /* In this case we don't expire */
+ value = -1;
+ }
+
+ if (value < rsec) {
+ value = rsec;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ loginfo.log_access_exptime_secs = value;
+ fe_cfg->accesslog_exptime = exptime;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ loginfo.log_error_exptime_secs = value;
+ fe_cfg->errorlog_exptime = exptime;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ loginfo.log_audit_exptime_secs = value;
+ fe_cfg->auditlog_exptime = exptime;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+
+ return rv;
+}
+/******************************************************************************
+* LOG EXPIRATION TIME UNIT
+* Return Values:
+* 1 -- fail
+* 0 -- success
+******************************************************************************/
+int
+log_set_expirationtimeunit(const char *attrname, char *expunit, int logtype, char *errorbuf, int apply)
+{
+ int value = 0;
+ int rv = 0;
+ int eunit, etimeunit, rsecs;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( NULL == expunit ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: NULL value", attrname );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( (strcasecmp(expunit, "month") == 0) ||
+ (strcasecmp(expunit, "week") == 0) ||
+ (strcasecmp(expunit, "day") == 0)) {
+ /* we have good values */
+ } else {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid time unit \"%s\"", attrname, expunit );
+ rv = LDAP_OPERATIONS_ERROR;;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply ) {
+ return rv;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ etimeunit = loginfo.log_access_exptime;
+ rsecs = loginfo.log_access_rotationtime_secs;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ etimeunit = loginfo.log_error_exptime;
+ rsecs = loginfo.log_error_rotationtime_secs;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ etimeunit = loginfo.log_audit_exptime;
+ rsecs = loginfo.log_audit_rotationtime_secs;
+ break;
+ default:
+ rv = 1;
+ etimeunit = -1;
+ rsecs = -1;
+ }
+
+ if (strcasecmp(expunit, "month") == 0) {
+ eunit = LOG_UNIT_MONTHS;
+ value = 31 * 24 * 60 * 60 * etimeunit;
+ } else if (strcasecmp(expunit, "week") == 0) {
+ eunit = LOG_UNIT_WEEKS;
+ value = 7 * 24 * 60 * 60 * etimeunit;
+ } else if (strcasecmp(expunit, "day") == 0) {
+ eunit = LOG_UNIT_DAYS;
+ value = 24 * 60 * 60 * etimeunit;
+ } else {
+ eunit = LOG_UNIT_UNKNOWN;
+ value = -1;
+ }
+
+ if ((value> 0) && value < rsecs ) {
+ value = rsecs;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ loginfo.log_access_exptime_secs = value;
+ slapi_ch_free ( (void **) &(fe_cfg->accesslog_exptimeunit) );
+ fe_cfg->accesslog_exptimeunit = slapi_ch_strdup ( expunit );
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ loginfo.log_error_exptime_secs = value;
+ slapi_ch_free ( (void **) &(fe_cfg->errorlog_exptimeunit) );
+ fe_cfg->errorlog_exptimeunit = slapi_ch_strdup ( expunit );
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ loginfo.log_audit_exptime_secs = value;
+ slapi_ch_free ( (void **) &(fe_cfg->auditlog_exptimeunit) );
+ fe_cfg->auditlog_exptimeunit = slapi_ch_strdup ( expunit );
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+
+ return rv;
+}
+
+/******************************************************************************
+ * Write title line in log file
+ *****************************************************************************/
+static void
+log_write_title (LOGFD fp)
+{
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+ char *buildnum = config_get_buildnum();
+ char buff[512];
+ int bufflen = sizeof(buff);
+
+ PR_snprintf(buff, bufflen, "\t%s B%s\n",
+ fe_cfg->versionstring ? fe_cfg->versionstring : "Netscape-Directory",
+ buildnum ? buildnum : "");
+ LOG_WRITE_NOW(fp, buff, strlen(buff), 0);
+
+ if (fe_cfg->localhost) {
+ PR_snprintf(buff, bufflen, "\t%s:%d (%s)\n\n",
+ fe_cfg->localhost,
+ fe_cfg->security ? fe_cfg->secureport : fe_cfg->port,
+ fe_cfg->instancedir ? fe_cfg->instancedir : "");
+ }
+ else {
+ /* If fe_cfg->localhost is not set, ignore fe_cfg->port since
+ * it is the default and might be misleading.
+ */
+ PR_snprintf(buff, bufflen, "\t<host>:<port> (%s)\n\n",
+ fe_cfg->instancedir ? fe_cfg->instancedir : "");
+ }
+ LOG_WRITE_NOW(fp, buff, strlen(buff), 0);
+ slapi_ch_free((void **)&buildnum);
+}
+
+/******************************************************************************
+* init function for the error log
+* Returns:
+* 0 - success
+* 1 - fail
+******************************************************************************/
+int error_log_openf( char *pathname, int locked)
+{
+
+ int rv = 0;
+ int logfile_type =0;
+ char buf[BUFSIZ];
+
+ if (!locked) LOG_ERROR_LOCK_WRITE ();
+ /* save the file name */
+ slapi_ch_free ((void**)&loginfo.log_error_file);
+ loginfo.log_error_file = slapi_ch_strdup(pathname);
+
+ /* store the rotation info fiel path name */
+ sprintf (buf, "%s.rotationinfo",pathname);
+ slapi_ch_free ((void**)&loginfo.log_errorinfo_file);
+ loginfo.log_errorinfo_file = slapi_ch_strdup ( buf );
+
+ /*
+ ** Check if we have a log file already. If we have it then
+ ** we need to parse the header info and update the loginfo
+ ** struct.
+ */
+ logfile_type = log__error_rotationinfof(loginfo.log_errorinfo_file);
+
+ if (log__open_errorlogfile(logfile_type, 1/* got lock*/) != LOG_SUCCESS) {
+ rv = 1;
+ }
+
+ if (!locked) LOG_ERROR_UNLOCK_WRITE();
+ return rv;
+
+}
+/******************************************************************************
+* init function for the audit log
+* Returns:
+* 0 - success
+* 1 - fail
+******************************************************************************/
+int
+audit_log_openf( char *pathname, int locked)
+{
+
+ int rv=0;
+ int logfile_type = 0;
+ char buf[BUFSIZ];
+
+ if (!locked) LOG_AUDIT_LOCK_WRITE( );
+
+ /* store the path name */
+ loginfo.log_audit_file = slapi_ch_strdup ( pathname );
+
+ /* store the rotation info file path name */
+ sprintf (buf, "%s.rotationinfo",pathname);
+ loginfo.log_auditinfo_file = slapi_ch_strdup ( buf );
+
+ /*
+ ** Check if we have a log file already. If we have it then
+ ** we need to parse the header info and update the loginfo
+ ** struct.
+ */
+ logfile_type = log__audit_rotationinfof(loginfo.log_auditinfo_file);
+
+ if (log__open_auditlogfile(logfile_type, 1/* got lock*/) != LOG_SUCCESS) {
+ rv = 1;
+ }
+
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE();
+
+ return rv;
+}
+/******************************************************************************
+* write in the audit log
+******************************************************************************/
+int
+slapd_log_audit_proc (
+ char *buffer,
+ int buf_len)
+{
+ if ( (loginfo.log_audit_state & LOGGING_ENABLED) && (loginfo.log_audit_file != NULL) ){
+ LOG_AUDIT_LOCK_WRITE( );
+ if (log__needrotation(loginfo.log_audit_fdes,
+ SLAPD_AUDIT_LOG) == LOG_ROTATE) {
+ if (log__open_auditlogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "LOGINFO: Unable to open audit file:%s\n",
+ loginfo.log_audit_file,0,0);
+ LOG_AUDIT_UNLOCK_WRITE();
+ return 0;
+ }
+ while (loginfo.log_audit_rotationsyncclock <= loginfo.log_audit_ctime) {
+ loginfo.log_audit_rotationsyncclock += loginfo.log_audit_rotationtime_secs;
+ }
+ }
+ if (loginfo.log_audit_state & LOGGING_NEED_TITLE) {
+ log_write_title( loginfo.log_audit_fdes);
+ loginfo.log_audit_state &= ~LOGGING_NEED_TITLE;
+ }
+ LOG_WRITE_NOW(loginfo.log_audit_fdes, buffer, buf_len, 0);
+ LOG_AUDIT_UNLOCK_WRITE();
+ return 0;
+ }
+ return 0;
+}
+/******************************************************************************
+* write in the error log
+******************************************************************************/
+int
+slapd_log_error_proc(
+ char *subsystem, /* omitted if NULL */
+ char *fmt,
+ ... )
+{
+ va_list ap_err;
+ va_list ap_file;
+ va_start( ap_err, fmt );
+ va_start( ap_file, fmt );
+ slapd_log_error_proc_internal(subsystem, fmt, ap_err, ap_file);
+ va_end(ap_err);
+ va_end(ap_file);
+ return 0;
+}
+
+static int
+slapd_log_error_proc_internal(
+ char *subsystem, /* omitted if NULL */
+ char *fmt,
+ va_list ap_err,
+ va_list ap_file)
+{
+ int rc = 0;
+
+ if ( (loginfo.log_error_state & LOGGING_ENABLED) && (loginfo.log_error_file != NULL) ) {
+ LOG_ERROR_LOCK_WRITE( );
+ if (log__needrotation(loginfo.log_error_fdes,
+ SLAPD_ERROR_LOG) == LOG_ROTATE) {
+ if (log__open_errorlogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) {
+ LOG_ERROR_UNLOCK_WRITE();
+ return 0;
+ }
+ while (loginfo.log_error_rotationsyncclock <= loginfo.log_error_ctime) {
+ loginfo.log_error_rotationsyncclock += loginfo.log_error_rotationtime_secs;
+ }
+ }
+
+ if (!(detached)) {
+ rc = vslapd_log_error( NULL, subsystem, fmt, ap_err );
+ }
+ if ( loginfo.log_error_fdes != NULL ) {
+ if (loginfo.log_error_state & LOGGING_NEED_TITLE) {
+ log_write_title(loginfo.log_error_fdes);
+ loginfo.log_error_state &= ~LOGGING_NEED_TITLE;
+ }
+ rc = vslapd_log_error( loginfo.log_error_fdes, subsystem, fmt, ap_file );
+ }
+ LOG_ERROR_UNLOCK_WRITE();
+ } else {
+ /* log the problem in the stderr */
+ rc = vslapd_log_error( NULL, subsystem, fmt, ap_err );
+ }
+ return( rc );
+}
+
+static int
+vslapd_log_error(
+ LOGFD fp,
+ char *subsystem, /* omitted if NULL */
+ char *fmt,
+ va_list ap )
+{
+ time_t tnl;
+ long tz;
+ struct tm *tmsp, tms;
+ char tbuf[ TBUFSIZE ];
+ char sign;
+ char buffer[SLAPI_LOG_BUFSIZ];
+ int blen;
+ char *vbuf;
+ int header_len = 0;
+
+ tnl = current_time();
+#ifdef _WIN32
+ {
+ struct tm *pt = localtime( &tnl );
+ tmsp = &tms;
+ memcpy(&tms, pt, sizeof(struct tm) );
+ }
+#else
+ (void)localtime_r( &tnl, &tms );
+ tmsp = &tms;
+#endif
+#ifdef BSD_TIME
+ tz = tmsp->tm_gmtoff;
+#else /* BSD_TIME */
+ tz = - timezone;
+ if ( tmsp->tm_isdst ) {
+ tz += 3600;
+ }
+#endif /* BSD_TIME */
+ sign = ( tz >= 0 ? '+' : '-' );
+ if ( tz < 0 ) {
+ tz = -tz;
+ }
+ (void)strftime( tbuf, (size_t)TBUFSIZE, "%d/%b/%Y:%H:%M:%S", tmsp);
+ sprintf( buffer, "[%s %c%02d%02d]%s%s - ", tbuf, sign,
+ (int)( tz / 3600 ), (int)( tz % 3600 ),
+ subsystem ? " " : "",
+ subsystem ? subsystem : "");
+
+ /* Bug 561525: to be able to remove timestamp to not over pollute syslog, we may need
+ to skip the timestamp part of the message.
+ The size of the header is:
+ the size of the time string
+ + size of space
+ + size of one char (sign)
+ + size of 2 char
+ + size of 2 char
+ + size of [
+ + size of ]
+ */
+
+ header_len = strlen(tbuf) + 8;
+
+ if ((vbuf = PR_vsmprintf(fmt, ap)) == NULL) {
+ return -1;
+ }
+ blen = strlen(buffer);
+ if ((unsigned int)(SLAPI_LOG_BUFSIZ - blen ) < strlen(vbuf)) {
+ free (vbuf);
+ return -1;
+ }
+
+ sprintf (buffer+blen, "%s", vbuf);
+
+ if (fp)
+ LOG_WRITE_NOW(fp, buffer, strlen(buffer), header_len);
+
+
+ else /* stderr is always unbuffered */
+ fprintf(stderr, "%s", buffer);
+
+ free (vbuf);
+ return( 0 );
+}
+
+int
+slapi_log_error( int severity, char *subsystem, char *fmt, ... )
+{
+ va_list ap1;
+ va_list ap2;
+ int rc;
+
+ if ( severity < SLAPI_LOG_MIN || severity > SLAPI_LOG_MAX ) {
+ (void)slapd_log_error_proc( subsystem,
+ "slapi_log_error: invalid severity %d (message %s)\n",
+ severity, fmt );
+ return( -1 );
+ }
+
+
+#ifdef _WIN32
+ if ( *module_ldap_debug
+#else
+ if ( slapd_ldap_debug
+#endif
+ & slapi_log_map[ severity ] ) {
+ va_start( ap1, fmt );
+ va_start( ap2, fmt );
+ rc = slapd_log_error_proc_internal( subsystem, fmt, ap1, ap2 );
+ va_end( ap1 );
+ va_end( ap2 );
+ } else {
+ rc = 0; /* nothing to be logged --> always return success */
+ }
+
+ return( rc );
+}
+
+int
+slapi_is_loglevel_set ( const int loglevel )
+{
+
+ return (
+#ifdef _WIN32
+ *module_ldap_debug
+#else
+ slapd_ldap_debug
+#endif
+ & slapi_log_map[ loglevel ] ? 1 : 0);
+}
+
+
+/******************************************************************************
+* write in the access log
+******************************************************************************/
+static int vslapd_log_access(char *fmt, va_list ap)
+{
+ time_t tnl;
+ long tz;
+ struct tm *tmsp, tms;
+ char tbuf[ TBUFSIZE ];
+ char sign;
+ char buffer[SLAPI_LOG_BUFSIZ];
+ char vbuf[SLAPI_LOG_BUFSIZ];
+ int blen, vlen;
+ /* info needed to keep us from calling localtime/strftime so often: */
+ static time_t old_time = 0;
+ static char old_tbuf[TBUFSIZE];
+ static int old_blen = 0;
+
+ tnl = current_time();
+
+ /* check if we can use the old strftime buffer */
+ PR_Lock(ts_time_lock);
+ if (tnl == old_time) {
+ strcpy(buffer, old_tbuf);
+ blen = old_blen;
+ PR_Unlock(ts_time_lock);
+ } else {
+ /* nope... painstakingly create the new strftime buffer */
+#ifdef _WIN32
+ {
+ struct tm *pt = localtime( &tnl );
+ tmsp = &tms;
+ memcpy(&tms, pt, sizeof(struct tm) );
+ }
+#else
+ (void)localtime_r( &tnl, &tms );
+ tmsp = &tms;
+#endif
+
+#ifdef BSD_TIME
+ tz = tmsp->tm_gmtoff;
+#else /* BSD_TIME */
+ tz = - timezone;
+ if ( tmsp->tm_isdst ) {
+ tz += 3600;
+ }
+#endif /* BSD_TIME */
+ sign = ( tz >= 0 ? '+' : '-' );
+ if ( tz < 0 ) {
+ tz = -tz;
+ }
+ (void)strftime( tbuf, (size_t)TBUFSIZE, "%d/%b/%Y:%H:%M:%S", tmsp);
+ sprintf( buffer, "[%s %c%02d%02d] ", tbuf, sign,
+ (int)( tz / 3600 ), (int)( tz % 3600));
+ old_time = tnl;
+ strcpy(old_tbuf, buffer);
+ blen = strlen(buffer);
+ old_blen = blen;
+ PR_Unlock(ts_time_lock);
+ }
+
+ vlen = PR_vsnprintf(vbuf, SLAPI_LOG_BUFSIZ, fmt, ap);
+ if (! vlen) {
+ return -1;
+ }
+
+ if (SLAPI_LOG_BUFSIZ - blen < vlen) {
+ return -1;
+ }
+
+ log_append_buffer2(tnl, loginfo.log_access_buffer, buffer, blen, vbuf, vlen);
+
+ return( 0 );
+}
+
+int
+slapi_log_access( int level,
+ char *fmt,
+ ... )
+{
+ va_list ap;
+ int rc=0;
+
+ if (!(loginfo.log_access_state & LOGGING_ENABLED)) {
+ return 0;
+ }
+ va_start( ap, fmt );
+ if (( level & loginfo.log_access_level ) &&
+ ( loginfo.log_access_fdes != NULL ) && (loginfo.log_access_file != NULL) ) {
+ rc = vslapd_log_access(fmt, ap);
+ }
+ va_end( ap );
+ return( rc );
+}
+
+/******************************************************************************
+* access_log_openf
+*
+* Open the access log file
+*
+* Returns:
+* 0 -- success
+* 1 -- fail
+******************************************************************************/
+int access_log_openf(char *pathname, int locked)
+{
+ int rv=0;
+ int logfile_type = 0;
+ char buf[BUFSIZ];
+
+ if (!locked) LOG_ACCESS_LOCK_WRITE( );
+
+ /* store the path name */
+ loginfo.log_access_file = slapi_ch_strdup ( pathname );
+
+ /* store the rotation info fiel path name */
+ sprintf (buf, "%s.rotationinfo",pathname);
+ loginfo.log_accessinfo_file = slapi_ch_strdup ( buf );
+
+ /*
+ ** Check if we have a log file already. If we have it then
+ ** we need to parse the header info and update the loginfo
+ ** struct.
+ */
+ logfile_type = log__access_rotationinfof(loginfo.log_accessinfo_file);
+
+ if (log__open_accesslogfile(logfile_type, 1/* got lock*/) != LOG_SUCCESS) {
+ rv = 1;
+ }
+
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE();
+
+
+ return rv;
+}
+
+/******************************************************************************
+* log__open_accesslogfile
+*
+* Open a new log file. If we have run out of the max logs we can have
+* then delete the oldest file.
+******************************************************************************/
+static int
+log__open_accesslogfile(int logfile_state, int locked)
+{
+
+ time_t now;
+ LOGFD fp;
+ LOGFD fpinfo = NULL;
+ char tbuf[TBUFSIZE];
+ struct logfileinfo *logp;
+ char buffer[BUFSIZ];
+
+ if (!locked) LOG_ACCESS_LOCK_WRITE( );
+
+ /*
+ ** Here we are trying to create a new log file.
+ ** If we alredy have one, then we need to rename it as
+ ** "filename.time", close it and update it's information
+ ** in the array stack.
+ */
+ if (loginfo.log_access_fdes != NULL) {
+ struct logfileinfo *log;
+ char newfile[BUFSIZ];
+ int f_size;
+
+ /* get rid of the old one */
+ if ((f_size = log__getfilesize(loginfo.log_access_fdes)) == -1) {
+ /* Then assume that we have the max size */
+ f_size = loginfo.log_access_maxlogsize;
+ }
+
+ /* Check if I have to delete any old file, delete it if it is required.
+ ** If there is just one file, then access and access.rotation files
+ ** are deleted. After that we start fresh
+ */
+ while (log__delete_access_logfile());
+
+ /* close the file */
+ LOG_CLOSE(loginfo.log_access_fdes);
+ /*
+ * loginfo.log_access_fdes is not set to NULL here, otherwise
+ * slapi_log_access() will not send a message to the access log
+ * if it is called between this point and where this field is
+ * set again after calling LOG_OPEN_APPEND.
+ */
+ if ( loginfo.log_access_maxnumlogs > 1 ) {
+ log = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ log->l_ctime = loginfo.log_access_ctime;
+ log->l_size = f_size;
+
+ log_convert_time (log->l_ctime, tbuf, 1 /*short */);
+ sprintf(newfile, "%s.%s", loginfo.log_access_file, tbuf);
+ if (PR_Rename (loginfo.log_access_file, newfile) != PR_SUCCESS) {
+ loginfo.log_access_fdes = NULL;
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE();
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+ /* add the log to the chain */
+ log->l_next = loginfo.log_access_logchain;
+ loginfo.log_access_logchain = log;
+ loginfo.log_numof_access_logs++;
+ }
+ }
+
+
+ /* open a new log file */
+ if (! LOG_OPEN_APPEND(fp, loginfo.log_access_file, loginfo.log_access_mode)) {
+ int oserr = errno;
+ loginfo.log_access_fdes = NULL;
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE();
+ LDAPDebug( LDAP_DEBUG_ANY, "access file open %s failed errno %d (%s)\n",
+ loginfo.log_access_file,
+ oserr, slapd_system_strerror(oserr));
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ loginfo.log_access_fdes = fp;
+ if (logfile_state == LOGFILE_REOPENED) {
+ /* we have all the information */
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE( );
+ return LOG_SUCCESS;
+ }
+
+ loginfo.log_access_state |= LOGGING_NEED_TITLE;
+
+ if (! LOG_OPEN_WRITE(fpinfo, loginfo.log_accessinfo_file, loginfo.log_access_mode)) {
+ int oserr = errno;
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE();
+ LDAPDebug( LDAP_DEBUG_ANY, "accessinfo file open %s failed errno %d (%s)\n",
+ loginfo.log_accessinfo_file,
+ oserr, slapd_system_strerror(oserr));
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+
+ /* write the header in the log */
+ now = current_time();
+ log_convert_time (now, tbuf, 2 /* long */);
+ sprintf (buffer,"LOGINFO:Log file created at: %s (%lu)\n", tbuf, now);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+
+ logp = loginfo.log_access_logchain;
+ while ( logp) {
+ log_convert_time (logp->l_ctime, tbuf, 1 /*short*/);
+ sprintf(buffer, "LOGINFO:Previous Log File:%s.%s (%lu) (%u)\n",
+ loginfo.log_access_file, tbuf, logp->l_ctime, logp->l_size);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+ logp = logp->l_next;
+ }
+ /* Close the info file. We need only when we need to rotate to the
+ ** next log file.
+ */
+ if (fpinfo) LOG_CLOSE(fpinfo);
+
+ /* This is now the current access log */
+ loginfo.log_access_ctime = now;
+
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE( );
+ return LOG_SUCCESS;
+}
+/******************************************************************************
+* log__needrotation
+*
+* Do we need to rotate the log file ?
+* Find out based on rotation time and the max log size;
+*
+* Return:
+* LOG_CONTINUE -- Use the same one
+* LOG_ROTATE -- log need to be rotated
+*
+* Note:
+* A READ LOCK is obtained.
+********************************************************************************/
+#define LOG_SIZE_EXCEEDED 1
+#define LOG_EXPIRED 2
+static int
+log__needrotation(LOGFD fp, int logtype)
+{
+ time_t curr_time;
+ time_t log_createtime= 0;
+ time_t syncclock;
+ int type = LOG_CONTINUE;
+ int f_size = 0;
+ int maxlogsize, nlogs;
+ int rotationtime_secs = -1;
+ int sync_enabled, synchour, syncmin, timeunit;
+
+ if (fp == NULL) {
+ return LOG_ROTATE;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ nlogs = loginfo.log_access_maxnumlogs;
+ maxlogsize = loginfo.log_access_maxlogsize;
+ sync_enabled = loginfo.log_access_rotationsync_enabled;
+ synchour = loginfo.log_access_rotationsynchour;
+ syncmin = loginfo.log_access_rotationsyncmin;
+ syncclock = loginfo.log_access_rotationsyncclock;
+ timeunit = loginfo.log_access_rotationunit;
+ rotationtime_secs = loginfo.log_access_rotationtime_secs;
+ log_createtime = loginfo.log_access_ctime;
+ break;
+ case SLAPD_ERROR_LOG:
+ nlogs = loginfo.log_error_maxnumlogs;
+ maxlogsize = loginfo.log_error_maxlogsize;
+ sync_enabled = loginfo.log_error_rotationsync_enabled;
+ synchour = loginfo.log_error_rotationsynchour;
+ syncmin = loginfo.log_error_rotationsyncmin;
+ syncclock = loginfo.log_error_rotationsyncclock;
+ timeunit = loginfo.log_error_rotationunit;
+ rotationtime_secs = loginfo.log_error_rotationtime_secs;
+ log_createtime = loginfo.log_error_ctime;
+ break;
+ case SLAPD_AUDIT_LOG:
+ nlogs = loginfo.log_audit_maxnumlogs;
+ maxlogsize = loginfo.log_audit_maxlogsize;
+ sync_enabled = loginfo.log_audit_rotationsync_enabled;
+ synchour = loginfo.log_audit_rotationsynchour;
+ syncmin = loginfo.log_audit_rotationsyncmin;
+ syncclock = loginfo.log_audit_rotationsyncclock;
+ timeunit = loginfo.log_audit_rotationunit;
+ rotationtime_secs = loginfo.log_audit_rotationtime_secs;
+ log_createtime = loginfo.log_audit_ctime;
+ break;
+ default: /* error */
+ maxlogsize = -1;
+ nlogs = 1;
+
+ }
+
+ /* If we have one log then can't rotate at all */
+ if (nlogs == 1)
+ return LOG_CONTINUE;
+
+ if ((f_size = log__getfilesize(fp)) == -1) {
+ /* The next option is to rotate based on the rotation time */
+ f_size = 0;
+ }
+
+ /* If the log size is more than the limit, then it's time to rotate. */
+ if ((maxlogsize > 0) && (f_size >= maxlogsize)) {
+ type = LOG_SIZE_EXCEEDED;
+ goto log_rotate;
+ }
+
+ /* If rotation interval <= 0 then can't rotate by time */
+ if (rotationtime_secs <= 0)
+ return LOG_CONTINUE;
+
+ /*
+ ** If the log is older than the time allowed to be active,
+ ** then it's time to move on (i.e., rotate).
+ */
+ time (&curr_time);
+
+ if ( !sync_enabled || timeunit == LOG_UNIT_HOURS || timeunit == LOG_UNIT_MINS ) {
+ if (curr_time - log_createtime > rotationtime_secs) {
+ type = LOG_EXPIRED;
+ goto log_rotate;
+ }
+
+ } else if (curr_time > syncclock) {
+ type = LOG_EXPIRED;
+ goto log_rotate;
+ }
+
+log_rotate:
+ /*
+ ** Don't send messages to the error log whilst we're rotating it.
+ ** This'll lead to a recursive call to the logging function, and
+ ** an assertion trying to relock the write lock.
+ */
+ if (logtype!=SLAPD_ERROR_LOG)
+ {
+ if (type == LOG_SIZE_EXCEEDED) {
+ LDAPDebug (LDAP_DEBUG_TRACE,
+ "LOGINFO:End of Log because size exceeded(Max:%d bytes) (Is:%d bytes)\n", maxlogsize, f_size, 0);
+ } else if ( type == LOG_EXPIRED) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:End of Log because time exceeded(Max:%d secs) (Is:%d secs)\n",
+ rotationtime_secs, curr_time - log_createtime,0);
+ }
+ }
+ return (type == LOG_CONTINUE) ? LOG_CONTINUE : LOG_ROTATE;
+}
+
+/******************************************************************************
+* log__delete_access_logfile
+*
+* Do we need to delete a logfile. Find out if we need to delete the log
+* file based on expiration time, max diskspace, and minfreespace.
+* Delete the file if we need to.
+*
+* Assumption: A WRITE lock has been acquired for the ACCESS
+******************************************************************************/
+
+static int
+log__delete_access_logfile()
+{
+
+ struct logfileinfo *logp = NULL;
+ struct logfileinfo *delete_logp = NULL;
+ struct logfileinfo *p_delete_logp = NULL;
+ struct logfileinfo *prev_logp = NULL;
+ int total_size=0;
+ time_t cur_time;
+ int f_size;
+ int numoflogs=loginfo.log_numof_access_logs;
+ int rv = 0;
+ char *logstr;
+ char buffer[BUFSIZ];
+ char tbuf[TBUFSIZE];
+
+ /* If we have only one log, then will delete this one */
+ if (loginfo.log_access_maxnumlogs == 1) {
+ LOG_CLOSE(loginfo.log_access_fdes);
+ loginfo.log_access_fdes = NULL;
+ sprintf (buffer, "%s", loginfo.log_access_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s\n", loginfo.log_access_file,0,0);
+ }
+
+ /* Delete the rotation file also. */
+ sprintf (buffer, "%s.rotationinfo", loginfo.log_access_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_access_file,0,0);
+ }
+ return 0;
+ }
+
+ /* If we have already the maximum number of log files, we
+ ** have to delete one any how.
+ */
+ if (++numoflogs > loginfo.log_access_maxnumlogs) {
+ logstr = "Exceeded max number of logs allowed";
+ goto delete_logfile;
+ }
+
+ /* Now check based on the maxdiskspace */
+ if (loginfo.log_access_maxdiskspace > 0) {
+ logp = loginfo.log_access_logchain;
+ while (logp) {
+ total_size += logp->l_size;
+ logp = logp->l_next;
+ }
+ if ((f_size = log__getfilesize(loginfo.log_access_fdes)) == -1) {
+ /* then just assume the max size */
+ total_size += loginfo.log_access_maxlogsize;
+ } else {
+ total_size += f_size;
+ }
+
+ /* If we have exceeded the max disk space or we have less than the
+ ** minimum, then we have to delete a file.
+ */
+ if (total_size >= loginfo.log_access_maxdiskspace) {
+ logstr = "exceeded maximum log disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the free space */
+ if ( loginfo.log_access_minfreespace > 0) {
+ rv = log__enough_freespace(loginfo.log_access_file);
+ if ( rv == 0) {
+ /* Not enough free space */
+ logstr = "Not enough free disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the expiration time */
+ if ( loginfo.log_access_exptime_secs > 0 ) {
+ /* is the file old enough */
+ time (&cur_time);
+ prev_logp = logp = loginfo.log_access_logchain;
+ while (logp) {
+ if ((cur_time - logp->l_ctime) > loginfo.log_access_exptime_secs) {
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ logstr = "The file is older than the log expiration time";
+ goto delete_logfile;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ }
+
+ /* No log files to delete */
+ return 0;
+
+delete_logfile:
+ if (delete_logp == NULL) {
+ time_t oldest;
+
+ time(&oldest);
+
+ prev_logp = logp = loginfo.log_access_logchain;
+ while (logp) {
+ if (logp->l_ctime <= oldest) {
+ oldest = logp->l_ctime;
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ /* We might face this case if we have only one log file and
+ ** trying to delete it because of deletion requirement.
+ */
+ if (!delete_logp) {
+ return 0;
+ }
+ }
+
+ if (p_delete_logp == delete_logp) {
+ /* then we are deleteing the first one */
+ loginfo.log_access_logchain = delete_logp->l_next;
+ } else {
+ p_delete_logp->l_next = delete_logp->l_next;
+ }
+
+
+ /* Delete the access file */
+ log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
+ sprintf (buffer, "%s.%s", loginfo.log_access_file, tbuf);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s.%s\n",
+ loginfo.log_access_file,tbuf,0);
+
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Removed file:%s.%s because of (%s)\n",
+ loginfo.log_access_file, tbuf,
+ logstr);
+ }
+ slapi_ch_free((void**)&delete_logp);
+ loginfo.log_numof_access_logs--;
+
+ return 1;
+}
+/******************************************************************************
+* log__access_rotationinfof
+*
+* Try to open the log file. If we have one already, then try to read the
+* header and update the information.
+*
+* Assumption: Lock has been acquired already
+******************************************************************************/
+static int
+log__access_rotationinfof( char *pathname)
+{
+ long f_ctime;
+ int f_size;
+ int main_log = 1;
+ time_t now;
+ FILE *fp;
+
+
+ /*
+ ** Okay -- I confess, we want to use NSPR calls but I want to
+ ** use fgets and not use PR_Read() and implement a complicated
+ ** parsing module. Since this will be called only during the startup
+ ** and never aftre that, we can live by it.
+ */
+
+ if ((fp = fopen (pathname, "r")) == NULL) {
+ return LOGFILE_NEW;
+ }
+
+ loginfo.log_numof_access_logs = 0;
+
+ /*
+ ** We have reopened the log access file. Now we need to read the
+ ** log file info and update the values.
+ */
+ while (log__extract_logheader(fp, &f_ctime, &f_size) == LOG_CONTINUE) {
+ /* first we would get the main log info */
+ if (f_ctime == 0 && f_size == 0)
+ continue;
+
+ time (&now);
+ if (main_log) {
+ if (f_ctime > 0L)
+ loginfo.log_access_ctime = f_ctime;
+ else {
+ loginfo.log_access_ctime = now;
+ }
+ main_log = 0;
+ } else {
+ struct logfileinfo *logp;
+
+ logp = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ if (f_ctime > 0L)
+ logp->l_ctime = f_ctime;
+ else
+ logp->l_ctime = now;
+ if (f_size > 0)
+ logp->l_size = f_size;
+ else {
+ /* make it the max log size */
+ logp->l_size = loginfo.log_access_maxlogsize;
+ }
+
+ logp->l_next = loginfo.log_access_logchain;
+ loginfo.log_access_logchain = logp;
+ }
+ loginfo.log_numof_access_logs++;
+ }
+
+ /* Check if there is a rotation overdue */
+ if (loginfo.log_access_rotationsync_enabled &&
+ loginfo.log_access_rotationunit != LOG_UNIT_HOURS &&
+ loginfo.log_access_rotationunit != LOG_UNIT_MINS &&
+ loginfo.log_access_ctime < loginfo.log_access_rotationsyncclock - loginfo.log_access_rotationtime_secs) {
+ loginfo.log_access_rotationsyncclock -= loginfo.log_access_rotationtime_secs;
+ }
+ fclose (fp);
+ return LOGFILE_REOPENED;
+}
+
+/******************************************************************************
+* log__extract_logheader
+*
+* Extract each LOGINFO heder line. From there extract the time and
+* size info of all the old log files.
+******************************************************************************/
+static int
+log__extract_logheader (FILE *fp, long *f_ctime, int *f_size)
+{
+
+ char buf[BUFSIZ];
+ char *p, *s, *next;
+
+ *f_ctime = 0L;
+ *f_size = 0;
+
+ if ( fp == NULL)
+ return LOG_ERROR;
+
+ if (fgets(buf, BUFSIZ, fp) == NULL) {
+ return LOG_ERROR;
+ }
+
+ if ((p=strstr(buf, "LOGINFO")) == NULL) {
+ return LOG_ERROR;
+ }
+
+ s = p;
+ if ((p = strchr(p, '(')) == NULL) {
+ return LOG_CONTINUE;
+ }
+ if ((next= strchr(p, ')')) == NULL) {
+ return LOG_CONTINUE;
+ }
+
+ p++;
+ s = next;
+ next++;
+ *s = '\0';
+
+ /* Now p must hold the ctime value */
+ *f_ctime = atoi(p);
+
+ if ((p = strchr(next, '(')) == NULL) {
+ /* that's fine -- it means we have no size info */
+ *f_size = 0;
+ return LOG_CONTINUE;
+ }
+
+ if ((next= strchr(p, ')')) == NULL) {
+ return LOG_CONTINUE;
+ }
+
+ p++;
+ *next = '\0';
+
+ /* Now p must hold the size value */
+ *f_size = atoi(p);
+
+ return LOG_CONTINUE;
+
+}
+
+/******************************************************************************
+* log__getfilesize
+* Get the file size
+*
+* Assumption: Lock has been acquired already.
+******************************************************************************/
+/* this kinda has to be diff't on each platform :( */
+/* using an int implies that all logfiles will be under 2G. this is
+ * probably a safe assumption for now.
+ */
+#ifdef XP_WIN32
+static int
+log__getfilesize(LOGFD fp)
+{
+ struct stat info;
+ int rv;
+
+ if ((rv = fstat(fileno(fp), &info)) != 0) {
+ return -1;
+ }
+ return info.st_size;
+}
+#else
+static int
+log__getfilesize(LOGFD fp)
+{
+ PRFileInfo info;
+ int rv;
+
+ if ((rv = PR_GetOpenFileInfo (fp, &info)) == PR_FAILURE) {
+ return -1;
+ }
+ return info.size;
+}
+#endif
+
+
+/******************************************************************************
+* log__enough_freespace
+*
+* Returns:
+* 1 - we have enough space
+* 0 - No the avialable space is less than recomended
+* Assumption: Lock has been acquired already.
+******************************************************************************/
+static int
+log__enough_freespace(char *path)
+{
+
+#ifdef _WIN32
+DWORD sectorsPerCluster, bytesPerSector, freeClusters, totalClusters;
+char rootpath[4];
+#else
+#ifdef LINUX
+ struct statfs buf;
+#else
+ struct statvfs buf;
+#endif /* LINUX */
+#endif
+ PRInt64 freeBytes;
+ PRInt64 tmpval;
+
+
+#ifdef _WIN32
+ strncpy(rootpath, path, 3);
+ rootpath[3] = '\0';
+ /* we should consider using GetDiskFreeSpaceEx here someday */
+ if ( !GetDiskFreeSpace(rootpath, &sectorsPerCluster, &bytesPerSector,
+ &freeClusters, &totalClusters)) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "log__enough_freespace: Unable to get the free space\n",0,0,0);
+ return 1;
+ } else {
+ LL_UI2L(freeBytes, freeClusters);
+ LL_UI2L(tmpval, sectorsPerCluster);
+ LL_MUL(freeBytes, freeBytes, tmpval);
+ LL_UI2L(tmpval, bytesPerSector);
+ LL_MUL(freeBytes, freeBytes, tmpval);
+/* freeBytes = freeClusters * sectorsPerCluster * bytesPerSector; */
+
+ }
+
+#else
+#ifdef LINUX
+ if (statfs(path, &buf) == -1)
+#else
+ if (statvfs(path, &buf) == -1)
+#endif
+ {
+ int oserr = errno;
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "log__enough_freespace: Unable to get the free space (errno:%d)\n",
+ oserr,0,0);
+ return 1;
+ } else {
+ LL_UI2L(freeBytes, buf.f_bavail);
+ LL_UI2L(tmpval, buf.f_bsize);
+ LL_MUL(freeBytes, freeBytes, tmpval);
+ /* freeBytes = buf.f_bavail * buf.f_bsize; */
+ }
+#endif
+ LL_UI2L(tmpval, loginfo.log_access_minfreespace);
+ if (LL_UCMP(freeBytes, <, tmpval)) {
+ /* if (freeBytes < loginfo.log_access_minfreespace) { */
+ return 0;
+ }
+ return 1;
+}
+/******************************************************************************
+* log__getaccesslist
+* Update the previous access files in the slapdFrontendConfig_t.
+* Returns:
+* num > 1 -- how many are there
+* 0 -- otherwise
+******************************************************************************/
+char **
+log_get_loglist(int logtype)
+{
+ char **list=NULL;
+ int num, i;
+ LogFileInfo *logp = NULL;
+ char buf[BUFSIZ];
+ char tbuf[TBUFSIZE];
+ char *file;
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_READ( );
+ num = loginfo.log_numof_access_logs;
+ logp = loginfo.log_access_logchain;
+ file = loginfo.log_access_file;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_READ( );
+ num = loginfo.log_numof_error_logs;
+ logp = loginfo.log_error_logchain;
+ file = loginfo.log_error_file;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_READ( );
+ num = loginfo.log_numof_audit_logs;
+ logp = loginfo.log_audit_logchain;
+ file = loginfo.log_audit_file;
+ break;
+ default:
+ return NULL;
+ }
+ list = (char **) slapi_ch_calloc(1, num * sizeof(char *));
+ i = 0;
+ while (logp) {
+ log_convert_time (logp->l_ctime, tbuf, 1 /*short */);
+ sprintf(buf, "%s.%s", file, tbuf);
+ list[i] = slapi_ch_strdup(buf);
+ i++;
+ logp = logp->l_next;
+ }
+ list[i] = NULL;
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_UNLOCK_READ();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_UNLOCK_READ();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_UNLOCK_READ();
+ break;
+ }
+ return list;
+}
+
+/******************************************************************************
+* log__delete_error_logfile
+*
+* Do we need to delete a logfile. Find out if we need to delete the log
+* file based on expiration time, max diskspace, and minfreespace.
+* Delete the file if we need to.
+*
+* Assumption: A WRITE lock has been acquired for the error log.
+******************************************************************************/
+
+static int
+log__delete_error_logfile()
+{
+
+ struct logfileinfo *logp = NULL;
+ struct logfileinfo *delete_logp = NULL;
+ struct logfileinfo *p_delete_logp = NULL;
+ struct logfileinfo *prev_logp = NULL;
+ int total_size=0;
+ time_t cur_time;
+ int f_size;
+ int numoflogs=loginfo.log_numof_error_logs;
+ int rv = 0;
+ char *logstr;
+ char buffer[BUFSIZ];
+ char tbuf[TBUFSIZE];
+
+
+ /* If we have only one log, then will delete this one */
+ if (loginfo.log_error_maxnumlogs == 1) {
+ LOG_CLOSE(loginfo.log_error_fdes);
+ loginfo.log_error_fdes = NULL;
+ sprintf (buffer, "%s", loginfo.log_error_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s\n", loginfo.log_error_file,0,0);
+ }
+
+ /* Delete the rotation file also. */
+ sprintf (buffer, "%s.rotationinfo", loginfo.log_error_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_error_file,0,0);
+ }
+ return 0;
+ }
+
+ /* If we have already the maximum number of log files, we
+ ** have to delete one any how.
+ */
+ if (++numoflogs > loginfo.log_error_maxnumlogs) {
+ logstr = "Exceeded max number of logs allowed";
+ goto delete_logfile;
+ }
+
+ /* Now check based on the maxdiskspace */
+ if (loginfo.log_error_maxdiskspace > 0) {
+ logp = loginfo.log_error_logchain;
+ while (logp) {
+ total_size += logp->l_size;
+ logp = logp->l_next;
+ }
+ if ((f_size = log__getfilesize(loginfo.log_error_fdes)) == -1) {
+ /* then just assume the max size */
+ total_size += loginfo.log_error_maxlogsize;
+ } else {
+ total_size += f_size;
+ }
+
+ /* If we have exceeded the max disk space or we have less than the
+ ** minimum, then we have to delete a file.
+ */
+ if (total_size >= loginfo.log_error_maxdiskspace) {
+ logstr = "exceeded maximum log disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the free space */
+ if ( loginfo.log_error_minfreespace > 0) {
+ rv = log__enough_freespace(loginfo.log_error_file);
+ if ( rv == 0) {
+ /* Not enough free space */
+ logstr = "Not enough free disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the expiration time */
+ if ( loginfo.log_error_exptime_secs > 0 ) {
+ /* is the file old enough */
+ time (&cur_time);
+ prev_logp = logp = loginfo.log_error_logchain;
+ while (logp) {
+ if ((cur_time - logp->l_ctime) > loginfo.log_error_exptime_secs) {
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ logstr = "The file is older than the log expiration time";
+ goto delete_logfile;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ }
+
+ /* No log files to delete */
+ return 0;
+
+delete_logfile:
+ if (delete_logp == NULL) {
+ time_t oldest;
+
+ time(&oldest);
+
+ prev_logp = logp = loginfo.log_error_logchain;
+ while (logp) {
+ if (logp->l_ctime <= oldest) {
+ oldest = logp->l_ctime;
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ /* We might face this case if we have only one log file and
+ ** trying to delete it because of deletion requirement.
+ */
+ if (!delete_logp) {
+ return 0;
+ }
+ }
+
+ if (p_delete_logp == delete_logp) {
+ /* then we are deleteing the first one */
+ loginfo.log_error_logchain = delete_logp->l_next;
+ } else {
+ p_delete_logp->l_next = delete_logp->l_next;
+ }
+
+ /* Delete the error file */
+ log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
+ sprintf (buffer, "%s.%s", loginfo.log_error_file, tbuf);
+ PR_Delete(buffer);
+ slapi_ch_free((void**)&delete_logp);
+ loginfo.log_numof_error_logs--;
+
+ return 1;
+}
+
+/******************************************************************************
+* log__delete_audit_logfile
+*
+* Do we need to delete a logfile. Find out if we need to delete the log
+* file based on expiration time, max diskspace, and minfreespace.
+* Delete the file if we need to.
+*
+* Assumption: A WRITE lock has been acquired for the audit
+******************************************************************************/
+
+static int
+log__delete_audit_logfile()
+{
+ struct logfileinfo *logp = NULL;
+ struct logfileinfo *delete_logp = NULL;
+ struct logfileinfo *p_delete_logp = NULL;
+ struct logfileinfo *prev_logp = NULL;
+ int total_size=0;
+ time_t cur_time;
+ int f_size;
+ int numoflogs=loginfo.log_numof_audit_logs;
+ int rv = 0;
+ char *logstr;
+ char buffer[BUFSIZ];
+ char tbuf[TBUFSIZE];
+
+ /* If we have only one log, then will delete this one */
+ if (loginfo.log_audit_maxnumlogs == 1) {
+ LOG_CLOSE(loginfo.log_audit_fdes);
+ loginfo.log_audit_fdes = NULL;
+ sprintf (buffer, "%s", loginfo.log_audit_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s\n", loginfo.log_audit_file,0,0);
+ }
+
+ /* Delete the rotation file also. */
+ sprintf (buffer, "%s.rotationinfo", loginfo.log_audit_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_audit_file,0,0);
+ }
+ return 0;
+ }
+
+ /* If we have already the maximum number of log files, we
+ ** have to delete one any how.
+ */
+ if (++numoflogs > loginfo.log_audit_maxnumlogs) {
+ logstr = "Exceeded max number of logs allowed";
+ goto delete_logfile;
+ }
+
+ /* Now check based on the maxdiskspace */
+ if (loginfo.log_audit_maxdiskspace > 0) {
+ logp = loginfo.log_audit_logchain;
+ while (logp) {
+ total_size += logp->l_size;
+ logp = logp->l_next;
+ }
+ if ((f_size = log__getfilesize(loginfo.log_audit_fdes)) == -1) {
+ /* then just assume the max size */
+ total_size += loginfo.log_audit_maxlogsize;
+ } else {
+ total_size += f_size;
+ }
+
+ /* If we have exceeded the max disk space or we have less than the
+ ** minimum, then we have to delete a file.
+ */
+ if (total_size >= loginfo.log_audit_maxdiskspace) {
+ logstr = "exceeded maximum log disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the free space */
+ if ( loginfo.log_audit_minfreespace > 0) {
+ rv = log__enough_freespace(loginfo.log_audit_file);
+ if ( rv == 0) {
+ /* Not enough free space */
+ logstr = "Not enough free disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the expiration time */
+ if ( loginfo.log_audit_exptime_secs > 0 ) {
+ /* is the file old enough */
+ time (&cur_time);
+ prev_logp = logp = loginfo.log_audit_logchain;
+ while (logp) {
+ if ((cur_time - logp->l_ctime) > loginfo.log_audit_exptime_secs) {
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ logstr = "The file is older than the log expiration time";
+ goto delete_logfile;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ }
+
+ /* No log files to delete */
+ return 0;
+
+delete_logfile:
+ if (delete_logp == NULL) {
+ time_t oldest;
+
+ time(&oldest);
+
+ prev_logp = logp = loginfo.log_audit_logchain;
+ while (logp) {
+ if (logp->l_ctime <= oldest) {
+ oldest = logp->l_ctime;
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ /* We might face this case if we have only one log file and
+ ** trying to delete it because of deletion requirement.
+ */
+ if (!delete_logp) {
+ return 0;
+ }
+ }
+
+ if (p_delete_logp == delete_logp) {
+ /* then we are deleteing the first one */
+ loginfo.log_audit_logchain = delete_logp->l_next;
+ } else {
+ p_delete_logp->l_next = delete_logp->l_next;
+ }
+
+ /* Delete the audit file */
+ log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
+ sprintf (buffer, "%s.%s", loginfo.log_audit_file, tbuf );
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s.%s\n",
+ loginfo.log_audit_file, tbuf,0);
+
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Removed file:%s.%s because of (%s)\n",
+ loginfo.log_audit_file, tbuf,
+ logstr);
+ }
+ slapi_ch_free((void**)&delete_logp);
+ loginfo.log_numof_audit_logs--;
+
+ return 1;
+}
+
+/******************************************************************************
+* log__error_rotationinfof
+*
+* Try to open the log file. If we have one already, then try to read the
+* header and update the information.
+*
+* Assumption: Lock has been acquired already
+******************************************************************************/
+static int
+log__error_rotationinfof( char *pathname)
+{
+ long f_ctime;
+ int f_size;
+ int main_log = 1;
+ time_t now;
+ FILE *fp;
+
+
+ /*
+ ** Okay -- I confess, we want to use NSPR calls but I want to
+ ** use fgets and not use PR_Read() and implement a complicated
+ ** parsing module. Since this will be called only during the startup
+ ** and never aftre that, we can live by it.
+ */
+
+ if ((fp = fopen (pathname, "r")) == NULL) {
+ return LOGFILE_NEW;
+ }
+
+ loginfo.log_numof_error_logs = 0;
+
+ /*
+ ** We have reopened the log error file. Now we need to read the
+ ** log file info and update the values.
+ */
+ while (log__extract_logheader(fp, &f_ctime, &f_size) == LOG_CONTINUE) {
+ /* first we would get the main log info */
+ if (f_ctime == 0 && f_size == 0)
+ continue;
+
+ time (&now);
+ if (main_log) {
+ if (f_ctime > 0L)
+ loginfo.log_error_ctime = f_ctime;
+ else {
+ loginfo.log_error_ctime = now;
+ }
+ main_log = 0;
+ } else {
+ struct logfileinfo *logp;
+
+ logp = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ if (f_ctime > 0L)
+ logp->l_ctime = f_ctime;
+ else
+ logp->l_ctime = now;
+ if (f_size > 0)
+ logp->l_size = f_size;
+ else {
+ /* make it the max log size */
+ logp->l_size = loginfo.log_error_maxlogsize;
+ }
+
+ logp->l_next = loginfo.log_error_logchain;
+ loginfo.log_error_logchain = logp;
+ }
+ loginfo.log_numof_error_logs++;
+ }
+
+ /* Check if there is a rotation overdue */
+ if (loginfo.log_error_rotationsync_enabled &&
+ loginfo.log_error_rotationunit != LOG_UNIT_HOURS &&
+ loginfo.log_error_rotationunit != LOG_UNIT_MINS &&
+ loginfo.log_error_ctime < loginfo.log_error_rotationsyncclock - loginfo.log_error_rotationtime_secs) {
+ loginfo.log_error_rotationsyncclock -= loginfo.log_error_rotationtime_secs;
+ }
+
+ fclose (fp);
+ return LOGFILE_REOPENED;
+}
+
+/******************************************************************************
+* log__audit_rotationinfof
+*
+* Try to open the log file. If we have one already, then try to read the
+* header and update the information.
+*
+* Assumption: Lock has been acquired already
+******************************************************************************/
+static int
+log__audit_rotationinfof( char *pathname)
+{
+ long f_ctime;
+ int f_size;
+ int main_log = 1;
+ time_t now;
+ FILE *fp;
+
+
+ /*
+ ** Okay -- I confess, we want to use NSPR calls but I want to
+ ** use fgets and not use PR_Read() and implement a complicated
+ ** parsing module. Since this will be called only during the startup
+ ** and never aftre that, we can live by it.
+ */
+
+ if ((fp = fopen (pathname, "r")) == NULL) {
+ return LOGFILE_NEW;
+ }
+
+ loginfo.log_numof_audit_logs = 0;
+
+ /*
+ ** We have reopened the log audit file. Now we need to read the
+ ** log file info and update the values.
+ */
+ while (log__extract_logheader(fp, &f_ctime, &f_size) == LOG_CONTINUE) {
+ /* first we would get the main log info */
+ if (f_ctime == 0 && f_size == 0)
+ continue;
+
+ time (&now);
+ if (main_log) {
+ if (f_ctime > 0L)
+ loginfo.log_audit_ctime = f_ctime;
+ else {
+ loginfo.log_audit_ctime = now;
+ }
+ main_log = 0;
+ } else {
+ struct logfileinfo *logp;
+
+ logp = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ if (f_ctime > 0L)
+ logp->l_ctime = f_ctime;
+ else
+ logp->l_ctime = now;
+ if (f_size > 0)
+ logp->l_size = f_size;
+ else {
+ /* make it the max log size */
+ logp->l_size = loginfo.log_audit_maxlogsize;
+ }
+
+ logp->l_next = loginfo.log_audit_logchain;
+ loginfo.log_audit_logchain = logp;
+ }
+ loginfo.log_numof_audit_logs++;
+ }
+
+ /* Check if there is a rotation overdue */
+ if (loginfo.log_audit_rotationsync_enabled &&
+ loginfo.log_audit_rotationunit != LOG_UNIT_HOURS &&
+ loginfo.log_audit_rotationunit != LOG_UNIT_MINS &&
+ loginfo.log_audit_ctime < loginfo.log_audit_rotationsyncclock - loginfo.log_audit_rotationtime_secs) {
+ loginfo.log_audit_rotationsyncclock -= loginfo.log_audit_rotationtime_secs;
+ }
+
+ fclose (fp);
+ return LOGFILE_REOPENED;
+}
+
+/******************************************************************************
+* log__open_errorlogfile
+*
+* Open a new log file. If we have run out of the max logs we can have
+* then delete the oldest file.
+******************************************************************************/
+static int
+log__open_errorlogfile(int logfile_state, int locked)
+{
+
+ time_t now;
+ LOGFD fp;
+ LOGFD fpinfo = NULL;
+ char tbuf[TBUFSIZE];
+ struct logfileinfo *logp;
+ char buffer[BUFSIZ];
+
+ if (!locked) LOG_ERROR_LOCK_WRITE( );
+
+ /*
+ ** Here we are trying to create a new log file.
+ ** If we alredy have one, then we need to rename it as
+ ** "filename.time", close it and update it's information
+ ** in the array stack.
+ */
+ if (loginfo.log_error_fdes != NULL) {
+ struct logfileinfo *log;
+ char newfile[BUFSIZ];
+ int f_size;
+
+ /* get rid of the old one */
+ if ((f_size = log__getfilesize(loginfo.log_error_fdes)) == -1) {
+ /* Then assume that we have the max size */
+ f_size = loginfo.log_error_maxlogsize;
+ }
+
+
+ /* Check if I have to delete any old file, delete it if it is required.*/
+ while (log__delete_error_logfile());
+
+ /* close the file */
+ if ( loginfo.log_error_fdes != NULL ) {
+ LOG_CLOSE(loginfo.log_error_fdes);
+ }
+ loginfo.log_error_fdes = NULL;
+
+ if ( loginfo.log_error_maxnumlogs > 1 ) {
+ log = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ log->l_ctime = loginfo.log_error_ctime;
+ log->l_size = f_size;
+
+ log_convert_time (log->l_ctime, tbuf, 1/*short */);
+ sprintf(newfile, "%s.%s", loginfo.log_error_file, tbuf);
+ if (PR_Rename (loginfo.log_error_file, newfile) != PR_SUCCESS) {
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ /* add the log to the chain */
+ log->l_next = loginfo.log_error_logchain;
+ loginfo.log_error_logchain = log;
+ loginfo.log_numof_error_logs++;
+ }
+ }
+
+
+ /* open a new log file */
+ if (! LOG_OPEN_APPEND(fp, loginfo.log_error_file, loginfo.log_error_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ loginfo.log_error_file, errno, slapd_system_strerror(errno));
+ if (!locked) LOG_ERROR_UNLOCK_WRITE();
+ /*if I have an old log file -- I should log a message
+ ** that I can't open the new file. Let the caller worry
+ ** about logging message.
+ */
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ loginfo.log_error_fdes = fp;
+ if (logfile_state == LOGFILE_REOPENED) {
+ /* we have all the information */
+ if (!locked) LOG_ERROR_UNLOCK_WRITE( );
+ return LOG_SUCCESS;
+ }
+
+ loginfo.log_error_state |= LOGGING_NEED_TITLE;
+
+ if (! LOG_OPEN_WRITE(fpinfo, loginfo.log_errorinfo_file, loginfo.log_error_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ loginfo.log_errorinfo_file, errno, slapd_system_strerror(errno));
+ if (!locked) LOG_ERROR_UNLOCK_WRITE();
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ /* write the header in the log */
+ now = current_time();
+ log_convert_time (now, tbuf, 2 /*long */);
+ sprintf (buffer,"LOGINFO:Log file created at: %s (%lu)\n", tbuf, now);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+
+ logp = loginfo.log_error_logchain;
+ while ( logp) {
+ log_convert_time (logp->l_ctime, tbuf, 1 /*short */);
+ sprintf(buffer, "LOGINFO:Previous Log File:%s.%s (%lu) (%u)\n",
+ loginfo.log_error_file, tbuf, logp->l_ctime, logp->l_size);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+ logp = logp->l_next;
+ }
+ /* Close the info file. We need only when we need to rotate to the
+ ** next log file.
+ */
+ if (fpinfo) LOG_CLOSE(fpinfo);
+
+ /* This is now the current error log */
+ loginfo.log_error_ctime = now;
+
+ if (!locked) LOG_ERROR_UNLOCK_WRITE( );
+ return LOG_SUCCESS;
+}
+
+/******************************************************************************
+* log__open_auditlogfile
+*
+* Open a new log file. If we have run out of the max logs we can have
+* then delete the oldest file.
+******************************************************************************/
+static int
+log__open_auditlogfile(int logfile_state, int locked)
+{
+
+ time_t now;
+ LOGFD fp;
+ LOGFD fpinfo = NULL;
+ char tbuf[TBUFSIZE];
+ struct logfileinfo *logp;
+ char buffer[BUFSIZ];
+
+ if (!locked) LOG_AUDIT_LOCK_WRITE( );
+
+ /*
+ ** Here we are trying to create a new log file.
+ ** If we alredy have one, then we need to rename it as
+ ** "filename.time", close it and update it's information
+ ** in the array stack.
+ */
+ if (loginfo.log_audit_fdes != NULL) {
+ struct logfileinfo *log;
+ char newfile[BUFSIZ];
+ int f_size;
+
+
+ /* get rid of the old one */
+ if ((f_size = log__getfilesize(loginfo.log_audit_fdes)) == -1) {
+ /* Then assume that we have the max size */
+ f_size = loginfo.log_audit_maxlogsize;
+ }
+
+
+ /* Check if I have to delete any old file, delete it if it is required. */
+ while (log__delete_audit_logfile());
+
+ /* close the file */
+ LOG_CLOSE(loginfo.log_audit_fdes);
+ loginfo.log_audit_fdes = NULL;
+
+ if ( loginfo.log_audit_maxnumlogs > 1 ) {
+ log = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ log->l_ctime = loginfo.log_audit_ctime;
+ log->l_size = f_size;
+
+ log_convert_time (log->l_ctime, tbuf, 1 /*short */);
+ sprintf(newfile, "%s.%s", loginfo.log_audit_file, tbuf);
+ if (PR_Rename (loginfo.log_audit_file, newfile) != PR_SUCCESS) {
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE();
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ /* add the log to the chain */
+ log->l_next = loginfo.log_audit_logchain;
+ loginfo.log_audit_logchain = log;
+ loginfo.log_numof_audit_logs++;
+ }
+ }
+
+
+ /* open a new log file */
+ if (! LOG_OPEN_APPEND(fp, loginfo.log_audit_file, loginfo.log_audit_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ loginfo.log_audit_file, errno, slapd_system_strerror(errno));
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE();
+ /*if I have an old log file -- I should log a message
+ ** that I can't open the new file. Let the caller worry
+ ** about logging message.
+ */
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ loginfo.log_audit_fdes = fp;
+ if (logfile_state == LOGFILE_REOPENED) {
+ /* we have all the information */
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE();
+ return LOG_SUCCESS;
+ }
+
+ loginfo.log_audit_state |= LOGGING_NEED_TITLE;
+
+ if (! LOG_OPEN_WRITE(fpinfo, loginfo.log_auditinfo_file, loginfo.log_audit_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ loginfo.log_auditinfo_file, errno, slapd_system_strerror(errno));
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE();
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ /* write the header in the log */
+ now = current_time();
+ log_convert_time (now, tbuf, 2 /*long */);
+ sprintf (buffer,"LOGINFO:Log file created at: %s (%lu)\n", tbuf, now);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+
+ logp = loginfo.log_audit_logchain;
+ while ( logp) {
+ log_convert_time (logp->l_ctime, tbuf, 1 /*short */);
+ sprintf(buffer, "LOGINFO:Previous Log File:%s.%s (%d) (%d)\n",
+ loginfo.log_audit_file, tbuf, (int)logp->l_ctime, logp->l_size);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+ logp = logp->l_next;
+ }
+ /* Close the info file. We need only when we need to rotate to the
+ ** next log file.
+ */
+ if (fpinfo) LOG_CLOSE(fpinfo);
+
+ /* This is now the current audit log */
+ loginfo.log_audit_ctime = now;
+
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE( );
+ return LOG_SUCCESS;
+}
+
+/*
+** Log Buffering
+** only supports access log at this time
+*/
+
+static LogBufferInfo *log_create_buffer(size_t sz)
+{
+ LogBufferInfo *lbi;
+
+ lbi = (LogBufferInfo *) slapi_ch_malloc(sizeof(LogBufferInfo));
+ lbi->top = (char *) slapi_ch_malloc(sz);
+ lbi->current = lbi->top;
+ lbi->maxsize = sz;
+ lbi->refcount = 0;
+ return lbi;
+}
+
+#if 0
+/* for some reason, we never call this. */
+static void log_destroy_buffer(LogBufferInfo *lbi)
+{
+ slapi_ch_free((void *)&(lbi->top));
+ slapi_ch_free((void *)&lbi);
+}
+#endif
+
+/*
+ Some notes about this function. It is written the
+ way it is for performance reasons.
+ Tests showed that on 4 processor systems, there is
+ significant contention for the
+ lbi->lock. This is because the lock was held for
+ the duration of the copy of the
+ log message into the buffer. Therefore the routine
+ was re-written to avoid holding
+ the lock for that time. Instead we gain the lock,
+ take a copy of the buffer pointer
+ where we need to copy our message, increase the
+ size, move the current pointer beyond
+ our portion of the buffer, then increment a reference
+ count.
+ Then we release the lock and do the actual copy
+ in to the reserved buffer area.
+ We then atomically decrement the reference count.
+ The reference count is used to ensure that when
+ the buffer is flushed to the
+ filesystem, there are no threads left copying
+ data into the buffer.
+ The wait on zero reference count is implemented
+ in the flush routine because
+ it is also called from log_access_flush().
+ Tests show this speeds up searches by 10% on 4-way systems.
+ */
+
+static void log_append_buffer2(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, char *msg2, size_t size2)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ size_t size = size1 + size2;
+ char* insert_point = NULL;
+
+ /* While holding the lock, we determine if there is space in the buffer for our payload,
+ and if we need to flush.
+ */
+ PR_Lock(lbi->lock);
+ if ( ((lbi->current - lbi->top) + size > lbi->maxsize) ||
+ (tnl >= loginfo.log_access_rotationsyncclock &&
+ loginfo.log_access_rotationsync_enabled) ) {
+
+ log_flush_buffer(lbi, SLAPD_ACCESS_LOG,
+ 0 /* do not sync to disk right now */ );
+
+ }
+ insert_point = lbi->current;
+ lbi->current += size;
+ /* Increment the copy refcount */
+ PR_AtomicIncrement(&(lbi->refcount));
+ PR_Unlock(lbi->lock);
+
+ /* Now we can copy without holding the lock */
+ memcpy(insert_point, msg1, size1);
+ memcpy(insert_point + size1, msg2, size2);
+
+ /* Decrement the copy refcount */
+ PR_AtomicDecrement(&(lbi->refcount));
+
+ /* If we are asked to sync to disk immediately, do so */
+ if (!slapdFrontendConfig->accesslogbuffering) {
+ PR_Lock(lbi->lock);
+ log_flush_buffer(lbi, SLAPD_ACCESS_LOG, 1 /* sync to disk now */ );
+ PR_Unlock(lbi->lock);
+ }
+
+}
+
+/* this function assumes the lock is already acquired */
+/* if sync_now is non-zero, data is flushed to physical storage */
+static void log_flush_buffer(LogBufferInfo *lbi, int type, int sync_now)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if (type == SLAPD_ACCESS_LOG) {
+
+ /* It is only safe to flush once any other threads which are copying are finished */
+ while (lbi->refcount > 0) {
+ /* It's ok to sleep for a while because we only flush every second or so */
+ DS_Sleep (PR_MillisecondsToInterval(1));
+ }
+
+ if ((lbi->current - lbi->top) == 0) return;
+
+ if (log__needrotation(loginfo.log_access_fdes,
+ SLAPD_ACCESS_LOG) == LOG_ROTATE) {
+ if (log__open_accesslogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "LOGINFO: Unable to open access file:%s\n",
+ loginfo.log_access_file,0,0);
+ lbi->current = lbi->top; /* reset counter to prevent overwriting rest of lbi struct */
+ return;
+ }
+ while (loginfo.log_access_rotationsyncclock <= loginfo.log_access_ctime) {
+ loginfo.log_access_rotationsyncclock += loginfo.log_access_rotationtime_secs;
+ }
+ }
+
+ if (loginfo.log_access_state & LOGGING_NEED_TITLE) {
+ log_write_title(loginfo.log_access_fdes);
+ loginfo.log_access_state &= ~LOGGING_NEED_TITLE;
+ }
+ if (!sync_now && slapdFrontendConfig->accesslogbuffering) {
+ LOG_WRITE(loginfo.log_access_fdes, lbi->top, lbi->current - lbi->top, 0);
+ } else {
+ LOG_WRITE_NOW(loginfo.log_access_fdes, lbi->top, lbi->current - lbi->top, 0);
+ }
+
+ lbi->current = lbi->top;
+ }
+}
+
+void log_access_flush()
+{
+ LOG_ACCESS_LOCK_WRITE();
+ log_flush_buffer(loginfo.log_access_buffer, SLAPD_ACCESS_LOG,
+ 1 /* sync to disk now */ );
+ LOG_ACCESS_UNLOCK_WRITE();
+}
+
+/*
+ *
+ * log_convert_time
+ * returns the time converted into the string format.
+ *
+ */
+static void
+log_convert_time (time_t ctime, char *tbuf, int type)
+{
+
+ struct tm *tmsp, tms;
+
+#ifdef _WIN32
+ {
+ struct tm *pt = localtime( &ctime );
+ tmsp = &tms;
+ memcpy(&tms, pt, sizeof(struct tm) );
+ }
+#else
+ (void)localtime_r( &ctime, &tms );
+ tmsp = &tms;
+#endif
+ if (type == 1) /* get the short form */
+ (void) strftime (tbuf, (size_t) TBUFSIZE, "%Y%m%d-%H%M%S",tmsp);
+ else /* wants the long form */
+ (void) strftime (tbuf, (size_t) TBUFSIZE, "%d/%b/%Y:%H:%M:%S",tmsp);
+
+}
+
+int
+check_log_max_size( char *maxdiskspace_str,
+ char *mlogsize_str,
+ int maxdiskspace,
+ int mlogsize,
+ char * returntext,
+ int logtype)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int rc = LDAP_SUCCESS;
+ int current_mlogsize = -1;
+ int current_maxdiskspace = -1;
+
+ switch (logtype)
+ {
+ case SLAPD_ACCESS_LOG:
+ current_mlogsize = slapdFrontendConfig->accesslog_maxlogsize;
+ current_maxdiskspace = slapdFrontendConfig->accesslog_maxdiskspace;
+ break;
+ case SLAPD_ERROR_LOG:
+ current_mlogsize = slapdFrontendConfig->errorlog_maxlogsize;
+ current_maxdiskspace = slapdFrontendConfig->errorlog_maxdiskspace;
+ break;
+ case SLAPD_AUDIT_LOG:
+ current_mlogsize = slapdFrontendConfig->auditlog_maxlogsize;
+ current_maxdiskspace = slapdFrontendConfig->auditlog_maxdiskspace;
+ break;
+ default:
+ current_mlogsize = -1;
+ current_maxdiskspace = -1;
+ }
+
+ if ( maxdiskspace == -1 )
+ maxdiskspace = current_maxdiskspace;
+ if ( mlogsize == -1 )
+ mlogsize = current_mlogsize;
+
+ if ( maxdiskspace < mlogsize )
+ {
+ /* fail */
+ PR_snprintf ( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: maxdiskspace \"%d\" is less than max log size \"%d\"",
+ maxdiskspace_str, maxdiskspace*LOG_MB_IN_BYTES, mlogsize*LOG_MB_IN_BYTES );
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+ switch (logtype)
+ {
+ case SLAPD_ACCESS_LOG:
+ loginfo.log_access_maxlogsize = mlogsize * LOG_MB_IN_BYTES;
+ loginfo.log_access_maxdiskspace = maxdiskspace * LOG_MB_IN_BYTES;
+ break;
+ case SLAPD_ERROR_LOG:
+ loginfo.log_error_maxlogsize = mlogsize * LOG_MB_IN_BYTES;
+ loginfo.log_error_maxdiskspace = maxdiskspace * LOG_MB_IN_BYTES;
+ break;
+ case SLAPD_AUDIT_LOG:
+ loginfo.log_audit_maxlogsize = mlogsize * LOG_MB_IN_BYTES;
+ loginfo.log_audit_maxdiskspace = maxdiskspace * LOG_MB_IN_BYTES;
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+/************************************************************************************/
+/* E N D */
+/************************************************************************************/
+