#include "replace.h"
#include "system/filesys.h"
#include "system/network.h"
-#include "system/syslog.h"
#include "system/time.h"
#include <talloc.h>
const char *debug_extra = "";
-struct ctdb_log_backend {
- struct ctdb_log_backend *prev, *next;
- const char *prefix;
- ctdb_log_setup_fn_t setup;
-};
-
struct ctdb_log_state {
const char *prefix;
int fd, pfd;
uint16_t buf_used;
void (*logfn)(const char *, uint16_t, void *);
void *logfn_private;
- struct ctdb_log_backend *backends;
};
/* Used by ctdb_set_child_logging() */
static struct ctdb_log_state *log_state;
-void ctdb_log_register_backend(const char *prefix, ctdb_log_setup_fn_t setup)
-{
- struct ctdb_log_backend *b;
-
- b = talloc_zero(log_state, struct ctdb_log_backend);
- if (b == NULL) {
- printf("Failed to register backend \"%s\" - no memory\n",
- prefix);
- return;
- }
-
- b->prefix = prefix;
- b->setup = setup;
-
- DLIST_ADD_END(log_state->backends, b);
-}
-
-
/* Initialise logging */
bool ctdb_logging_init(TALLOC_CTX *mem_ctx, const char *logging)
{
- struct ctdb_log_backend *b;
int ret;
log_state = talloc_zero(mem_ctx, struct ctdb_log_state);
if (log_state == NULL) {
- printf("talloc_zero failed\n");
- abort();
+ return false;
}
- ctdb_log_init_file();
- ctdb_log_init_syslog();
-
- for (b = log_state->backends; b != NULL; b = b->next) {
- size_t l = strlen(b->prefix);
- /* Exact match with prefix or prefix followed by ':' */
- if (strncmp(b->prefix, logging, l) == 0 &&
- (logging[l] == '\0' || logging[l] == ':')) {
- ret = b->setup(mem_ctx, logging, "ctdbd");
- if (ret == 0) {
- return true;
- }
- printf("Log init for \"%s\" failed with \"%s\"\n",
- logging, strerror(ret));
- return false;
- }
+ ret = logging_init(mem_ctx, logging, NULL, "ctdbd");
+ if (ret != 0) {
+ return false;
}
- printf("Unable to find log backend for \"%s\"\n", logging);
- return false;
+ return true;
}
/* Note that do_debug always uses the global log state. */
int old_stdout, old_stderr;
struct tevent_fd *fde;
- if (log_state->fd == STDOUT_FILENO) {
- /* not needed for stdout logging */
- return 0;
- }
-
/* setup a pipe to catch IO from subprocesses */
if (pipe(p) != 0) {
DEBUG(DEBUG_ERR,(__location__ " Failed to setup for child logging pipe\n"));
+++ /dev/null
-/*
- ctdb logging code
-
- Copyright (C) Andrew Tridgell 2008
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "replace.h"
-#include "system/time.h"
-#include "system/filesys.h"
-#include "system/network.h"
-
-#include <talloc.h>
-
-#include "lib/util/debug.h"
-#include "lib/util/sys_rw.h"
-#include "lib/util/time_basic.h"
-
-#include "ctdb_private.h"
-#include "ctdb_client.h"
-
-#define CTDB_LOG_FILE_PREFIX "file"
-
-struct file_state {
- int fd;
-};
-
-/*
- log file logging function
- */
-static void ctdb_log_to_file(void *private_ptr, int dbglevel, const char *s)
-{
- struct file_state *state = talloc_get_type(
- private_ptr, struct file_state);
- struct timeval tv;
- struct timeval_buf tvbuf;
- char *s2 = NULL;
- int ret;
-
- GetTimeOfDay(&tv);
- timeval_str_buf(&tv, false, true, &tvbuf);
-
- ret = asprintf(&s2, "%s [%s%5u]: %s\n",
- tvbuf.buf,
- debug_extra, (unsigned)getpid(), s);
- if (ret == -1) {
- const char *errstr = "asprintf failed\n";
- sys_write(state->fd, errstr, strlen(errstr));
- return;
- }
- if (s2) {
- sys_write(state->fd, s2, strlen(s2));
- free(s2);
- }
-}
-
-static int file_state_destructor(struct file_state *state)
-{
- close(state->fd);
- state->fd = -1;
- return 0;
-}
-
-static int ctdb_log_setup_file(TALLOC_CTX *mem_ctx,
- const char *logging,
- const char *app_name)
-{
- struct file_state *state;
- const char *logfile;
- size_t l;
-
- l = strlen(CTDB_LOG_FILE_PREFIX);
- if (logging[l] != ':') {
- return EINVAL;
- }
- logfile = &logging[0] + l + 1;
-
- state = talloc_zero(mem_ctx, struct file_state);
- if (state == NULL) {
- return ENOMEM;
- }
-
- if (logfile == NULL || strcmp(logfile, "-") == 0) {
- int ret;
-
- state->fd = 1;
- /* also catch stderr of subcommands to stdout */
- ret = dup2(1, 2);
- if (ret == -1) {
- return errno;
- }
- } else {
- state->fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT, 0666);
- if (state->fd == -1) {
- return errno;
- }
- }
-
- talloc_set_destructor(state, file_state_destructor);
- debug_set_callback(state, ctdb_log_to_file);
-
- return 0;
-}
-
-void ctdb_log_init_file(void)
-{
- ctdb_log_register_backend(CTDB_LOG_FILE_PREFIX, ctdb_log_setup_file);
-}
+++ /dev/null
-/*
- ctdb logging code - syslog backend
-
- Copyright (C) Andrew Tridgell 2008
- Copyright (C) Martin Schwenke 2014
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "replace.h"
-#include "system/network.h"
-#include "system/syslog.h"
-
-#include "lib/util/debug.h"
-#include "lib/util/blocking.h"
-#include "lib/util/time_basic.h"
-#include "lib/util/samba_util.h" /* get_myname */
-
-#include "ctdb_private.h"
-
-#include "common/logging.h"
-
-/* Linux and FreeBSD define this appropriately - try good old /dev/log
- * for anything that doesn't... */
-#ifndef _PATH_LOG
-#define _PATH_LOG "/dev/log"
-#endif
-
-#define CTDB_LOG_SYSLOG_PREFIX "syslog"
-#define CTDB_SYSLOG_FACILITY LOG_USER
-
-struct ctdb_syslog_sock_state {
- int fd;
- const char *app_name;
- const char *hostname;
- int (*format)(int dbglevel, struct ctdb_syslog_sock_state *state,
- const char *str, char *buf, int bsize);
-};
-
-/**********************************************************************/
-
-static int ctdb_debug_to_syslog_level(int dbglevel)
-{
- int level;
-
- switch (dbglevel) {
- case DEBUG_ERR:
- level = LOG_ERR;
- break;
- case DEBUG_WARNING:
- level = LOG_WARNING;
- break;
- case DEBUG_NOTICE:
- level = LOG_NOTICE;
- break;
- case DEBUG_INFO:
- level = LOG_INFO;
- break;
- default:
- level = LOG_DEBUG;
- break;
- }
-
- return level;
-}
-
-/**********************************************************************/
-
-/* Format messages as per RFC3164. */
-
-/* It appears that some syslog daemon implementations do not allow a
- * hostname when messages are sent via a Unix domain socket, so omit
- * it. Similarly, syslogd on FreeBSD does not understand the hostname
- * part of the header, even when logging via UDP. Note that most
- * implementations will log messages against "localhost" when logging
- * via UDP. A timestamp could be sent but rsyslogd on Linux limits
- * the timestamp logged to the precision that was received on
- * /dev/log. It seems sane to send degenerate RFC3164 messages
- * without a header at all, so that the daemon will generate high
- * resolution timestamps if configured. */
-static int format_rfc3164(int dbglevel, struct ctdb_syslog_sock_state *state,
- const char *str, char *buf, int bsize)
-{
- int pri;
- int len;
-
- pri = CTDB_SYSLOG_FACILITY | ctdb_debug_to_syslog_level(dbglevel);
- len = snprintf(buf, bsize, "<%d>%s[%u]: %s%s",
- pri, state->app_name, getpid(), debug_extra, str);
- len = MIN(len, bsize - 1);
-
- return len;
-}
-
-/* Format messages as per RFC5424
- *
- * <165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1
- * myproc 8710 - - %% It's time to make the do-nuts.
- */
-static int format_rfc5424(int dbglevel, struct ctdb_syslog_sock_state *state,
- const char *str, char *buf, int bsize)
-{
- int pri;
- struct timeval tv;
- struct timeval_buf tvbuf;
- int len, s;
-
- /* Header */
- pri = CTDB_SYSLOG_FACILITY | ctdb_debug_to_syslog_level(dbglevel);
- GetTimeOfDay(&tv);
- len = snprintf(buf, bsize,
- "<%d>1 %s %s %s %u - - ",
- pri, timeval_str_buf(&tv, true, true, &tvbuf),
- state->hostname, state->app_name, getpid());
- /* A truncated header is not useful... */
- if (len >= bsize) {
- return -1;
- }
-
- /* Message */
- s = snprintf(&buf[len], bsize - len, "%s %s", debug_extra, str);
- len = MIN(len + s, bsize - 1);
-
- return len;
-}
-
-/**********************************************************************/
-
-/* Non-blocking logging */
-
-static void ctdb_log_to_syslog_sock(void *private_ptr,
- int dbglevel, const char *str)
-{
- struct ctdb_syslog_sock_state *state = talloc_get_type(
- private_ptr, struct ctdb_syslog_sock_state);
-
- /* RFC3164 says: The total length of the packet MUST be 1024
- bytes or less. */
- char buf[1024];
- int n;
-
- n = state->format(dbglevel, state, str, buf, sizeof(buf));
- if (n == -1) {
- fprintf(stderr, "Failed to format syslog message %s\n", str);
- return;
- }
-
- /* Could extend this to count failures, which probably
- * indicate dropped messages due to EAGAIN or EWOULDBLOCK */
- (void)send(state->fd, buf, n, 0);
-}
-
-static int
-ctdb_syslog_sock_state_destructor(struct ctdb_syslog_sock_state *state)
-{
- if (state->fd != -1) {
- close(state->fd);
- state->fd = -1;
- }
- return 0;
-}
-
-static struct ctdb_syslog_sock_state *
-ctdb_log_setup_syslog_common(TALLOC_CTX *mem_ctx,
- const char *app_name)
-{
- struct ctdb_syslog_sock_state *state;
-
- state = talloc_zero(mem_ctx, struct ctdb_syslog_sock_state);
- if (state == NULL) {
- return NULL;
- }
- state->fd = -1;
- state->app_name = app_name;
- talloc_set_destructor(state, ctdb_syslog_sock_state_destructor);
-
- return state;
-}
-
-static int ctdb_log_setup_syslog_un(TALLOC_CTX *mem_ctx,
- const char *app_name)
-{
- struct ctdb_syslog_sock_state *state;
- struct sockaddr_un dest;
- int ret;
-
- state = ctdb_log_setup_syslog_common(mem_ctx, app_name);
- if (state == NULL) {
- return ENOMEM;
- }
-
- state->fd = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (state->fd == -1) {
- int save_errno = errno;
- talloc_free(state);
- return save_errno;
- }
-
- dest.sun_family = AF_UNIX;
- strncpy(dest.sun_path, _PATH_LOG, sizeof(dest.sun_path)-1);
- ret = connect(state->fd,
- (struct sockaddr *)&dest, sizeof(dest));
- if (ret == -1) {
- int save_errno = errno;
- talloc_free(state);
- return save_errno;
- }
-
- ret = set_blocking(state->fd, false);
- if (ret != 0) {
- int save_errno = errno;
- talloc_free(state);
- return save_errno;
- }
-
- state->hostname = NULL; /* Make this explicit */
- state->format = format_rfc3164;
-
- debug_set_callback(state, ctdb_log_to_syslog_sock);
-
- return 0;
-}
-
-static int ctdb_log_setup_syslog_udp(TALLOC_CTX *mem_ctx,
- const char *app_name,
- bool rfc5424)
-{
- struct ctdb_syslog_sock_state *state;
- struct sockaddr_in dest;
- int ret;
-
- state = ctdb_log_setup_syslog_common(mem_ctx, app_name);
- if (state == NULL) {
- return ENOMEM;
- }
-
- state->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (state->fd == -1) {
- int save_errno = errno;
- talloc_free(state);
- return save_errno;
- }
-
- dest.sin_family = AF_INET;
- dest.sin_port = htons(514);
- dest.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- ret = connect(state->fd,
- (struct sockaddr *)&dest, sizeof(dest));
- if (ret == -1) {
- int save_errno = errno;
- talloc_free(state);
- return save_errno;
- }
-
- state->hostname = get_myname(state);
- if (state->hostname == NULL) {
- /* Use a fallback instead of failing initialisation */
- state->hostname = "localhost";
- }
- if (rfc5424) {
- state->format = format_rfc5424;
- } else {
- state->format = format_rfc3164;
- }
-
- debug_set_callback(state, ctdb_log_to_syslog_sock);
-
- return 0;
-}
-
-/**********************************************************************/
-
-static void ctdb_log_to_syslog(void *private_ptr, int dbglevel, const char *s)
-{
- syslog(ctdb_debug_to_syslog_level(dbglevel),
- "%s%s", debug_extra, s);
-}
-
-static int ctdb_log_setup_syslog(TALLOC_CTX *mem_ctx,
- const char *logging,
- const char *app_name)
-{
- size_t l = strlen(CTDB_LOG_SYSLOG_PREFIX);
-
- if (logging[l] != '\0') {
- /* Handle non-blocking extensions here */
- const char *method;
-
- if (logging[l] != ':') {
- return EINVAL;
- }
- method = &logging[0] + l + 1;
- if (strcmp(method, "nonblocking") == 0) {
- ctdb_log_setup_syslog_un(mem_ctx, app_name);
- return 0;
- }
- if (strcmp(method, "udp") == 0) {
- ctdb_log_setup_syslog_udp(mem_ctx, app_name, false);
- return 0;
- }
- if (strcmp(method, "udp-rfc5424") == 0) {
- ctdb_log_setup_syslog_udp(mem_ctx, app_name, true);
- return 0;
- }
-
- return EINVAL;
- }
-
- debug_set_callback(NULL, ctdb_log_to_syslog);
- return 0;
-}
-
-void ctdb_log_init_syslog(void)
-{
- ctdb_log_register_backend(CTDB_LOG_SYSLOG_PREFIX,
- ctdb_log_setup_syslog);
-}