/* * log.c - logging functionality * * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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, see . * * Author(s): Erik Troan * Matt Wilson * Michael Fulbright * Jeremy Katz */ #include #include #include #include #include #include #include #include #include "log.h" static FILE * main_log_tty = NULL; static FILE * main_log_file = NULL; static FILE * program_log_file = NULL; static loglevel_t minLevel = INFO; static const char * main_tag = "anaconda"; static const char * program_tag = "program"; static const int syslog_facility = LOG_LOCAL1; /* maps our loglevel to syslog loglevel */ static int mapLogLevel(loglevel_t level) { switch (level) { case DEBUGLVL: return LOG_DEBUG; case INFO: return LOG_INFO; case WARNING: return LOG_WARNING; case CRITICAL: return LOG_CRIT; case ERROR: default: /* if someone called us with an invalid level value, log it as an error too. */ return LOG_ERR; } } const char *log_level_to_str[] = { [DEBUGLVL] = "DEBUG", [INFO] = "INFO", [WARNING] = "WARN", [ERROR] = "ERR", [CRITICAL] = "CRIT" }; static void printLogHeader(loglevel_t level, const char *tag, FILE *outfile) { struct timeval current_time; struct tm *t; int msecs; const char *level_name; gettimeofday(¤t_time, NULL); t = gmtime(¤t_time.tv_sec); msecs = current_time.tv_usec / 1000; level_name = log_level_to_str[level]; fprintf(outfile, "%02d:%02d:%02d,%03d %s %s: ", t->tm_hour, t->tm_min, t->tm_sec, msecs, level_name, tag); } static void printLogMessage(loglevel_t level, const char *tag, FILE *outfile, const char *s, va_list ap) { printLogHeader(level, tag, outfile); va_list apc; va_copy(apc, ap); vfprintf(outfile, s, apc); va_end(apc); fprintf(outfile, "\n"); fflush(outfile); } static void retagSyslog(const char* new_tag) { closelog(); openlog(new_tag, 0, syslog_facility); } void logMessageV(enum logger_t logger, loglevel_t level, const char * s, va_list ap) { FILE *log_tty = main_log_tty; FILE *log_file = main_log_file; const char *tag = main_tag; if (logger == PROGRAM_LOG) { /* tty output is done directly for programs */ log_tty = NULL; log_file = program_log_file; tag = program_tag; /* close and reopen syslog so we get the tagging right */ retagSyslog(tag); } va_list apc; /* Log everything into syslog */ va_copy(apc, ap); vsyslog(mapLogLevel(level), s, apc); va_end(apc); /* Only log to the screen things that are above the minimum level. */ if (main_log_tty && level >= minLevel && log_tty) { printLogMessage(level, tag, log_tty, s, ap); } /* But log everything to the file. */ if (main_log_file) { printLogMessage(level, tag, log_file, s, ap); } /* change the syslog tag back to the default again */ if (logger == PROGRAM_LOG) retagSyslog(main_tag); } void logMessage(loglevel_t level, const char * s, ...) { va_list args; va_start(args, s); logMessageV(MAIN_LOG, level, s, args); va_end(args); } void logProgramMessage(loglevel_t level, const char * s, ...) { va_list args; va_start(args, s); logMessageV(PROGRAM_LOG, level, s, args); va_end(args); } int tty_logfd = -1; int file_logfd = -1; void openLog() { /* init syslog logging (so log messages can also be forwarded to a remote syslog daemon */ openlog(main_tag, 0, syslog_facility); int flags; main_log_tty = fopen("/dev/tty3", "a"); main_log_file = fopen("/tmp/anaconda.log", "a"); program_log_file = fopen("/tmp/program.log", "a"); if (main_log_tty) { tty_logfd = fileno(main_log_tty); flags = fcntl(tty_logfd, F_GETFD, 0) | FD_CLOEXEC; fcntl(tty_logfd, F_SETFD, flags); } if (main_log_file) { file_logfd = fileno(main_log_file); flags = fcntl(file_logfd, F_GETFD, 0) | FD_CLOEXEC; fcntl(file_logfd, F_SETFD, flags); } if (program_log_file) { int fd; fd = fileno(program_log_file); flags = fcntl(fd, F_GETFD, 0) | FD_CLOEXEC; fcntl(file_logfd, F_SETFD, flags); } } void closeLog(void) { if (main_log_tty) fclose(main_log_tty); if (main_log_file) fclose(main_log_file); if (program_log_file) fclose(program_log_file); main_log_tty = main_log_file = program_log_file = NULL; /* close syslog logger */ closelog(); } /* set the level. higher means you see more verbosity */ void setLogLevel(loglevel_t level) { minLevel = level; } loglevel_t getLogLevel(void) { return minLevel; } /* returns non-null if logging has been initialized */ int loggingReady(void) { return main_log_tty != NULL; } /* vim:set shiftwidth=4 softtabstop=4: */