1 /* 2 * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT 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 static syslog_context * 55 get_context() 56 { 57 if (sThreadContextSlot == B_NO_MEMORY) 58 return &sTeamContext; 59 60 if (sThreadContextSlot < 0) { 61 static int32 lock = 0; 62 if (atomic_add(&lock, 1) == 0) { 63 int32 slot = tls_allocate(); 64 65 if (slot < 0) { 66 sThreadContextSlot = B_NO_MEMORY; 67 return &sTeamContext; 68 } 69 70 *tls_address(slot) = allocate_context(); 71 sThreadContextSlot = slot; 72 return (syslog_context *)tls_get(slot); 73 } else { 74 while (sThreadContextSlot == -1) 75 snooze(10000); 76 } 77 } 78 79 syslog_context *context = (syslog_context *)tls_get(sThreadContextSlot); 80 if (context == NULL) { 81 // try to allocate the context again; it might have 82 // been deleted, or there was not enough memory last 83 // time 84 context = allocate_context(); 85 } 86 if (context != NULL) 87 return context; 88 89 return &sTeamContext; 90 } 91 92 93 //! Prints simplified syslog message to stderr. 94 static void 95 message_to_console(syslog_context *context, const char *text, va_list args) 96 { 97 if (context->ident[0]) 98 fprintf(stderr, "'%s' ", context->ident); 99 if (context->options & LOG_PID) 100 fprintf(stderr, "[%ld] ", find_thread(NULL)); 101 102 vfprintf(stderr, text, args); 103 fputc('\n', stderr); 104 } 105 106 107 /*! Creates the message from the given context and sends it to the syslog 108 daemon, if the priority mask matches. 109 If the message couldn't be delivered, and LOG_CONS was set, it will 110 redirect the message to stderr. 111 */ 112 static void 113 send_syslog_message(syslog_context *context, int priority, const char *text, 114 va_list args) 115 { 116 int options = context->options; 117 118 // do we have to do anything? 119 if ((context->mask & LOG_MASK(SYSLOG_PRIORITY(priority))) == 0) 120 return; 121 122 port_id port = find_port(SYSLOG_PORT_NAME); 123 if ((options & LOG_PERROR) != 0 124 || ((options & LOG_CONS) != 0 && port < B_OK)) { 125 // if asked for, print out the (simplified) message on stderr 126 message_to_console(context, text, args); 127 } 128 if (port < B_OK) { 129 // apparently, there is no syslog daemon running; 130 return; 131 } 132 133 // adopt facility from openlog() if not yet set 134 if (SYSLOG_FACILITY(priority) == 0) 135 priority |= context->facility; 136 137 char buffer[2048]; 138 syslog_message &message = *(syslog_message *)&buffer[0]; 139 140 message.from = find_thread(NULL); 141 message.when = real_time_clock(); 142 message.options = options; 143 message.priority = priority; 144 strcpy(message.ident, context->ident); 145 146 int length = vsnprintf(message.message, sizeof(buffer) 147 - sizeof(syslog_message), text, args); 148 149 status_t status; 150 do { 151 // make sure the message gets send (if there is a valid port) 152 status = write_port(port, SYSLOG_MESSAGE, &message, 153 sizeof(syslog_message) + length); 154 } while (status == B_INTERRUPTED); 155 156 if (status < B_OK && (options & LOG_CONS) != 0 157 && (options & LOG_PERROR) == 0) { 158 // LOG_CONS redirects all output to the console in case contacting 159 // the syslog daemon failed 160 message_to_console(context, text, args); 161 } 162 } 163 164 165 // #pragma mark - POSIX API 166 167 168 void 169 closelog(void) 170 { 171 closelog_thread(); 172 } 173 174 175 void 176 openlog(const char *ident, int options, int facility) 177 { 178 openlog_thread(ident, options, facility); 179 } 180 181 182 int 183 setlogmask(int priorityMask) 184 { 185 return setlogmask_thread(priorityMask); 186 } 187 188 189 void 190 syslog(int priority, const char *message, ...) 191 { 192 va_list args; 193 194 va_start(args, message); 195 send_syslog_message(get_context(), priority, message, args); 196 va_end(args); 197 } 198 199 200 // #pragma mark - Be extensions 201 // ToDo: it would probably be better to export these symbols as weak symbols only 202 203 204 void 205 closelog_team(void) 206 { 207 // nothing to do here... 208 } 209 210 211 void 212 openlog_team(const char *ident, int options, int facility) 213 { 214 if (ident != NULL) 215 strcpy(sTeamContext.ident, ident); 216 217 sTeamContext.options = options; 218 sTeamContext.facility = SYSLOG_FACILITY(facility); 219 } 220 221 222 int 223 setlogmask_team(int priorityMask) 224 { 225 int oldMask = sTeamContext.mask; 226 227 if (priorityMask != 0) 228 sTeamContext.mask = priorityMask; 229 230 return oldMask; 231 } 232 233 234 void 235 log_team(int priority, const char *message, ...) 236 { 237 va_list args; 238 239 va_start(args, message); 240 send_syslog_message(&sTeamContext, priority, message, args); 241 va_end(args); 242 } 243 244 245 void 246 closelog_thread(void) 247 { 248 if (sThreadContextSlot < 0) 249 return; 250 251 free(tls_get(sThreadContextSlot)); 252 *tls_address(sThreadContextSlot) = NULL; 253 } 254 255 256 void 257 openlog_thread(const char *ident, int options, int facility) 258 { 259 syslog_context *context = get_context(); 260 261 if (ident) 262 strcpy(context->ident, ident); 263 264 context->options = options; 265 context->facility = SYSLOG_FACILITY(facility); 266 } 267 268 269 int 270 setlogmask_thread(int priorityMask) 271 { 272 syslog_context *context = get_context(); 273 int oldMask = context->mask; 274 275 if (priorityMask != 0) 276 context->mask = priorityMask; 277 278 return oldMask; 279 } 280 281 282 void 283 log_thread(int priority, const char *message, ...) 284 { 285 va_list args; 286 287 va_start(args, message); 288 send_syslog_message(get_context(), priority, message, args); 289 va_end(args); 290 } 291 292 293 // #pragma mark - BSD extensions 294 295 296 void 297 vsyslog(int priority, const char *message, va_list args) 298 { 299 send_syslog_message(get_context(), priority, message, args); 300 } 301 302