xref: /haiku/src/servers/syslog_daemon/SyslogDaemon.cpp (revision 106388ddbfdd00f4409c86bd3fe8d581bae532ec)
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