xref: /haiku/src/servers/syslog_daemon/SyslogDaemon.cpp (revision 7749d0bb0c358a3279b1b9cc76d8376e900130a5)
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_TRANSLATE_CONTEXT
22 #define B_TRANSLATE_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_COMMON_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->Go(NULL);
77 }
78 
79 
80 bool
81 SyslogDaemon::QuitRequested()
82 {
83 	delete_port(fPort);
84 
85 	int32 returnCode;
86 	wait_for_thread(fDaemon, &returnCode);
87 
88 	return true;
89 }
90 
91 
92 void
93 SyslogDaemon::MessageReceived(BMessage *msg)
94 {
95 	switch (msg->what) {
96 		case SYSLOG_ADD_LISTENER:
97 		{
98 			BMessenger messenger;
99 			if (msg->FindMessenger("target", &messenger) == B_OK)
100 				add_listener(&messenger);
101 			break;
102 		}
103 		case SYSLOG_REMOVE_LISTENER:
104 		{
105 			BMessenger messenger;
106 			if (msg->FindMessenger("target", &messenger) == B_OK)
107 				remove_listener(&messenger);
108 			break;
109 		}
110 
111 		default:
112 			BApplication::MessageReceived(msg);
113 	}
114 }
115 
116 
117 void
118 SyslogDaemon::AddHandler(handler_func function)
119 {
120 	fHandlers.AddItem((void *)function);
121 }
122 
123 
124 void
125 SyslogDaemon::Daemon()
126 {
127 	char buffer[SYSLOG_MESSAGE_BUFFER_SIZE + 1];
128 	syslog_message &message = *(syslog_message *)buffer;
129 	int32 code;
130 
131 	while (true) {
132 		ssize_t bytesRead = read_port(fPort, &code, &message, sizeof(buffer));
133 		if (bytesRead == B_BAD_PORT_ID) {
134 			// we've been quit
135 			break;
136 		}
137 
138 		// if we don't get what we want, ignore it
139 		if (bytesRead < (ssize_t)sizeof(syslog_message) || code != SYSLOG_MESSAGE)
140 			continue;
141 
142 		// add terminating null byte
143 		message.message[bytesRead - sizeof(syslog_message)] = '\0';
144 
145 		if (!message.message[0]) {
146 			// ignore empty messages
147 			continue;
148 		}
149 
150 		fHandlerLock.Lock();
151 
152 		for (int32 i = fHandlers.CountItems(); i-- > 0;) {
153 			handler_func handle = (handler_func)fHandlers.ItemAt(i);
154 
155 			handle(message);
156 		}
157 
158 		fHandlerLock.Unlock();
159 	}
160 }
161 
162 
163 int32
164 SyslogDaemon::daemon_thread(void *data)
165 {
166 	((SyslogDaemon *)data)->Daemon();
167 	return B_OK;
168 }
169 
170 
171 int
172 main(int argc, char **argv)
173 {
174 	SyslogDaemon daemon;
175 	daemon.Run();
176 
177 	return 0;
178 }
179