add missing checks on so far ignored return values
[nivanova/samba-autobuild/.git] / ctdb / server / ctdb_logging.c
1 /* 
2    ctdb logging code
3
4    Copyright (C) Andrew Tridgell  2008
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "lib/events/events.h"
22 #include "../include/ctdb_private.h"
23 #include "system/syslog.h"
24 #include "system/time.h"
25 #include "system/filesys.h"
26
27 struct ctdb_log_state {
28         int fd, pfd;
29         char buf[1024];
30         uint16_t buf_used;
31         bool use_syslog;
32 };
33
34 /* we need this global to eep the DEBUG() syntax */
35 static struct ctdb_log_state *log_state;
36
37 /*
38   syslog logging function
39  */
40 static void ctdb_syslog_log(const char *format, va_list ap)
41 {
42         int level = LOG_DEBUG;
43         switch (this_log_level) {
44         case DEBUG_EMERG: 
45                 level = LOG_EMERG; 
46                 break;
47         case DEBUG_ALERT: 
48                 level = LOG_ALERT; 
49                 break;
50         case DEBUG_CRIT: 
51                 level = LOG_CRIT; 
52                 break;
53         case DEBUG_ERR: 
54                 level = LOG_ERR; 
55                 break;
56         case DEBUG_WARNING: 
57                 level = LOG_WARNING; 
58                 break;
59         case DEBUG_NOTICE: 
60                 level = LOG_NOTICE;
61                 break;
62         case DEBUG_INFO: 
63                 level = LOG_INFO;
64                 break;
65         default:
66                 level = LOG_DEBUG;
67                 break;          
68         }
69         vsyslog(level, format, ap);
70 }
71
72
73 /*
74   log file logging function
75  */
76 static void ctdb_logfile_log(const char *format, va_list ap)
77 {
78         struct timeval t;
79         char *s = NULL;
80         struct tm *tm;
81         char tbuf[100];
82         char *s2 = NULL;
83         int ret;
84
85         ret = vasprintf(&s, format, ap);
86         if (ret == -1) {
87                 write(log_state->fd, "vasprintf failed\n", strlen("vasprintf failed\n"));
88                 return;
89         }
90
91         t = timeval_current();
92         tm = localtime(&t.tv_sec);
93
94         strftime(tbuf,sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm);
95
96         ret = asprintf(&s2, "%s.%06u [%5u]: %s",
97                  tbuf, (unsigned)t.tv_usec, (unsigned)getpid(), s);
98         free(s);
99         if (ret == -1) {
100                 write(log_state->fd, "asprintf failed\n", strlen("asprintf failed\n"));
101                 return;
102         }
103         if (s2) {
104                 write(log_state->fd, s2, strlen(s2));
105                 free(s2);
106         }
107 }
108
109 /*
110   choose the logfile location
111 */
112 int ctdb_set_logfile(struct ctdb_context *ctdb, const char *logfile, bool use_syslog)
113 {
114         int ret;
115         ctdb->log = talloc_zero(ctdb, struct ctdb_log_state);
116         if (ctdb->log == NULL) {
117                 printf("talloc_zero failed\n");
118                 abort();
119         }
120
121         log_state = ctdb->log;
122
123         if (use_syslog) {
124                 do_debug_v = ctdb_syslog_log;
125                 ctdb->log->use_syslog = true;
126         } else if (logfile == NULL || strcmp(logfile, "-") == 0) {
127                 do_debug_v = ctdb_logfile_log;
128                 ctdb->log->fd = 1;
129                 /* also catch stderr of subcommands to stdout */
130                 ret = dup2(1, 2);
131                 if (ret == -1) {
132                         printf("dup2 failed: %s\n", strerror(errno));
133                         abort();
134                 }
135         } else {
136                 do_debug_v = ctdb_logfile_log;
137
138                 ctdb->log->fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT, 0666);
139                 if (ctdb->log->fd == -1) {
140                         printf("Failed to open logfile %s\n", logfile);
141                         abort();
142                 }
143         }
144
145         return 0;
146 }
147
148
149
150 /*
151   called when log data comes in from a child process
152  */
153 static void ctdb_log_handler(struct event_context *ev, struct fd_event *fde, 
154                              uint16_t flags, void *private)
155 {
156         struct ctdb_context *ctdb = talloc_get_type(private, struct ctdb_context);
157         char *p;
158         int n;
159
160         if (!(flags & EVENT_FD_READ)) {
161                 return;
162         }
163         
164         n = read(ctdb->log->pfd, &ctdb->log->buf[ctdb->log->buf_used],
165                  sizeof(ctdb->log->buf) - ctdb->log->buf_used);
166         if (n > 0) {
167                 ctdb->log->buf_used += n;
168         }
169
170         this_log_level = script_log_level;
171
172         while (ctdb->log->buf_used > 0 &&
173                (p = memchr(ctdb->log->buf, '\n', ctdb->log->buf_used)) != NULL) {
174                 int n1 = (p - ctdb->log->buf)+1;
175                 int n2 = n1 - 1;
176                 /* swallow \r from child processes */
177                 if (n2 > 0 && ctdb->log->buf[n2-1] == '\r') {
178                         n2--;
179                 }
180                 if (script_log_level <= LogLevel) {
181                         do_debug("%*.*s\n", n2, n2, ctdb->log->buf);
182                         /* log it in the eventsystem as well */
183                         ctdb_log_event_script_output(ctdb, ctdb->log->buf, n2);
184                 }
185                 memmove(ctdb->log->buf, p+1, sizeof(ctdb->log->buf) - n1);
186                 ctdb->log->buf_used -= n1;
187         }
188
189         /* the buffer could have completely filled - unfortunately we have
190            no choice but to dump it out straight away */
191         if (ctdb->log->buf_used == sizeof(ctdb->log->buf)) {
192                 if (script_log_level <= LogLevel) {
193                         do_debug("%*.*s\n", 
194                                 (int)ctdb->log->buf_used, (int)ctdb->log->buf_used, ctdb->log->buf);
195                         /* log it in the eventsystem as well */
196                         ctdb_log_event_script_output(ctdb, ctdb->log->buf, ctdb->log->buf_used);
197                 }
198                 ctdb->log->buf_used = 0;
199         }
200 }
201
202
203
204 /*
205   setup for logging of child process stdout
206 */
207 int ctdb_set_child_logging(struct ctdb_context *ctdb)
208 {
209         int p[2];
210         int ret;
211
212         if (ctdb->log->fd == 1) {
213                 /* not needed for stdout logging */
214                 return 0;
215         }
216
217         /* setup a pipe to catch IO from subprocesses */
218         if (pipe(p) != 0) {
219                 DEBUG(DEBUG_ERR,(__location__ " Failed to setup for child logging pipe\n"));
220                 return -1;
221         }
222
223         event_add_fd(ctdb->ev, ctdb, p[0], EVENT_FD_READ, 
224                      ctdb_log_handler, ctdb);
225         set_close_on_exec(p[0]);
226         ctdb->log->pfd = p[0];
227
228         close(1);
229         close(2);
230         if (p[1] != 1) {
231                 ret = dup2(p[1], 1);
232                 if (ret == -1) {
233                         printf("dup2 failed: %s\n", strerror(errno));
234                         return -1;
235                 }
236                 close(p[1]);
237         }
238         /* also catch stderr of subcommands to the log */
239         ret = dup2(1, 2);
240         if (ret == -1) {
241                 printf("dup2 failed: %s\n", strerror(errno));
242                 return -1;
243         }
244
245         return 0;
246 }