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 && (size_t)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; i
< 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 static bool file_log_validate(const char *option
)
120 if (option
== NULL
|| strcmp(option
, "-") == 0) {
131 ret
= stat(dir
, &st
);
137 if (! S_ISDIR(st
.st_mode
)) {
144 static int file_log_setup(TALLOC_CTX
*mem_ctx
,
146 const char *app_name
)
148 struct debug_settings settings
= {
149 .debug_syslog_format
= DEBUG_SYSLOG_FORMAT_ALWAYS
,
150 .debug_hires_timestamp
= true,
151 .debug_no_stderr_redirect
= true,
153 const char *t
= NULL
;
155 if (option
== NULL
|| strcmp(option
, "-") == 0) {
157 * Logging to stderr is the default and has already
158 * been done in logging init
164 * Support logging of fake hostname in local daemons. This
165 * hostname is basename(getenv(CTDB_BASE)).
167 t
= getenv("CTDB_TEST_MODE");
169 t
= getenv("CTDB_BASE");
171 const char *p
= strrchr(t
, '/');
181 debug_set_hostname(p
);
185 debug_set_settings(&settings
, "file", 0, false);
186 debug_set_logfile(option
);
187 setup_logging(app_name
, DEBUG_FILE
);
193 * syslog logging backend
196 /* Copied from lib/util/debug.c */
197 static int debug_level_to_priority(int level
)
200 * map debug levels to syslog() priorities
202 static const int priority_map
[] = {
216 if ((size_t)level
>= ARRAY_SIZE(priority_map
) || level
< 0) {
217 priority
= LOG_DEBUG
;
219 priority
= priority_map
[level
];
224 struct syslog_log_state
{
226 const char *app_name
;
227 const char *hostname
;
228 int (*format
)(int dbglevel
, struct syslog_log_state
*state
,
229 const char *str
, char *buf
, int bsize
);
230 /* RFC3164 says: The total length of the packet MUST be 1024
233 unsigned int dropped_count
;
236 /* Format messages as per RFC3164
238 * It appears that some syslog daemon implementations do not allow a
239 * hostname when messages are sent via a Unix domain socket, so omit
240 * it. Similarly, syslogd on FreeBSD does not understand the hostname
241 * part of the header, even when logging via UDP. Note that most
242 * implementations will log messages against "localhost" when logging
243 * via UDP. A timestamp could be sent but rsyslogd on Linux limits
244 * the timestamp logged to the precision that was received on
245 * /dev/log. It seems sane to send degenerate RFC3164 messages
246 * without a header at all, so that the daemon will generate high
247 * resolution timestamps if configured.
249 static int format_rfc3164(int dbglevel
, struct syslog_log_state
*state
,
250 const char *str
, char *buf
, int bsize
)
255 pri
= LOG_DAEMON
| debug_level_to_priority(dbglevel
);
256 len
= snprintf(buf
, bsize
, "<%d>%s[%u]: %s",
257 pri
, state
->app_name
, getpid(), str
);
259 len
= MIN(len
, bsize
- 1);
264 /* Format messages as per RFC5424
266 * <165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1
267 * myproc 8710 - - %% It's time to make the do-nuts.
269 static int format_rfc5424(int dbglevel
, struct syslog_log_state
*state
,
270 const char *str
, char *buf
, int bsize
)
274 struct timeval_buf tvbuf
;
278 pri
= LOG_DAEMON
| debug_level_to_priority(dbglevel
);
280 len
= snprintf(buf
, bsize
,
281 "<%d>1 %s %s %s %u - - ",
282 pri
, timeval_str_buf(&tv
, true, true, &tvbuf
),
283 state
->hostname
, state
->app_name
, getpid());
284 /* A truncated header is not useful... */
290 s
= snprintf(&buf
[len
], bsize
- len
, "%s", str
);
292 len
= MIN(len
+ s
, bsize
- 1);
297 static void syslog_log(void *private_data
, int level
, const char *msg
)
299 syslog(debug_level_to_priority(level
), "%s", msg
);
302 static int syslog_log_sock_maybe(struct syslog_log_state
*state
,
303 int level
, const char *msg
)
308 n
= state
->format(level
, state
, msg
, state
->buffer
,
309 sizeof(state
->buffer
));
315 ret
= write(state
->fd
, state
->buffer
, n
);
316 } while (ret
== -1 && errno
== EINTR
);
325 static void syslog_log_sock(void *private_data
, int level
, const char *msg
)
327 struct syslog_log_state
*state
= talloc_get_type_abort(
328 private_data
, struct syslog_log_state
);
331 if (state
->dropped_count
> 0) {
333 snprintf(t
, sizeof(t
),
334 "[Dropped %u log messages]\n",
335 state
->dropped_count
);
336 t
[sizeof(t
)-1] = '\0';
337 ret
= syslog_log_sock_maybe(state
, level
, t
);
338 if (ret
== EAGAIN
|| ret
== EWOULDBLOCK
) {
339 state
->dropped_count
++;
341 * If above failed then actually drop the
342 * message that would be logged below, since
343 * it would have been dropped anyway and it is
344 * also likely to fail. Falling through and
345 * attempting to log the message also means
346 * that the dropped message count will be
347 * logged out of order.
352 /* Silent failure on any other error */
355 state
->dropped_count
= 0;
358 ret
= syslog_log_sock_maybe(state
, level
, msg
);
359 if (ret
== EAGAIN
|| ret
== EWOULDBLOCK
) {
360 state
->dropped_count
++;
364 static int syslog_log_setup_syslog(TALLOC_CTX
*mem_ctx
, const char *app_name
)
366 openlog(app_name
, LOG_PID
, LOG_DAEMON
);
368 debug_set_callback(NULL
, syslog_log
);
373 static int syslog_log_state_destructor(struct syslog_log_state
*state
)
375 if (state
->fd
!= -1) {
382 static int syslog_log_setup_common(TALLOC_CTX
*mem_ctx
, const char *app_name
,
383 struct syslog_log_state
**result
)
385 struct syslog_log_state
*state
;
387 state
= talloc_zero(mem_ctx
, struct syslog_log_state
);
393 state
->app_name
= app_name
;
394 talloc_set_destructor(state
, syslog_log_state_destructor
);
401 static int syslog_log_setup_nonblocking(TALLOC_CTX
*mem_ctx
,
402 const char *app_name
)
404 struct syslog_log_state
*state
= NULL
;
405 struct sockaddr_un dest
;
408 ret
= syslog_log_setup_common(mem_ctx
, app_name
, &state
);
413 state
->fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
414 if (state
->fd
== -1) {
415 int save_errno
= errno
;
420 dest
.sun_family
= AF_UNIX
;
421 strncpy(dest
.sun_path
, _PATH_LOG
, sizeof(dest
.sun_path
)-1);
422 ret
= connect(state
->fd
,
423 (struct sockaddr
*)&dest
, sizeof(dest
));
425 int save_errno
= errno
;
430 ret
= set_blocking(state
->fd
, false);
432 int save_errno
= errno
;
437 if (! set_close_on_exec(state
->fd
)) {
438 int save_errno
= errno
;
443 state
->hostname
= NULL
; /* Make this explicit */
444 state
->format
= format_rfc3164
;
446 debug_set_callback(state
, syslog_log_sock
);
450 #endif /* _PATH_LOG */
452 static int syslog_log_setup_udp(TALLOC_CTX
*mem_ctx
, const char *app_name
,
455 struct syslog_log_state
*state
= NULL
;
456 struct sockaddr_in dest
;
459 ret
= syslog_log_setup_common(mem_ctx
, app_name
, &state
);
464 state
->fd
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
465 if (state
->fd
== -1) {
466 int save_errno
= errno
;
471 dest
.sin_family
= AF_INET
;
472 dest
.sin_port
= htons(514);
473 dest
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
474 ret
= connect(state
->fd
,
475 (struct sockaddr
*)&dest
, sizeof(dest
));
477 int save_errno
= errno
;
482 if (! set_close_on_exec(state
->fd
)) {
483 int save_errno
= errno
;
488 state
->hostname
= get_myname(state
);
489 if (state
->hostname
== NULL
) {
490 /* Use a fallback instead of failing initialisation */
491 state
->hostname
= "localhost";
494 state
->format
= format_rfc5424
;
496 state
->format
= format_rfc3164
;
499 debug_set_callback(state
, syslog_log_sock
);
504 static bool syslog_log_validate(const char *option
)
506 if (option
== NULL
) {
509 } else if (strcmp(option
, "nonblocking") == 0) {
512 } else if (strcmp(option
, "udp") == 0) {
514 } else if (strcmp(option
, "udp-rfc5424") == 0) {
521 static int syslog_log_setup(TALLOC_CTX
*mem_ctx
, const char *option
,
522 const char *app_name
)
524 if (option
== NULL
) {
525 return syslog_log_setup_syslog(mem_ctx
, app_name
);
527 } else if (strcmp(option
, "nonblocking") == 0) {
528 return syslog_log_setup_nonblocking(mem_ctx
, app_name
);
530 } else if (strcmp(option
, "udp") == 0) {
531 return syslog_log_setup_udp(mem_ctx
, app_name
, false);
532 } else if (strcmp(option
, "udp-rfc5424") == 0) {
533 return syslog_log_setup_udp(mem_ctx
, app_name
, true);
541 bool (*validate
)(const char *option
);
542 int (*setup
)(TALLOC_CTX
*mem_ctx
,
544 const char *app_name
);
547 static struct log_backend log_backend
[] = {
550 .validate
= file_log_validate
,
551 .setup
= file_log_setup
,
555 .validate
= syslog_log_validate
,
556 .setup
= syslog_log_setup
,
560 static int log_backend_parse(TALLOC_CTX
*mem_ctx
,
562 struct log_backend
**backend
,
563 char **backend_option
)
565 struct log_backend
*b
= NULL
;
566 char *t
, *name
, *option
;
569 t
= talloc_strdup(mem_ctx
, logging
);
574 name
= strtok(t
, ":");
579 option
= strtok(NULL
, ":");
581 for (i
=0; i
<ARRAY_SIZE(log_backend
); i
++) {
582 if (strcmp(log_backend
[i
].name
, name
) == 0) {
593 if (option
!= NULL
) {
594 *backend_option
= talloc_strdup(mem_ctx
, option
);
595 if (*backend_option
== NULL
) {
600 *backend_option
= NULL
;
607 bool logging_validate(const char *logging
)
610 struct log_backend
*backend
;
615 tmp_ctx
= talloc_new(NULL
);
616 if (tmp_ctx
== NULL
) {
620 ret
= log_backend_parse(tmp_ctx
, logging
, &backend
, &option
);
622 talloc_free(tmp_ctx
);
626 status
= backend
->validate(option
);
627 talloc_free(tmp_ctx
);
631 /* Initialise logging */
632 int logging_init(TALLOC_CTX
*mem_ctx
, const char *logging
,
633 const char *debug_level
, const char *app_name
)
635 struct log_backend
*backend
= NULL
;
640 setup_logging(app_name
, DEBUG_DEFAULT_STDERR
);
642 if (debug_level
== NULL
) {
643 debug_level
= getenv("CTDB_DEBUGLEVEL");
645 if (! debug_level_parse(debug_level
, &level
)) {
648 debuglevel_set(level
);
650 if (logging
== NULL
) {
651 logging
= getenv("CTDB_LOGGING");
653 if (logging
== NULL
|| logging
[0] == '\0') {
657 ret
= log_backend_parse(mem_ctx
, logging
, &backend
, &option
);
660 fprintf(stderr
, "Invalid logging option \'%s\'\n",
667 ret
= backend
->setup(mem_ctx
, option
, app_name
);
672 bool logging_reopen_logs(void)
676 status
= reopen_logs_internal();
681 struct logging_reopen_logs_data
{
682 void (*hook
)(void *private_data
);
686 static void logging_sig_hup_handler(struct tevent_context
*ev
,
687 struct tevent_signal
*se
,
695 if (private_data
!= NULL
) {
696 struct logging_reopen_logs_data
*data
= talloc_get_type_abort(
697 private_data
, struct logging_reopen_logs_data
);
699 if (data
->hook
!= NULL
) {
700 data
->hook(data
->private_data
);
704 status
= logging_reopen_logs();
706 D_WARNING("Failed to reopen logs\n");
710 D_NOTICE("Reopened logs\n");
714 bool logging_setup_sighup_handler(struct tevent_context
*ev
,
715 TALLOC_CTX
*talloc_ctx
,
716 void (*hook
)(void *private_data
),
719 struct logging_reopen_logs_data
*data
= NULL
;
720 struct tevent_signal
*se
;
723 data
= talloc(talloc_ctx
, struct logging_reopen_logs_data
);
729 data
->private_data
= private_data
;
733 se
= tevent_add_signal(ev
,
737 logging_sig_hup_handler
,