/* * Copyright 2003-2015, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #include "SyslogDaemon.h" #include #include #include #include #include #include #include #include #include #include #include #include "listener_output.h" #include "syslog_output.h" #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "SyslogDaemon" static const int32 kQuitDaemon = 'quit'; SyslogDaemon::SyslogDaemon() : BServer(B_SYSTEM_LOGGER_SIGNATURE, false, NULL), fHandlerLock("handler lock") { } void SyslogDaemon::ReadyToRun() { fPort = BLaunchRoster().GetPort("logger"); fDaemon = spawn_thread(_DaemonThread, "daemon", B_NORMAL_PRIORITY, this); if (fPort >= 0 && fDaemon >= 0) { _kern_register_syslog_daemon(fPort); init_syslog_output(this); init_listener_output(this); resume_thread(fDaemon); } else Quit(); } void SyslogDaemon::AboutRequested() { BPath path; find_directory(B_SYSTEM_LOG_DIRECTORY, &path); path.Append("syslog"); BString name(B_TRANSLATE("Syslog Daemon")); BString message; snprintf(message.LockBuffer(512), 512, B_TRANSLATE("%s\n\nThis daemon collects all system messages and writes them to the " "system-wide log at \"%s\".\n\n"), name.String(), path.Path()); message.UnlockBuffer(); BAlert* alert = new BAlert(name.String(), message.String(), B_TRANSLATE("OK")); BTextView* view = alert->TextView(); BFont font; view->SetStylable(true); view->GetFont(&font); font.SetSize(21); font.SetFace(B_BOLD_FACE); view->SetFontAndColor(0, name.Length(), &font); alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); alert->Go(NULL); } bool SyslogDaemon::QuitRequested() { write_port(fPort, kQuitDaemon, NULL, 0); wait_for_thread(fDaemon, NULL); return true; } void SyslogDaemon::MessageReceived(BMessage* message) { switch (message->what) { case SYSLOG_ADD_LISTENER: { BMessenger messenger; if (message->FindMessenger("target", &messenger) == B_OK) add_listener(&messenger); break; } case SYSLOG_REMOVE_LISTENER: { BMessenger messenger; if (message->FindMessenger("target", &messenger) == B_OK) remove_listener(&messenger); break; } default: BApplication::MessageReceived(message); } } void SyslogDaemon::AddHandler(handler_func function) { fHandlers.AddItem((void*)function); } void SyslogDaemon::_Daemon() { char buffer[SYSLOG_MESSAGE_BUFFER_SIZE + 1]; syslog_message& message = *(syslog_message*)buffer; int32 code; while (true) { ssize_t bytesRead = read_port(fPort, &code, &message, sizeof(buffer)); if (bytesRead == B_BAD_PORT_ID) { // we've been quit break; } if (code == kQuitDaemon) return; // if we don't get what we want, ignore it if (bytesRead < (ssize_t)sizeof(syslog_message) || code != SYSLOG_MESSAGE) continue; // add terminating null byte message.message[bytesRead - sizeof(syslog_message)] = '\0'; if (!message.message[0]) { // ignore empty messages continue; } fHandlerLock.Lock(); for (int32 i = fHandlers.CountItems(); i-- > 0;) { handler_func handle = (handler_func)fHandlers.ItemAt(i); handle(message); } fHandlerLock.Unlock(); } } int32 SyslogDaemon::_DaemonThread(void* data) { ((SyslogDaemon*)data)->_Daemon(); return B_OK; } // #pragma mark - int main(int argc, char** argv) { SyslogDaemon daemon; daemon.Run(); return 0; }