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 31 static const int32 kQuitDaemon = 'quit'; 32 33 34 SyslogDaemon::SyslogDaemon() 35 : 36 BServer(B_SYSTEM_LOGGER_SIGNATURE, false, NULL), 37 fHandlerLock("handler lock") 38 { 39 } 40 41 42 void 43 SyslogDaemon::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 60 void 61 SyslogDaemon::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 91 bool 92 SyslogDaemon::QuitRequested() 93 { 94 write_port(fPort, kQuitDaemon, NULL, 0); 95 wait_for_thread(fDaemon, NULL); 96 97 return true; 98 } 99 100 101 void 102 SyslogDaemon::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 126 void 127 SyslogDaemon::AddHandler(handler_func function) 128 { 129 fHandlers.AddItem((void*)function); 130 } 131 132 133 void 134 SyslogDaemon::_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 176 int32 177 SyslogDaemon::_DaemonThread(void* data) 178 { 179 ((SyslogDaemon*)data)->_Daemon(); 180 return B_OK; 181 } 182 183 184 // #pragma mark - 185 186 187 int 188 main(int argc, char** argv) 189 { 190 SyslogDaemon daemon; 191 daemon.Run(); 192 193 return 0; 194 } 195