s3-util: Fix asking for username and password in smbget.
[Samba.git] / ctdb / server / ctdb_logging_syslog.c
blob54643e23277045b78c1a03a528fe8169bbb7d213
1 /*
2 ctdb logging code - syslog backend
4 Copyright (C) Andrew Tridgell 2008
5 Copyright (C) Martin Schwenke 2014
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "replace.h"
22 #include "system/network.h"
23 #include "system/syslog.h"
25 #include "lib/util/debug.h"
26 #include "lib/util/blocking.h"
27 #include "lib/util/time_basic.h"
28 #include "lib/util/samba_util.h" /* get_myname */
30 #include "ctdb_private.h"
32 #include "common/logging.h"
34 /* Linux and FreeBSD define this appropriately - try good old /dev/log
35 * for anything that doesn't... */
36 #ifndef _PATH_LOG
37 #define _PATH_LOG "/dev/log"
38 #endif
40 #define CTDB_LOG_SYSLOG_PREFIX "syslog"
41 #define CTDB_SYSLOG_FACILITY LOG_USER
43 struct ctdb_syslog_sock_state {
44 int fd;
45 const char *app_name;
46 const char *hostname;
47 int (*format)(int dbglevel, struct ctdb_syslog_sock_state *state,
48 const char *str, char *buf, int bsize);
51 /**********************************************************************/
53 static int ctdb_debug_to_syslog_level(int dbglevel)
55 int level;
57 switch (dbglevel) {
58 case DEBUG_ERR:
59 level = LOG_ERR;
60 break;
61 case DEBUG_WARNING:
62 level = LOG_WARNING;
63 break;
64 case DEBUG_NOTICE:
65 level = LOG_NOTICE;
66 break;
67 case DEBUG_INFO:
68 level = LOG_INFO;
69 break;
70 default:
71 level = LOG_DEBUG;
72 break;
75 return level;
78 /**********************************************************************/
80 /* Format messages as per RFC3164. */
82 /* It appears that some syslog daemon implementations do not allow a
83 * hostname when messages are sent via a Unix domain socket, so omit
84 * it. Similarly, syslogd on FreeBSD does not understand the hostname
85 * part of the header, even when logging via UDP. Note that most
86 * implementations will log messages against "localhost" when logging
87 * via UDP. A timestamp could be sent but rsyslogd on Linux limits
88 * the timestamp logged to the precision that was received on
89 * /dev/log. It seems sane to send degenerate RFC3164 messages
90 * without a header at all, so that the daemon will generate high
91 * resolution timestamps if configured. */
92 static int format_rfc3164(int dbglevel, struct ctdb_syslog_sock_state *state,
93 const char *str, char *buf, int bsize)
95 int pri;
96 int len;
98 pri = CTDB_SYSLOG_FACILITY | ctdb_debug_to_syslog_level(dbglevel);
99 len = snprintf(buf, bsize, "<%d>%s[%u]: %s%s",
100 pri, state->app_name, getpid(), debug_extra, str);
101 len = MIN(len, bsize - 1);
103 return len;
106 /* Format messages as per RFC5424
108 * <165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1
109 * myproc 8710 - - %% It's time to make the do-nuts.
111 static int format_rfc5424(int dbglevel, struct ctdb_syslog_sock_state *state,
112 const char *str, char *buf, int bsize)
114 int pri;
115 struct timeval tv;
116 struct timeval_buf tvbuf;
117 int len, s;
119 /* Header */
120 pri = CTDB_SYSLOG_FACILITY | ctdb_debug_to_syslog_level(dbglevel);
121 GetTimeOfDay(&tv);
122 len = snprintf(buf, bsize,
123 "<%d>1 %s %s %s %u - - ",
124 pri, timeval_str_buf(&tv, true, true, &tvbuf),
125 state->hostname, state->app_name, getpid());
126 /* A truncated header is not useful... */
127 if (len >= bsize) {
128 return -1;
131 /* Message */
132 s = snprintf(&buf[len], bsize - len, "%s %s", debug_extra, str);
133 len = MIN(len + s, bsize - 1);
135 return len;
138 /**********************************************************************/
140 /* Non-blocking logging */
142 static void ctdb_log_to_syslog_sock(void *private_ptr,
143 int dbglevel, const char *str)
145 struct ctdb_syslog_sock_state *state = talloc_get_type(
146 private_ptr, struct ctdb_syslog_sock_state);
148 /* RFC3164 says: The total length of the packet MUST be 1024
149 bytes or less. */
150 char buf[1024];
151 int n;
153 n = state->format(dbglevel, state, str, buf, sizeof(buf));
154 if (n == -1) {
155 fprintf(stderr, "Failed to format syslog message %s\n", str);
156 return;
159 /* Could extend this to count failures, which probably
160 * indicate dropped messages due to EAGAIN or EWOULDBLOCK */
161 (void)send(state->fd, buf, n, 0);
164 static int
165 ctdb_syslog_sock_state_destructor(struct ctdb_syslog_sock_state *state)
167 if (state->fd != -1) {
168 close(state->fd);
169 state->fd = -1;
171 return 0;
174 static struct ctdb_syslog_sock_state *
175 ctdb_log_setup_syslog_common(TALLOC_CTX *mem_ctx,
176 const char *app_name)
178 struct ctdb_syslog_sock_state *state;
180 state = talloc_zero(mem_ctx, struct ctdb_syslog_sock_state);
181 if (state == NULL) {
182 return NULL;
184 state->fd = -1;
185 state->app_name = app_name;
186 talloc_set_destructor(state, ctdb_syslog_sock_state_destructor);
188 return state;
191 static int ctdb_log_setup_syslog_un(TALLOC_CTX *mem_ctx,
192 const char *app_name)
194 struct ctdb_syslog_sock_state *state;
195 struct sockaddr_un dest;
196 int ret;
198 state = ctdb_log_setup_syslog_common(mem_ctx, app_name);
199 if (state == NULL) {
200 return ENOMEM;
203 state->fd = socket(AF_UNIX, SOCK_DGRAM, 0);
204 if (state->fd == -1) {
205 int save_errno = errno;
206 talloc_free(state);
207 return save_errno;
210 dest.sun_family = AF_UNIX;
211 strncpy(dest.sun_path, _PATH_LOG, sizeof(dest.sun_path)-1);
212 ret = connect(state->fd,
213 (struct sockaddr *)&dest, sizeof(dest));
214 if (ret == -1) {
215 int save_errno = errno;
216 talloc_free(state);
217 return save_errno;
219 set_blocking(state->fd, false);
221 state->hostname = NULL; /* Make this explicit */
222 state->format = format_rfc3164;
224 debug_set_callback(state, ctdb_log_to_syslog_sock);
226 return 0;
229 static int ctdb_log_setup_syslog_udp(TALLOC_CTX *mem_ctx,
230 const char *app_name,
231 bool rfc5424)
233 struct ctdb_syslog_sock_state *state;
234 struct sockaddr_in dest;
235 int ret;
237 state = ctdb_log_setup_syslog_common(mem_ctx, app_name);
238 if (state == NULL) {
239 return ENOMEM;
242 state->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
243 if (state->fd == -1) {
244 int save_errno = errno;
245 talloc_free(state);
246 return save_errno;
249 dest.sin_family = AF_INET;
250 dest.sin_port = htons(514);
251 dest.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
252 ret = connect(state->fd,
253 (struct sockaddr *)&dest, sizeof(dest));
254 if (ret == -1) {
255 int save_errno = errno;
256 talloc_free(state);
257 return save_errno;
260 state->hostname = get_myname(state);
261 if (state->hostname == NULL) {
262 /* Use a fallback instead of failing initialisation */
263 state->hostname = "localhost";
265 if (rfc5424) {
266 state->format = format_rfc5424;
267 } else {
268 state->format = format_rfc3164;
271 debug_set_callback(state, ctdb_log_to_syslog_sock);
273 return 0;
276 /**********************************************************************/
278 static void ctdb_log_to_syslog(void *private_ptr, int dbglevel, const char *s)
280 syslog(ctdb_debug_to_syslog_level(dbglevel),
281 "%s%s", debug_extra, s);
284 static int ctdb_log_setup_syslog(TALLOC_CTX *mem_ctx,
285 const char *logging,
286 const char *app_name)
288 size_t l = strlen(CTDB_LOG_SYSLOG_PREFIX);
290 if (logging[l] != '\0') {
291 /* Handle non-blocking extensions here */
292 const char *method;
294 if (logging[l] != ':') {
295 return EINVAL;
297 method = &logging[0] + l + 1;
298 if (strcmp(method, "nonblocking") == 0) {
299 ctdb_log_setup_syslog_un(mem_ctx, app_name);
300 return 0;
302 if (strcmp(method, "udp") == 0) {
303 ctdb_log_setup_syslog_udp(mem_ctx, app_name, false);
304 return 0;
306 if (strcmp(method, "udp-rfc5424") == 0) {
307 ctdb_log_setup_syslog_udp(mem_ctx, app_name, true);
308 return 0;
311 return EINVAL;
314 debug_set_callback(NULL, ctdb_log_to_syslog);
315 return 0;
318 void ctdb_log_init_syslog(void)
320 ctdb_log_register_backend(CTDB_LOG_SYSLOG_PREFIX,
321 ctdb_log_setup_syslog);