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 BApplication(B_SYSTEM_LOGGER_SIGNATURE), 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 is responsible for collecting " 71 "all system messages and write them to the system-wide log " 72 "at \"%s\".\n\n"), name.String(), path.Path()); 73 message.UnlockBuffer(); 74 75 BAlert* alert = new BAlert(name.String(), message.String(), 76 B_TRANSLATE("OK")); 77 BTextView* view = alert->TextView(); 78 BFont font; 79 80 view->SetStylable(true); 81 82 view->GetFont(&font); 83 font.SetSize(21); 84 font.SetFace(B_BOLD_FACE); 85 view->SetFontAndColor(0, name.Length(), &font); 86 87 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 88 alert->Go(NULL); 89 } 90 91 92 bool 93 SyslogDaemon::QuitRequested() 94 { 95 write_port(fPort, kQuitDaemon, NULL, 0); 96 wait_for_thread(fDaemon, NULL); 97 98 return true; 99 } 100 101 102 void 103 SyslogDaemon::MessageReceived(BMessage* message) 104 { 105 switch (message->what) { 106 case SYSLOG_ADD_LISTENER: 107 { 108 BMessenger messenger; 109 if (message->FindMessenger("target", &messenger) == B_OK) 110 add_listener(&messenger); 111 break; 112 } 113 case SYSLOG_REMOVE_LISTENER: 114 { 115 BMessenger messenger; 116 if (message->FindMessenger("target", &messenger) == B_OK) 117 remove_listener(&messenger); 118 break; 119 } 120 121 default: 122 BApplication::MessageReceived(message); 123 } 124 } 125 126 127 void 128 SyslogDaemon::AddHandler(handler_func function) 129 { 130 fHandlers.AddItem((void*)function); 131 } 132 133 134 void 135 SyslogDaemon::_Daemon() 136 { 137 char buffer[SYSLOG_MESSAGE_BUFFER_SIZE + 1]; 138 syslog_message& message = *(syslog_message*)buffer; 139 int32 code; 140 141 while (true) { 142 ssize_t bytesRead = read_port(fPort, &code, &message, sizeof(buffer)); 143 if (bytesRead == B_BAD_PORT_ID) { 144 // we've been quit 145 break; 146 } 147 148 if (code == kQuitDaemon) 149 return; 150 151 // if we don't get what we want, ignore it 152 if (bytesRead < (ssize_t)sizeof(syslog_message) 153 || code != SYSLOG_MESSAGE) 154 continue; 155 156 // add terminating null byte 157 message.message[bytesRead - sizeof(syslog_message)] = '\0'; 158 159 if (!message.message[0]) { 160 // ignore empty messages 161 continue; 162 } 163 164 fHandlerLock.Lock(); 165 166 for (int32 i = fHandlers.CountItems(); i-- > 0;) { 167 handler_func handle = (handler_func)fHandlers.ItemAt(i); 168 169 handle(message); 170 } 171 172 fHandlerLock.Unlock(); 173 } 174 } 175 176 177 int32 178 SyslogDaemon::_DaemonThread(void* data) 179 { 180 ((SyslogDaemon*)data)->_Daemon(); 181 return B_OK; 182 } 183 184 185 // #pragma mark - 186 187 188 int 189 main(int argc, char** argv) 190 { 191 SyslogDaemon daemon; 192 daemon.Run(); 193 194 return 0; 195 } 196