libroot_debug: Merge guarded heap into libroot_debug.
[haiku.git] / src / system / libroot / posix / syslog.cpp
blob71482c6f31b1719bff630ab3af1e359b32eef28e
1 /*
2 * Copyright 2003-2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <syslog.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdarg.h>
14 #include <launch.h>
15 #include <syslog_daemon.h>
16 #include <TLS.h>
17 #include <util/KMessage.h>
20 struct syslog_context {
21 char ident[B_OS_NAME_LENGTH];
22 int16 mask;
23 int16 facility;
24 int32 options;
27 static syslog_context sTeamContext = {
28 "",
29 -1,
30 LOG_USER,
31 LOG_CONS
33 static int32 sThreadContextSlot = -1;
34 static port_id sSystemLoggerPort = -1;
37 static syslog_context *
38 allocate_context()
40 syslog_context *context = (syslog_context *)malloc(sizeof(syslog_context));
41 if (context == NULL)
42 return NULL;
44 // inherit the attributes of the team context
45 memcpy(context, &sTeamContext, sizeof(syslog_context));
46 return context;
50 /*! This function returns the current syslog context structure.
51 If there is none for the current thread, it will create one
52 that inherits the context attributes from the team and put it
53 into TLS.
54 If it could not allocate a thread context, it will return the
55 team context; this function is guaranteed to return a valid
56 syslog context.
58 static syslog_context *
59 get_context()
61 if (sThreadContextSlot == B_NO_MEMORY)
62 return &sTeamContext;
64 if (sThreadContextSlot < 0) {
65 static int32 lock = 0;
66 if (atomic_add(&lock, 1) == 0) {
67 int32 slot = tls_allocate();
69 if (slot < 0) {
70 sThreadContextSlot = B_NO_MEMORY;
71 return &sTeamContext;
74 sThreadContextSlot = slot;
75 } else {
76 while (sThreadContextSlot == -1)
77 snooze(10000);
81 syslog_context *context = (syslog_context *)tls_get(sThreadContextSlot);
82 if (context == NULL) {
83 // try to allocate the context again; it might have
84 // been deleted, or there was not enough memory last
85 // time
86 *tls_address(sThreadContextSlot) = context = allocate_context();
88 if (context != NULL)
89 return context;
91 return &sTeamContext;
95 //! Prints simplified syslog message to stderr.
96 static void
97 message_to_console(syslog_context *context, const char *text, va_list args)
99 if (context->ident[0])
100 fprintf(stderr, "'%s' ", context->ident);
101 if (context->options & LOG_PID)
102 fprintf(stderr, "[%" B_PRId32 "] ", find_thread(NULL));
104 vfprintf(stderr, text, args);
105 fputc('\n', stderr);
109 /*! Retrieves the port of the system logger from the launch_daemon.
111 static port_id
112 get_system_logger_port()
114 if (sSystemLoggerPort >= 0)
115 return sSystemLoggerPort;
117 BPrivate::KMessage data;
118 if (BPrivate::get_launch_data(B_SYSTEM_LOGGER_SIGNATURE, data) == B_OK)
119 sSystemLoggerPort = data.GetInt32("logger_port", -1);
121 return sSystemLoggerPort;
125 /*! Creates the message from the given context and sends it to the syslog
126 daemon, if the priority mask matches.
127 If the message couldn't be delivered, and LOG_CONS was set, it will
128 redirect the message to stderr.
130 static void
131 send_syslog_message(syslog_context *context, int priority, const char *text,
132 va_list args)
134 int options = context->options;
136 // do we have to do anything?
137 if ((context->mask & LOG_MASK(SYSLOG_PRIORITY(priority))) == 0)
138 return;
140 port_id port = get_system_logger_port();
141 if ((options & LOG_PERROR) != 0
142 || ((options & LOG_CONS) != 0 && port < B_OK)) {
143 // if asked for, print out the (simplified) message on stderr
144 message_to_console(context, text, args);
146 if (port < B_OK) {
147 // apparently, there is no syslog daemon running;
148 return;
151 // adopt facility from openlog() if not yet set
152 if (SYSLOG_FACILITY(priority) == 0)
153 priority |= context->facility;
155 char buffer[2048];
156 syslog_message &message = *(syslog_message *)&buffer[0];
158 message.from = find_thread(NULL);
159 message.when = real_time_clock();
160 message.options = options;
161 message.priority = priority;
162 strcpy(message.ident, context->ident);
164 int length = vsnprintf(message.message, sizeof(buffer)
165 - sizeof(syslog_message), text, args);
166 if (message.message + length - buffer < (int32)sizeof(buffer)) {
167 if (length == 0 || message.message[length - 1] != '\n')
168 message.message[length++] = '\n';
169 } else
170 buffer[length - 1] = '\n';
172 status_t status;
173 do {
174 // make sure the message gets send (if there is a valid port)
175 status = write_port(port, SYSLOG_MESSAGE, &message,
176 sizeof(syslog_message) + length);
177 } while (status == B_INTERRUPTED);
179 if (status < B_OK && (options & LOG_CONS) != 0
180 && (options & LOG_PERROR) == 0) {
181 // LOG_CONS redirects all output to the console in case contacting
182 // the syslog daemon failed
183 message_to_console(context, text, args);
188 // #pragma mark - POSIX API
191 void
192 closelog(void)
194 closelog_thread();
198 void
199 openlog(const char *ident, int options, int facility)
201 openlog_thread(ident, options, facility);
206 setlogmask(int priorityMask)
208 return setlogmask_thread(priorityMask);
212 void
213 syslog(int priority, const char *message, ...)
215 va_list args;
217 va_start(args, message);
218 send_syslog_message(get_context(), priority, message, args);
219 va_end(args);
223 // #pragma mark - Be extensions
224 // ToDo: it would probably be better to export these symbols as weak symbols only
227 void
228 closelog_team(void)
230 // nothing to do here...
234 void
235 openlog_team(const char *ident, int options, int facility)
237 if (ident != NULL)
238 strlcpy(sTeamContext.ident, ident, sizeof(sTeamContext.ident));
240 sTeamContext.options = options;
241 sTeamContext.facility = SYSLOG_FACILITY(facility);
246 setlogmask_team(int priorityMask)
248 int oldMask = sTeamContext.mask;
250 if (priorityMask != 0)
251 sTeamContext.mask = priorityMask;
253 return oldMask;
257 void
258 log_team(int priority, const char *message, ...)
260 va_list args;
262 va_start(args, message);
263 send_syslog_message(&sTeamContext, priority, message, args);
264 va_end(args);
268 void
269 closelog_thread(void)
271 if (sThreadContextSlot < 0)
272 return;
274 free(tls_get(sThreadContextSlot));
275 *tls_address(sThreadContextSlot) = NULL;
279 void
280 openlog_thread(const char *ident, int options, int facility)
282 syslog_context *context = get_context();
284 if (ident)
285 strcpy(context->ident, ident);
287 context->options = options;
288 context->facility = SYSLOG_FACILITY(facility);
293 setlogmask_thread(int priorityMask)
295 syslog_context *context = get_context();
296 int oldMask = context->mask;
298 if (priorityMask != 0)
299 context->mask = priorityMask;
301 return oldMask;
305 void
306 log_thread(int priority, const char *message, ...)
308 va_list args;
310 va_start(args, message);
311 send_syslog_message(get_context(), priority, message, args);
312 va_end(args);
316 // #pragma mark - BSD extensions
319 void
320 vsyslog(int priority, const char *message, va_list args)
322 send_syslog_message(get_context(), priority, message, args);