2 * Copyright 2003-2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
15 #include <syslog_daemon.h>
17 #include <util/KMessage.h>
20 struct syslog_context
{
21 char ident
[B_OS_NAME_LENGTH
];
27 static syslog_context sTeamContext
= {
33 static int32 sThreadContextSlot
= -1;
34 static port_id sSystemLoggerPort
= -1;
37 static syslog_context
*
40 syslog_context
*context
= (syslog_context
*)malloc(sizeof(syslog_context
));
44 // inherit the attributes of the team context
45 memcpy(context
, &sTeamContext
, sizeof(syslog_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
54 If it could not allocate a thread context, it will return the
55 team context; this function is guaranteed to return a valid
58 static syslog_context
*
61 if (sThreadContextSlot
== B_NO_MEMORY
)
64 if (sThreadContextSlot
< 0) {
65 static int32 lock
= 0;
66 if (atomic_add(&lock
, 1) == 0) {
67 int32 slot
= tls_allocate();
70 sThreadContextSlot
= B_NO_MEMORY
;
74 sThreadContextSlot
= slot
;
76 while (sThreadContextSlot
== -1)
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
86 *tls_address(sThreadContextSlot
) = context
= allocate_context();
95 //! Prints simplified syslog message to stderr.
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
);
109 /*! Retrieves the port of the system logger from the launch_daemon.
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.
131 send_syslog_message(syslog_context
*context
, int priority
, const char *text
,
134 int options
= context
->options
;
136 // do we have to do anything?
137 if ((context
->mask
& LOG_MASK(SYSLOG_PRIORITY(priority
))) == 0)
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
);
147 // apparently, there is no syslog daemon running;
151 // adopt facility from openlog() if not yet set
152 if (SYSLOG_FACILITY(priority
) == 0)
153 priority
|= context
->facility
;
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';
170 buffer
[length
- 1] = '\n';
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
199 openlog(const char *ident
, int options
, int facility
)
201 openlog_thread(ident
, options
, facility
);
206 setlogmask(int priorityMask
)
208 return setlogmask_thread(priorityMask
);
213 syslog(int priority
, const char *message
, ...)
217 va_start(args
, message
);
218 send_syslog_message(get_context(), priority
, message
, args
);
223 // #pragma mark - Be extensions
224 // ToDo: it would probably be better to export these symbols as weak symbols only
230 // nothing to do here...
235 openlog_team(const char *ident
, int options
, int facility
)
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
;
258 log_team(int priority
, const char *message
, ...)
262 va_start(args
, message
);
263 send_syslog_message(&sTeamContext
, priority
, message
, args
);
269 closelog_thread(void)
271 if (sThreadContextSlot
< 0)
274 free(tls_get(sThreadContextSlot
));
275 *tls_address(sThreadContextSlot
) = NULL
;
280 openlog_thread(const char *ident
, int options
, int facility
)
282 syslog_context
*context
= get_context();
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
;
306 log_thread(int priority
, const char *message
, ...)
310 va_start(args
, message
);
311 send_syslog_message(get_context(), priority
, message
, args
);
316 // #pragma mark - BSD extensions
320 vsyslog(int priority
, const char *message
, va_list args
)
322 send_syslog_message(get_context(), priority
, message
, args
);