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"
29 #include "lib/util/time_basic.h"
30 #include "lib/util/sys_rw.h"
31 #include "lib/util/debug.h"
32 #include "lib/util/blocking.h"
33 #include "lib/util/samba_util.h" /* get_myname() */
35 #include "common/logging.h"
39 const char *log_string
;
40 } log_string_map
[] = {
41 { DEBUG_ERR
, "ERROR" },
42 { DEBUG_WARNING
, "WARNING" },
44 { DEBUG_NOTICE
, "NOTICE" },
46 { DEBUG_INFO
, "INFO" },
51 { DEBUG_DEBUG
, "DEBUG" },
54 bool debug_level_parse(const char *log_string
, int *log_level
)
58 if (log_string
== NULL
) {
62 if (isdigit(log_string
[0])) {
63 int level
= atoi(log_string
);
65 if (level
>= 0 && level
< ARRAY_SIZE(log_string_map
)) {
72 for (i
=0; i
<ARRAY_SIZE(log_string_map
); i
++) {
73 if (strncasecmp(log_string_map
[i
].log_string
,
74 log_string
, strlen(log_string
)) == 0) {
75 *log_level
= log_string_map
[i
].log_level
;
83 const char *debug_level_to_string(int log_level
)
87 for (i
=0; ARRAY_SIZE(log_string_map
); i
++) {
88 if (log_string_map
[i
].log_level
== log_level
) {
89 return log_string_map
[i
].log_string
;
95 int debug_level_from_string(const char *log_string
)
100 found
= debug_level_parse(log_string
, &log_level
);
105 /* Default debug level */
110 * file logging backend
113 struct file_log_state
{
114 const char *app_name
;
119 static void file_log(void *private_data
, int level
, const char *msg
)
121 struct file_log_state
*state
= talloc_get_type_abort(
122 private_data
, struct file_log_state
);
124 struct timeval_buf tvbuf
;
127 if (state
->fd
== STDERR_FILENO
) {
128 ret
= snprintf(state
->buffer
, sizeof(state
->buffer
),
130 state
->app_name
, (unsigned)getpid(), msg
);
133 timeval_str_buf(&tv
, false, true, &tvbuf
);
135 ret
= snprintf(state
->buffer
, sizeof(state
->buffer
),
136 "%s %s[%u]: %s\n", tvbuf
.buf
,
137 state
->app_name
, (unsigned)getpid(), msg
);
143 state
->buffer
[sizeof(state
->buffer
)-1] = '\0';
145 sys_write_v(state
->fd
, state
->buffer
, strlen(state
->buffer
));
148 static int file_log_state_destructor(struct file_log_state
*state
)
150 if (state
->fd
!= -1 && state
->fd
!= STDERR_FILENO
) {
157 static int file_log_setup(TALLOC_CTX
*mem_ctx
, const char *option
,
158 const char *app_name
)
160 struct file_log_state
*state
;
162 state
= talloc_zero(mem_ctx
, struct file_log_state
);
167 state
->app_name
= app_name
;
169 if (option
== NULL
|| strcmp(option
, "-") == 0) {
172 state
->fd
= STDERR_FILENO
;
173 ret
= dup2(STDERR_FILENO
, STDOUT_FILENO
);
175 int save_errno
= errno
;
181 state
->fd
= open(option
, O_WRONLY
|O_APPEND
|O_CREAT
, 0644);
182 if (state
->fd
== -1) {
183 int save_errno
= errno
;
188 if (! set_close_on_exec(state
->fd
)) {
189 int save_errno
= errno
;
195 talloc_set_destructor(state
, file_log_state_destructor
);
196 debug_set_callback(state
, file_log
);
202 * syslog logging backend
205 /* Copied from lib/util/debug.c */
206 static int debug_level_to_priority(int level
)
209 * map debug levels to syslog() priorities
211 static const int priority_map
[] = {
225 if( level
>= ARRAY_SIZE(priority_map
) || level
< 0)
226 priority
= LOG_DEBUG
;
228 priority
= priority_map
[level
];
233 struct syslog_log_state
{
235 const char *app_name
;
236 const char *hostname
;
237 int (*format
)(int dbglevel
, struct syslog_log_state
*state
,
238 const char *str
, char *buf
, int bsize
);
239 /* RFC3164 says: The total length of the packet MUST be 1024
244 /* Format messages as per RFC3164
246 * It appears that some syslog daemon implementations do not allow a
247 * hostname when messages are sent via a Unix domain socket, so omit
248 * it. Similarly, syslogd on FreeBSD does not understand the hostname
249 * part of the header, even when logging via UDP. Note that most
250 * implementations will log messages against "localhost" when logging
251 * via UDP. A timestamp could be sent but rsyslogd on Linux limits
252 * the timestamp logged to the precision that was received on
253 * /dev/log. It seems sane to send degenerate RFC3164 messages
254 * without a header at all, so that the daemon will generate high
255 * resolution timestamps if configured.
257 static int format_rfc3164(int dbglevel
, struct syslog_log_state
*state
,
258 const char *str
, char *buf
, int bsize
)
263 pri
= LOG_DAEMON
| debug_level_to_priority(dbglevel
);
264 len
= snprintf(buf
, bsize
, "<%d>%s[%u]: %s",
265 pri
, state
->app_name
, getpid(), str
);
267 len
= MIN(len
, bsize
- 1);
272 /* Format messages as per RFC5424
274 * <165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1
275 * myproc 8710 - - %% It's time to make the do-nuts.
277 static int format_rfc5424(int dbglevel
, struct syslog_log_state
*state
,
278 const char *str
, char *buf
, int bsize
)
282 struct timeval_buf tvbuf
;
286 pri
= LOG_DAEMON
| debug_level_to_priority(dbglevel
);
288 len
= snprintf(buf
, bsize
,
289 "<%d>1 %s %s %s %u - - ",
290 pri
, timeval_str_buf(&tv
, true, true, &tvbuf
),
291 state
->hostname
, state
->app_name
, getpid());
292 /* A truncated header is not useful... */
298 s
= snprintf(&buf
[len
], bsize
- len
, "%s", str
);
300 len
= MIN(len
+ s
, bsize
- 1);
305 static void syslog_log(void *private_data
, int level
, const char *msg
)
307 syslog(debug_level_to_priority(level
), "%s", msg
);
310 static void syslog_log_sock(void *private_data
, int level
, const char *msg
)
312 struct syslog_log_state
*state
= talloc_get_type_abort(
313 private_data
, struct syslog_log_state
);
316 n
= state
->format(level
, state
, msg
, state
->buffer
,
317 sizeof(state
->buffer
));
322 sys_write_v(state
->fd
, state
->buffer
, n
);
325 static int syslog_log_setup_syslog(TALLOC_CTX
*mem_ctx
, const char *app_name
)
327 openlog(app_name
, LOG_PID
, LOG_DAEMON
);
329 debug_set_callback(NULL
, syslog_log
);
334 static int syslog_log_state_destructor(struct syslog_log_state
*state
)
336 if (state
->fd
!= -1) {
343 static int syslog_log_setup_common(TALLOC_CTX
*mem_ctx
, const char *app_name
,
344 struct syslog_log_state
**result
)
346 struct syslog_log_state
*state
;
348 state
= talloc_zero(mem_ctx
, struct syslog_log_state
);
354 state
->app_name
= app_name
;
355 talloc_set_destructor(state
, syslog_log_state_destructor
);
361 static int syslog_log_setup_nonblocking(TALLOC_CTX
*mem_ctx
,
362 const char *app_name
)
364 struct syslog_log_state
*state
= NULL
;
365 struct sockaddr_un dest
;
368 ret
= syslog_log_setup_common(mem_ctx
, app_name
, &state
);
373 state
->fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
374 if (state
->fd
== -1) {
375 int save_errno
= errno
;
380 dest
.sun_family
= AF_UNIX
;
381 strncpy(dest
.sun_path
, _PATH_LOG
, sizeof(dest
.sun_path
)-1);
382 ret
= connect(state
->fd
,
383 (struct sockaddr
*)&dest
, sizeof(dest
));
385 int save_errno
= errno
;
390 ret
= set_blocking(state
->fd
, false);
392 int save_errno
= errno
;
397 if (! set_close_on_exec(state
->fd
)) {
398 int save_errno
= errno
;
403 state
->hostname
= NULL
; /* Make this explicit */
404 state
->format
= format_rfc3164
;
406 debug_set_callback(state
, syslog_log_sock
);
410 #endif /* _PATH_LOG */
412 static int syslog_log_setup_udp(TALLOC_CTX
*mem_ctx
, const char *app_name
,
415 struct syslog_log_state
*state
= NULL
;
416 struct sockaddr_in dest
;
419 ret
= syslog_log_setup_common(mem_ctx
, app_name
, &state
);
424 state
->fd
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
425 if (state
->fd
== -1) {
426 int save_errno
= errno
;
431 dest
.sin_family
= AF_INET
;
432 dest
.sin_port
= htons(514);
433 dest
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
434 ret
= connect(state
->fd
,
435 (struct sockaddr
*)&dest
, sizeof(dest
));
437 int save_errno
= errno
;
442 if (! set_close_on_exec(state
->fd
)) {
443 int save_errno
= errno
;
448 state
->hostname
= get_myname(state
);
449 if (state
->hostname
== NULL
) {
450 /* Use a fallback instead of failing initialisation */
451 state
->hostname
= "localhost";
454 state
->format
= format_rfc5424
;
456 state
->format
= format_rfc3164
;
459 debug_set_callback(state
, syslog_log_sock
);
464 static int syslog_log_setup(TALLOC_CTX
*mem_ctx
, const char *option
,
465 const char *app_name
)
467 if (option
== NULL
) {
468 return syslog_log_setup_syslog(mem_ctx
, app_name
);
470 } else if (strcmp(option
, "nonblocking") == 0) {
471 return syslog_log_setup_nonblocking(mem_ctx
, app_name
);
473 } else if (strcmp(option
, "udp") == 0) {
474 return syslog_log_setup_udp(mem_ctx
, app_name
, false);
475 } else if (strcmp(option
, "udp-rfc5424") == 0) {
476 return syslog_log_setup_udp(mem_ctx
, app_name
, true);
482 /* Initialise logging */
483 int logging_init(TALLOC_CTX
*mem_ctx
, const char *logging
,
484 const char *debug_level
, const char *app_name
)
488 int (*setup
)(TALLOC_CTX
*mem_ctx
, const char *option
,
489 const char *app_name
);
493 .setup
= file_log_setup
,
497 .setup
= syslog_log_setup
,
500 int (*setup
)(TALLOC_CTX
*, const char *, const char *) = NULL
;
501 char *str
, *name
, *option
;
504 if (debug_level
== NULL
) {
505 debug_level
= getenv("CTDB_DEBUGLEVEL");
507 if (! debug_level_parse(debug_level
, &DEBUGLEVEL
)) {
511 if (logging
== NULL
) {
512 logging
= getenv("CTDB_LOGGING");
514 if (logging
== NULL
|| logging
[0] == '\0') {
518 str
= talloc_strdup(mem_ctx
, logging
);
523 name
= strtok(str
, ":");
528 option
= strtok(NULL
, ":");
530 * option can be NULL here, both setup()
531 * backends handle this.
534 for (i
=0; i
<ARRAY_SIZE(log_backend
); i
++) {
535 if (strcmp(log_backend
[i
].name
, name
) == 0) {
536 setup
= log_backend
[i
].setup
;
542 fprintf(stderr
, "Invalid logging option \'%s\'\n", logging
);
546 ret
= setup(mem_ctx
, option
, app_name
);