1/* 2 * Copyright 2003-2015, Axel D��rfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include "SyslogDaemon.h" 8 9#include <stdio.h> 10#include <string.h> 11 12#include <Alert.h> 13#include <Catalog.h> 14#include <FindDirectory.h> 15#include <Font.h> 16#include <Path.h> 17#include <TextView.h> 18 19#include <LaunchRoster.h> 20#include <syscalls.h> 21#include <syslog_daemon.h> 22 23#include "listener_output.h" 24#include "syslog_output.h" 25 26 27#undef B_TRANSLATION_CONTEXT 28#define B_TRANSLATION_CONTEXT "SyslogDaemon" 29 30 31static const int32 kQuitDaemon = 'quit'; 32 33 34SyslogDaemon::SyslogDaemon() 35 : 36 BServer(B_SYSTEM_LOGGER_SIGNATURE, false, NULL), 37 fHandlerLock("handler lock") 38{ 39} 40 41 42void 43SyslogDaemon::ReadyToRun() 44{ 45 fPort = BLaunchRoster().GetPort("logger"); 46 fDaemon = spawn_thread(_DaemonThread, "daemon", B_NORMAL_PRIORITY, this); 47 48 if (fPort >= 0 && fDaemon >= 0) { 49 _kern_register_syslog_daemon(fPort); 50 51 init_syslog_output(this); 52 init_listener_output(this); 53 54 resume_thread(fDaemon); 55 } else 56 Quit(); 57} 58 59 60void 61SyslogDaemon::AboutRequested() 62{ 63 BPath path; 64 find_directory(B_SYSTEM_LOG_DIRECTORY, &path); 65 path.Append("syslog"); 66 67 BString name(B_TRANSLATE("Syslog Daemon")); 68 BString message; 69 snprintf(message.LockBuffer(512), 512, 70 B_TRANSLATE("%s\n\nThis daemon collects all system messages and writes them to the " 71 "system-wide log at \"%s\".\n\n"), name.String(), path.Path()); 72 message.UnlockBuffer(); 73 74 BAlert* alert = new BAlert(name.String(), message.String(), 75 B_TRANSLATE("OK")); 76 BTextView* view = alert->TextView(); 77 BFont font; 78 79 view->SetStylable(true); 80 81 view->GetFont(&font); 82 font.SetSize(21); 83 font.SetFace(B_BOLD_FACE); 84 view->SetFontAndColor(0, name.Length(), &font); 85 86 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 87 alert->Go(NULL); 88} 89 90 91bool 92SyslogDaemon::QuitRequested() 93{ 94 write_port(fPort, kQuitDaemon, NULL, 0); 95 wait_for_thread(fDaemon, NULL); 96 97 return true; 98} 99 100 101void 102SyslogDaemon::MessageReceived(BMessage* message) 103{ 104 switch (message->what) { 105 case SYSLOG_ADD_LISTENER: 106 { 107 BMessenger messenger; 108 if (message->FindMessenger("target", &messenger) == B_OK) 109 add_listener(&messenger); 110 break; 111 } 112 case SYSLOG_REMOVE_LISTENER: 113 { 114 BMessenger messenger; 115 if (message->FindMessenger("target", &messenger) == B_OK) 116 remove_listener(&messenger); 117 break; 118 } 119 120 default: 121 BApplication::MessageReceived(message); 122 } 123} 124 125 126void 127SyslogDaemon::AddHandler(handler_func function) 128{ 129 fHandlers.AddItem((void*)function); 130} 131 132 133void 134SyslogDaemon::_Daemon() 135{ 136 char buffer[SYSLOG_MESSAGE_BUFFER_SIZE + 1]; 137 syslog_message& message = *(syslog_message*)buffer; 138 int32 code; 139 140 while (true) { 141 ssize_t bytesRead = read_port(fPort, &code, &message, sizeof(buffer)); 142 if (bytesRead == B_BAD_PORT_ID) { 143 // we've been quit 144 break; 145 } 146 147 if (code == kQuitDaemon) 148 return; 149 150 // if we don't get what we want, ignore it 151 if (bytesRead < (ssize_t)sizeof(syslog_message) 152 || code != SYSLOG_MESSAGE) 153 continue; 154 155 // add terminating null byte 156 message.message[bytesRead - sizeof(syslog_message)] = '\0'; 157 158 if (!message.message[0]) { 159 // ignore empty messages 160 continue; 161 } 162 163 fHandlerLock.Lock(); 164 165 for (int32 i = fHandlers.CountItems(); i-- > 0;) { 166 handler_func handle = (handler_func)fHandlers.ItemAt(i); 167 168 handle(message); 169 } 170 171 fHandlerLock.Unlock(); 172 } 173} 174 175 176int32 177SyslogDaemon::_DaemonThread(void* data) 178{ 179 ((SyslogDaemon*)data)->_Daemon(); 180 return B_OK; 181} 182 183 184// #pragma mark - 185 186 187int 188main(int argc, char** argv) 189{ 190 SyslogDaemon daemon; 191 daemon.Run(); 192 193 return 0; 194} 195