summaryrefslogblamecommitdiffstats
path: root/src/shared/log.c
blob: 055acb404b3c86fb8bd434944eaca9affb76ef38 (plain) (tree)






















                                                               


                   






                                                           

                                       



                            

                                      



                                                     




                                                         









                                       




                                      


























                                                                     
                           
                              











                                                                                       




                                                                       

                                       
                                          
                                      
         


                                         
         
                       

                                               

                                                
                                                                                                
                                               
                                                                       


                                                                                                
                                                   



                                                 

                                                             
               
                                            

                                 
                                            
                                 
      


         
                                         

                                           
                          

                                           
                          


                                             
                          







                                                         
                           
                   


































                                                    
/*
 * This file is part of the Distributed Network Block Device 3
 *
 * Copyright(c) 2011-2012 Simon Rettberg
 *
 * This file may be licensed under the terms of of the
 * GNU General Public License Version 2 (the ``GPL'').
 *
 * Software distributed under the License is distributed
 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
 * express or implied. See the GPL for the specific language
 * governing rights and limitations.
 *
 * You should have received a copy of the GPL along with this
 * program. If not, go to http://www.gnu.org/licenses/gpl.html
 * or write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include "log.h"
#include <stdarg.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#define LINE_LEN (800)

static pthread_mutex_t logLock = PTHREAD_MUTEX_INITIALIZER;
static _Atomic logmask_t maskFile = 31;
static _Atomic logmask_t maskCon  = 15;

static char *logFile = NULL;
static int logFd = -1;

static bool consoleTimestamps = false;


static int writeLevel(char *buffer, logmask_t level);


bool log_hasMask(const logmask_t mask)
{
	return ( ( maskFile | maskCon ) & mask ) == mask;
}

void log_setFileMask(logmask_t mask)
{
	maskFile = mask;
}

void log_setConsoleMask(logmask_t mask)
{
	maskCon = mask;
}

void log_setConsoleTimestamps(bool on)
{
	consoleTimestamps = on;
}

bool log_openLogFile(const char *path)
{
	pthread_mutex_lock( &logLock );
	if ( logFd >= 0 ) {
		close( logFd );
	}
	if ( path == NULL && logFile == NULL )
		goto unlock;
	if ( path != NULL ) {
		free( logFile );
		logFile = strdup( path );
	}
	logFd = open( logFile, O_WRONLY | O_CREAT | O_APPEND, 0644 );
	if ( logFd < 0 )
		goto unlock;
unlock: ;
	pthread_mutex_unlock( &logLock );
	return logFd >= 0;
}

void logadd(const logmask_t mask, const char *fmt, ...)
{
	if ( ( (maskFile | maskCon) & mask ) == 0 )
		return;
	va_list ap;
	int ret;
	time_t rawtime;
	struct tm timeinfo;
	char buffer[LINE_LEN];
	bool toFile = maskFile & mask;
	bool toStdout = maskCon & mask;
	size_t offset;

	if ( toFile || ( toStdout && consoleTimestamps ) ) {
		time( &rawtime );
		localtime_r( &rawtime, &timeinfo );
		offset = strftime( buffer, LINE_LEN, "[%d.%m. %H:%M:%S] ", &timeinfo );
	} else {
		offset = 0;
	}
	const char *stdoutLine = buffer + offset;
	offset += writeLevel( buffer + offset, mask );
	va_start( ap, fmt );
	ret = vsnprintf( buffer + offset, LINE_LEN - offset, fmt, ap );
	va_end( ap );
	if ( ret < 0 ) return;
	offset += ret;
	if ( offset + 1 >= LINE_LEN ) {
		buffer[LINE_LEN-2] = '\0';
		offset = LINE_LEN - 2;
	}
	if ( buffer[offset-1] != '\n' ) {
		buffer[offset++] = '\n';
		buffer[offset] = '\0';
	}
	if ( toFile ) {
		pthread_mutex_lock( &logLock );
		if ( logFd >= 0 ) {
			size_t done = 0;
			while (done < offset ) {
				const ssize_t wr = write( logFd, buffer + done, offset - done );
				if ( wr < 0 ) {
					if ( errno == EINTR ) continue;
					printf( "Logging to file failed! (errno=%d)\n", errno );
					break;
				}
				done += (size_t)wr;
			}
		}
		pthread_mutex_unlock( &logLock );
	}
	if ( toStdout ) {
		if ( consoleTimestamps ) stdoutLine = buffer;
#ifdef AFL_MODE
		fputs( stdoutLine, stderr );
		fflush( stderr );
#else
		fputs( stdoutLine, stdout );
		fflush( stdout );
#endif
	}
}

ssize_t log_fetch(char *buffer, int size)
{
	if ( logFile == NULL || size <= 1 )
		return -1;
	int fd = open( logFile, O_RDONLY );
	if ( fd < 0 )
		return -1;
	off_t off = lseek( fd, 0, SEEK_END );
	if ( off == (off_t)-1 ) {
		close( fd );
		return -1;
	}
	if ( (off_t)size <= off ) {
		off -= size;
	} else {
		off = 0;
	}
	ssize_t ret = pread( fd, buffer, size - 1, off );
	close( fd );
	buffer[ret] = '\0';
	return ret;
}

static int writeLevel(char *buffer, logmask_t level)
{
	const char *word;
	char *dest = buffer;
	switch ( level ) {
	case LOG_ERROR:
		word = "ERROR";
		break;
	case LOG_WARNING:
		word = "WARNING";
		break;
	case LOG_MINOR:
		word = "Warning";
		break;
	case LOG_INFO:
		word = "Info";
		break;
	case LOG_DEBUG1:
		word = "DEBUG1";
		break;
	case LOG_DEBUG2:
		word = "DEBUG2";
		break;
	default:
		word = "!?!?!?";
		break;
	}
	while ( ( *dest++ = *word++ ) );
	*--dest = ':';
	*++dest = ' ';
	return (int)( dest - buffer ) + 1;
}