diff options
author | yaworsky <yaworsky> | 2005-09-16 08:33:41 +0000 |
---|---|---|
committer | yaworsky <yaworsky> | 2005-09-16 08:33:41 +0000 |
commit | a2c534419863b2c09fd122d8d1ef6769398f7cf0 (patch) | |
tree | c58907db78a04c9d4fae9999651e1a7293cf38f1 /daemon/logrotate.c | |
parent | 7875bee3ddfd14f2128540609519306742a78dec (diff) | |
download | syslog-win32-a2c534419863b2c09fd122d8d1ef6769398f7cf0.tar.gz syslog-win32-a2c534419863b2c09fd122d8d1ef6769398f7cf0.tar.xz syslog-win32-a2c534419863b2c09fd122d8d1ef6769398f7cf0.zip |
Added to repository.
Diffstat (limited to 'daemon/logrotate.c')
-rw-r--r-- | daemon/logrotate.c | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/daemon/logrotate.c b/daemon/logrotate.c new file mode 100644 index 0000000..5b0932a --- /dev/null +++ b/daemon/logrotate.c @@ -0,0 +1,264 @@ +/* + * logrotate.c - syslogd implementation for windows, log rotation + * + * Created by Alexander Yaworsky + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <windows.h> +#include <sys/stat.h> + +#include <glib.h> + +#include <syslog.h> +#include <syslogd.h> + +/****************************************************************************** + * expand_options + * + * Substitute $PATHNAME and $FILENAME + */ +static gchar* expand_options( const gchar* compressoptions, const gchar* pathname ) +{ + gchar *filename = g_path_get_basename( pathname ); + GString *str = g_string_new( compressoptions ); + gchar *substr_pathname; + gchar *substr_filename; + + TRACE_ENTER( "\n" ); + do { + substr_pathname = strstr( str->str, "$PATHNAME" ); + substr_filename = strstr( str->str, "$FILENAME" ); + + if( substr_pathname ) + { + int pos = substr_pathname - str->str; + g_string_erase( str, pos, 9 ); + g_string_insert( str, pos, pathname ); + } + + if( substr_filename ) + { + int pos = substr_filename - str->str; + g_string_erase( str, pos, 9 ); + g_string_insert( str, pos, filename ); + } + } while( substr_pathname || substr_filename ); + g_free( filename ); + TRACE_LEAVE( "return %s\n", str->str ); + return g_string_free( str, FALSE ); +} + +/****************************************************************************** + * compress_backlog + * + * Run external compression program. + * Return TRUE if all right. + */ +static gboolean compress_backlog( const gchar* compresscmd, const gchar* compressoptions, + const gchar* backlog ) +{ + gboolean ret = FALSE; + char command_pathname[ MAX_PATH ]; + LPTSTR command_filename; + gchar *options; + gchar *command_line; + STARTUPINFO si; + PROCESS_INFORMATION pi; + DWORD exit_code; + + TRACE_ENTER( "\n" ); + + if( !SearchPath( NULL, compresscmd, ".exe", + sizeof(command_pathname), command_pathname, &command_filename ) ) + { + ERR( "Command %s not found\n", compresscmd ); + TRACE_LEAVE( "error\n" ); + return FALSE; + } + + options = expand_options( compressoptions, backlog ); + command_line = g_strconcat( command_pathname, " ", options, NULL ); + + memset( &si, 0, sizeof(si ) ); + si.cb = sizeof(si); + TRACE_2( "command_line=%s\n", command_line ); + if( !CreateProcess( NULL, command_line, NULL, NULL, FALSE, + DETACHED_PROCESS, NULL, NULL, &si, &pi ) ) + ERR( "Cannot create process %s; error %lu\n", command_line, GetLastError() ); + else + { + CloseHandle( pi.hThread ); + TRACE_2( "waiting for %s\n", command_line ); + WaitForSingleObject( pi.hProcess, INFINITE ); + if( !GetExitCodeProcess( pi.hProcess, &exit_code ) ) + exit_code = 1; + CloseHandle( pi.hProcess ); + ret = 0 == exit_code; + } + + g_free( command_line ); + g_free( options ); + + TRACE_LEAVE( "ret=%d\n", ret ); + return ret; +} + +/****************************************************************************** + * do_rotate + * + * All criteria for rotation are met, just do it. + */ +static void do_rotate( const gchar* pathname, struct destination* destination ) +{ + int i; + gchar *dest_pathname; + gchar *backlog; + + TRACE_ENTER( "\n" ); + + /* construct destination pathname for backlogs */ + if( destination->olddir ) + { + gchar *filename = g_path_get_basename( pathname ); + + if( g_path_is_absolute( destination->olddir ) ) + dest_pathname = g_build_filename( destination->olddir, filename, NULL ); + else + { + gchar *prefix = g_path_get_dirname( __argv[0] ); + dest_pathname = g_build_filename( prefix, destination->olddir, filename, NULL ); + g_free( prefix ); + } + g_free( filename ); + } + else + dest_pathname = g_strdup( pathname ); + + /* remove earliest backlog */ + backlog = g_strdup_printf( "%s.%d", dest_pathname, destination->backlogs ); + DeleteFile( backlog ); + g_free( backlog ); + + /* rotate backlogs */ + for( i = destination->backlogs; i > 1; i-- ) + { + gchar *old_backlog = g_strdup_printf( "%s.%d", dest_pathname, i - 1 ); + gchar *new_backlog = g_strdup_printf( "%s.%d", dest_pathname, i ); + TRACE_2( "Move %s to %s\n", old_backlog, new_backlog ); + if( !MoveFile( old_backlog, new_backlog ) ) + { + /* most possible that old backlog file does not exist */ + TRACE_2( "Can't move %s to %s; error %lu\n", old_backlog, new_backlog, GetLastError() ); + } + g_free( old_backlog ); + g_free( new_backlog ); + } + + backlog = g_strconcat( dest_pathname, ".1", NULL ); + + /* move current log */ + TRACE_2( "Move %s to %s\n", pathname, backlog ); + if( !MoveFile( pathname, backlog ) ) + ERR( "Can't move %s to %s; error %lu\n", pathname, backlog, GetLastError() ); + + /* compress new backlog */ + if( destination->compresscmd ) + { + if( compress_backlog( destination->compresscmd, destination->compressoptions, backlog ) ) + /* remove original uncompressed file */ + DeleteFile( backlog ); + } + + g_free( backlog ); + g_free( dest_pathname ); + + TRACE_LEAVE( "done\n" ); +} + +/****************************************************************************** + * rotate_logfile + */ +void rotate_logfile( const gchar* pathname, struct destination* destination ) +{ + struct stat fst; + gboolean rotated = FALSE; + time_t current_time; + struct tm *tm; + + TRACE_ENTER( "pathname=%s\n", pathname ); + + if( 0 == destination->backlogs + || (RP_UNDEFINED == destination->rotate && 0 == destination->size) ) + { + TRACE_LEAVE( "no conditions for rotation\n" ); + return; + } + + if( stat( pathname, &fst ) ) + { + /* most possible that file does not exist */ + TRACE_2( "stat(%s) error %s\n", pathname, strerror( errno ) ); + goto done; + } + + if( destination->size ) + { + if( fst.st_size > destination->size ) + { + do_rotate( pathname, destination ); + rotated = TRUE; + goto done; + } + TRACE_2( "checked size: file=%d, max=%d\n", fst.st_size, destination->size ); + } + + current_time = time(NULL); + tm = gmtime( ¤t_time ); + TRACE_2( "checking time: creation=%d, modification=%d\n", fst.st_ctime, fst.st_mtime ); + switch( destination->rotate ) + { + case RP_DAILY: + if( fst.st_mtime - (fst.st_ctime - fst.st_ctime % (24 * 3600)) > 24 * 3600 ) + break; + goto done; + case RP_WEEKLY: + if( 0 == tm->tm_wday && fst.st_mtime - fst.st_ctime > 24 * 3600 ) + break; + goto done; + case RP_MONTHLY: + if( 1 == tm->tm_mday && fst.st_mtime - fst.st_ctime > 24 * 3600 ) + break; + goto done; + default: + goto done; + } + + if( fst.st_size || destination->ifempty ) + { + do_rotate( pathname, destination ); + rotated = TRUE; + } + else + { + TRACE_2( "do not rotate empty file\n" ); + } + +done: + TRACE_LEAVE( "done; %s\n", rotated? "rotated" : "not rotated" ); +} |