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
242 unsigned int dropped_count
;
245 /* Format messages as per RFC3164
247 * It appears that some syslog daemon implementations do not allow a
248 * hostname when messages are sent via a Unix domain socket, so omit
249 * it. Similarly, syslogd on FreeBSD does not understand the hostname
250 * part of the header, even when logging via UDP. Note that most
251 * implementations will log messages against "localhost" when logging
252 * via UDP. A timestamp could be sent but rsyslogd on Linux limits
253 * the timestamp logged to the precision that was received on
254 * /dev/log. It seems sane to send degenerate RFC3164 messages
255 * without a header at all, so that the daemon will generate high
256 * resolution timestamps if configured.
258 static int format_rfc3164(int dbglevel
, struct syslog_log_state
*state
,
259 const char *str
, char *buf
, int bsize
)
264 pri
= LOG_DAEMON
| debug_level_to_priority(dbglevel
);
265 len
= snprintf(buf
, bsize
, "<%d>%s[%u]: %s",
266 pri
, state
->app_name
, getpid(), str
);
268 len
= MIN(len
, bsize
- 1);
273 /* Format messages as per RFC5424
275 * <165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1
276 * myproc 8710 - - %% It's time to make the do-nuts.
278 static int format_rfc5424(int dbglevel
, struct syslog_log_state
*state
,
279 const char *str
, char *buf
, int bsize
)
283 struct timeval_buf tvbuf
;
287 pri
= LOG_DAEMON
| debug_level_to_priority(dbglevel
);
289 len
= snprintf(buf
, bsize
,
290 "<%d>1 %s %s %s %u - - ",
291 pri
, timeval_str_buf(&tv
, true, true, &tvbuf
),
292 state
->hostname
, state
->app_name
, getpid());
293 /* A truncated header is not useful... */
299 s
= snprintf(&buf
[len
], bsize
- len
, "%s", str
);
301 len
= MIN(len
+ s
, bsize
- 1);
306 static void syslog_log(void *private_data
, int level
, const char *msg
)
308 syslog(debug_level_to_priority(level
), "%s", msg
);
311 static int syslog_log_sock_maybe(struct syslog_log_state
*state
,
312 int level
, const char *msg
)
317 n
= state
->format(level
, state
, msg
, state
->buffer
,
318 sizeof(state
->buffer
));
324 ret
= write(state
->fd
, state
->buffer
, n
);
325 } while (ret
== -1 && errno
== EINTR
);
334 static void syslog_log_sock(void *private_data
, int level
, const char *msg
)
336 struct syslog_log_state
*state
= talloc_get_type_abort(
337 private_data
, struct syslog_log_state
);
340 if (state
->dropped_count
> 0) {
342 snprintf(t
, sizeof(t
),
343 "[Dropped %u log messages]\n",
344 state
->dropped_count
);
345 t
[sizeof(t
)-1] = '\0';
346 ret
= syslog_log_sock_maybe(state
, level
, t
);
347 if (ret
== EAGAIN
|| ret
== EWOULDBLOCK
) {
348 state
->dropped_count
++;
350 * If above failed then actually drop the
351 * message that would be logged below, since
352 * it would have been dropped anyway and it is
353 * also likely to fail. Falling through and
354 * attempting to log the message also means
355 * that the dropped message count will be
356 * logged out of order.
361 /* Silent failure on any other error */
364 state
->dropped_count
= 0;
367 ret
= syslog_log_sock_maybe(state
, level
, msg
);
368 if (ret
== EAGAIN
|| ret
== EWOULDBLOCK
) {
369 state
->dropped_count
++;
373 static int syslog_log_setup_syslog(TALLOC_CTX
*mem_ctx
, const char *app_name
)
375 openlog(app_name
, LOG_PID
, LOG_DAEMON
);
377 debug_set_callback(NULL
, syslog_log
);
382 static int syslog_log_state_destructor(struct syslog_log_state
*state
)
384 if (state
->fd
!= -1) {
391 static int syslog_log_setup_common(TALLOC_CTX
*mem_ctx
, const char *app_name
,
392 struct syslog_log_state
**result
)
394 struct syslog_log_state
*state
;
396 state
= talloc_zero(mem_ctx
, struct syslog_log_state
);
402 state
->app_name
= app_name
;
403 talloc_set_destructor(state
, syslog_log_state_destructor
);
410 static int syslog_log_setup_nonblocking(TALLOC_CTX
*mem_ctx
,
411 const char *app_name
)
413 struct syslog_log_state
*state
= NULL
;
414 struct sockaddr_un dest
;
417 ret
= syslog_log_setup_common(mem_ctx
, app_name
, &state
);
422 state
->fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
423 if (state
->fd
== -1) {
424 int save_errno
= errno
;
429 dest
.sun_family
= AF_UNIX
;
430 strncpy(dest
.sun_path
, _PATH_LOG
, sizeof(dest
.sun_path
)-1);
431 ret
= connect(state
->fd
,
432 (struct sockaddr
*)&dest
, sizeof(dest
));
434 int save_errno
= errno
;
439 ret
= set_blocking(state
->fd
, false);
441 int save_errno
= errno
;
446 if (! set_close_on_exec(state
->fd
)) {
447 int save_errno
= errno
;
452 state
->hostname
= NULL
; /* Make this explicit */
453 state
->format
= format_rfc3164
;
455 debug_set_callback(state
, syslog_log_sock
);
459 #endif /* _PATH_LOG */
461 static int syslog_log_setup_udp(TALLOC_CTX
*mem_ctx
, const char *app_name
,
464 struct syslog_log_state
*state
= NULL
;
465 struct sockaddr_in dest
;
468 ret
= syslog_log_setup_common(mem_ctx
, app_name
, &state
);
473 state
->fd
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
474 if (state
->fd
== -1) {
475 int save_errno
= errno
;
480 dest
.sin_family
= AF_INET
;
481 dest
.sin_port
= htons(514);
482 dest
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
483 ret
= connect(state
->fd
,
484 (struct sockaddr
*)&dest
, sizeof(dest
));
486 int save_errno
= errno
;
491 if (! set_close_on_exec(state
->fd
)) {
492 int save_errno
= errno
;
497 state
->hostname
= get_myname(state
);
498 if (state
->hostname
== NULL
) {
499 /* Use a fallback instead of failing initialisation */
500 state
->hostname
= "localhost";
503 state
->format
= format_rfc5424
;
505 state
->format
= format_rfc3164
;
508 debug_set_callback(state
, syslog_log_sock
);
513 static int syslog_log_setup(TALLOC_CTX
*mem_ctx
, const char *option
,
514 const char *app_name
)
516 if (option
== NULL
) {
517 return syslog_log_setup_syslog(mem_ctx
, app_name
);
519 } else if (strcmp(option
, "nonblocking") == 0) {
520 return syslog_log_setup_nonblocking(mem_ctx
, app_name
);
522 } else if (strcmp(option
, "udp") == 0) {
523 return syslog_log_setup_udp(mem_ctx
, app_name
, false);
524 } else if (strcmp(option
, "udp-rfc5424") == 0) {
525 return syslog_log_setup_udp(mem_ctx
, app_name
, true);
531 /* Initialise logging */
532 int logging_init(TALLOC_CTX
*mem_ctx
, const char *logging
,
533 const char *debug_level
, const char *app_name
)
537 int (*setup
)(TALLOC_CTX
*mem_ctx
, const char *option
,
538 const char *app_name
);
542 .setup
= file_log_setup
,
546 .setup
= syslog_log_setup
,
549 int (*setup
)(TALLOC_CTX
*, const char *, const char *) = NULL
;
550 char *str
, *name
, *option
;
553 setup_logging(app_name
, DEBUG_STDERR
);
555 if (debug_level
== NULL
) {
556 debug_level
= getenv("CTDB_DEBUGLEVEL");
558 if (! debug_level_parse(debug_level
, &DEBUGLEVEL
)) {
562 if (logging
== NULL
) {
563 logging
= getenv("CTDB_LOGGING");
565 if (logging
== NULL
|| logging
[0] == '\0') {
569 str
= talloc_strdup(mem_ctx
, logging
);
574 name
= strtok(str
, ":");
579 option
= strtok(NULL
, ":");
581 * option can be NULL here, both setup()
582 * backends handle this.
585 for (i
=0; i
<ARRAY_SIZE(log_backend
); i
++) {
586 if (strcmp(log_backend
[i
].name
, name
) == 0) {
587 setup
= log_backend
[i
].setup
;
593 fprintf(stderr
, "Invalid logging option \'%s\'\n", logging
);
597 ret
= setup(mem_ctx
, option
, app_name
);