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