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