/* ** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. ** Distributed under the terms of the OpenBeOS License. */ #include #include #include #include #include #include #include struct syslog_context { char ident[B_OS_NAME_LENGTH]; int16 mask; int16 facility; int32 options; }; static syslog_context sTeamContext = { "", -1, LOG_USER, LOG_CONS }; static int32 sThreadContextSlot = -1; static syslog_context * allocate_context() { syslog_context *context = (syslog_context *)malloc(sizeof(syslog_context)); if (context == NULL) return NULL; // inherit the attributes of the team context memcpy(context, &sTeamContext, sizeof(syslog_context)); return context; } /** This function returns the current syslog context structure. * If there is none for the current thread, it will create one * that inherits the context attributes from the team and put it * into TLS. * If it could not allocate a thread context, it will return the * team context; this function is guaranteed to return a valid * syslog context. */ static syslog_context * get_context() { if (sThreadContextSlot == B_NO_MEMORY) return &sTeamContext; if (sThreadContextSlot < 0) { static int32 lock = 0; if (atomic_add(&lock, 1) == 0) { int32 slot = tls_allocate(); if (slot < 0) { sThreadContextSlot = B_NO_MEMORY; return &sTeamContext; } *tls_address(slot) = allocate_context(); sThreadContextSlot = slot; return (syslog_context *)tls_get(slot); } else { while (sThreadContextSlot == -1) snooze(10000); } } syslog_context *context = (syslog_context *)tls_get(sThreadContextSlot); if (context == NULL) { // try to allocate the context again; it might have // been deleted, or there was not enough memory last // time context = allocate_context(); } if (context != NULL) return context; return &sTeamContext; } /** Creates the message from the given context and sends it to the syslog * daemon, if the priority mask matches. * If the message couldn't be delivered, and LOG_CONS was set, it will * redirect the message to stderr. */ static void send_syslog_message(syslog_context *context, int priority, const char *text, va_list args) { int options = context->options; // do we have to do anything? if ((context->mask & LOG_MASK(SYSLOG_PRIORITY(priority))) == 0) return; port_id port = find_port(SYSLOG_PORT_NAME); if ((options & LOG_PERROR) != 0 || ((options & LOG_CONS) != 0 && port < B_OK)) { // if asked for, print out the (simplified) message on stderr if (context->ident[0]) fprintf(stderr, "'%s' ", context->ident); if (context->options & LOG_PID) fprintf(stderr, "[%ld] ", find_thread(NULL)); vfprintf(stderr, text, args); fputc('\n', stderr); } if (port < B_OK) { // apparently, there is no syslog daemon running; return; } char buffer[2048]; syslog_message &message = *(syslog_message *)&buffer[0]; message.from = find_thread(NULL); message.when = real_time_clock(); message.options = options; message.priority = priority | context->facility; strcpy(message.ident, context->ident); int length = vsnprintf(message.message, sizeof(buffer) - sizeof(syslog_message), text, args); while (write_port(port, SYSLOG_MESSAGE, &message, sizeof(syslog_message) + length) == B_INTERRUPTED); // make sure the message gets send (if there is a valid port) // ToDo: if write_port() returns an error, LOG_CONS is not respected } // #pragma mark - // public Be API // ToDo: it would probably be better to export these symbols as weak symbols only void closelog_team(void) { // nothing to do here... } void openlog_team(const char *ident, int options, int facility) { if (ident != NULL) strcpy(sTeamContext.ident, ident); sTeamContext.options = options; sTeamContext.facility = SYSLOG_FACILITY(facility); } int setlogmask_team(int priorityMask) { int oldMask = sTeamContext.mask; if (priorityMask != 0) sTeamContext.mask = priorityMask; return oldMask; } void log_team(int priority, const char *message, ...) { va_list args; va_start(args, message); send_syslog_message(&sTeamContext, priority, message, args); va_end(args); } void closelog_thread(void) { if (sThreadContextSlot < 0) return; free(tls_get(sThreadContextSlot)); *tls_address(sThreadContextSlot) = NULL; } void openlog_thread(const char *ident, int options, int facility) { syslog_context *context = get_context(); if (ident) strcpy(context->ident, ident); context->options = options; context->facility = SYSLOG_FACILITY(facility); } int setlogmask_thread(int priorityMask) { syslog_context *context = get_context(); int oldMask = context->mask; if (priorityMask != 0) context->mask = priorityMask; return oldMask; } void log_thread(int priority, const char *message, ...) { va_list args; va_start(args, message); send_syslog_message(get_context(), priority, message, args); va_end(args); } // #pragma mark - // POSIX API - just uses the thread syslog functions void closelog(void) { closelog_thread(); } void openlog(const char *ident, int options, int facility) { openlog_thread(ident, options, facility); } int setlogmask(int priorityMask) { return setlogmask_thread(priorityMask); } void syslog(int priority, const char *message, ...) { va_list args; va_start(args, message); send_syslog_message(get_context(), priority, message, args); va_end(args); }