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