1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066 |
- #include <kopano/platform.h>
- #include <kopano/ECLogger.h>
- #include <kopano/lockhelper.hpp>
- #include <mutex>
- #include <cassert>
- #include <clocale>
- #include <pthread.h>
- #include <cstdarg>
- #include <csignal>
- #include <zlib.h>
- #include <kopano/stringutil.h>
- #include "charset/localeutil.h"
- #include "config.h"
- #include <poll.h>
- #if HAVE_SYSLOG_H
- #include <syslog.h>
- #endif
- #include <grp.h>
- #include <libgen.h>
- #include <pwd.h>
- #include <sys/resource.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/utsname.h>
- #include <kopano/ECConfig.h>
- using namespace std;
- namespace KC {
- static const char *const ll_names[] = {
- " notice",
- "crit ",
- "error ",
- "warning",
- "notice ",
- "info ",
- "debug "
- };
- static ECLogger_File ec_log_fallback_target(EC_LOGLEVEL_WARNING, false, "-", false);
- static ECLogger *ec_log_target = &ec_log_fallback_target;
- ECLogger::ECLogger(int max_ll) {
- max_loglevel = max_ll;
-
- timelocale = createlocale(LC_TIME, "C");
- datalocale = createUTF8Locale();
- prefix = LP_NONE;
- m_ulRef = 1;
- }
- ECLogger::~ECLogger() {
- if (ec_log_target == this)
- ec_log_set(NULL);
- if (timelocale)
- freelocale(timelocale);
- if (datalocale)
- freelocale(datalocale);
- }
- void ECLogger::SetLoglevel(unsigned int max_ll) {
- max_loglevel = max_ll;
- }
- std::string ECLogger::MakeTimestamp() {
- time_t now = time(NULL);
- tm local;
- localtime_r(&now, &local);
- char buffer[_LOG_TSSIZE];
- if (timelocale)
- strftime_l(buffer, sizeof buffer, "%c", &local, timelocale);
- else
- strftime(buffer, sizeof buffer, "%c", &local);
- return buffer;
- }
- bool ECLogger::Log(unsigned int loglevel) {
- unsigned int ext_bits = loglevel & EC_LOGLEVEL_EXTENDED_MASK;
- unsigned int level = loglevel & EC_LOGLEVEL_MASK;
- unsigned int max_loglevel_only = max_loglevel & EC_LOGLEVEL_MASK;
- unsigned int allowed_extended_bits_only = max_loglevel & EC_LOGLEVEL_EXTENDED_MASK;
-
- if (ext_bits) {
-
-
- if (ext_bits & allowed_extended_bits_only)
- return true;
- return false;
- }
-
-
- if (max_loglevel_only == EC_LOGLEVEL_NONE)
- return false;
- if (level == EC_LOGLEVEL_ALWAYS)
- return true;
-
- return level <= max_loglevel_only;
- }
- void ECLogger::SetLogprefix(logprefix lp) {
- prefix = lp;
- }
- unsigned int ECLogger::AddRef(void)
- {
- scoped_lock locker(m_mutex);
- assert(m_ulRef < UINT_MAX);
- return ++m_ulRef;
- }
- unsigned ECLogger::Release() {
- ulock_normal locker(m_mutex);
- unsigned int ulRef = --m_ulRef;
- locker.unlock();
- if (ulRef == 0)
- delete this;
- return ulRef;
- }
- int ECLogger::snprintf(char *str, size_t size, const char *format, ...) {
- va_list va;
- int len = 0;
- va_start(va, format);
- len = _vsnprintf_l(str, size, format, datalocale, va);
- va_end(va);
- return len;
- }
- ECLogger_Null::ECLogger_Null() : ECLogger(EC_LOGLEVEL_NONE) {}
- void ECLogger_Null::Reset() {}
- void ECLogger_Null::Log(unsigned int loglevel, const string &message) {}
- void ECLogger_Null::Log(unsigned int loglevel, const char *format, ...) {}
- void ECLogger_Null::LogVA(unsigned int loglevel, const char *format, va_list& va) {}
- ECLogger_File::ECLogger_File(const unsigned int max_ll, const bool add_timestamp, const char *const filename, const bool compress) : ECLogger(max_ll) {
- logname = filename;
- timestamp = add_timestamp;
- if (logname == "-") {
- init_for_stderr();
- } else {
- if (compress)
- init_for_gzfile();
- else
- init_for_file();
- log = fnOpen(logname.c_str(), szMode);
- if (log == nullptr) {
- init_for_stderr();
- fnPrintf(log, "Unable to open logfile %s: %s. Logging to stderr.\n",
- logname.c_str(), strerror(errno));
- }
- }
- reinit_buffer(0);
-
-
-
- prevcount = 0;
- prevmsg.clear();
- prevloglevel = 0;
- }
- ECLogger_File::~ECLogger_File() {
-
- KC::shared_lock<KC::shared_mutex> lh(handle_lock);
- if (prevcount > 1)
- fnPrintf(log, "%sPrevious message logged %d times\n", DoPrefix().c_str(), prevcount);
- if (log && fnClose)
- fnClose(log);
- }
- void ECLogger_File::init_for_stderr(void)
- {
- log = stderr;
- fnOpen = nullptr;
- fnClose = nullptr;
- fnPrintf = reinterpret_cast<printf_func>(&fprintf);
- fnFileno = reinterpret_cast<fileno_func>(&fileno);
- szMode = nullptr;
- }
- void ECLogger_File::init_for_file(void)
- {
- fnOpen = reinterpret_cast<open_func>(&fopen);
- fnClose = reinterpret_cast<close_func>(&fclose);
- fnPrintf = reinterpret_cast<printf_func>(&fprintf);
- fnFileno = reinterpret_cast<fileno_func>(&fileno);
- szMode = "a";
- }
- void ECLogger_File::init_for_gzfile(void)
- {
- fnOpen = reinterpret_cast<open_func>(&gzopen);
- fnClose = reinterpret_cast<close_func>(&gzclose);
- fnPrintf = reinterpret_cast<printf_func>(&gzprintf);
- fnFileno = nullptr;
- szMode = "wb";
- }
- void ECLogger_File::reinit_buffer(size_t size)
- {
- if (size == 0)
- setvbuf(static_cast<FILE *>(log), NULL, _IOLBF, size);
- else
- setvbuf(static_cast<FILE *>(log), NULL, _IOFBF, size);
-
- buffer_size = size;
- }
- void ECLogger_File::Reset() {
- std::lock_guard<KC::shared_mutex> lh(handle_lock);
- if (log == stderr || fnClose == nullptr || fnOpen == nullptr)
- return;
- if (log)
- fnClose(log);
-
- log = fnOpen(logname.c_str(), szMode);
- if (log == nullptr) {
- init_for_stderr();
- fnPrintf(log, "%s%sECLogger reset issued, but cannot (re-)open %s: %s. Logging to stderr.\n",
- DoPrefix().c_str(), EmitLevel(EC_LOGLEVEL_ERROR).c_str(),
- logname.c_str(), strerror(errno));
- return;
- }
- reinit_buffer(buffer_size);
- }
- int ECLogger_File::GetFileDescriptor() {
- KC::shared_lock<KC::shared_mutex> lh(handle_lock);
- if (log && fnFileno)
- return fnFileno(log);
- return -1;
- }
- std::string ECLogger_File::EmitLevel(const unsigned int loglevel) {
- if (loglevel == EC_LOGLEVEL_ALWAYS)
- return format("[%s] ", ll_names[0]);
- else if (loglevel <= EC_LOGLEVEL_DEBUG)
- return format("[%s] ", ll_names[loglevel]);
- return format("[%7x] ", loglevel);
- }
- std::string ECLogger_File::DoPrefix() {
- std::string out;
- if (timestamp)
- out += MakeTimestamp() + ": ";
- if (prefix == LP_TID) {
- #ifdef HAVE_PTHREAD_GETNAME_NP
- pthread_t th = pthread_self();
- char name[32] = { 0 };
- if (pthread_getname_np(th, name, sizeof name))
- out += format("[0x%lx] ", kc_threadid());
- else
- out += format("[%s|0x%lx] ", name, kc_threadid());
- #else
- out += format("[0x%lx] ", kc_threadid());
- #endif
- }
- else if (prefix == LP_PID) {
- out += format("[%5d] ", getpid());
- }
- return out;
- }
- bool ECLogger_File::IsStdErr() {
- return logname == "-";
- }
- bool ECLogger_File::DupFilter(const unsigned int loglevel, const std::string &message) {
- bool exit_with_true = false;
- KC::shared_lock<KC::shared_mutex> lr_dup(dupfilter_lock);
- if (prevmsg == message) {
- ++prevcount;
- if (prevcount < 100)
- exit_with_true = true;
- }
- lr_dup.unlock();
- if (exit_with_true)
- return true;
- if (prevcount > 1) {
- KC::shared_lock<KC::shared_mutex> lr_handle(handle_lock);
- fnPrintf(log, "%s%sPrevious message logged %d times\n", DoPrefix().c_str(), EmitLevel(prevloglevel).c_str(), prevcount);
- }
- std::lock_guard<KC::shared_mutex> lw_dup(dupfilter_lock);
- prevloglevel = loglevel;
- prevmsg = message;
- prevcount = 0;
- return false;
- }
- void ECLogger_File::Log(unsigned int loglevel, const string &message) {
- if (!ECLogger::Log(loglevel))
- return;
- if (DupFilter(loglevel, message))
- return;
- KC::shared_lock<KC::shared_mutex> lh(handle_lock);
- if (log == nullptr)
- return;
- fnPrintf(log, "%s%s%s\n", DoPrefix().c_str(), EmitLevel(loglevel).c_str(), message.c_str());
-
- if (buffer_size > 0 && (loglevel <= EC_LOGLEVEL_WARNING || loglevel == EC_LOGLEVEL_ALWAYS))
- fflush((FILE *)log);
- }
- void ECLogger_File::Log(unsigned int loglevel, const char *format, ...) {
- va_list va;
- if (ECLogger::Log(loglevel)) {
- va_start(va, format);
- LogVA(loglevel, format, va);
- va_end(va);
- }
- }
- void ECLogger_File::LogVA(unsigned int loglevel, const char *format, va_list& va) {
- char msgbuffer[_LOG_BUFSIZE];
- _vsnprintf_l(msgbuffer, sizeof msgbuffer, format, datalocale, va);
- Log(loglevel, std::string(msgbuffer));
- }
- const int ECLogger_Syslog::levelmap[16] = {
- LOG_DEBUG,
- LOG_CRIT,
- LOG_WARNING,
- LOG_WARNING,
- LOG_NOTICE,
- LOG_INFO,
- LOG_DEBUG,
- 0,0,0,0,0,0,0,0,
- LOG_ALERT,
- };
- ECLogger_Syslog::ECLogger_Syslog(unsigned int max_ll, const char *ident, int facility) : ECLogger(max_ll) {
-
- if (ident == NULL) {
- m_ident = NULL;
- openlog(ident, LOG_PID, facility);
- } else {
- m_ident = strdup(ident);
- openlog(m_ident, LOG_PID, facility);
- }
- }
- ECLogger_Syslog::~ECLogger_Syslog() {
- closelog();
- free(m_ident);
- }
- void ECLogger_Syslog::Reset() {
-
- }
- void ECLogger_Syslog::Log(unsigned int loglevel, const string &message) {
- if (!ECLogger::Log(loglevel))
- return;
- syslog(levelmap[loglevel & EC_LOGLEVEL_MASK], "%s", message.c_str());
- }
- void ECLogger_Syslog::Log(unsigned int loglevel, const char *format, ...) {
- va_list va;
- if (!ECLogger::Log(loglevel))
- return;
- va_start(va, format);
- LogVA(loglevel, format, va);
- va_end(va);
- }
- void ECLogger_Syslog::LogVA(unsigned int loglevel, const char *format, va_list& va) {
- #if HAVE_VSYSLOG
- vsyslog(levelmap[loglevel & EC_LOGLEVEL_MASK], format, va);
- #else
- char msgbuffer[_LOG_BUFSIZE];
- _vsnprintf_l(msgbuffer, sizeof msgbuffer, format, datalocale, va);
- syslog(levelmap[loglevel & EC_LOGLEVEL_MASK], "%s", msgbuffer);
- #endif
- }
- ECLogger_Tee::ECLogger_Tee(): ECLogger(EC_LOGLEVEL_DEBUG) {
- }
- ECLogger_Tee::~ECLogger_Tee(void)
- {
- for (auto log : m_loggers)
- log->Release();
- }
- void ECLogger_Tee::Reset(void)
- {
- for (auto log : m_loggers)
- log->Reset();
- }
- bool ECLogger_Tee::Log(unsigned int loglevel)
- {
- bool bResult = false;
- for (auto log : m_loggers)
- bResult = log->Log(loglevel);
- return bResult;
- }
- void ECLogger_Tee::Log(unsigned int loglevel, const std::string &message)
- {
- for (auto log : m_loggers)
- log->Log(loglevel, message);
- }
- void ECLogger_Tee::Log(unsigned int loglevel, const char *format, ...) {
- va_list va;
- va_start(va, format);
- LogVA(loglevel, format, va);
- va_end(va);
- }
- void ECLogger_Tee::LogVA(unsigned int loglevel, const char *format, va_list &va)
- {
- char msgbuffer[_LOG_BUFSIZE];
- _vsnprintf_l(msgbuffer, sizeof msgbuffer, format, datalocale, va);
- for (auto log : m_loggers)
- log->Log(loglevel, std::string(msgbuffer));
- }
- void ECLogger_Tee::AddLogger(ECLogger *lpLogger) {
- if (lpLogger == nullptr)
- return;
- lpLogger->AddRef();
- m_loggers.push_back(lpLogger);
- }
- ECLogger_Pipe::ECLogger_Pipe(int fd, pid_t childpid, int loglevel) :
- ECLogger(loglevel), m_fd(fd), m_childpid(childpid)
- {
- }
- ECLogger_Pipe::~ECLogger_Pipe() {
- close(m_fd);
- if (m_childpid)
- waitpid(m_childpid, NULL, 0);
- }
- void ECLogger_Pipe::Reset() {
-
- kill(m_childpid, SIGHUP);
- }
- void ECLogger_Pipe::Log(unsigned int loglevel, const std::string &message) {
- int len = 0;
- int off = 0;
- char msgbuffer[_LOG_BUFSIZE];
- msgbuffer[0] = loglevel;
- off += 1;
- if (prefix == LP_TID)
- len = snprintf(msgbuffer + off, sizeof(msgbuffer) - off,
- "[0x%lx] ", kc_threadid());
- else if (prefix == LP_PID)
- len = snprintf(msgbuffer + off, sizeof msgbuffer - off, "[%5d] ", getpid());
- if (len < 0)
- len = 0;
- else
- off += len;
- len = min((int)message.length(), (int)sizeof msgbuffer - (off + 1));
- if (len < 0)
- len = 0;
- else {
- memcpy(msgbuffer+off, message.c_str(), len);
- off += len;
- }
- msgbuffer[off] = '\0';
- ++off;
-
- write(m_fd, msgbuffer, off);
- }
- void ECLogger_Pipe::Log(unsigned int loglevel, const char *format, ...) {
- va_list va;
- va_start(va, format);
- LogVA(loglevel, format, va);
- va_end(va);
- }
- void ECLogger_Pipe::LogVA(unsigned int loglevel, const char *format, va_list& va) {
- int len = 0;
- int off = 0;
- char msgbuffer[_LOG_BUFSIZE];
- msgbuffer[0] = loglevel;
- off += 1;
- if (prefix == LP_TID)
- len = snprintf(msgbuffer + off, sizeof(msgbuffer) - off, "[0x%lx] ", kc_threadid());
- else if (prefix == LP_PID)
- len = snprintf(msgbuffer + off, sizeof msgbuffer - off, "[%5d] ", getpid());
- if (len < 0)
- len = 0;
- else
- off += len;
-
- len = _vsnprintf_l(msgbuffer + off, sizeof msgbuffer - off - 1, format, datalocale, va);
-
- if (len < 0)
- len = 0;
- len = min(len, (int)sizeof msgbuffer - off - 2);
- off += len;
- msgbuffer[off] = '\0';
- ++off;
-
- write(m_fd, msgbuffer, off);
- }
- void ECLogger_Pipe::Disown()
- {
- m_childpid = 0;
- }
- namespace PrivatePipe {
- ECLogger_File *m_lpFileLogger;
- ECConfig *m_lpConfig;
- pthread_t signal_thread;
- sigset_t signal_mask;
- static void sighup(int)
- {
- if (m_lpConfig) {
- const char *ll;
- m_lpConfig->ReloadSettings();
- ll = m_lpConfig->GetSetting("log_level");
- if (ll)
- m_lpFileLogger->SetLoglevel(atoi(ll));
- }
- m_lpFileLogger->Reset();
- m_lpFileLogger->Log(EC_LOGLEVEL_INFO, "[%5d] Log process received sighup", getpid());
- }
- static int PipePassLoop(int readfd, ECLogger_File *lpFileLogger,
- ECConfig *lpConfig)
- {
- ssize_t ret;
- char buffer[_LOG_BUFSIZE] = {0};
- std::string complete;
- const char *p = NULL;
- int s;
- int l;
- m_lpConfig = lpConfig;
- m_lpFileLogger = lpFileLogger;
- m_lpFileLogger->AddRef();
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_handler = sighup;
- act.sa_flags = SA_RESTART | SA_ONSTACK;
- sigemptyset(&act.sa_mask);
- sigaction(SIGHUP, &act, nullptr);
- signal(SIGPIPE, SIG_IGN);
-
- signal(SIGTERM, SIG_IGN);
- signal(SIGINT, SIG_IGN);
-
- signal(SIGCHLD, SIG_IGN);
- signal(SIGUSR1, SIG_IGN);
- signal(SIGUSR2, SIG_IGN);
-
- m_lpFileLogger->SetLogprefix(LP_NONE);
- struct pollfd fds = {readfd, POLLIN, 0};
- while(true) {
-
- fds.revents = 0;
- ret = poll(&fds, 1, -1);
- if (ret == -1) {
- if (errno == EINTR)
- continue;
- break;
- }
- if (ret == 0)
- continue;
- complete.clear();
- do {
-
- ret = read(readfd, buffer, sizeof buffer);
- if (ret <= 0)
- break;
- complete.append(buffer,ret);
- } while (ret == sizeof buffer);
- if (ret <= 0)
- break;
- p = complete.data();
- ret = complete.size();
- while (ret && p) {
-
- l = *p++;
- --ret;
- s = strlen(p);
- if (s == 0) {
- p = NULL;
- continue;
- }
- lpFileLogger->Log(l, string(p, s));
- ++s;
- p += s;
- ret -= s;
- }
- }
-
- kill(getpid(), SIGPIPE);
- m_lpFileLogger->Log(EC_LOGLEVEL_INFO, "[%5d] Log process is done", getpid());
- m_lpFileLogger->Release();
- return ret;
- }
- }
- ECLogger* StartLoggerProcess(ECConfig* lpConfig, ECLogger* lpLogger) {
- auto lpFileLogger = dynamic_cast<ECLogger_File *>(lpLogger);
- ECLogger_Pipe *lpPipeLogger = NULL;
- int filefd;
- int pipefds[2];
- pid_t child = 0;
- if (lpFileLogger == NULL)
- return lpLogger;
- filefd = lpFileLogger->GetFileDescriptor();
- child = pipe(pipefds);
- if (child < 0)
- return NULL;
- child = fork();
- if (child < 0)
- return NULL;
- if (child == 0) {
-
- int t = getdtablesize();
- for (int i = 3; i < t; ++i) {
- if (i == pipefds[0] || i == filefd) continue;
- close(i);
- }
- PrivatePipe::PipePassLoop(pipefds[0], lpFileLogger, lpConfig);
- close(pipefds[0]);
- delete lpFileLogger;
- delete lpConfig;
- _exit(0);
- }
-
-
- unsigned int refs = lpLogger->Release();
- if (refs > 0)
-
- lpLogger->Log(EC_LOGLEVEL_WARNING, "StartLoggerProcess called with large refcount %u", refs + 1);
- close(pipefds[0]);
- lpPipeLogger = new ECLogger_Pipe(pipefds[1], child, atoi(lpConfig->GetSetting("log_level")));
- lpPipeLogger->SetLogprefix(LP_PID);
- lpPipeLogger->Log(EC_LOGLEVEL_INFO, "Logger process started on pid %d", child);
- return lpPipeLogger;
- }
- ECLogger* CreateLogger(ECConfig *lpConfig, const char *argv0,
- const char *lpszServiceName, bool bAudit)
- {
- ECLogger *lpLogger = NULL;
- string prepend;
- int loglevel = 0;
- int syslog_facility = LOG_MAIL;
- if (bAudit) {
- #if 1
- if (!parseBool(lpConfig->GetSetting("audit_log_enabled")))
- return NULL;
- prepend = "audit_";
- syslog_facility = LOG_AUTHPRIV;
- #else
- return NULL;
- #endif
- }
- loglevel = strtol(lpConfig->GetSetting((prepend+"log_level").c_str()), NULL, 0);
- if (strcasecmp(lpConfig->GetSetting((prepend+"log_method").c_str()), "syslog") == 0) {
- char *argzero = strdup(argv0);
- lpLogger = new ECLogger_Syslog(loglevel, basename(argzero), syslog_facility);
- free(argzero);
- } else if (strcasecmp(lpConfig->GetSetting((prepend+"log_method").c_str()), "eventlog") == 0) {
- fprintf(stderr, "eventlog logging is only available on windows.\n");
- } else if (strcasecmp(lpConfig->GetSetting((prepend+"log_method").c_str()), "file") == 0) {
- int ret = 0;
- const struct passwd *pw = NULL;
- const struct group *gr = NULL;
- if (strcmp(lpConfig->GetSetting((prepend+"log_file").c_str()), "-")) {
- if (lpConfig->GetSetting("run_as_user") && strcmp(lpConfig->GetSetting("run_as_user"),""))
- pw = getpwnam(lpConfig->GetSetting("run_as_user"));
- else
- pw = getpwuid(getuid());
- if (lpConfig->GetSetting("run_as_group") && strcmp(lpConfig->GetSetting("run_as_group"),""))
- gr = getgrnam(lpConfig->GetSetting("run_as_group"));
- else
- gr = getgrgid(getgid());
-
- if (pw || gr) {
- ret = fork();
- if (ret == 0) {
-
- setgroups(0, NULL);
- if (gr)
- setgid(gr->gr_gid);
- if (pw)
- setuid(pw->pw_uid);
- FILE *test = fopen(lpConfig->GetSetting((prepend+"log_file").c_str()), "a");
- if (!test) {
- fprintf(stderr, "Unable to open logfile '%s' as user '%s'\n",
- lpConfig->GetSetting((prepend+"log_file").c_str()), pw ? pw->pw_name : "???");
- _exit(1);
- }
- else {
- fclose(test);
- }
-
- delete lpConfig;
- _exit(0);
- }
- if (ret > 0) {
- wait(&ret);
- ret = WEXITSTATUS(ret);
- }
- }
- }
- if (ret == 0) {
- bool logtimestamp = parseBool(lpConfig->GetSetting((prepend + "log_timestamp").c_str()));
- size_t log_buffer_size = 0;
- const char *log_buffer_size_str = lpConfig->GetSetting("log_buffer_size");
- if (log_buffer_size_str)
- log_buffer_size = strtoul(log_buffer_size_str, NULL, 0);
- auto log = new ECLogger_File(loglevel, logtimestamp, lpConfig->GetSetting((prepend + "log_file").c_str()), false);
- log->reinit_buffer(log_buffer_size);
- lpLogger = log;
-
- if (pw || gr) {
- uid_t uid = -1;
- gid_t gid = -1;
- if (pw)
- uid = pw->pw_uid;
- if (gr)
- gid = gr->gr_gid;
- chown(lpConfig->GetSetting((prepend+"log_file").c_str()), uid, gid);
- }
- } else {
- fprintf(stderr, "Not enough permissions to append logfile '%s'. Reverting to stderr.\n", lpConfig->GetSetting((prepend+"log_file").c_str()));
- bool logtimestamp = parseBool(lpConfig->GetSetting((prepend + "log_timestamp").c_str()));
- lpLogger = new ECLogger_File(loglevel, logtimestamp, "-", false);
- }
- }
- if (!lpLogger) {
- fprintf(stderr, "Incorrect logging method selected. Reverting to stderr.\n");
- bool logtimestamp = parseBool(lpConfig->GetSetting((prepend + "log_timestamp").c_str()));
- lpLogger = new ECLogger_File(loglevel, logtimestamp, "-", false);
- }
- return lpLogger;
- }
- int DeleteLogger(ECLogger *lpLogger) {
- if (lpLogger)
- lpLogger->Release();
- return 0;
- }
- void LogConfigErrors(ECConfig *lpConfig)
- {
- if (lpConfig == NULL)
- return;
- for (const auto &i : *lpConfig->GetWarnings())
- ec_log_warn("Config warning: " + i);
- for (const auto &i : *lpConfig->GetErrors())
- ec_log_crit("Config error: " + i);
- }
- void generic_sigsegv_handler(ECLogger *lpLogger, const char *app_name,
- const char *version_string, int signr, const siginfo_t *si, const void *uc)
- {
- ECLogger_Syslog localLogger(EC_LOGLEVEL_DEBUG, app_name, LOG_MAIL);
- if (lpLogger == NULL)
- lpLogger = &localLogger;
- lpLogger->Log(EC_LOGLEVEL_FATAL, "----------------------------------------------------------------------");
- lpLogger->Log(EC_LOGLEVEL_FATAL, "Fatal error detected. Please report all following information.");
- lpLogger->Log(EC_LOGLEVEL_FATAL, "Application %s version: %s", app_name, version_string);
- struct utsname buf;
- if (uname(&buf) == -1)
- lpLogger->Log(EC_LOGLEVEL_FATAL, "uname() failed: %s", strerror(errno));
- else
- lpLogger->Log(EC_LOGLEVEL_FATAL, "OS: %s, release: %s, version: %s, hardware: %s", buf.sysname, buf.release, buf.version, buf.machine);
- #ifdef HAVE_PTHREAD_GETNAME_NP
- char name[32] = { 0 };
- int rc = pthread_getname_np(pthread_self(), name, sizeof name);
- if (rc)
- lpLogger->Log(EC_LOGLEVEL_FATAL, "pthread_getname_np failed: %s", strerror(rc));
- else
- lpLogger->Log(EC_LOGLEVEL_FATAL, "Thread name: %s", name);
- #endif
- struct rusage rusage;
- if (getrusage(RUSAGE_SELF, &rusage) == -1)
- lpLogger->Log(EC_LOGLEVEL_FATAL, "getrusage() failed: %s", strerror(errno));
- else
- lpLogger->Log(EC_LOGLEVEL_FATAL, "Peak RSS: %ld", rusage.ru_maxrss);
-
- switch (signr) {
- case SIGSEGV:
- lpLogger->Log(EC_LOGLEVEL_FATAL, "Pid %d caught SIGSEGV (%d), traceback:", getpid(), signr);
- break;
- case SIGBUS:
- lpLogger->Log(EC_LOGLEVEL_FATAL, "Pid %d caught SIGBUS (%d), possible invalid mapped memory access, traceback:", getpid(), signr);
- break;
- case SIGABRT:
- lpLogger->Log(EC_LOGLEVEL_FATAL, "Pid %d caught SIGABRT (%d), out of memory or unhandled exception, traceback:", getpid(), signr);
- break;
- }
- ec_log_bt(EC_LOGLEVEL_CRIT, "Backtrace:");
- ec_log_crit("Signal errno: %s, signal code: %d", strerror(si->si_errno), si->si_code);
- ec_log_crit("Sender pid: %d, sender uid: %d, si_status: %d", si->si_pid, si->si_uid, si->si_status);
- ec_log_crit("User time: %ld, system time: %ld, signal value: %d", si->si_utime, si->si_stime, si->si_value.sival_int);
- ec_log_crit("Faulting address: %p, affected fd: %d", si->si_addr, si->si_fd);
- lpLogger->Log(EC_LOGLEVEL_FATAL, "When reporting this traceback, please include Linux distribution name (and version), system architecture and Kopano version.");
-
- if (signal(signr, SIG_DFL) < 0)
- ec_log_warn("Cannot reset signal handler: %s", strerror(errno));
- else if (kill(getpid(), signr) <= 0)
- ec_log_warn("Killing self with signal had no effect. Error code: %s", strerror(errno));
- ec_log_warn("Regular exit without coredump.");
- _exit(1);
- }
- void ec_log_set(ECLogger *logger)
- {
- if (logger == NULL)
- logger = &ec_log_fallback_target;
- ec_log_target = logger;
- }
- ECLogger *ec_log_get(void)
- {
- return ec_log_target;
- }
- bool ec_log_has_target(void)
- {
- return ec_log_target != &ec_log_fallback_target;
- }
- void ec_log(unsigned int level, const char *fmt, ...)
- {
- if (!ec_log_target->Log(level))
- return;
- va_list argp;
- va_start(argp, fmt);
- ec_log_target->LogVA(level, fmt, argp);
- va_end(argp);
- }
- void ec_log(unsigned int level, const std::string &msg)
- {
- ec_log_target->Log(level, msg);
- }
- void ec_log_bt(unsigned int level, const char *fmt, ...)
- {
- if (!ec_log_target->Log(level))
- return;
- va_list argp;
- va_start(argp, fmt);
- ec_log_target->LogVA(level, fmt, argp);
- va_end(argp);
- static bool notified = false;
- std::vector<std::string> bt = get_backtrace();
- if (!bt.empty()) {
- for (size_t i = 0; i < bt.size(); ++i)
- ec_log(level, "#%zu. %s", i, bt[i].c_str());
- } else if (!notified) {
- ec_log_info("Backtrace not available");
- notified = true;
- }
- }
- }
|