Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/exec/logsys.c b/exec/logsys.c
index 4c3e11a5..34de6443 100644
--- a/exec/logsys.c
+++ b/exec/logsys.c
@@ -1,1677 +1,1700 @@
/*
* Copyright (c) 2002-2004 MontaVista Software, Inc.
* Copyright (c) 2006-2010 Red Hat, Inc.
*
* Author: Steven Dake (sdake@redhat.com)
* Author: Lon Hohberger (lhh@redhat.com)
* Author: Fabio M. Di Nitto (fdinitto@redhat.com)
*
* All rights reserved.
*
* This software licensed under BSD license, the text of which follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the MontaVista Software, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <config.h>
#include <stdint.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdarg.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#if defined(COROSYNC_LINUX)
#include <linux/un.h>
#endif
#if defined(COROSYNC_BSD) || defined(COROSYNC_DARWIN)
#include <sys/un.h>
#endif
#include <syslog.h>
#include <stdlib.h>
#include <pthread.h>
#include <limits.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <corosync/list.h>
#include <corosync/engine/logsys.h>
#include "util.h"
#define YIELD_AFTER_LOG_OPS 10
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
/*
* syslog prioritynames, facility names to value mapping
* Some C libraries build this in to their headers, but it is non-portable
* so logsys supplies its own version.
*/
struct syslog_names {
const char *c_name;
int c_val;
};
struct syslog_names prioritynames[] =
{
{ "alert", LOG_ALERT },
{ "crit", LOG_CRIT },
{ "debug", LOG_DEBUG },
{ "emerg", LOG_EMERG },
{ "err", LOG_ERR },
{ "error", LOG_ERR },
{ "info", LOG_INFO },
{ "notice", LOG_NOTICE },
{ "warning", LOG_WARNING },
{ NULL, -1 }
};
struct syslog_names facilitynames[] =
{
{ "auth", LOG_AUTH },
{ "cron", LOG_CRON },
{ "daemon", LOG_DAEMON },
{ "kern", LOG_KERN },
{ "lpr", LOG_LPR },
{ "mail", LOG_MAIL },
{ "news", LOG_NEWS },
{ "syslog", LOG_SYSLOG },
{ "user", LOG_USER },
{ "uucp", LOG_UUCP },
{ "local0", LOG_LOCAL0 },
{ "local1", LOG_LOCAL1 },
{ "local2", LOG_LOCAL2 },
{ "local3", LOG_LOCAL3 },
{ "local4", LOG_LOCAL4 },
{ "local5", LOG_LOCAL5 },
{ "local6", LOG_LOCAL6 },
{ "local7", LOG_LOCAL7 },
{ NULL, -1 }
};
struct record {
unsigned int rec_ident;
const char *file_name;
const char *function_name;
int file_line;
char *buffer;
struct list_head list;
};
/*
* need unlogical order to preserve 64bit alignment
*/
struct logsys_logger {
char subsys[LOGSYS_MAX_SUBSYS_NAMELEN]; /* subsystem name */
char *logfile; /* log to file */
FILE *logfile_fp; /* track file descriptor */
unsigned int mode; /* subsystem mode */
unsigned int debug; /* debug on|off */
int syslog_facility; /* facility */
int syslog_priority; /* priority */
int logfile_priority; /* priority to file */
int init_status; /* internal field to handle init queues
for subsystems */
+ unsigned int trace1_allowed;
};
/*
* These are not static so they can be read from the core file
*/
int *flt_data;
uint32_t flt_head;
uint32_t flt_tail;
unsigned int flt_data_size;
#define COMBINE_BUFFER_SIZE 2048
/* values for logsys_logger init_status */
#define LOGSYS_LOGGER_INIT_DONE 0
#define LOGSYS_LOGGER_NEEDS_INIT 1
static int logsys_system_needs_init = LOGSYS_LOGGER_NEEDS_INIT;
static int logsys_memory_used = 0;
static int logsys_sched_param_queued = 0;
static int logsys_sched_policy;
static struct sched_param logsys_sched_param;
static int logsys_after_log_ops_yield = 10;
static struct logsys_logger logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT + 1];
static int wthread_active = 0;
static int wthread_should_exit = 0;
static pthread_mutex_t logsys_config_mutex = PTHREAD_MUTEX_INITIALIZER;
static unsigned int records_written = 1;
static pthread_t logsys_thread_id;
static sem_t logsys_thread_start;
static sem_t logsys_print_finished;
static pthread_mutex_t logsys_flt_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t logsys_wthread_mutex = PTHREAD_MUTEX_INITIALIZER;
static int logsys_buffer_full = 0;
static char *format_buffer=NULL;
static int logsys_dropped_messages = 0;
void *logsys_rec_end;
static DECLARE_LIST_INIT(logsys_print_finished_records);
#define FDMAX_ARGS 64
#define CIRCULAR_BUFFER_WRITE_SIZE 64
/* forward declarations */
static void logsys_close_logfile(int subsysid);
static uint32_t circular_memory_map (void **buf, size_t bytes)
{
void *addr_orig;
void *addr;
int fd;
int res;
const char *file = "fdata-XXXXXX";
char path[PATH_MAX];
char buffer[CIRCULAR_BUFFER_WRITE_SIZE];
int i;
int written;
int error_return = 0;
snprintf (path, PATH_MAX, "/dev/shm/%s", file);
fd = mkstemp (path);
if (fd == -1) {
snprintf (path, PATH_MAX, LOCALSTATEDIR "/run/%s", file);
fd = mkstemp (path);
if (fd == -1) {
error_return = -1;
goto error_exit;
}
}
/*
* ftruncate doesn't return ENOSPC
* have to use write to determine if shared memory is actually available
*/
res = ftruncate (fd, 0);
if (res == -1) {
error_return = -1;
goto unlink_exit;
}
memset (buffer, 0, sizeof (buffer));
for (i = 0; i < (bytes / CIRCULAR_BUFFER_WRITE_SIZE); i++) {
retry_write:
written = write (fd, buffer, CIRCULAR_BUFFER_WRITE_SIZE);
if (written == -1 && errno == EINTR) {
goto retry_write;
}
if (written != 64) {
error_return = -1;
goto unlink_exit;
}
}
addr_orig = mmap (NULL, bytes << 1, PROT_NONE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (addr_orig == MAP_FAILED) {
error_return = -1;
goto unlink_exit;
}
addr = mmap (addr_orig, bytes, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, fd, 0);
if (addr != addr_orig) {
error_return = -1;
goto mmap_exit;
}
#if (defined COROSYNC_BSD && defined MADV_NOSYNC)
madvise(addr_orig, bytes, MADV_NOSYNC);
#endif
addr = mmap (((char *)addr_orig) + bytes,
bytes, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED, fd, 0);
if ((char *)addr != (char *)((char *)addr_orig + bytes)) {
error_return = -1;
goto mmap_exit;
}
#if (defined COROSYNC_BSD && defined MADV_NOSYNC)
madvise(((char *)addr_orig) + bytes, bytes, MADV_NOSYNC);
#endif
*buf = addr_orig;
error_return = 0;
goto unlink_exit;
mmap_exit:
munmap (addr_orig, bytes << 1);
unlink_exit:
unlink (path);
close (fd);
error_exit:
return (error_return);
}
static void logsys_flt_lock (void)
{
pthread_mutex_lock (&logsys_flt_mutex);
}
static void logsys_flt_unlock (void)
{
pthread_mutex_unlock (&logsys_flt_mutex);
}
static void logsys_wthread_lock (void)
{
pthread_mutex_lock (&logsys_wthread_mutex);
}
static void logsys_wthread_unlock (void)
{
pthread_mutex_unlock (&logsys_wthread_mutex);
}
/*
* Before any write operation, a reclaim on the buffer area must be executed
*/
static inline void records_reclaim (unsigned int idx, unsigned int words)
{
unsigned int should_reclaim;
should_reclaim = 0;
if ((idx + words) >= flt_data_size) {
logsys_buffer_full = 1;
}
if (logsys_buffer_full == 0) {
return;
}
if (flt_tail > flt_head) {
if (idx + words >= flt_tail) {
should_reclaim = 1;
}
} else {
if ((idx + words) >= (flt_tail + flt_data_size)) {
should_reclaim = 1;
}
}
if (should_reclaim) {
int words_needed = 0;
words_needed = words + 1;
do {
unsigned int old_tail;
words_needed -= flt_data[flt_tail];
old_tail = flt_tail;
flt_tail =
(flt_tail +
flt_data[flt_tail]) % (flt_data_size);
} while (words_needed > 0);
}
}
#define idx_word_step(idx) \
do { \
if (idx > (flt_data_size - 1)) { \
idx = 0; \
} \
} while (0);
#define idx_buffer_step(idx) \
do { \
if (idx > (flt_data_size - 1)) { \
idx = ((idx) % (flt_data_size)); \
} \
} while (0);
/*
* Internal threaded logging implementation
*/
static inline int strcpy_cutoff (char *dest, const char *src, size_t cutoff,
size_t buf_len)
{
size_t len = strlen (src);
if (buf_len <= 1) {
if (buf_len == 0)
dest[0] = 0;
return 0;
}
if (cutoff == 0) {
cutoff = len;
}
cutoff = MIN (cutoff, buf_len - 1);
len = MIN (len, cutoff);
memcpy (dest, src, len);
memset (dest + len, ' ', cutoff - len);
dest[cutoff] = '\0';
return (cutoff);
}
static const char log_month_name[][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
/*
* %s SUBSYSTEM
* %n FUNCTION NAME
* %f FILENAME
* %l FILELINE
* %p PRIORITY
* %t TIMESTAMP
* %b BUFFER
*
* any number between % and character specify field length to pad or chop
*/
static void log_printf_to_logs (
unsigned int rec_ident,
const char *file_name,
const char *function_name,
int file_line,
const char *buffer)
{
char normal_output_buffer[COMBINE_BUFFER_SIZE];
char syslog_output_buffer[COMBINE_BUFFER_SIZE];
char char_time[128];
char line_no[30];
unsigned int format_buffer_idx = 0;
unsigned int normal_output_buffer_idx = 0;
unsigned int syslog_output_buffer_idx = 0;
struct timeval tv;
size_t cutoff;
unsigned int normal_len, syslog_len;
int subsysid;
unsigned int level;
int c;
struct tm tm_res;
- if (LOGSYS_DECODE_RECID(rec_ident) != LOGSYS_RECID_LOG) {
- return;
- }
-
subsysid = LOGSYS_DECODE_SUBSYSID(rec_ident);
level = LOGSYS_DECODE_LEVEL(rec_ident);
+ if (!((LOGSYS_DECODE_RECID(rec_ident) == LOGSYS_RECID_LOG) ||
+ (logsys_loggers[subsysid].trace1_allowed && LOGSYS_DECODE_RECID(rec_ident) == LOGSYS_RECID_TRACE1))) {
+ return;
+ }
+
while ((c = format_buffer[format_buffer_idx])) {
cutoff = 0;
if (c != '%') {
normal_output_buffer[normal_output_buffer_idx++] = c;
syslog_output_buffer[syslog_output_buffer_idx++] = c;
format_buffer_idx++;
} else {
const char *normal_p, *syslog_p;
format_buffer_idx += 1;
if (isdigit (format_buffer[format_buffer_idx])) {
cutoff = atoi (&format_buffer[format_buffer_idx]);
}
while (isdigit (format_buffer[format_buffer_idx])) {
format_buffer_idx += 1;
}
switch (format_buffer[format_buffer_idx]) {
case 's':
normal_p = logsys_loggers[subsysid].subsys;
syslog_p = logsys_loggers[subsysid].subsys;
break;
case 'n':
normal_p = function_name;
syslog_p = function_name;
break;
case 'f':
normal_p = file_name;
syslog_p = file_name;
break;
case 'l':
snprintf (line_no, sizeof (line_no), "%d", file_line);
normal_p = line_no;
syslog_p = line_no;
break;
case 't':
gettimeofday (&tv, NULL);
(void)localtime_r ((time_t *)&tv.tv_sec, &tm_res);
snprintf (char_time, sizeof (char_time), "%s %02d %02d:%02d:%02d",
log_month_name[tm_res.tm_mon], tm_res.tm_mday, tm_res.tm_hour,
tm_res.tm_min, tm_res.tm_sec);
normal_p = char_time;
/*
* syslog does timestamping on its own.
* also strip extra space in case.
*/
syslog_p = "";
break;
case 'b':
normal_p = buffer;
syslog_p = buffer;
break;
case 'p':
normal_p = logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].subsys;
syslog_p = "";
break;
default:
normal_p = "";
syslog_p = "";
break;
}
normal_len = strcpy_cutoff (normal_output_buffer + normal_output_buffer_idx,
normal_p, cutoff,
(sizeof (normal_output_buffer)
- normal_output_buffer_idx));
normal_output_buffer_idx += normal_len;
syslog_len = strcpy_cutoff (syslog_output_buffer + syslog_output_buffer_idx,
syslog_p, cutoff,
(sizeof (syslog_output_buffer)
- syslog_output_buffer_idx));
syslog_output_buffer_idx += syslog_len;
format_buffer_idx += 1;
}
if ((normal_output_buffer_idx >= sizeof (normal_output_buffer) - 2) ||
(syslog_output_buffer_idx >= sizeof (syslog_output_buffer) - 1)) {
/* Note: we make allowance for '\0' at the end of
* both of these arrays and normal_output_buffer also
* needs a '\n'.
*/
break;
}
}
normal_output_buffer[normal_output_buffer_idx] = '\0';
syslog_output_buffer[syslog_output_buffer_idx] = '\0';
/*
* Output to syslog
*/
if ((logsys_loggers[subsysid].mode & LOGSYS_MODE_OUTPUT_SYSLOG) &&
((level <= logsys_loggers[subsysid].syslog_priority) ||
(logsys_loggers[subsysid].debug != 0))) {
syslog (level | logsys_loggers[subsysid].syslog_facility, "%s", syslog_output_buffer);
}
/*
* Terminate string with \n \0
*/
normal_output_buffer[normal_output_buffer_idx++] = '\n';
normal_output_buffer[normal_output_buffer_idx] = '\0';
/*
* Output to configured file
*/
if (((logsys_loggers[subsysid].mode & LOGSYS_MODE_OUTPUT_FILE) &&
(logsys_loggers[subsysid].logfile_fp != NULL)) &&
((level <= logsys_loggers[subsysid].logfile_priority) ||
(logsys_loggers[subsysid].debug != 0))) {
/*
* Output to a file
*/
if ((fwrite (normal_output_buffer, strlen (normal_output_buffer), 1,
logsys_loggers[subsysid].logfile_fp) < 1) ||
(fflush (logsys_loggers[subsysid].logfile_fp) == EOF)) {
char tmpbuffer[1024];
/*
* if we are here, it's bad.. it's really really bad.
* Best thing would be to light a candle in a church
* and pray.
*/
snprintf(tmpbuffer, sizeof(tmpbuffer),
"LOGSYS EMERGENCY: %s Unable to write to %s.",
logsys_loggers[subsysid].subsys,
logsys_loggers[subsysid].logfile);
pthread_mutex_lock (&logsys_config_mutex);
logsys_close_logfile(subsysid);
logsys_loggers[subsysid].mode &= ~LOGSYS_MODE_OUTPUT_FILE;
pthread_mutex_unlock (&logsys_config_mutex);
log_printf_to_logs(
LOGSYS_ENCODE_RECID(
LOGSYS_LEVEL_EMERG,
subsysid,
LOGSYS_RECID_LOG),
__FILE__, __FUNCTION__, __LINE__,
tmpbuffer);
}
}
/*
* Output to stderr
*/
if ((logsys_loggers[subsysid].mode & LOGSYS_MODE_OUTPUT_STDERR) &&
((level <= logsys_loggers[subsysid].logfile_priority) ||
(logsys_loggers[subsysid].debug != 0))) {
if (write (STDERR_FILENO, normal_output_buffer, strlen (normal_output_buffer)) < 0) {
char tmpbuffer[1024];
/*
* if we are here, it's bad.. it's really really bad.
* Best thing would be to light 20 candles for each saint
* in the calendar and pray a lot...
*/
pthread_mutex_lock (&logsys_config_mutex);
logsys_loggers[subsysid].mode &= ~LOGSYS_MODE_OUTPUT_STDERR;
pthread_mutex_unlock (&logsys_config_mutex);
snprintf(tmpbuffer, sizeof(tmpbuffer),
"LOGSYS EMERGENCY: %s Unable to write to STDERR.",
logsys_loggers[subsysid].subsys);
log_printf_to_logs(
LOGSYS_ENCODE_RECID(
LOGSYS_LEVEL_EMERG,
subsysid,
LOGSYS_RECID_LOG),
__FILE__, __FUNCTION__, __LINE__,
tmpbuffer);
}
}
}
static void log_printf_to_logs_wthread (
unsigned int rec_ident,
const char *file_name,
const char *function_name,
int file_line,
const char *buffer)
{
struct record *rec;
uint32_t length;
rec = malloc (sizeof (struct record));
if (rec == NULL) {
return;
}
length = strlen (buffer);
rec->rec_ident = rec_ident;
rec->file_name = file_name;
rec->function_name = function_name;
rec->file_line = file_line;
rec->buffer = malloc (length + 1);
if (rec->buffer == NULL) {
free (rec);
return;
}
memcpy (rec->buffer, buffer, length + 1);
list_init (&rec->list);
logsys_wthread_lock();
logsys_memory_used += length + 1 + sizeof (struct record);
if (logsys_memory_used > 512000) {
free (rec->buffer);
free (rec);
logsys_memory_used = logsys_memory_used - length - 1 - sizeof (struct record);
logsys_dropped_messages += 1;
logsys_wthread_unlock();
return;
} else {
list_add_tail (&rec->list, &logsys_print_finished_records);
}
logsys_wthread_unlock();
sem_post (&logsys_print_finished);
}
static void *logsys_worker_thread (void *data) __attribute__((noreturn));
static void *logsys_worker_thread (void *data)
{
struct record *rec;
int dropped = 0;
int res;
/*
* Signal wthread_create that the initialization process may continue
*/
sem_post (&logsys_thread_start);
for (;;) {
dropped = 0;
retry_sem_wait:
res = sem_wait (&logsys_print_finished);
if (res == -1 && errno == EINTR) {
goto retry_sem_wait;
} else
if (res == -1) {
/*
* This case shouldn't happen
*/
pthread_exit (NULL);
}
logsys_wthread_lock();
if (wthread_should_exit) {
int value;
res = sem_getvalue (&logsys_print_finished, &value);
if (value == 0) {
logsys_wthread_unlock();
pthread_exit (NULL);
}
}
rec = list_entry (logsys_print_finished_records.next, struct record, list);
list_del (&rec->list);
logsys_memory_used = logsys_memory_used - strlen (rec->buffer) -
sizeof (struct record) - 1;
dropped = logsys_dropped_messages;
logsys_dropped_messages = 0;
logsys_wthread_unlock();
if (dropped) {
printf ("%d messages lost\n", dropped);
}
log_printf_to_logs (
rec->rec_ident,
rec->file_name,
rec->function_name,
rec->file_line,
rec->buffer);
free (rec->buffer);
free (rec);
}
}
static void wthread_create (void)
{
int res;
if (wthread_active) {
return;
}
wthread_active = 1;
/*
* TODO: propagate pthread_create errors back to the caller
*/
res = pthread_create (&logsys_thread_id, NULL,
logsys_worker_thread, NULL);
sem_wait (&logsys_thread_start);
if (res == 0) {
if (logsys_sched_param_queued == 1) {
/*
* TODO: propagate logsys_thread_priority_set errors back to
* the caller
*/
res = logsys_thread_priority_set (
logsys_sched_policy,
&logsys_sched_param,
logsys_after_log_ops_yield);
logsys_sched_param_queued = 0;
}
} else {
wthread_active = 0;
}
}
static int _logsys_config_subsys_get_unlocked (const char *subsys)
{
unsigned int i;
if (!subsys) {
return LOGSYS_MAX_SUBSYS_COUNT;
}
for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
if (strcmp (logsys_loggers[i].subsys, subsys) == 0) {
return i;
}
}
return (-1);
}
static void syslog_facility_reconf (void)
{
closelog();
openlog(logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].subsys,
LOG_CONS|LOG_PID,
logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].syslog_facility);
}
/*
* this is always invoked within the mutex, so it's safe to parse the
* whole thing as we need.
*/
static void logsys_close_logfile (
int subsysid)
{
int i;
if ((logsys_loggers[subsysid].logfile_fp == NULL) &&
(logsys_loggers[subsysid].logfile == NULL)) {
return;
}
/*
* if there is another subsystem or system using the same fp,
* then we clean our own structs, but we can't close the file
* as it is in use by somebody else.
* Only the last users will be allowed to perform the fclose.
*/
for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
if ((logsys_loggers[i].logfile_fp == logsys_loggers[subsysid].logfile_fp) &&
(i != subsysid)) {
logsys_loggers[subsysid].logfile = NULL;
logsys_loggers[subsysid].logfile_fp = NULL;
return;
}
}
/*
* if we are here, we are the last users of that fp, so we can safely
* close it.
*/
fclose (logsys_loggers[subsysid].logfile_fp);
logsys_loggers[subsysid].logfile_fp = NULL;
free (logsys_loggers[subsysid].logfile);
logsys_loggers[subsysid].logfile = NULL;
}
/*
* we need a version that can work when somebody else is already
* holding a config mutex lock or we will never get out of here
*/
static int logsys_config_file_set_unlocked (
int subsysid,
const char **error_string,
const char *file)
{
static char error_string_response[512];
int i;
logsys_close_logfile(subsysid);
if ((file == NULL) ||
(strcmp(logsys_loggers[subsysid].subsys, "") == 0)) {
return (0);
}
if (strlen(file) >= PATH_MAX) {
snprintf (error_string_response,
sizeof(error_string_response),
"%s: logfile name exceed maximum system filename lenght\n",
logsys_loggers[subsysid].subsys);
*error_string = error_string_response;
return (-1);
}
for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
if ((logsys_loggers[i].logfile != NULL) &&
(strcmp (logsys_loggers[i].logfile, file) == 0) &&
(i != subsysid)) {
logsys_loggers[subsysid].logfile =
logsys_loggers[i].logfile;
logsys_loggers[subsysid].logfile_fp =
logsys_loggers[i].logfile_fp;
return (0);
}
}
logsys_loggers[subsysid].logfile = strdup(file);
if (logsys_loggers[subsysid].logfile == NULL) {
snprintf (error_string_response,
sizeof(error_string_response),
"Unable to allocate memory for logfile '%s'\n",
file);
*error_string = error_string_response;
return (-1);
}
logsys_loggers[subsysid].logfile_fp = fopen (file, "a+");
if (logsys_loggers[subsysid].logfile_fp == NULL) {
int err;
char error_str[LOGSYS_MAX_PERROR_MSG_LEN];
const char *error_ptr;
err = errno;
#ifdef COROSYNC_LINUX
/* The GNU version of strerror_r returns a (char*) that *must* be used */
error_ptr = strerror_r(err, error_str, sizeof(error_str));
#else
/* The XSI-compliant strerror_r() return 0 or -1 (in case the buffer is full) */
if ( strerror_r(err, error_str, sizeof(error_str)) < 0 )
error_ptr = "";
else
error_ptr = error_str;
#endif
free(logsys_loggers[subsysid].logfile);
logsys_loggers[subsysid].logfile = NULL;
snprintf (error_string_response,
sizeof(error_string_response),
"Can't open logfile '%s' for reason: %s (%d).\n",
file, error_ptr, err);
*error_string = error_string_response;
return (-1);
}
return (0);
}
static void logsys_subsys_init (
const char *subsys,
int subsysid)
{
if (logsys_system_needs_init == LOGSYS_LOGGER_NEEDS_INIT) {
logsys_loggers[subsysid].init_status =
LOGSYS_LOGGER_NEEDS_INIT;
} else {
memcpy(&logsys_loggers[subsysid],
&logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT],
sizeof(logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT]));
logsys_loggers[subsysid].init_status =
LOGSYS_LOGGER_INIT_DONE;
}
strncpy (logsys_loggers[subsysid].subsys, subsys,
sizeof (logsys_loggers[subsysid].subsys));
logsys_loggers[subsysid].subsys[
sizeof (logsys_loggers[subsysid].subsys) - 1] = '\0';
}
/*
* Internal API - exported
*/
int _logsys_system_setup(
const char *mainsystem,
unsigned int mode,
unsigned int debug,
const char *logfile,
int logfile_priority,
int syslog_facility,
int syslog_priority)
{
int i;
const char *errstr;
char tempsubsys[LOGSYS_MAX_SUBSYS_NAMELEN];
if ((mainsystem == NULL) ||
(strlen(mainsystem) >= LOGSYS_MAX_SUBSYS_NAMELEN)) {
return -1;
}
i = LOGSYS_MAX_SUBSYS_COUNT;
pthread_mutex_lock (&logsys_config_mutex);
snprintf(logsys_loggers[i].subsys,
LOGSYS_MAX_SUBSYS_NAMELEN,
"%s", mainsystem);
logsys_loggers[i].mode = mode;
logsys_loggers[i].debug = debug;
+ logsys_loggers[i].trace1_allowed = 0;
if (logsys_config_file_set_unlocked (i, &errstr, logfile) < 0) {
pthread_mutex_unlock (&logsys_config_mutex);
return (-1);
}
logsys_loggers[i].logfile_priority = logfile_priority;
logsys_loggers[i].syslog_facility = syslog_facility;
logsys_loggers[i].syslog_priority = syslog_priority;
syslog_facility_reconf();
logsys_loggers[i].init_status = LOGSYS_LOGGER_INIT_DONE;
logsys_system_needs_init = LOGSYS_LOGGER_INIT_DONE;
for (i = 0; i < LOGSYS_MAX_SUBSYS_COUNT; i++) {
if ((strcmp (logsys_loggers[i].subsys, "") != 0) &&
(logsys_loggers[i].init_status ==
LOGSYS_LOGGER_NEEDS_INIT)) {
strncpy (tempsubsys, logsys_loggers[i].subsys,
sizeof (tempsubsys));
tempsubsys[sizeof (tempsubsys) - 1] = '\0';
logsys_subsys_init(tempsubsys, i);
}
}
pthread_mutex_unlock (&logsys_config_mutex);
return (0);
}
int _logsys_subsys_create (const char *subsys)
{
int i;
if ((subsys == NULL) ||
(strlen(subsys) >= LOGSYS_MAX_SUBSYS_NAMELEN)) {
return -1;
}
pthread_mutex_lock (&logsys_config_mutex);
i = _logsys_config_subsys_get_unlocked (subsys);
if ((i > -1) && (i < LOGSYS_MAX_SUBSYS_COUNT)) {
pthread_mutex_unlock (&logsys_config_mutex);
return i;
}
for (i = 0; i < LOGSYS_MAX_SUBSYS_COUNT; i++) {
if (strcmp (logsys_loggers[i].subsys, "") == 0) {
logsys_subsys_init(subsys, i);
break;
}
}
if (i >= LOGSYS_MAX_SUBSYS_COUNT) {
i = -1;
}
pthread_mutex_unlock (&logsys_config_mutex);
return i;
}
int _logsys_wthread_create (void)
{
if (((logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].mode & LOGSYS_MODE_FORK) == 0) &&
((logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].mode & LOGSYS_MODE_THREADED) != 0)) {
wthread_create();
}
return (0);
}
int _logsys_rec_init (unsigned int fltsize)
{
size_t flt_real_size;
int res;
sem_init (&logsys_thread_start, 0, 0);
sem_init (&logsys_print_finished, 0, 0);
/*
* XXX: kill me for 1.1 because I am a dirty hack
* temporary workaround that will be replaced by supporting
* 0 byte size flight recorder buffer.
* 0 byte size buffer will enable direct printing to logs
* without flight recoder.
*/
if (fltsize < 64000) {
fltsize = 64000;
}
flt_real_size = ROUNDUP(fltsize, sysconf(_SC_PAGESIZE)) * 4;
res = circular_memory_map ((void **)&flt_data, flt_real_size);
if (res == -1) {
sem_destroy (&logsys_thread_start);
sem_destroy (&logsys_print_finished);
}
memset (flt_data, 0, flt_real_size * 2);
/*
* flt_data_size tracks data by ints and not bytes/chars.
*/
flt_data_size = flt_real_size / sizeof (uint32_t);
/*
* First record starts at zero
* Last record ends at zero
*/
flt_head = 0;
flt_tail = 0;
return (0);
}
/*
* u32 RECORD SIZE
* u32 record ident
* u32 arg count
* u32 file line
* u32 subsys length
* buffer null terminated subsys
* u32 filename length
* buffer null terminated filename
* u32 filename length
* buffer null terminated function
* u32 arg1 length
* buffer arg1
* ... repeats length & arg
*/
void _logsys_log_rec (
unsigned int rec_ident,
const char *function_name,
const char *file_name,
int file_line,
...)
{
va_list ap;
const void *buf_args[FDMAX_ARGS];
unsigned int buf_len[FDMAX_ARGS];
unsigned int i;
unsigned int idx;
unsigned int arguments = 0;
unsigned int record_reclaim_size = 0;
unsigned int index_start;
int words_written;
int subsysid;
subsysid = LOGSYS_DECODE_SUBSYSID(rec_ident);
/*
* Decode VA Args
*/
va_start (ap, file_line);
arguments = 3;
for (;;) {
buf_args[arguments] = va_arg (ap, void *);
if (buf_args[arguments] == LOGSYS_REC_END) {
break;
}
buf_len[arguments] = va_arg (ap, int);
record_reclaim_size += ((buf_len[arguments] + 3) >> 2) + 1;
arguments++;
if (arguments >= FDMAX_ARGS) {
break;
}
}
va_end (ap);
/*
* Encode logsys subsystem identity, filename, and function
*/
buf_args[0] = logsys_loggers[subsysid].subsys;
buf_len[0] = strlen (logsys_loggers[subsysid].subsys) + 1;
buf_args[1] = file_name;
buf_len[1] = strlen (file_name) + 1;
buf_args[2] = function_name;
buf_len[2] = strlen (function_name) + 1;
for (i = 0; i < 3; i++) {
record_reclaim_size += ((buf_len[i] + 3) >> 2) + 1;
}
logsys_flt_lock();
idx = flt_head;
index_start = idx;
/*
* Reclaim data needed for record including 4 words for the header
*/
records_reclaim (idx, record_reclaim_size + 4);
/*
* Write record size of zero and rest of header information
*/
flt_data[idx++] = 0;
idx_word_step(idx);
flt_data[idx++] = rec_ident;
idx_word_step(idx);
flt_data[idx++] = file_line;
idx_word_step(idx);
flt_data[idx++] = records_written;
idx_word_step(idx);
/*
* Encode all of the arguments into the log message
*/
for (i = 0; i < arguments; i++) {
unsigned int bytes;
unsigned int total_words;
bytes = buf_len[i];
total_words = (bytes + 3) >> 2;
flt_data[idx++] = total_words;
idx_word_step(idx);
memcpy (&flt_data[idx], buf_args[i], buf_len[i]);
idx += total_words;
idx_buffer_step (idx);
}
words_written = idx - index_start;
if (words_written < 0) {
words_written += flt_data_size;
}
/*
* Commit the write of the record size now that the full record
* is in the memory buffer
*/
flt_data[index_start] = words_written;
flt_head = idx;
logsys_flt_unlock();
records_written++;
}
void _logsys_log_vprintf (
unsigned int rec_ident,
const char *function_name,
const char *file_name,
int file_line,
const char *format,
va_list ap)
{
char logsys_print_buffer[COMBINE_BUFFER_SIZE];
unsigned int len;
unsigned int level;
int subsysid;
const char *short_file_name;
subsysid = LOGSYS_DECODE_SUBSYSID(rec_ident);
level = LOGSYS_DECODE_LEVEL(rec_ident);
len = vsnprintf (logsys_print_buffer, sizeof (logsys_print_buffer), format, ap);
if (logsys_print_buffer[len - 1] == '\n') {
logsys_print_buffer[len - 1] = '\0';
len -= 1;
}
#ifdef BUILDING_IN_PLACE
short_file_name = file_name;
#else
short_file_name = strrchr (file_name, '/');
if (short_file_name == NULL)
short_file_name = file_name;
else
short_file_name++; /* move past the "/" */
#endif /* BUILDING_IN_PLACE */
/*
* Create a log record
*/
_logsys_log_rec (
rec_ident,
function_name,
short_file_name,
file_line,
logsys_print_buffer, len + 1,
LOGSYS_REC_END);
/*
* If logsys is not going to print a message to a log target don't
* queue one
*/
if ((level > logsys_loggers[subsysid].syslog_priority &&
level > logsys_loggers[subsysid].logfile_priority &&
logsys_loggers[subsysid].debug == 0) ||
(level == LOGSYS_LEVEL_DEBUG &&
logsys_loggers[subsysid].debug == 0)) {
return;
}
if ((logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].mode & LOGSYS_MODE_THREADED) == 0) {
/*
* Output (and block) if the log mode is not threaded otherwise
* expect the worker thread to output the log data once signaled
*/
log_printf_to_logs (rec_ident,
short_file_name,
function_name,
file_line,
logsys_print_buffer);
} else {
/*
* Signal worker thread to display logging output
*/
log_printf_to_logs_wthread (rec_ident,
short_file_name,
function_name,
file_line,
logsys_print_buffer);
}
}
void _logsys_log_printf (
unsigned int rec_ident,
const char *function_name,
const char *file_name,
int file_line,
const char *format,
...)
{
va_list ap;
va_start (ap, format);
_logsys_log_vprintf (rec_ident, function_name, file_name, file_line,
format, ap);
va_end (ap);
}
int _logsys_config_subsys_get (const char *subsys)
{
unsigned int i;
pthread_mutex_lock (&logsys_config_mutex);
i = _logsys_config_subsys_get_unlocked (subsys);
pthread_mutex_unlock (&logsys_config_mutex);
return i;
}
/*
* External Configuration and Initialization API
*/
void logsys_fork_completed (void)
{
logsys_loggers[LOGSYS_MAX_SUBSYS_COUNT].mode &= ~LOGSYS_MODE_FORK;
(void)_logsys_wthread_create ();
}
int logsys_config_mode_set (const char *subsys, unsigned int mode)
{
int i;
pthread_mutex_lock (&logsys_config_mutex);
if (subsys != NULL) {
i = _logsys_config_subsys_get_unlocked (subsys);
if (i >= 0) {
logsys_loggers[i].mode = mode;
i = 0;
}
} else {
for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
logsys_loggers[i].mode = mode;
}
i = 0;
}
pthread_mutex_unlock (&logsys_config_mutex);
return i;
}
unsigned int logsys_config_mode_get (const char *subsys)
{
int i;
i = _logsys_config_subsys_get (subsys);
if (i < 0) {
return i;
}
return logsys_loggers[i].mode;
}
int logsys_config_file_set (
const char *subsys,
const char **error_string,
const char *file)
{
int i;
int res;
pthread_mutex_lock (&logsys_config_mutex);
if (subsys != NULL) {
i = _logsys_config_subsys_get_unlocked (subsys);
if (i < 0) {
res = i;
} else {
res = logsys_config_file_set_unlocked(i, error_string, file);
}
} else {
for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
res = logsys_config_file_set_unlocked(i, error_string, file);
if (res < 0) {
break;
}
}
}
pthread_mutex_unlock (&logsys_config_mutex);
return res;
}
int logsys_format_set (const char *format)
{
int ret = 0;
pthread_mutex_lock (&logsys_config_mutex);
if (format_buffer) {
free(format_buffer);
format_buffer = NULL;
}
format_buffer = strdup(format ? format : "%p [%6s] %b");
if (format_buffer == NULL) {
ret = -1;
}
pthread_mutex_unlock (&logsys_config_mutex);
return ret;
}
char *logsys_format_get (void)
{
return format_buffer;
}
int logsys_config_syslog_facility_set (
const char *subsys,
unsigned int facility)
{
int i;
pthread_mutex_lock (&logsys_config_mutex);
if (subsys != NULL) {
i = _logsys_config_subsys_get_unlocked (subsys);
if (i >= 0) {
logsys_loggers[i].syslog_facility = facility;
if (i == LOGSYS_MAX_SUBSYS_COUNT) {
syslog_facility_reconf();
}
i = 0;
}
} else {
for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
logsys_loggers[i].syslog_facility = facility;
}
syslog_facility_reconf();
i = 0;
}
pthread_mutex_unlock (&logsys_config_mutex);
return i;
}
int logsys_config_syslog_priority_set (
const char *subsys,
unsigned int priority)
{
int i;
pthread_mutex_lock (&logsys_config_mutex);
if (subsys != NULL) {
i = _logsys_config_subsys_get_unlocked (subsys);
if (i >= 0) {
logsys_loggers[i].syslog_priority = priority;
i = 0;
}
} else {
for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
logsys_loggers[i].syslog_priority = priority;
}
i = 0;
}
pthread_mutex_unlock (&logsys_config_mutex);
return i;
}
int logsys_config_logfile_priority_set (
const char *subsys,
unsigned int priority)
{
int i;
pthread_mutex_lock (&logsys_config_mutex);
if (subsys != NULL) {
i = _logsys_config_subsys_get_unlocked (subsys);
if (i >= 0) {
logsys_loggers[i].logfile_priority = priority;
i = 0;
}
} else {
for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
logsys_loggers[i].logfile_priority = priority;
}
i = 0;
}
pthread_mutex_unlock (&logsys_config_mutex);
return i;
}
int logsys_config_debug_set (
const char *subsys,
unsigned int debug)
{
int i;
pthread_mutex_lock (&logsys_config_mutex);
if (subsys != NULL) {
i = _logsys_config_subsys_get_unlocked (subsys);
if (i >= 0) {
- logsys_loggers[i].debug = debug;
+ switch (debug) {
+ case LOGSYS_DEBUG_OFF:
+ case LOGSYS_DEBUG_ON:
+ logsys_loggers[i].debug = debug;
+ logsys_loggers[i].trace1_allowed = 0;
+ break;
+ case LOGSYS_DEBUG_TRACE:
+ logsys_loggers[i].debug = LOGSYS_DEBUG_ON;
+ logsys_loggers[i].trace1_allowed = 1;
+ break;
+ }
i = 0;
}
} else {
for (i = 0; i <= LOGSYS_MAX_SUBSYS_COUNT; i++) {
- logsys_loggers[i].debug = debug;
+ switch (debug) {
+ case LOGSYS_DEBUG_OFF:
+ case LOGSYS_DEBUG_ON:
+ logsys_loggers[i].debug = debug;
+ logsys_loggers[i].trace1_allowed = 0;
+ break;
+ case LOGSYS_DEBUG_TRACE:
+ logsys_loggers[i].debug = LOGSYS_DEBUG_ON;
+ logsys_loggers[i].trace1_allowed = 1;
+ break;
+ }
}
i = 0;
}
pthread_mutex_unlock (&logsys_config_mutex);
return i;
}
int logsys_facility_id_get (const char *name)
{
unsigned int i;
for (i = 0; facilitynames[i].c_name != NULL; i++) {
if (strcasecmp(name, facilitynames[i].c_name) == 0) {
return (facilitynames[i].c_val);
}
}
return (-1);
}
const char *logsys_facility_name_get (unsigned int facility)
{
unsigned int i;
for (i = 0; facilitynames[i].c_name != NULL; i++) {
if (facility == facilitynames[i].c_val) {
return (facilitynames[i].c_name);
}
}
return (NULL);
}
int logsys_priority_id_get (const char *name)
{
unsigned int i;
for (i = 0; prioritynames[i].c_name != NULL; i++) {
if (strcasecmp(name, prioritynames[i].c_name) == 0) {
return (prioritynames[i].c_val);
}
}
return (-1);
}
const char *logsys_priority_name_get (unsigned int priority)
{
unsigned int i;
for (i = 0; prioritynames[i].c_name != NULL; i++) {
if (priority == prioritynames[i].c_val) {
return (prioritynames[i].c_name);
}
}
return (NULL);
}
int logsys_thread_priority_set (
int policy,
const struct sched_param *param,
unsigned int after_log_ops_yield)
{
int res = 0;
if (param == NULL) {
return (0);
}
#if defined(HAVE_PTHREAD_SETSCHEDPARAM) && defined(HAVE_SCHED_GET_PRIORITY_MAX)
if (wthread_active == 0) {
logsys_sched_policy = policy;
memcpy(&logsys_sched_param, param, sizeof(struct sched_param));
logsys_sched_param_queued = 1;
} else {
res = pthread_setschedparam (logsys_thread_id, policy, param);
}
#endif
if (after_log_ops_yield > 0) {
logsys_after_log_ops_yield = after_log_ops_yield;
}
return (res);
}
int logsys_log_rec_store (const char *filename)
{
int fd;
ssize_t written_size = 0;
size_t this_write_size;
fd = open (filename, O_CREAT|O_RDWR, 0700);
if (fd < 0) {
return (-1);
}
logsys_flt_lock();
this_write_size = write (fd, &flt_data_size, sizeof(uint32_t));
if (this_write_size != sizeof(unsigned int)) {
goto error_exit;
}
written_size += this_write_size;
this_write_size = write (fd, flt_data, flt_data_size * sizeof (uint32_t));
if (this_write_size != (flt_data_size * sizeof(uint32_t))) {
goto error_exit;
}
written_size += this_write_size;
this_write_size = write (fd, &flt_head, sizeof (uint32_t));
if (this_write_size != (sizeof(uint32_t))) {
goto error_exit;
}
written_size += this_write_size;
this_write_size = write (fd, &flt_tail, sizeof (uint32_t));
if (this_write_size != (sizeof(uint32_t))) {
goto error_exit;
}
written_size += this_write_size;
if (written_size != ((flt_data_size + 3) * sizeof (uint32_t))) {
goto error_exit;
}
logsys_flt_unlock();
close (fd);
return (0);
error_exit:
logsys_flt_unlock();
close (fd);
return (-1);
}
void logsys_atexit (void)
{
int res;
int value;
struct record *rec;
if (wthread_active == 0) {
for (;;) {
logsys_wthread_lock();
res = sem_getvalue (&logsys_print_finished, &value);
if (value == 0) {
logsys_wthread_unlock();
return;
}
sem_wait (&logsys_print_finished);
rec = list_entry (logsys_print_finished_records.next, struct record, list);
list_del (&rec->list);
logsys_memory_used = logsys_memory_used - strlen (rec->buffer) -
sizeof (struct record) - 1;
logsys_wthread_unlock();
log_printf_to_logs (
rec->rec_ident,
rec->file_name,
rec->function_name,
rec->file_line,
rec->buffer);
free (rec->buffer);
free (rec);
}
} else {
wthread_should_exit = 1;
sem_post (&logsys_print_finished);
pthread_join (logsys_thread_id, NULL);
}
}
void logsys_flush (void)
{
}
diff --git a/exec/mainconfig.c b/exec/mainconfig.c
index cbc41f59..d15dd49b 100644
--- a/exec/mainconfig.c
+++ b/exec/mainconfig.c
@@ -1,765 +1,771 @@
/*
* Copyright (c) 2002-2005 MontaVista Software, Inc.
* Copyright (c) 2006-2009 Red Hat, Inc.
*
* All rights reserved.
*
* Author: Steven Dake (sdake@redhat.com)
*
* This software licensed under BSD license, the text of which follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the MontaVista Software, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pwd.h>
#include <grp.h>
#include <limits.h>
#include <corosync/corotypes.h>
#include <corosync/list.h>
#include <corosync/totem/totem.h>
#include <corosync/engine/logsys.h>
#include "util.h"
#include "mainconfig.h"
static char error_string_response[512];
static struct objdb_iface_ver0 *global_objdb;
DECLARE_LIST_INIT(uidgid_list_head);
/* This just makes the code below a little neater */
static inline int objdb_get_string (
const struct objdb_iface_ver0 *objdb,
hdb_handle_t object_service_handle,
const char *key, char **value)
{
int res;
*value = NULL;
if ( !(res = objdb->object_key_get (object_service_handle,
key,
strlen (key),
(void *)value,
NULL))) {
if (*value) {
return 0;
}
}
return -1;
}
static inline void objdb_get_int (
const struct objdb_iface_ver0 *objdb,
hdb_handle_t object_service_handle,
char *key, unsigned int *intvalue)
{
char *value = NULL;
if (!objdb->object_key_get (object_service_handle,
key,
strlen (key),
(void *)&value,
NULL)) {
if (value) {
*intvalue = atoi(value);
}
}
}
/**
* insert_into_buffer
* @target_buffer: a buffer where to write results
* @bufferlen: tell us the size of the buffer to avoid overflows
* @entry: entry that needs to be added to the buffer
* @after: can either be NULL or set to a string.
* if NULL, @entry is prependend to logsys_format_get buffer.
* if set, @entry is added immediately after @after.
*
* Since the function is specific to logsys_format_get handling, it is implicit
* that source is logsys_format_get();
*
* In case of failure, target_buffer could be left dirty. So don't trust
* any data leftover in it.
*
* Searching for "after" assumes that there is only entry of "after"
* in the source. Afterall we control the string here and for logging format
* it makes little to no sense to have duplicate format entries.
*
* Returns: 0 on success, -1 on failure
**/
static int insert_into_buffer(
char *target_buffer,
size_t bufferlen,
const char *entry,
const char *after)
{
const char *current_format = NULL;
current_format = logsys_format_get();
/* if the entry is already in the format we don't add it again */
if (strstr(current_format, entry) != NULL) {
return -1;
}
/* if there is no "after", simply prepend the requested entry
* otherwise go for beautiful string manipulation.... </sarcasm> */
if (!after) {
if (snprintf(target_buffer, bufferlen - 1, "%s%s",
entry,
current_format) >= bufferlen - 1) {
return -1;
}
} else {
const char *afterpos;
size_t afterlen;
size_t templen;
/* check if after is contained in the format
* and afterlen has a meaning or return an error */
afterpos = strstr(current_format, after);
afterlen = strlen(after);
if ((!afterpos) || (!afterlen)) {
return -1;
}
templen = afterpos - current_format + afterlen;
if (snprintf(target_buffer, templen + 1, "%s", current_format)
>= bufferlen - 1) {
return -1;
}
if (snprintf(target_buffer + templen, bufferlen - ( templen + 1 ),
"%s%s", entry, current_format + templen)
>= bufferlen - ( templen + 1 )) {
return -1;
}
}
return 0;
}
/*
* format set is the only global specific option that
* doesn't apply at system/subsystem level.
*/
static int corosync_main_config_format_set (
struct objdb_iface_ver0 *objdb,
hdb_handle_t object_handle,
const char **error_string)
{
const char *error_reason;
char new_format_buffer[PATH_MAX];
char *value;
int err = 0;
if (!objdb_get_string (objdb,object_handle, "fileline", &value)) {
if (strcmp (value, "on") == 0) {
if (!insert_into_buffer(new_format_buffer,
sizeof(new_format_buffer),
" %f:%l", "s]")) {
err = logsys_format_set(new_format_buffer);
} else
if (!insert_into_buffer(new_format_buffer,
sizeof(new_format_buffer),
"%f:%l", NULL)) {
err = logsys_format_set(new_format_buffer);
}
} else
if (strcmp (value, "off") == 0) {
/* nothing to do here */
} else {
error_reason = "unknown value for fileline";
goto parse_error;
}
}
if (!objdb_get_string (objdb,object_handle, "function_name", &value)) {
if (strcmp (value, "on") == 0) {
if (!insert_into_buffer(new_format_buffer,
sizeof(new_format_buffer),
"%n:", "f:")) {
err = logsys_format_set(new_format_buffer);
} else
if (!insert_into_buffer(new_format_buffer,
sizeof(new_format_buffer),
" %n", "s]")) {
err = logsys_format_set(new_format_buffer);
}
} else
if (strcmp (value, "off") == 0) {
/* nothing to do here */
} else {
error_reason = "unknown value for function_name";
goto parse_error;
}
}
if (!objdb_get_string (objdb,object_handle, "timestamp", &value)) {
if (strcmp (value, "on") == 0) {
if(!insert_into_buffer(new_format_buffer,
sizeof(new_format_buffer),
"%t ", NULL)) {
err = logsys_format_set(new_format_buffer);
}
} else
if (strcmp (value, "off") == 0) {
/* nothing to do here */
} else {
error_reason = "unknown value for timestamp";
goto parse_error;
}
}
if (err) {
error_reason = "exhausted virtual memory";
goto parse_error;
}
return (0);
parse_error:
*error_string = error_reason;
return (-1);
}
static int corosync_main_config_log_destination_set (
struct objdb_iface_ver0 *objdb,
hdb_handle_t object_handle,
const char *subsys,
const char **error_string,
const char *objdb_key,
unsigned int mode_mask,
char deprecated,
const char *replacement)
{
static char formatted_error_reason[128];
char *value;
unsigned int mode;
if (!objdb_get_string (objdb, object_handle, objdb_key, &value)) {
if (deprecated) {
log_printf(LOGSYS_LEVEL_WARNING,
"Warning: the %s config paramater has been obsoleted."
" See corosync.conf man page %s directive.",
objdb_key, replacement);
}
mode = logsys_config_mode_get (subsys);
if (strcmp (value, "yes") == 0 || strcmp (value, "on") == 0) {
mode |= mode_mask;
if (logsys_config_mode_set(subsys, mode) < 0) {
sprintf (formatted_error_reason, "unable to set mode %s", objdb_key);
*error_string = formatted_error_reason;
return -1;
}
} else
if (strcmp (value, "no") == 0 || strcmp (value, "off") == 0) {
mode &= ~mode_mask;
if (logsys_config_mode_set(subsys, mode) < 0) {
sprintf (formatted_error_reason, "unable to unset mode %s", objdb_key);
*error_string = formatted_error_reason;
return -1;
}
} else {
sprintf (formatted_error_reason, "unknown value for %s", objdb_key);
*error_string = formatted_error_reason;
return -1;
}
}
return 0;
}
static int corosync_main_config_set (
struct objdb_iface_ver0 *objdb,
hdb_handle_t object_handle,
const char *subsys,
const char **error_string)
{
const char *error_reason = error_string_response;
char *value;
int mode;
/*
* this bit abuses the internal logsys exported API
* to guarantee that all configured subsystems are
* initialized too.
*
* using this approach avoids some headaches caused
* by IPC and TOTEM that have a special logging
* handling requirements
*/
if (subsys != NULL) {
if (_logsys_subsys_create(subsys) < 0) {
error_reason = "unable to create new logging subsystem";
goto parse_error;
}
}
mode = logsys_config_mode_get(subsys);
if (mode < 0) {
error_reason = "unable to get mode";
goto parse_error;
}
if (corosync_main_config_log_destination_set (objdb, object_handle, subsys, &error_reason,
"to_logfile", LOGSYS_MODE_OUTPUT_FILE, 0, NULL) != 0)
goto parse_error;
if (corosync_main_config_log_destination_set (objdb, object_handle, subsys, &error_reason,
"to_stderr", LOGSYS_MODE_OUTPUT_STDERR, 0, NULL) != 0)
goto parse_error;
if (corosync_main_config_log_destination_set (objdb, object_handle, subsys, &error_reason,
"to_syslog", LOGSYS_MODE_OUTPUT_SYSLOG, 0, NULL) != 0)
goto parse_error;
if (corosync_main_config_log_destination_set (objdb, object_handle, subsys, &error_reason,
"to_file", LOGSYS_MODE_OUTPUT_FILE, 1, "to_logfile") != 0)
goto parse_error;
if (!objdb_get_string (objdb,object_handle, "syslog_facility", &value)) {
int syslog_facility;
syslog_facility = logsys_facility_id_get(value);
if (syslog_facility < 0) {
error_reason = "unknown syslog facility specified";
goto parse_error;
}
if (logsys_config_syslog_facility_set(subsys,
syslog_facility) < 0) {
error_reason = "unable to set syslog facility";
goto parse_error;
}
}
if (!objdb_get_string (objdb,object_handle, "syslog_level", &value)) {
int syslog_priority;
log_printf(LOGSYS_LEVEL_WARNING,
"Warning: the syslog_level config paramater has been obsoleted."
" See corosync.conf man page syslog_priority directive.");
syslog_priority = logsys_priority_id_get(value);
if (syslog_priority < 0) {
error_reason = "unknown syslog level specified";
goto parse_error;
}
if (logsys_config_syslog_priority_set(subsys,
syslog_priority) < 0) {
error_reason = "unable to set syslog level";
goto parse_error;
}
}
if (!objdb_get_string (objdb,object_handle, "syslog_priority", &value)) {
int syslog_priority;
syslog_priority = logsys_priority_id_get(value);
if (syslog_priority < 0) {
error_reason = "unknown syslog priority specified";
goto parse_error;
}
if (logsys_config_syslog_priority_set(subsys,
syslog_priority) < 0) {
error_reason = "unable to set syslog priority";
goto parse_error;
}
}
if (!objdb_get_string (objdb,object_handle, "logfile", &value)) {
if (logsys_config_file_set (subsys, &error_reason, value) < 0) {
goto parse_error;
}
}
if (!objdb_get_string (objdb,object_handle, "logfile_priority", &value)) {
int logfile_priority;
logfile_priority = logsys_priority_id_get(value);
if (logfile_priority < 0) {
error_reason = "unknown logfile priority specified";
goto parse_error;
}
if (logsys_config_logfile_priority_set(subsys,
logfile_priority) < 0) {
error_reason = "unable to set logfile priority";
goto parse_error;
}
}
if (!objdb_get_string (objdb, object_handle, "debug", &value)) {
+ if (strcmp (value, "trace") == 0) {
+ if (logsys_config_debug_set (subsys, LOGSYS_DEBUG_TRACE) < 0) {
+ error_reason = "unable to set debug on";
+ goto parse_error;
+ }
+ } else
if (strcmp (value, "on") == 0) {
- if (logsys_config_debug_set (subsys, 1) < 0) {
+ if (logsys_config_debug_set (subsys, LOGSYS_DEBUG_ON) < 0) {
error_reason = "unable to set debug on";
goto parse_error;
}
} else
if (strcmp (value, "off") == 0) {
- if (logsys_config_debug_set (subsys, 0) < 0) {
+ if (logsys_config_debug_set (subsys, LOGSYS_DEBUG_OFF) < 0) {
error_reason = "unable to set debug off";
goto parse_error;
}
} else {
error_reason = "unknown value for debug";
goto parse_error;
}
}
return (0);
parse_error:
*error_string = error_reason;
return (-1);
}
static int corosync_main_config_read_logging (
struct objdb_iface_ver0 *objdb,
const char **error_string)
{
hdb_handle_t object_service_handle;
hdb_handle_t object_logger_subsys_handle;
hdb_handle_t object_find_handle;
hdb_handle_t object_find_logsys_handle;
const char *error_reason;
char *value;
objdb->object_find_create (
OBJECT_PARENT_HANDLE,
"logging",
strlen ("logging"),
&object_find_handle);
if (objdb->object_find_next (
object_find_handle,
&object_service_handle) == 0) {
/* format set is supported only for toplevel */
if (corosync_main_config_format_set (objdb,
object_service_handle,
&error_reason) < 0) {
goto parse_error;
}
if (corosync_main_config_set (objdb,
object_service_handle,
NULL,
&error_reason) < 0) {
goto parse_error;
}
/* we will need 2 of these to compensate for new logging
* config format */
objdb->object_find_create (
object_service_handle,
"logger_subsys",
strlen ("logger_subsys"),
&object_find_logsys_handle);
while (objdb->object_find_next (
object_find_logsys_handle,
&object_logger_subsys_handle) == 0) {
if (!objdb_get_string (objdb,
object_logger_subsys_handle,
"subsys", &value)) {
if (corosync_main_config_set (objdb,
object_logger_subsys_handle,
value,
&error_reason) < 0) {
goto parse_error;
}
}
else {
error_reason = "subsys required for logger directive";
goto parse_error;
}
}
objdb->object_find_destroy (object_find_logsys_handle);
objdb->object_find_create (
object_service_handle,
"logging_daemon",
strlen ("logging_daemon"),
&object_find_logsys_handle);
while (objdb->object_find_next (
object_find_logsys_handle,
&object_logger_subsys_handle) == 0) {
if (!objdb_get_string (objdb,
object_logger_subsys_handle,
"name", &value)) {
if (strcmp(value, "corosync") == 0) {
if (!objdb_get_string (objdb,
object_logger_subsys_handle,
"subsys", &value)) {
if (corosync_main_config_set (objdb,
object_logger_subsys_handle,
value,
&error_reason) < 0) {
goto parse_error;
}
}
else {
if (corosync_main_config_set (objdb,
object_logger_subsys_handle,
NULL,
&error_reason) < 0) {
goto parse_error;
}
}
}
}
else {
error_reason = "name required for logging_daemon directive";
goto parse_error;
}
}
objdb->object_find_destroy (object_find_logsys_handle);
}
objdb->object_find_destroy (object_find_handle);
return 0;
parse_error:
*error_string = error_reason;
return (-1);
}
static int uid_determine (const char *req_user)
{
int pw_uid = 0;
struct passwd passwd;
struct passwd* pwdptr = &passwd;
struct passwd* temp_pwd_pt;
char *pwdbuffer;
int pwdlinelen;
pwdlinelen = sysconf (_SC_GETPW_R_SIZE_MAX);
if (pwdlinelen == -1) {
pwdlinelen = 256;
}
pwdbuffer = malloc (pwdlinelen);
if ((getpwnam_r (req_user, pwdptr, pwdbuffer, pwdlinelen, &temp_pwd_pt)) != 0) {
log_printf (LOGSYS_LEVEL_ERROR,
"ERROR: The '%s' user is not found in /etc/passwd, please read the documentation.\n",
req_user);
corosync_exit_error (AIS_DONE_UID_DETERMINE);
}
pw_uid = passwd.pw_uid;
free (pwdbuffer);
return pw_uid;
}
static int gid_determine (const char *req_group)
{
int ais_gid = 0;
struct group group;
struct group * grpptr = &group;
struct group * temp_grp_pt;
char *grpbuffer;
int grplinelen;
grplinelen = sysconf (_SC_GETGR_R_SIZE_MAX);
if (grplinelen == -1) {
grplinelen = 256;
}
grpbuffer = malloc (grplinelen);
if ((getgrnam_r (req_group, grpptr, grpbuffer, grplinelen, &temp_grp_pt)) != 0) {
log_printf (LOGSYS_LEVEL_ERROR,
"ERROR: The '%s' group is not found in /etc/group, please read the documentation.\n",
req_group);
corosync_exit_error (AIS_DONE_GID_DETERMINE);
}
ais_gid = group.gr_gid;
free (grpbuffer);
return ais_gid;
}
static void main_objdb_reload_notify(objdb_reload_notify_type_t type, int flush,
void *priv_data_pt)
{
const char *error_string;
if (type == OBJDB_RELOAD_NOTIFY_END) {
/*
* Reload the logsys configuration
*/
if (logsys_format_set(NULL) == -1) {
fprintf (stderr, "Unable to setup logging format.\n");
}
corosync_main_config_read_logging(global_objdb,
&error_string);
}
}
static void add_logsys_config_notification(
struct objdb_iface_ver0 *objdb)
{
global_objdb = objdb;
objdb->object_track_start(OBJECT_PARENT_HANDLE,
1,
NULL,
NULL,
NULL,
main_objdb_reload_notify,
NULL);
}
static int corosync_main_config_read_uidgid (
struct objdb_iface_ver0 *objdb,
const char **error_string)
{
hdb_handle_t object_find_handle;
hdb_handle_t object_service_handle;
char *value;
int uid, gid;
struct uidgid_item *ugi;
objdb->object_find_create (
OBJECT_PARENT_HANDLE,
"uidgid",
strlen ("uidgid"),
&object_find_handle);
while (objdb->object_find_next (
object_find_handle,
&object_service_handle) == 0) {
uid = -1;
gid = -1;
if (!objdb_get_string (objdb,object_service_handle, "uid", &value)) {
uid = uid_determine(value);
}
if (!objdb_get_string (objdb,object_service_handle, "gid", &value)) {
gid = gid_determine(value);
}
if (uid > -1 || gid > -1) {
ugi = malloc (sizeof (*ugi));
if (ugi == NULL) {
_corosync_out_of_memory_error();
}
ugi->uid = uid;
ugi->gid = gid;
list_init (&ugi->list);
list_add (&ugi->list, &uidgid_list_head);
}
}
objdb->object_find_destroy (object_find_handle);
return 0;
}
int corosync_main_config_read (
struct objdb_iface_ver0 *objdb,
const char **error_string)
{
const char *error_reason = error_string_response;
if (corosync_main_config_read_logging(objdb, error_string) < 0) {
error_reason = *error_string;
goto parse_error;
}
corosync_main_config_read_uidgid (objdb, error_string);
add_logsys_config_notification(objdb);
return 0;
parse_error:
snprintf (error_string_response, sizeof(error_string_response),
"parse error in config: %s.\n",
error_reason);
*error_string = error_string_response;
return (-1);
}
int corosync_main_config_compatibility_read (
struct objdb_iface_ver0 *objdb,
enum cs_sync_mode *minimum_sync_mode,
const char **error_string)
{
const char *error_reason = error_string_response;
char *value;
*minimum_sync_mode = CS_SYNC_V1;
if (!objdb_get_string (objdb, OBJECT_PARENT_HANDLE, "compatibility", &value)) {
if (strcmp (value, "whitetank") == 0) {
*minimum_sync_mode = CS_SYNC_V1;
} else
if (strcmp (value, "none") == 0) {
*minimum_sync_mode = CS_SYNC_V2;
} else {
snprintf (error_string_response, sizeof (error_string_response),
"Invalid compatibility option '%s' specified, must be none or whitetank.\n", value);
goto parse_error;
}
}
return 0;
parse_error:
*error_string = error_reason;
return (-1);
}
diff --git a/include/corosync/engine/logsys.h b/include/corosync/engine/logsys.h
index df1db1d4..6b26a9fb 100644
--- a/include/corosync/engine/logsys.h
+++ b/include/corosync/engine/logsys.h
@@ -1,457 +1,464 @@
/*
* Copyright (c) 2002-2004 MontaVista Software, Inc.
* Copyright (c) 2006-2009 Red Hat, Inc.
*
* Author: Steven Dake (sdake@redhat.com)
* Author: Lon Hohberger (lhh@redhat.com)
* Author: Fabio M. Di Nitto (fdinitto@redhat.com)
*
* All rights reserved.
*
* This software licensed under BSD license, the text of which follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the MontaVista Software, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LOGSYS_H_DEFINED
#define LOGSYS_H_DEFINED
#include <stdarg.h>
#include <stdlib.h>
#include <syslog.h>
#include <pthread.h>
#include <limits.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* All of the LOGSYS_MODE's can be ORed together for combined behavior
*
* FORK and THREADED are ignored for SUBSYSTEMS
*/
#define LOGSYS_MODE_OUTPUT_FILE (1<<0)
#define LOGSYS_MODE_OUTPUT_STDERR (1<<1)
#define LOGSYS_MODE_OUTPUT_SYSLOG (1<<2)
#define LOGSYS_MODE_FORK (1<<3)
#define LOGSYS_MODE_THREADED (1<<4)
+
/*
* Log priorities, compliant with syslog and SA Forum Log spec.
*/
#define LOGSYS_LEVEL_EMERG LOG_EMERG
#define LOGSYS_LEVEL_ALERT LOG_ALERT
#define LOGSYS_LEVEL_CRIT LOG_CRIT
#define LOGSYS_LEVEL_ERROR LOG_ERR
#define LOGSYS_LEVEL_WARNING LOG_WARNING
#define LOGSYS_LEVEL_NOTICE LOG_NOTICE
#define LOGSYS_LEVEL_INFO LOG_INFO
#define LOGSYS_LEVEL_DEBUG LOG_DEBUG
/*
* All of the LOGSYS_RECID's are mutually exclusive. Only one RECID at any time
* can be specified.
*
* RECID_LOG indicates a message that should be sent to log. Anything else
* is stored only in the flight recorder.
*/
#define LOGSYS_RECID_MAX ((UINT_MAX) >> LOGSYS_SUBSYSID_END)
#define LOGSYS_RECID_LOG (LOGSYS_RECID_MAX - 1)
#define LOGSYS_RECID_ENTER (LOGSYS_RECID_MAX - 2)
#define LOGSYS_RECID_LEAVE (LOGSYS_RECID_MAX - 3)
#define LOGSYS_RECID_TRACE1 (LOGSYS_RECID_MAX - 4)
#define LOGSYS_RECID_TRACE2 (LOGSYS_RECID_MAX - 5)
#define LOGSYS_RECID_TRACE3 (LOGSYS_RECID_MAX - 6)
#define LOGSYS_RECID_TRACE4 (LOGSYS_RECID_MAX - 7)
#define LOGSYS_RECID_TRACE5 (LOGSYS_RECID_MAX - 8)
#define LOGSYS_RECID_TRACE6 (LOGSYS_RECID_MAX - 9)
#define LOGSYS_RECID_TRACE7 (LOGSYS_RECID_MAX - 10)
#define LOGSYS_RECID_TRACE8 (LOGSYS_RECID_MAX - 11)
+/*
+ * Debug levels
+ */
+#define LOGSYS_DEBUG_OFF 0
+#define LOGSYS_DEBUG_ON 1
+#define LOGSYS_DEBUG_TRACE 2
/*
* Internal APIs that must be globally exported
* (External API below)
*/
/*
* logsys_logger bits
*
* SUBSYS_COUNT defines the maximum number of subsystems
* SUBSYS_NAMELEN defines the maximum len of a subsystem name
*/
#define LOGSYS_MAX_SUBSYS_COUNT 64
#define LOGSYS_MAX_SUBSYS_NAMELEN 64
/*
* rec_ident explained:
*
* rec_ident is an unsigned int and carries bitfields information
* on subsys_id, log priority (level) and type of message (RECID).
*
* level values are imported from syslog.h.
* At the time of writing it's a 3 bits value (0 to 7).
*
* subsys_id is any value between 0 and 64 (LOGSYS_MAX_SUBSYS_COUNT)
*
* RECID identifies the type of message. A set of predefined values
* are available via logsys, but other custom values can be defined
* by users.
*
* ----
* bitfields:
*
* 0 - 2 level
* 3 - 9 subsysid
* 10 - n RECID
*/
#define LOGSYS_LEVEL_END (3)
#define LOGSYS_SUBSYSID_END (LOGSYS_LEVEL_END + 7)
#define LOGSYS_RECID_LEVEL_MASK (LOG_PRIMASK)
#define LOGSYS_RECID_SUBSYSID_MASK ((2 << (LOGSYS_SUBSYSID_END - 1)) - \
(LOG_PRIMASK + 1))
#define LOGSYS_RECID_RECID_MASK (UINT_MAX - \
(LOGSYS_RECID_SUBSYSID_MASK + LOG_PRIMASK))
#define LOGSYS_ENCODE_RECID(level,subsysid,recid) \
(((recid) << LOGSYS_SUBSYSID_END) | \
((subsysid) << LOGSYS_LEVEL_END) | \
(level))
#define LOGSYS_DECODE_LEVEL(rec_ident) \
((rec_ident) & LOGSYS_RECID_LEVEL_MASK)
#define LOGSYS_DECODE_SUBSYSID(rec_ident) \
(((rec_ident) & LOGSYS_RECID_SUBSYSID_MASK) >> LOGSYS_LEVEL_END)
#define LOGSYS_DECODE_RECID(rec_ident) \
(((rec_ident) & LOGSYS_RECID_RECID_MASK) >> LOGSYS_SUBSYSID_END)
#define LOGSYS_MAX_PERROR_MSG_LEN 128
#ifdef COROSYNC_LINUX
/* The GNU version of strerror_r returns a (char*) that *must* be used */
#define LOGSYS_STRERROR_R(out_ptr, err_num, buffer, sizeof_buffer) \
out_ptr = strerror_r(err_num, buffer, sizeof_buffer);
#else
/* The XSI-compliant strerror_r() return 0 or -1 (in case the buffer is full) */
#define LOGSYS_STRERROR_R(out_ptr, err_num, buffer, sizeof_buffer) do { \
if ( strerror_r(err_num, buffer, sizeof_buffer) == 0 ) { \
out_ptr = buffer; \
} else { \
out_ptr = ""; \
} \
} while(0)
#endif
#define LOGSYS_PERROR(err_num, level, fmt, args...) do { \
char _error_str[LOGSYS_MAX_PERROR_MSG_LEN]; \
const char *_error_ptr; \
LOGSYS_STRERROR_R(_error_ptr, err_num, _error_str, sizeof(_error_str)); \
log_printf(level, fmt ": %s (%d)\n", ##args, _error_ptr, err_num); \
} while(0)
#ifndef LOGSYS_UTILS_ONLY
extern int _logsys_system_setup(
const char *mainsystem,
unsigned int mode,
unsigned int debug,
const char *logfile,
int logfile_priority,
int syslog_facility,
int syslog_priority);
extern int _logsys_config_subsys_get (
const char *subsys);
extern int _logsys_subsys_create (const char *subsys);
extern int _logsys_rec_init (unsigned int size);
extern void _logsys_log_vprintf (
unsigned int rec_ident,
const char *function_name,
const char *file_name,
int file_line,
const char *format,
va_list ap) __attribute__((format(printf, 5, 0)));
extern void _logsys_log_printf (
unsigned int rec_ident,
const char *function_name,
const char *file_name,
int file_line,
const char *format,
...) __attribute__((format(printf, 5, 6)));
extern void _logsys_log_rec (
unsigned int rec_ident,
const char *function_name,
const char *file_name,
int file_line,
...);
extern int _logsys_wthread_create (void);
static int logsys_subsys_id __attribute__((unused)) = LOGSYS_MAX_SUBSYS_COUNT;
/*
* External API - init
* See below:
*
* LOGSYS_DECLARE_SYSTEM
* LOGSYS_DECLARE_SUBSYS
*
*/
extern void logsys_fork_completed (void);
extern void logsys_atexit (void);
/*
* External API - misc
*/
extern void logsys_flush (void);
extern int logsys_log_rec_store (const char *filename);
/*
* External API - configuration
*/
/*
* configuration bits that can only be done for the whole system
*/
extern int logsys_format_set (
const char *format);
extern char *logsys_format_get (void);
/*
* per system/subsystem settings.
*
* NOTE: once a subsystem is created and configured, changing
* the default does NOT affect the subsystems.
*
* Pass a NULL subsystem to change them all
*/
extern int logsys_config_syslog_facility_set (
const char *subsys,
unsigned int facility);
extern int logsys_config_syslog_priority_set (
const char *subsys,
unsigned int priority);
extern int logsys_config_mode_set (
const char *subsys,
unsigned int mode);
extern unsigned int logsys_config_mode_get (
const char *subsys);
/*
* to close a logfile, just invoke this function with a NULL
* file or if you want to change logfile, the old one will
* be closed for you.
*/
extern int logsys_config_file_set (
const char *subsys,
const char **error_string,
const char *file);
extern int logsys_config_logfile_priority_set (
const char *subsys,
unsigned int priority);
/*
* enabling debug, disable message priority filtering.
* everything is sent everywhere. priority values
* for file and syslog are not overwritten.
*/
extern int logsys_config_debug_set (
const char *subsys,
unsigned int value);
/*
* External API - helpers
*
* convert facility/priority to/from name/values
*/
extern int logsys_facility_id_get (
const char *name);
extern const char *logsys_facility_name_get (
unsigned int facility);
extern int logsys_priority_id_get (
const char *name);
extern const char *logsys_priority_name_get (
unsigned int priority);
extern int logsys_thread_priority_set (
int policy,
const struct sched_param *param,
unsigned int after_log_ops_yield);
/*
* External definitions
*/
extern void *logsys_rec_end;
#define LOGSYS_REC_END (&logsys_rec_end)
#define LOGSYS_DECLARE_SYSTEM(name,mode,debug,file,file_priority, \
syslog_facility,syslog_priority,format,fltsize) \
__attribute__ ((constructor)) \
static void logsys_system_init (void) \
{ \
if (_logsys_system_setup (name,mode,debug,file,file_priority, \
syslog_facility,syslog_priority) < 0) { \
fprintf (stderr, \
"Unable to setup logging system: %s.\n", name); \
exit (-1); \
} \
\
if (logsys_format_set (format) == -1) { \
fprintf (stderr, \
"Unable to setup logging format.\n"); \
exit (-1); \
} \
\
if (_logsys_rec_init (fltsize) < 0) { \
fprintf (stderr, \
"Unable to initialize log flight recorder.\n"); \
exit (-1); \
} \
\
if (_logsys_wthread_create() < 0) { \
fprintf (stderr, \
"Unable to initialize logging thread.\n"); \
exit (-1); \
} \
}
#define LOGSYS_DECLARE_SUBSYS(subsys) \
__attribute__ ((constructor)) \
static void logsys_subsys_init (void) \
{ \
logsys_subsys_id = \
_logsys_subsys_create ((subsys)); \
if (logsys_subsys_id == -1) { \
fprintf (stderr, \
"Unable to create logging subsystem: %s.\n", subsys); \
exit (-1); \
} \
}
#define log_rec(rec_ident, args...) \
do { \
_logsys_log_rec (rec_ident, __FUNCTION__, \
__FILE__, __LINE__, ##args, \
LOGSYS_REC_END); \
} while(0)
#define log_printf(level, format, args...) \
do { \
_logsys_log_printf ( \
LOGSYS_ENCODE_RECID(level, \
logsys_subsys_id, \
LOGSYS_RECID_LOG), \
__FUNCTION__, __FILE__, __LINE__, \
format, ##args); \
} while(0)
#define ENTER() do { \
_logsys_log_rec ( \
LOGSYS_ENCODE_RECID(LOGSYS_LEVEL_DEBUG, \
logsys_subsys_id, \
LOGSYS_RECID_ENTER), \
__FUNCTION__, __FILE__, __LINE__, LOGSYS_REC_END); \
} while(0)
#define LEAVE() do { \
_logsys_log_rec ( \
LOGSYS_ENCODE_RECID(LOGSYS_LEVEL_DEBUG, \
logsys_subsys_id, \
LOGSYS_RECID_LEAVE), \
__FUNCTION__, __FILE__, __LINE__, LOGSYS_REC_END); \
} while(0)
#define TRACE(recid, format, args...) do { \
_logsys_log_printf ( \
LOGSYS_ENCODE_RECID(LOGSYS_LEVEL_DEBUG, \
logsys_subsys_id, \
recid), \
__FUNCTION__, __FILE__, __LINE__, \
format, ##args); \
} while(0)
#define TRACE1(format, args...) do { \
TRACE(LOGSYS_RECID_TRACE1, format, ##args); \
} while(0)
#define TRACE2(format, args...) do { \
TRACE(LOGSYS_RECID_TRACE2, format, ##args); \
} while(0)
#define TRACE3(format, args...) do { \
TRACE(LOGSYS_RECID_TRACE3, format, ##args); \
} while(0)
#define TRACE4(format, args...) do { \
TRACE(LOGSYS_RECID_TRACE4, format, ##args); \
} while(0)
#define TRACE5(format, args...) do { \
TRACE(LOGSYS_RECID_TRACE5, format, ##args); \
} while(0)
#define TRACE6(format, args...) do { \
TRACE(LOGSYS_RECID_TRACE6, format, ##args); \
} while(0)
#define TRACE7(format, args...) do { \
TRACE(LOGSYS_RECID_TRACE7, format, ##args); \
} while(0)
#define TRACE8(format, args...) do { \
TRACE(LOGSYS_RECID_TRACE8, format, ##args); \
} while(0)
#endif /* LOGSYS_UTILS_ONLY */
#ifdef __cplusplus
}
#endif
#endif /* LOGSYS_H_DEFINED */
diff --git a/man/corosync.conf.5 b/man/corosync.conf.5
index 82ec80ec..bad97008 100644
--- a/man/corosync.conf.5
+++ b/man/corosync.conf.5
@@ -1,646 +1,647 @@
.\"/*
.\" * Copyright (c) 2005 MontaVista Software, Inc.
.\" * Copyright (c) 2006-2010 Red Hat, Inc.
.\" *
.\" * All rights reserved.
.\" *
.\" * Author: Steven Dake (sdake@redhat.com)
.\" *
.\" * This software licensed under BSD license, the text of which follows:
.\" *
.\" * Redistribution and use in source and binary forms, with or without
.\" * modification, are permitted provided that the following conditions are met:
.\" *
.\" * - Redistributions of source code must retain the above copyright notice,
.\" * this list of conditions and the following disclaimer.
.\" * - Redistributions in binary form must reproduce the above copyright notice,
.\" * this list of conditions and the following disclaimer in the documentation
.\" * and/or other materials provided with the distribution.
.\" * - Neither the name of the MontaVista Software, Inc. nor the names of its
.\" * contributors may be used to endorse or promote products derived from this
.\" * software without specific prior written permission.
.\" *
.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
.\" * THE POSSIBILITY OF SUCH DAMAGE.
.\" */
.TH COROSYNC_CONF 5 2006-03-28 "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
.SH NAME
corosync.conf - corosync executive configuration file
.SH SYNOPSIS
/etc/corosync.conf
.SH DESCRIPTION
The corosync.conf instructs the corosync executive about various parameters
needed to control the corosync executive. Empty lines and lines starting with
# character are ignored. The configuration file consists of bracketed top level
directives. The possible directive choices are:
.TP
totem { }
This top level directive contains configuration options for the totem protocol.
.TP
logging { }
This top level directive contains configuration options for logging.
.TP
event { }
This top level directive contains configuration options for the event service.
.PP
.PP
It is also possible to specify the top level parameter
.B compatibility.
This directive indicates the level of compatibility requested by the user. The
option whitetank can be specified to remain backward compatable with
openais-0.80.z. The option none can be specified to only be compatable
with corosync-1.Y.Z. Extra processing during configuration changes is
required to remain backward compatable.
The default is whitetank. (backwards compatibility)
.PP
.PP
Within the
.B totem
directive, an interface directive is required. There is also one configuration
option which is required:
.PP
.PP
Within the
.B interface
sub-directive of totem there are four parameters which are required. There is
one parameter which is optional.
.TP
ringnumber
This specifies the ring number for the interface. When using the redundant
ring protocol, each interface should specify separate ring numbers to uniquely
identify to the membership protocol which interface to use for which redundant
ring. The ringnumber must start at 0.
.TP
bindnetaddr
This specifies the network address the corosync executive should bind
to. For example, if the local interface is 192.168.5.92 with netmask
255.255.255.0, set bindnetaddr to 192.168.5.0. If the local interface
is 192.168.5.92 with netmask 255.255.255.192, set bindnetaddr to
192.168.5.64, and so forth.
This may also be an IPV6 address, in which case IPV6 networking will be used.
In this case, the full address must be specified and there is no automatic
selection of the network interface within a specific subnet as with IPv4.
If IPv6 networking is used, the nodeid field must be specified.
.TP
broadcast
This is optional and can be set to yes. If it is set to yes, the broadcast
address will be used for communication. If this option is set, mcastaddr
should not be set.
.TP
mcastaddr
This is the multicast address used by corosync executive. The default
should work for most networks, but the network administrator should be queried
about a multicast address to use. Avoid 224.x.x.x because this is a "config"
multicast address.
This may also be an IPV6 multicast address, in which case IPV6 networking
will be used. If IPv6 networking is used, the nodeid field must be specified.
.TP
mcastport
This specifies the UDP port number. It is possible to use the same multicast
address on a network with the corosync services configured for different
UDP ports.
Please note corosync uses two UDP ports mcastport (for mcast receives) and
mcastport - 1 (for mcast sends).
If you have multiple clusters on the same network using the same mcastaddr
please configure the mcastports with a gap.
.TP
ttl
This specifies the Time To Live (TTL). If you run your cluster on a routed
network then the default of "1" will be too small. This option provides
a way to increase this up to 255. The valid range is 0..255.
Note that this is only valid on multicast transport types.
.TP
member
This specifies a member on the interface and used with the udpu transport only.
Every node that should be a member of the membership should be specified as
a separate member directive. Within the member directive there is a parameter
memberaddr which specifies the ip address of one of the nodes.
.PP
.PP
Within the
.B totem
directive, there are seven configuration options of which one is required,
five are optional, and one is required when IPV6 is configured in the interface
subdirective. The required directive controls the version of the totem
configuration. The optional option unless using IPV6 directive controls
identification of the processor. The optional options control secrecy and
authentication, the redundant ring mode of operation, maximum network MTU,
and number of sending threads, and the nodeid field.
.TP
version
This specifies the version of the configuration file. Currently the only
valid version for this directive is 2.
.PP
.PP
.TP
nodeid
This configuration option is optional when using IPv4 and required when using
IPv6. This is a 32 bit value specifying the node identifier delivered to the
cluster membership service. If this is not specified with IPv4, the node id
will be determined from the 32 bit IP address the system to which the system
is bound with ring identifier of 0. The node identifier value of zero is
reserved and should not be used.
.TP
clear_node_high_bit
This configuration option is optional and is only relevant when no nodeid is
specified. Some openais clients require a signed 32 bit nodeid that is greater
than zero however by default openais uses all 32 bits of the IPv4 address space
when generating a nodeid. Set this option to yes to force the high bit to be
zero and therefor ensure the nodeid is a positive signed 32 bit integer.
WARNING: The clusters behavior is undefined if this option is enabled on only
a subset of the cluster (for example during a rolling upgrade).
.TP
secauth
This specifies that HMAC/SHA1 authentication should be used to authenticate
all messages. It further specifies that all data should be encrypted with the
sober128 encryption algorithm to protect data from eavesdropping.
Enabling this option adds a 36 byte header to every message sent by totem which
reduces total throughput. Encryption and authentication consume 75% of CPU
cycles in aisexec as measured with gprof when enabled.
For 100mbit networks with 1500 MTU frame transmissions:
A throughput of 9mb/sec is possible with 100% cpu utilization when this
option is enabled on 3ghz cpus.
A throughput of 10mb/sec is possible wth 20% cpu utilization when this
optin is disabled on 3ghz cpus.
For gig-e networks with large frame transmissions:
A throughput of 20mb/sec is possible when this option is enabled on
3ghz cpus.
A throughput of 60mb/sec is possible when this option is disabled on
3ghz cpus.
The default is on.
.TP
rrp_mode
This specifies the mode of redundant ring, which may be none, active, or
passive. Active replication offers slightly lower latency from transmit
to delivery in faulty network environments but with less performance.
Passive replication may nearly double the speed of the totem protocol
if the protocol doesn't become cpu bound. The final option is none, in
which case only one network interface will be used to operate the totem
protocol.
If only one interface directive is specified, none is automatically chosen.
If multiple interface directives are specified, only active or passive may
be chosen.
.TP
netmtu
This specifies the network maximum transmit unit. To set this value beyond
1500, the regular frame MTU, requires ethernet devices that support large, or
also called jumbo, frames. If any device in the network doesn't support large
frames, the protocol will not operate properly. The hosts must also have their
mtu size set from 1500 to whatever frame size is specified here.
Please note while some NICs or switches claim large frame support, they support
9000 MTU as the maximum frame size including the IP header. Setting the netmtu
and host MTUs to 9000 will cause totem to use the full 9000 bytes of the frame.
Then Linux will add a 18 byte header moving the full frame size to 9018. As a
result some hardware will not operate properly with this size of data. A netmtu
of 8982 seems to work for the few large frame devices that have been tested.
Some manufacturers claim large frame support when in fact they support frame
sizes of 4500 bytes.
Increasing the MTU from 1500 to 8982 doubles throughput performance from 30MB/sec
to 60MB/sec as measured with evsbench with 175000 byte messages with the secauth
directive set to off.
When sending multicast traffic, if the network frequently reconfigures, chances are
that some device in the network doesn't support large frames.
Choose hardware carefully if intending to use large frame support.
The default is 1500.
.TP
threads
This directive controls how many threads are used to encrypt and send multicast
messages. If secauth is off, the protocol will never use threaded sending.
If secauth is on, this directive allows systems to be configured to use
multiple threads to encrypt and send multicast messages.
A thread directive of 0 indicates that no threaded send should be used. This
mode offers best performance for non-SMP systems.
The default is 0.
.TP
vsftype
This directive controls the virtual synchrony filter type used to identify
a primary component. The preferred choice is YKD dynamic linear voting,
however, for clusters larger then 32 nodes YKD consumes alot of memory. For
large scale clusters that are created by changing the MAX_PROCESSORS_COUNT
#define in the C code totem.h file, the virtual synchrony filter "none" is
recommended but then AMF and DLCK services (which are currently experimental)
are not safe for use.
The default is ykd. The vsftype can also be set to none.
.TP
transport
This directive controls the transport mechanism used. If the interface to
which corosync is binding is an RDMA interface such as RoCEE or Infiniband, the
"iba" parameter may be specified. To avoid the use of multicast entirely, a
unicast transport parameter "udpu" can be specified. This requires specifying
the list of members that could potentially make up the membership before
deployment.
The default is udp. The transport type can also be set to udpu or iba.
Within the
.B totem
directive, there are several configuration options which are used to control
the operation of the protocol. It is generally not recommended to change any
of these values without proper guidance and sufficient testing. Some networks
may require larger values if suffering from frequent reconfigurations. Some
applications may require faster failure detection times which can be achieved
by reducing the token timeout.
.TP
token
This timeout specifies in milliseconds until a token loss is declared after not
receiving a token. This is the time spent detecting a failure of a processor
in the current configuration. Reforming a new configuration takes about 50
milliseconds in addition to this timeout.
The default is 1000 milliseconds.
.TP
token_retransmit
This timeout specifies in milliseconds after how long before receiving a token
the token is retransmitted. This will be automatically calculated if token
is modified. It is not recommended to alter this value without guidance from
the corosync community.
The default is 238 milliseconds.
.TP
hold
This timeout specifies in milliseconds how long the token should be held by
the representative when the protocol is under low utilization. It is not
recommended to alter this value without guidance from the corosync community.
The default is 180 milliseconds.
.TP
token_retransmits_before_loss_const
This value identifies how many token retransmits should be attempted before
forming a new configuration. If this value is set, retransmit and hold will
be automatically calculated from retransmits_before_loss and token.
The default is 4 retransmissions.
.TP
join
This timeout specifies in milliseconds how long to wait for join messages in
the membership protocol.
The default is 50 milliseconds.
.TP
send_join
This timeout specifies in milliseconds an upper range between 0 and send_join
to wait before sending a join message. For configurations with less then
32 nodes, this parameter is not necessary. For larger rings, this parameter
is necessary to ensure the NIC is not overflowed with join messages on
formation of a new ring. A reasonable value for large rings (128 nodes) would
be 80msec. Other timer values must also change if this value is changed. Seek
advice from the corosync mailing list if trying to run larger configurations.
The default is 0 milliseconds.
.TP
consensus
This timeout specifies in milliseconds how long to wait for consensus to be
achieved before starting a new round of membership configuration. The minimum
value for consensus must be 1.2 * token. This value will be automatically
calculated at 1.2 * token if the user doesn't specify a consensus value.
For two node clusters, a consensus larger then the join timeout but less then
token is safe. For three node or larger clusters, consensus should be larger
then token. There is an increasing risk of odd membership changes, which stil
guarantee virtual synchrony, as node count grows if consensus is less than
token.
The default is 1200 milliseconds.
.TP
merge
This timeout specifies in milliseconds how long to wait before checking for
a partition when no multicast traffic is being sent. If multicast traffic
is being sent, the merge detection happens automatically as a function of
the protocol.
The default is 200 milliseconds.
.TP
downcheck
This timeout specifies in milliseconds how long to wait before checking
that a network interface is back up after it has been downed.
The default is 1000 millseconds.
.TP
fail_recv_const
This constant specifies how many rotations of the token without receiving any
of the messages when messages should be received may occur before a new
configuration is formed.
The default is 2500 failures to receive a message.
.TP
seqno_unchanged_const
This constant specifies how many rotations of the token without any multicast
traffic should occur before the hold timer is started.
The default is 30 rotations.
.TP
heartbeat_failures_allowed
[HeartBeating mechanism]
Configures the optional HeartBeating mechanism for faster failure detection. Keep in
mind that engaging this mechanism in lossy networks could cause faulty loss declaration
as the mechanism relies on the network for heartbeating.
So as a rule of thumb use this mechanism if you require improved failure in low to
medium utilized networks.
This constant specifies the number of heartbeat failures the system should tolerate
before declaring heartbeat failure e.g 3. Also if this value is not set or is 0 then the
heartbeat mechanism is not engaged in the system and token rotation is the method
of failure detection
The default is 0 (disabled).
.TP
max_network_delay
[HeartBeating mechanism]
This constant specifies in milliseconds the approximate delay that your network takes
to transport one packet from one machine to another. This value is to be set by system
engineers and please dont change if not sure as this effects the failure detection
mechanism using heartbeat.
The default is 50 milliseconds.
.TP
window_size
This constant specifies the maximum number of messages that may be sent on one
token rotation. If all processors perform equally well, this value could be
large (300), which would introduce higher latency from origination to delivery
for very large rings. To reduce latency in large rings(16+), the defaults are
a safe compromise. If 1 or more slow processor(s) are present among fast
processors, window_size should be no larger then 256000 / netmtu to avoid
overflow of the kernel receive buffers. The user is notified of this by
the display of a retransmit list in the notification logs. There is no loss
of data, but performance is reduced when these errors occur.
The default is 50 messages.
.TP
max_messages
This constant specifies the maximum number of messages that may be sent by one
processor on receipt of the token. The max_messages parameter is limited to
256000 / netmtu to prevent overflow of the kernel transmit buffers.
The default is 17 messages.
.TP
miss_count_const
This constant defines the maximum number of times on receipt of a token
a message is checked for retransmission before a retransmission occurs. This
parameter is useful to modify for switches that delay multicast packets
compared to unicast packets. The default setting works well for nearly all
modern switches.
The default is 5 messages.
.TP
rrp_problem_count_timeout
This specifies the time in milliseconds to wait before decrementing the
problem count by 1 for a particular ring to ensure a link is not marked
faulty for transient network failures.
The default is 2000 milliseconds.
.TP
rrp_problem_count_threshold
This specifies the number of times a problem is detected with a link before
setting the link faulty. Once a link is set faulty, no more data is
transmitted upon it. Also, the problem counter is no longer decremented when
the problem count timeout expires.
A problem is detected whenever all tokens from the proceeding processor have
not been received within the rrp_token_expired_timeout. The
rrp_problem_count_threshold * rrp_token_expired_timeout should be atleast 50
milliseconds less then the token timeout, or a complete reconfiguration
may occur.
The default is 10 problem counts.
.TP
rrp_problem_count_mcast_threshold
This specifies the number of times a problem is detected with multicast before
setting the link faulty for passive rrp mode. This variable is unused in active
rrp mode.
The default is 10 times rrp_problem_count_threshold.
.TP
rrp_token_expired_timeout
This specifies the time in milliseconds to increment the problem counter for
the redundant ring protocol after not having received a token from all rings
for a particular processor.
This value will automatically be calculated from the token timeout and
problem_count_threshold but may be overridden. It is not recommended to
override this value without guidance from the corosync community.
The default is 47 milliseconds.
.TP
rrp_autorecovery_check_timeout
This specifies the time in milliseconds to check if the failed ring can be
auto-recovered.
The default is 1000 milliseconds.
.PP
Within the
.B logging
directive, there are several configuration options which are all optional.
.PP
The following 3 options are valid only for the top level logging directive:
.TP
timestamp
This specifies that a timestamp is placed on all log messages.
The default is off.
.TP
fileline
This specifies that file and line should be printed.
The default is off.
.TP
function_name
This specifies that the code function name should be printed.
The default is off.
.PP
The following options are valid both for top level logging directive
and they can be overriden in logger_subsys entries.
.TP
to_stderr
.TP
to_logfile
.TP
to_syslog
These specify the destination of logging output. Any combination of
these options may be specified. Valid options are
.B yes
and
.B no.
The default is syslog and stderr.
Please note, if you are using to_logfile and want to rotate the file, use logrotate(8)
with the option
.B
copytruncate.
eg.
.IP
.RS
.ne 18
.nf
.ta 4n 30n 33n
/var/log/corosync.log {
missingok
compress
notifempty
daily
rotate 7
copytruncate
}
.ta
.fi
.RE
.IP
.PP
.TP
logfile
If the
.B to_logfile
directive is set to
.B yes
, this option specifies the pathname of the log file.
No default.
.TP
logfile_priority
This specifies the logfile priority for this particular subsystem. Ignored if debug is on.
Possible values are: alert, crit, debug (same as debug = on), emerg, err, info, notice, warning.
The default is: info.
.TP
syslog_facility
This specifies the syslog facility type that will be used for any messages
sent to syslog. options are daemon, local0, local1, local2, local3, local4,
local5, local6 & local7.
The default is daemon.
.TP
syslog_priority
This specifies the syslog level for this particular subsystem. Ignored if debug is on.
Possible values are: alert, crit, debug (same as debug = on), emerg, err, info, notice, warning.
The default is: info.
.TP
debug
-This specifies whether debug output is logged for this particular logger.
+This specifies whether debug output is logged for this particular logger. Also can contain
+value trace, what is highest level of debug informations.
The default is off.
.TP
tags
This specifies which tags should be traced for this particular logger.
Set debug directive to
.B on
in order to enable tracing using tags.
Values are specified using a vertical bar as a logical OR separator:
enter|leave|trace1|trace2|trace3|...
The default is none.
.PP
Within the
.B logging
directive, logger_subsys directives are optional.
.PP
Within the
.B logger_subsys
sub-directive, all of the above logging configuration options are valid and
can be used to override the default settings.
The subsys entry, described below, is mandatory to identify the subsystem.
.TP
subsys
This specifies the subsystem identity (name) for which logging is specified. This is the
name used by a service in the log_init () call. E.g. 'CKPT'. This directive is
required.
.SH "FILES"
.TP
/etc/corosync.conf
The corosync executive configuration file.
.SH "SEE ALSO"
.BR corosync_overview (8),
.BR logrotate (8)
.PP

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 2:33 PM (20 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018788
Default Alt Text
(97 KB)

Event Timeline