4 Copyright (C) Andrew Tridgell 2008
5 Copyright (C) Martin Schwenke 2014
6 Copyright (C) Amitay Isaacs 2015
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
23 #include "system/network.h"
24 #include "system/locale.h"
25 #include "system/time.h"
26 #include "system/filesys.h"
27 #include "system/syslog.h"
28 #include "system/dir.h"
30 #include "lib/util/time_basic.h"
31 #include "lib/util/sys_rw.h"
32 #include "lib/util/debug.h"
33 #include "lib/util/blocking.h"
34 #include "lib/util/samba_util.h" /* get_myname() */
36 #include "common/logging.h"
40 const char *log_string;
41 } log_string_map[] = {
42 { DEBUG_ERR, "ERROR" },
43 { DEBUG_WARNING, "WARNING" },
45 { DEBUG_NOTICE, "NOTICE" },
47 { DEBUG_INFO, "INFO" },
52 { DEBUG_DEBUG, "DEBUG" },
55 bool debug_level_parse(const char *log_string, int *log_level)
59 if (log_string == NULL) {
63 if (isdigit(log_string[0])) {
64 int level = atoi(log_string);
66 if (level >= 0 && level < ARRAY_SIZE(log_string_map)) {
73 for (i=0; i<ARRAY_SIZE(log_string_map); i++) {
74 if (strncasecmp(log_string_map[i].log_string,
75 log_string, strlen(log_string)) == 0) {
76 *log_level = log_string_map[i].log_level;
84 const char *debug_level_to_string(int log_level)
88 for (i=0; ARRAY_SIZE(log_string_map); i++) {
89 if (log_string_map[i].log_level == log_level) {
90 return log_string_map[i].log_string;
96 int debug_level_from_string(const char *log_string)
101 found = debug_level_parse(log_string, &log_level);
106 /* Default debug level */
111 * file logging backend
114 struct file_log_state {
115 const char *app_name;
120 static void file_log(void *private_data, int level, const char *msg)
122 struct file_log_state *state = talloc_get_type_abort(
123 private_data, struct file_log_state);
125 struct timeval_buf tvbuf;
128 if (state->fd == STDERR_FILENO) {
129 ret = snprintf(state->buffer, sizeof(state->buffer),
131 state->app_name, (unsigned)getpid(), msg);
134 timeval_str_buf(&tv, false, true, &tvbuf);
136 ret = snprintf(state->buffer, sizeof(state->buffer),
137 "%s %s[%u]: %s\n", tvbuf.buf,
138 state->app_name, (unsigned)getpid(), msg);
144 state->buffer[sizeof(state->buffer)-1] = '\0';
146 sys_write_v(state->fd, state->buffer, strlen(state->buffer));
149 static int file_log_state_destructor(struct file_log_state *state)
151 if (state->fd != -1 && state->fd != STDERR_FILENO) {
158 static bool file_log_validate(const char *option)
164 if (option == NULL || strcmp(option, "-") == 0) {
175 ret = stat(dir, &st);
181 if (! S_ISDIR(st.st_mode)) {
189 static int file_log_setup(TALLOC_CTX *mem_ctx, const char *option,
190 const char *app_name)
192 struct file_log_state *state;
194 state = talloc_zero(mem_ctx, struct file_log_state);
199 state->app_name = app_name;
201 if (option == NULL || strcmp(option, "-") == 0) {
204 state->fd = STDERR_FILENO;
205 ret = dup2(STDERR_FILENO, STDOUT_FILENO);
207 int save_errno = errno;
213 state->fd = open(option, O_WRONLY|O_APPEND|O_CREAT, 0644);
214 if (state->fd == -1) {
215 int save_errno = errno;
220 if (! set_close_on_exec(state->fd)) {
221 int save_errno = errno;
227 talloc_set_destructor(state, file_log_state_destructor);
228 debug_set_callback(state, file_log);
234 * syslog logging backend
237 /* Copied from lib/util/debug.c */
238 static int debug_level_to_priority(int level)
241 * map debug levels to syslog() priorities
243 static const int priority_map[] = {
257 if( level >= ARRAY_SIZE(priority_map) || level < 0)
258 priority = LOG_DEBUG;
260 priority = priority_map[level];
265 struct syslog_log_state {
267 const char *app_name;
268 const char *hostname;
269 int (*format)(int dbglevel, struct syslog_log_state *state,
270 const char *str, char *buf, int bsize);
271 /* RFC3164 says: The total length of the packet MUST be 1024
274 unsigned int dropped_count;
277 /* Format messages as per RFC3164
279 * It appears that some syslog daemon implementations do not allow a
280 * hostname when messages are sent via a Unix domain socket, so omit
281 * it. Similarly, syslogd on FreeBSD does not understand the hostname
282 * part of the header, even when logging via UDP. Note that most
283 * implementations will log messages against "localhost" when logging
284 * via UDP. A timestamp could be sent but rsyslogd on Linux limits
285 * the timestamp logged to the precision that was received on
286 * /dev/log. It seems sane to send degenerate RFC3164 messages
287 * without a header at all, so that the daemon will generate high
288 * resolution timestamps if configured.
290 static int format_rfc3164(int dbglevel, struct syslog_log_state *state,
291 const char *str, char *buf, int bsize)
296 pri = LOG_DAEMON | debug_level_to_priority(dbglevel);
297 len = snprintf(buf, bsize, "<%d>%s[%u]: %s",
298 pri, state->app_name, getpid(), str);
300 len = MIN(len, bsize - 1);
305 /* Format messages as per RFC5424
307 * <165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1
308 * myproc 8710 - - %% It's time to make the do-nuts.
310 static int format_rfc5424(int dbglevel, struct syslog_log_state *state,
311 const char *str, char *buf, int bsize)
315 struct timeval_buf tvbuf;
319 pri = LOG_DAEMON | debug_level_to_priority(dbglevel);
321 len = snprintf(buf, bsize,
322 "<%d>1 %s %s %s %u - - ",
323 pri, timeval_str_buf(&tv, true, true, &tvbuf),
324 state->hostname, state->app_name, getpid());
325 /* A truncated header is not useful... */
331 s = snprintf(&buf[len], bsize - len, "%s", str);
333 len = MIN(len + s, bsize - 1);
338 static void syslog_log(void *private_data, int level, const char *msg)
340 syslog(debug_level_to_priority(level), "%s", msg);
343 static int syslog_log_sock_maybe(struct syslog_log_state *state,
344 int level, const char *msg)
349 n = state->format(level, state, msg, state->buffer,
350 sizeof(state->buffer));
356 ret = write(state->fd, state->buffer, n);
357 } while (ret == -1 && errno == EINTR);
366 static void syslog_log_sock(void *private_data, int level, const char *msg)
368 struct syslog_log_state *state = talloc_get_type_abort(
369 private_data, struct syslog_log_state);
372 if (state->dropped_count > 0) {
374 snprintf(t, sizeof(t),
375 "[Dropped %u log messages]\n",
376 state->dropped_count);
377 t[sizeof(t)-1] = '\0';
378 ret = syslog_log_sock_maybe(state, level, t);
379 if (ret == EAGAIN || ret == EWOULDBLOCK) {
380 state->dropped_count++;
382 * If above failed then actually drop the
383 * message that would be logged below, since
384 * it would have been dropped anyway and it is
385 * also likely to fail. Falling through and
386 * attempting to log the message also means
387 * that the dropped message count will be
388 * logged out of order.
393 /* Silent failure on any other error */
396 state->dropped_count = 0;
399 ret = syslog_log_sock_maybe(state, level, msg);
400 if (ret == EAGAIN || ret == EWOULDBLOCK) {
401 state->dropped_count++;
405 static int syslog_log_setup_syslog(TALLOC_CTX *mem_ctx, const char *app_name)
407 openlog(app_name, LOG_PID, LOG_DAEMON);
409 debug_set_callback(NULL, syslog_log);
414 static int syslog_log_state_destructor(struct syslog_log_state *state)
416 if (state->fd != -1) {
423 static int syslog_log_setup_common(TALLOC_CTX *mem_ctx, const char *app_name,
424 struct syslog_log_state **result)
426 struct syslog_log_state *state;
428 state = talloc_zero(mem_ctx, struct syslog_log_state);
434 state->app_name = app_name;
435 talloc_set_destructor(state, syslog_log_state_destructor);
442 static int syslog_log_setup_nonblocking(TALLOC_CTX *mem_ctx,
443 const char *app_name)
445 struct syslog_log_state *state = NULL;
446 struct sockaddr_un dest;
449 ret = syslog_log_setup_common(mem_ctx, app_name, &state);
454 state->fd = socket(AF_UNIX, SOCK_DGRAM, 0);
455 if (state->fd == -1) {
456 int save_errno = errno;
461 dest.sun_family = AF_UNIX;
462 strncpy(dest.sun_path, _PATH_LOG, sizeof(dest.sun_path)-1);
463 ret = connect(state->fd,
464 (struct sockaddr *)&dest, sizeof(dest));
466 int save_errno = errno;
471 ret = set_blocking(state->fd, false);
473 int save_errno = errno;
478 if (! set_close_on_exec(state->fd)) {
479 int save_errno = errno;
484 state->hostname = NULL; /* Make this explicit */
485 state->format = format_rfc3164;
487 debug_set_callback(state, syslog_log_sock);
491 #endif /* _PATH_LOG */
493 static int syslog_log_setup_udp(TALLOC_CTX *mem_ctx, const char *app_name,
496 struct syslog_log_state *state = NULL;
497 struct sockaddr_in dest;
500 ret = syslog_log_setup_common(mem_ctx, app_name, &state);
505 state->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
506 if (state->fd == -1) {
507 int save_errno = errno;
512 dest.sin_family = AF_INET;
513 dest.sin_port = htons(514);
514 dest.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
515 ret = connect(state->fd,
516 (struct sockaddr *)&dest, sizeof(dest));
518 int save_errno = errno;
523 if (! set_close_on_exec(state->fd)) {
524 int save_errno = errno;
529 state->hostname = get_myname(state);
530 if (state->hostname == NULL) {
531 /* Use a fallback instead of failing initialisation */
532 state->hostname = "localhost";
535 state->format = format_rfc5424;
537 state->format = format_rfc3164;
540 debug_set_callback(state, syslog_log_sock);
545 static bool syslog_log_validate(const char *option)
547 if (option == NULL) {
550 } else if (strcmp(option, "nonblocking") == 0) {
553 } else if (strcmp(option, "udp") == 0) {
555 } else if (strcmp(option, "udp-rfc5424") == 0) {
562 static int syslog_log_setup(TALLOC_CTX *mem_ctx, const char *option,
563 const char *app_name)
565 if (option == NULL) {
566 return syslog_log_setup_syslog(mem_ctx, app_name);
568 } else if (strcmp(option, "nonblocking") == 0) {
569 return syslog_log_setup_nonblocking(mem_ctx, app_name);
571 } else if (strcmp(option, "udp") == 0) {
572 return syslog_log_setup_udp(mem_ctx, app_name, false);
573 } else if (strcmp(option, "udp-rfc5424") == 0) {
574 return syslog_log_setup_udp(mem_ctx, app_name, true);
582 bool (*validate)(const char *option);
583 int (*setup)(TALLOC_CTX *mem_ctx,
585 const char *app_name);
588 static struct log_backend log_backend[] = {
591 .validate = file_log_validate,
592 .setup = file_log_setup,
596 .validate = syslog_log_validate,
597 .setup = syslog_log_setup,
601 static int log_backend_parse(TALLOC_CTX *mem_ctx,
603 struct log_backend **backend,
604 char **backend_option)
606 struct log_backend *b = NULL;
607 char *t, *name, *option;
610 t = talloc_strdup(mem_ctx, logging);
615 name = strtok(t, ":");
620 option = strtok(NULL, ":");
622 for (i=0; i<ARRAY_SIZE(log_backend); i++) {
623 if (strcmp(log_backend[i].name, name) == 0) {
634 if (option != NULL) {
635 *backend_option = talloc_strdup(mem_ctx, option);
636 if (*backend_option == NULL) {
641 *backend_option = NULL;
648 bool logging_validate(const char *logging)
651 struct log_backend *backend;
656 tmp_ctx = talloc_new(NULL);
657 if (tmp_ctx == NULL) {
661 ret = log_backend_parse(tmp_ctx, logging, &backend, &option);
663 talloc_free(tmp_ctx);
667 status = backend->validate(option);
668 talloc_free(tmp_ctx);
672 /* Initialise logging */
673 int logging_init(TALLOC_CTX *mem_ctx, const char *logging,
674 const char *debug_level, const char *app_name)
676 struct log_backend *backend = NULL;
680 setup_logging(app_name, DEBUG_STDERR);
682 if (debug_level == NULL) {
683 debug_level = getenv("CTDB_DEBUGLEVEL");
685 if (! debug_level_parse(debug_level, &DEBUGLEVEL)) {
689 if (logging == NULL) {
690 logging = getenv("CTDB_LOGGING");
692 if (logging == NULL || logging[0] == '\0') {
696 ret = log_backend_parse(mem_ctx, logging, &backend, &option);
699 fprintf(stderr, "Invalid logging option \'%s\'\n",
706 ret = backend->setup(mem_ctx, option, app_name);