/* * Copyright (C) 2002 - 2005 Tomasz Kojm * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ #ifdef _MSC_VER #include #include #endif #if HAVE_CONFIG_H #include "clamav-config.h" #endif #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #ifndef C_WINDOWS #include #include #endif #if HAVE_SYS_TYPES_H #include #endif #if defined(USE_SYSLOG) && !defined(C_AIX) #include #endif #include "output.h" #ifdef CL_NOTHREADS #undef CL_THREAD_SAFE #endif #ifdef CL_THREAD_SAFE #include pthread_mutex_t logg_mutex = PTHREAD_MUTEX_INITIALIZER; #endif #ifdef C_LINUX #include #include #define gettext_noop(s) s #define _(s) gettext(s) #define N_(s) gettext_noop(s) #else #define _(s) s #define N_(s) s #endif FILE *logg_fd = NULL; short int logg_verbose = 0, logg_lock = 1, logg_time = 0, logg_foreground = 1; int logg_size = 0; const char *logg_file = NULL; #if defined(USE_SYSLOG) && !defined(C_AIX) short logg_syslog; #endif short int mprintf_disabled = 0, mprintf_verbose = 0, mprintf_quiet = 0, mprintf_stdout = 0; int mdprintf(int desc, const char *str, ...) { va_list args; char buff[512]; int bytes; va_start(args, str); bytes = vsnprintf(buff, sizeof(buff), str, args); va_end(args); if(bytes == -1) return bytes; if(bytes >= (int) sizeof(buff)) bytes = sizeof(buff) - 1; return send(desc, buff, bytes, 0); } void logg_close(void) { #ifdef CL_THREAD_SAFE pthread_mutex_lock(&logg_mutex); #endif if (logg_fd) { fclose(logg_fd); logg_fd = NULL; } #ifdef CL_THREAD_SAFE pthread_mutex_unlock(&logg_mutex); #endif #if defined(USE_SYSLOG) && !defined(C_AIX) if(logg_syslog) { closelog(); } #endif } int logg(const char *str, ...) { va_list args, argscpy, argsout; #ifdef F_WRLCK struct flock fl; #endif char *pt, *timestr, vbuff[1025]; time_t currtime; struct stat sb; mode_t old_umask; va_start(args, str); /* va_copy is less portable so we just use va_start once more */ va_start(argscpy, str); va_start(argsout, str); #ifdef CL_THREAD_SAFE pthread_mutex_lock(&logg_mutex); #endif if(logg_file) { if(!logg_fd) { old_umask = umask(0037); if((logg_fd = fopen(logg_file, "at")) == NULL) { umask(old_umask); #ifdef CL_THREAD_SAFE pthread_mutex_unlock(&logg_mutex); #endif printf("ERROR: Can't open %s in append mode (check permissions!).\n", logg_file); return -1; } else umask(old_umask); #ifdef F_WRLCK if(logg_lock) { memset(&fl, 0, sizeof(fl)); fl.l_type = F_WRLCK; if(fcntl(fileno(logg_fd), F_SETLK, &fl) == -1) { #ifdef CL_THREAD_SAFE pthread_mutex_unlock(&logg_mutex); #endif return -1; } } #endif } if(logg_size) { if(stat(logg_file, &sb) != -1) { if(sb.st_size > logg_size) { logg_file = NULL; fprintf(logg_fd, "Log size = %d, maximal = %d\n", (int) sb.st_size, logg_size); fprintf(logg_fd, "LOGGING DISABLED (Maximal log file size exceeded).\n"); fclose(logg_fd); logg_fd = NULL; } } } if(logg_fd) { /* Need to avoid logging time for verbose messages when logverbose is not set or we get a bunch of timestamps in the log without newlines... */ if(logg_time && ((*str != '*') || logg_verbose)) { time(&currtime); pt = ctime(&currtime); timestr = calloc(strlen(pt), 1); strncpy(timestr, pt, strlen(pt) - 1); fprintf(logg_fd, "%s -> ", timestr); free(timestr); } _(str); if(*str == '!') { fprintf(logg_fd, "ERROR: "); vfprintf(logg_fd, str + 1, args); } else if(*str == '^') { fprintf(logg_fd, "WARNING: "); vfprintf(logg_fd, str + 1, args); } else if(*str == '*') { if(logg_verbose) vfprintf(logg_fd, str + 1, args); } else if(*str == '#') { vfprintf(logg_fd, str + 1, args); } else vfprintf(logg_fd, str, args); fflush(logg_fd); } } #if defined(USE_SYSLOG) && !defined(C_AIX) if(logg_syslog) { _(str); vsnprintf(vbuff, 1024, str, argscpy); vbuff[1024] = 0; if(vbuff[0] == '!') { syslog(LOG_ERR, "%s", vbuff + 1); } else if(vbuff[0] == '^') { syslog(LOG_WARNING, "%s", vbuff + 1); } else if(vbuff[0] == '*') { if(logg_verbose) { syslog(LOG_DEBUG, "%s", vbuff + 1); } } else if(vbuff[0] == '#') { syslog(LOG_INFO, "%s", vbuff + 1); } else syslog(LOG_INFO, "%s", vbuff); } #endif if(logg_foreground) { _(str); vsnprintf(vbuff, 1024, str, argsout); vbuff[1024] = 0; if(vbuff[0] != '#') mprintf("%s", vbuff); } #ifdef CL_THREAD_SAFE pthread_mutex_unlock(&logg_mutex); #endif va_end(args); va_end(argscpy); va_end(argsout); return 0; } void mprintf(const char *str, ...) { va_list args; FILE *fd; char buff[512]; if(mprintf_disabled) return; fd = stdout; /* legend: * ! - error * @ - error with logging * ... */ /* * ERROR WARNING STANDARD * normal stderr stderr stdout * * verbose stderr stderr stdout * * quiet stderr no no */ va_start(args, str); vsnprintf(buff, sizeof(buff), str, args); va_end(args); if(buff[0] == '!') { if(!mprintf_stdout) fd = stderr; fprintf(fd, "ERROR: %s", &buff[1]); } else if(buff[0] == '@') { if(!mprintf_stdout) fd = stderr; fprintf(fd, "ERROR: %s", &buff[1]); } else if(!mprintf_quiet) { if(buff[0] == '^') { if(!mprintf_stdout) fd = stderr; fprintf(fd, "WARNING: %s", &buff[1]); } else if(buff[0] == '*') { if(mprintf_verbose) fprintf(fd, "%s", &buff[1]); } else fprintf(fd, "%s", buff); } if(fd == stdout) fflush(stdout); } struct facstruct { const char *name; int code; }; #if defined(USE_SYSLOG) && !defined(C_AIX) static const struct facstruct facilitymap[] = { #ifdef LOG_AUTH { "LOG_AUTH", LOG_AUTH }, #endif #ifdef LOG_AUTHPRIV { "LOG_AUTHPRIV", LOG_AUTHPRIV }, #endif #ifdef LOG_CRON { "LOG_CRON", LOG_CRON }, #endif #ifdef LOG_DAEMON { "LOG_DAEMON", LOG_DAEMON }, #endif #ifdef LOG_FTP { "LOG_FTP", LOG_FTP }, #endif #ifdef LOG_KERN { "LOG_KERN", LOG_KERN }, #endif #ifdef LOG_LPR { "LOG_LPR", LOG_LPR }, #endif #ifdef LOG_MAIL { "LOG_MAIL", LOG_MAIL }, #endif #ifdef LOG_NEWS { "LOG_NEWS", LOG_NEWS }, #endif #ifdef LOG_AUTH { "LOG_AUTH", LOG_AUTH }, #endif #ifdef LOG_SYSLOG { "LOG_SYSLOG", LOG_SYSLOG }, #endif #ifdef LOG_USER { "LOG_USER", LOG_USER }, #endif #ifdef LOG_UUCP { "LOG_UUCP", LOG_UUCP }, #endif #ifdef LOG_LOCAL0 { "LOG_LOCAL0", LOG_LOCAL0 }, #endif #ifdef LOG_LOCAL1 { "LOG_LOCAL1", LOG_LOCAL1 }, #endif #ifdef LOG_LOCAL2 { "LOG_LOCAL2", LOG_LOCAL2 }, #endif #ifdef LOG_LOCAL3 { "LOG_LOCAL3", LOG_LOCAL3 }, #endif #ifdef LOG_LOCAL4 { "LOG_LOCAL4", LOG_LOCAL4 }, #endif #ifdef LOG_LOCAL5 { "LOG_LOCAL5", LOG_LOCAL5 }, #endif #ifdef LOG_LOCAL6 { "LOG_LOCAL6", LOG_LOCAL6 }, #endif #ifdef LOG_LOCAL7 { "LOG_LOCAL7", LOG_LOCAL7 }, #endif { NULL, -1 } }; int logg_facility(const char *name) { int i; for(i = 0; facilitymap[i].name; i++) if(!strcmp(facilitymap[i].name, name)) return facilitymap[i].code; return -1; } #endif