xref: /haiku/src/system/libroot/posix/syslog.cpp (revision 5af32e752606778be5dd7379f319fe43cb3f6b8c)
1 /*
2 ** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 ** Distributed under the terms of the OpenBeOS License.
4 */
5 
6 
7 #include <syslog_daemon.h>
8 #include <TLS.h>
9 
10 #include <syslog.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdarg.h>
15 
16 
17 struct syslog_context {
18 	char	ident[B_OS_NAME_LENGTH];
19 	int16	mask;
20 	int16	facility;
21 	int32	options;
22 };
23 
24 static syslog_context sTeamContext = {
25 	"",
26 	-1,
27 	LOG_USER,
28 	LOG_CONS
29 };
30 static int32 sThreadContextSlot = -1;
31 
32 
33 static syslog_context *
34 allocate_context()
35 {
36 	syslog_context *context = (syslog_context *)malloc(sizeof(syslog_context));
37 	if (context == NULL)
38 		return NULL;
39 
40 	// inherit the attributes of the team context
41 	memcpy(context, &sTeamContext, sizeof(syslog_context));
42 	return context;
43 }
44 
45 
46 /** This function returns the current syslog context structure.
47  *	If there is none for the current thread, it will create one
48  *	that inherits the context attributes from the team and put it
49  *	into TLS.
50  *	If it could not allocate a thread context, it will return the
51  *	team context; this function is guaranteed to return a valid
52  *	syslog context.
53  */
54 
55 static syslog_context *
56 get_context()
57 {
58 	if (sThreadContextSlot == B_NO_MEMORY)
59 		return &sTeamContext;
60 
61 	if (sThreadContextSlot < 0) {
62 		static int32 lock = 0;
63 		if (atomic_add(&lock, 1) == 0) {
64 			int32 slot = tls_allocate();
65 
66 			if (slot < 0) {
67 				sThreadContextSlot = B_NO_MEMORY;
68 				return &sTeamContext;
69 			}
70 
71 			*tls_address(slot) = allocate_context();
72 			sThreadContextSlot = slot;
73 			return (syslog_context *)tls_get(slot);
74 		} else {
75 			while (sThreadContextSlot == -1)
76 				snooze(10000);
77 		}
78 	}
79 
80 	syslog_context *context = (syslog_context *)tls_get(sThreadContextSlot);
81 	if (context == NULL) {
82 		// try to allocate the context again; it might have
83 		// been deleted, or there was not enough memory last
84 		// time
85 		context = allocate_context();
86 	}
87 	if (context != NULL)
88 		return context;
89 
90 	return &sTeamContext;
91 }
92 
93 
94 /** Creates the message from the given context and sends it to the syslog
95  *	daemon, if the priority mask matches.
96  *	If the message couldn't be delivered, and LOG_CONS was set, it will
97  *	redirect the message to stderr.
98  */
99 
100 static void
101 send_syslog_message(syslog_context *context, int priority, const char *text, va_list args)
102 {
103 	int options = context->options;
104 
105 	// do we have to do anything?
106 	if ((context->mask & LOG_MASK(SYSLOG_PRIORITY(priority))) == 0)
107 		return;
108 
109 	port_id port = find_port(SYSLOG_PORT_NAME);
110 
111 	if ((options & LOG_PERROR) != 0
112 		|| ((options & LOG_CONS) != 0 && port < B_OK)) {
113 		// if asked for, print out the (simplified) message on stderr
114 		if (context->ident[0])
115 			fprintf(stderr, "'%s' ", context->ident);
116 		if (context->options & LOG_PID)
117 			fprintf(stderr, "[%ld] ", find_thread(NULL));
118 
119 		vfprintf(stderr, text, args);
120 		fputc('\n', stderr);
121 	}
122 	if (port < B_OK) {
123 		// apparently, there is no syslog daemon running;
124 		return;
125 	}
126 
127 	// adopt facility from openlog() if not yet set
128 	if (SYSLOG_FACILITY(priority) == 0)
129 		priority |= context->facility;
130 
131 	char buffer[2048];
132 	syslog_message &message = *(syslog_message *)&buffer[0];
133 
134 	message.from = find_thread(NULL);
135 	message.when = real_time_clock();
136 	message.options = options;
137 	message.priority = priority;
138 	strcpy(message.ident, context->ident);
139 
140 	int length = vsnprintf(message.message, sizeof(buffer) - sizeof(syslog_message), text, args);
141 
142 	while (write_port(port, SYSLOG_MESSAGE, &message, sizeof(syslog_message) + length) == B_INTERRUPTED);
143 		// make sure the message gets send (if there is a valid port)
144 
145 	// ToDo: if write_port() returns an error, LOG_CONS is not respected
146 }
147 
148 
149 //	#pragma mark -
150 //	public Be API
151 // ToDo: it would probably be better to export these symbols as weak symbols only
152 
153 
154 void
155 closelog_team(void)
156 {
157 	// nothing to do here...
158 }
159 
160 
161 void
162 openlog_team(const char *ident, int options, int facility)
163 {
164 	if (ident != NULL)
165 		strcpy(sTeamContext.ident, ident);
166 
167 	sTeamContext.options = options;
168 	sTeamContext.facility = SYSLOG_FACILITY(facility);
169 }
170 
171 
172 int
173 setlogmask_team(int priorityMask)
174 {
175 	int oldMask = sTeamContext.mask;
176 
177 	if (priorityMask != 0)
178 		sTeamContext.mask = priorityMask;
179 
180 	return oldMask;
181 }
182 
183 
184 void
185 log_team(int priority, const char *message, ...)
186 {
187 	va_list args;
188 
189 	va_start(args, message);
190 	send_syslog_message(&sTeamContext, priority, message, args);
191 	va_end(args);
192 }
193 
194 
195 void
196 closelog_thread(void)
197 {
198 	if (sThreadContextSlot < 0)
199 		return;
200 
201 	free(tls_get(sThreadContextSlot));
202 	*tls_address(sThreadContextSlot) = NULL;
203 }
204 
205 
206 void
207 openlog_thread(const char *ident, int options, int facility)
208 {
209 	syslog_context *context = get_context();
210 
211 	if (ident)
212 		strcpy(context->ident, ident);
213 
214 	context->options = options;
215 	context->facility = SYSLOG_FACILITY(facility);
216 }
217 
218 
219 int
220 setlogmask_thread(int priorityMask)
221 {
222 	syslog_context *context = get_context();
223 	int oldMask = context->mask;
224 
225 	if (priorityMask != 0)
226 		context->mask = priorityMask;
227 
228 	return oldMask;
229 }
230 
231 
232 void
233 log_thread(int priority, const char *message, ...)
234 {
235 	va_list args;
236 
237 	va_start(args, message);
238 	send_syslog_message(get_context(), priority, message, args);
239 	va_end(args);
240 }
241 
242 
243 //	#pragma mark -
244 //	POSIX API - just uses the thread syslog functions
245 
246 
247 void
248 closelog(void)
249 {
250 	closelog_thread();
251 }
252 
253 
254 void
255 openlog(const char *ident, int options, int facility)
256 {
257 	openlog_thread(ident, options, facility);
258 }
259 
260 
261 int
262 setlogmask(int priorityMask)
263 {
264 	return setlogmask_thread(priorityMask);
265 }
266 
267 
268 void
269 syslog(int priority, const char *message, ...)
270 {
271 	va_list args;
272 
273 	va_start(args, message);
274 	send_syslog_message(get_context(), priority, message, args);
275 	va_end(args);
276 }
277 
278 
279