Merge "Fix SIGSEV on freeing server domains list" into tizen
[platform/upstream/connman.git] / src / log.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
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, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <syslog.h>
32 #include <dlfcn.h>
33 #include <signal.h>
34
35 #include "connman.h"
36
37 static const char *program_exec;
38 static const char *program_path;
39
40 #if defined TIZEN_EXT
41 #include <sys/stat.h>
42 #include <sys/time.h>
43 #include <stdbool.h>
44 #include <dlog.h>
45
46 #undef LOG_TAG
47 #define LOG_TAG "CONNMAN"
48
49 #define LOG_FILE_PATH "/opt/usr/data/network/connman.log"
50 #define MAX_LOG_SIZE    1 * 1024 * 1024
51 #define MAX_LOG_COUNT   15
52
53 #define openlog __connman_log_open
54 #define closelog __connman_log_close
55 #define vsyslog __connman_log
56 #define syslog __connman_log_s
57
58 static FILE *log_file = NULL;
59 static bool dlog_logging = true;
60 static bool file_logging = true;
61 static bool simple_log = true;
62
63 bool get_simple_log_option(void)
64 {
65         return simple_log;
66 }
67
68 void set_simple_log_option(bool option)
69 {
70         simple_log = option;
71 }
72
73 void set_dlog_logging_option(bool option)
74 {
75         dlog_logging = option;
76 }
77
78 void set_file_logging_option(bool option)
79 {
80         file_logging = option;
81 }
82
83 void __connman_log_open(const char *ident, int option, int facility)
84 {
85         if (!log_file)
86                 log_file = (FILE *)fopen(LOG_FILE_PATH, "a+");
87 }
88
89 void __connman_log_close(void)
90 {
91         fclose(log_file);
92         log_file = NULL;
93 }
94
95 static void __connman_log_update_file_revision(int rev)
96 {
97         int next_log_rev = 0;
98         char *log_file = NULL;
99         char *next_log_file = NULL;
100
101         next_log_rev = rev + 1;
102
103         log_file = g_strdup_printf("%s.%d", LOG_FILE_PATH, rev);
104         next_log_file = g_strdup_printf("%s.%d", LOG_FILE_PATH, next_log_rev);
105
106         if (next_log_rev >= MAX_LOG_COUNT)
107                 if (remove(next_log_file) != 0)
108                         goto error;
109
110         if (access(next_log_file, F_OK) == 0)
111                 __connman_log_update_file_revision(next_log_rev);
112
113         if (rename(log_file, next_log_file) != 0)
114                 remove(log_file);
115
116 error:
117         g_free(log_file);
118         g_free(next_log_file);
119 }
120
121 static int __connman_log_make_backup(void)
122 {
123         const int rev = 0;
124         char *backup = NULL;
125         int ret = 0;
126
127         backup = g_strdup_printf("%s.%d", LOG_FILE_PATH, rev);
128
129         if (access(backup, F_OK) == 0)
130                 __connman_log_update_file_revision(rev);
131
132         if (rename(LOG_FILE_PATH, backup) != 0)
133                 if (remove(LOG_FILE_PATH) != 0)
134                         ret = -1;
135
136         g_free(backup);
137         return ret;
138 }
139
140 static void __connman_log_get_local_time(char *strtime, const int size)
141 {
142         struct timeval tv;
143         struct tm *local_ptm;
144         char buf[32];
145
146         gettimeofday(&tv, NULL);
147         local_ptm = localtime(&tv.tv_sec);
148
149         strftime(buf, sizeof(buf), "%m/%d %H:%M:%S", local_ptm);
150         snprintf(strtime, size, "%s.%03ld", buf, tv.tv_usec / 1000);
151 }
152
153 void __connman_log(const int log_priority, const char *format, va_list ap)
154 {
155         int log_size = 0;
156         struct stat buf;
157         char str[256];
158         char strtime[64];
159
160         if (!log_file)
161                 log_file = (FILE *)fopen(LOG_FILE_PATH, "a+");
162
163         if (!log_file)
164                 return;
165
166         if (fstat(fileno(log_file), &buf) < 0) {
167                 fclose(log_file);
168                 log_file = NULL;
169                 return;
170         }
171
172         log_size = buf.st_size;
173
174         if (log_size >= MAX_LOG_SIZE) {
175                 fclose(log_file);
176                 log_file = NULL;
177
178                 if (__connman_log_make_backup() != 0)
179                         return;
180
181                 log_file = (FILE *)fopen(LOG_FILE_PATH, "a+");
182
183                 if (!log_file)
184                         return;
185         }
186
187         __connman_log_get_local_time(strtime, sizeof(strtime));
188
189         if (vsnprintf(str, sizeof(str), format, ap) > 0)
190                 fprintf(log_file, "%s %s\n", strtime, str);
191 }
192
193 void __connman_log_s(int log_priority, const char *format, ...)
194 {
195         va_list ap;
196
197         va_start(ap, format);
198
199         if (dlog_logging)
200                 dlog_vprint(DLOG_DEBUG, LOG_TAG, format, ap);
201
202         va_end(ap);
203         va_start(ap, format);
204
205         if (file_logging)
206                 vsyslog(LOG_DEBUG, format, ap);
207
208         va_end(ap);
209 }
210 #endif
211
212 /* This makes sure we always have a __debug section. */
213 CONNMAN_DEBUG_DEFINE(dummy);
214
215 /**
216  * connman_info:
217  * @format: format string
218  * @Varargs: list of arguments
219  *
220  * Output general information
221  */
222 void connman_info(const char *format, ...)
223 {
224         va_list ap;
225
226         va_start(ap, format);
227 #if defined TIZEN_EXT
228         if (dlog_logging)
229                 dlog_vprint(DLOG_INFO, LOG_TAG, format, ap);
230
231         va_end(ap);
232         va_start(ap, format);
233
234         if (file_logging)
235 #endif
236         vsyslog(LOG_INFO, format, ap);
237
238         va_end(ap);
239 }
240
241 /**
242  * connman_warn:
243  * @format: format string
244  * @Varargs: list of arguments
245  *
246  * Output warning messages
247  */
248 void connman_warn(const char *format, ...)
249 {
250         va_list ap;
251
252         va_start(ap, format);
253 #if defined TIZEN_EXT
254         if (dlog_logging)
255                 dlog_vprint(DLOG_WARN, LOG_TAG, format, ap);
256
257         va_end(ap);
258         va_start(ap, format);
259
260         if (file_logging)
261 #endif
262         vsyslog(LOG_WARNING, format, ap);
263
264         va_end(ap);
265 }
266
267 /**
268  * connman_error:
269  * @format: format string
270  * @varargs: list of arguments
271  *
272  * Output error messages
273  */
274 void connman_error(const char *format, ...)
275 {
276         va_list ap;
277
278         va_start(ap, format);
279 #if defined TIZEN_EXT
280         if (dlog_logging)
281                 dlog_vprint(DLOG_ERROR, LOG_TAG, format, ap);
282
283         va_end(ap);
284         va_start(ap, format);
285
286         if (file_logging)
287 #endif
288         vsyslog(LOG_ERR, format, ap);
289
290         va_end(ap);
291 }
292
293 /**
294  * connman_debug:
295  * @format: format string
296  * @varargs: list of arguments
297  *
298  * Output debug message
299  */
300 void connman_debug(const char *format, ...)
301 {
302         va_list ap;
303
304         va_start(ap, format);
305 #if defined TIZEN_EXT
306         if (dlog_logging)
307                 dlog_vprint(DLOG_DEBUG, LOG_TAG, format, ap);
308
309         va_end(ap);
310         va_start(ap, format);
311
312         if (file_logging)
313 #endif
314         vsyslog(LOG_DEBUG, format, ap);
315
316         va_end(ap);
317 }
318
319 static void signal_handler(int signo)
320 {
321         connman_error("Aborting (signal %d) [%s]", signo, program_exec);
322
323         print_backtrace(program_path, program_exec, 2);
324
325         exit(EXIT_FAILURE);
326 }
327
328 static void signal_setup(sighandler_t handler)
329 {
330         struct sigaction sa;
331         sigset_t mask;
332
333         sigemptyset(&mask);
334         sa.sa_handler = handler;
335         sa.sa_mask = mask;
336         sa.sa_flags = 0;
337         sigaction(SIGBUS, &sa, NULL);
338         sigaction(SIGILL, &sa, NULL);
339         sigaction(SIGFPE, &sa, NULL);
340         sigaction(SIGSEGV, &sa, NULL);
341         sigaction(SIGABRT, &sa, NULL);
342         sigaction(SIGPIPE, &sa, NULL);
343 }
344
345 extern struct connman_debug_desc __start___debug[];
346 extern struct connman_debug_desc __stop___debug[];
347
348 static gchar **enabled = NULL;
349
350 static bool is_enabled(struct connman_debug_desc *desc)
351 {
352         int i;
353
354         if (!enabled)
355                 return false;
356
357         for (i = 0; enabled[i]; i++) {
358                 if (desc->name && g_pattern_match_simple(enabled[i],
359                                                         desc->name))
360                         return true;
361                 if (desc->file && g_pattern_match_simple(enabled[i],
362                                                         desc->file))
363                         return true;
364         }
365
366         return false;
367 }
368
369 void __connman_log_enable(struct connman_debug_desc *start,
370                                         struct connman_debug_desc *stop)
371 {
372         struct connman_debug_desc *desc;
373         const char *name = NULL, *file = NULL;
374
375         if (!start || !stop)
376                 return;
377
378         for (desc = start; desc < stop; desc++) {
379                 if (desc->flags & CONNMAN_DEBUG_FLAG_ALIAS) {
380                         file = desc->file;
381                         name = desc->name;
382                         continue;
383                 }
384
385                 if (file || name) {
386                         if (g_strcmp0(desc->file, file) == 0) {
387                                 if (!desc->name)
388                                         desc->name = name;
389                         } else
390                                 file = NULL;
391                 }
392
393                 if (is_enabled(desc))
394                         desc->flags |= CONNMAN_DEBUG_FLAG_PRINT;
395         }
396 }
397
398 int __connman_log_init(const char *program, const char *debug,
399                 gboolean detach, gboolean backtrace,
400                 const char *program_name, const char *program_version)
401 {
402         static char path[PATH_MAX];
403         int option = LOG_NDELAY | LOG_PID;
404
405         program_exec = program;
406         program_path = getcwd(path, sizeof(path));
407
408         if (debug)
409                 enabled = g_strsplit_set(debug, ":, ", 0);
410
411         __connman_log_enable(__start___debug, __stop___debug);
412
413         if (!detach)
414                 option |= LOG_PERROR;
415
416         if (backtrace)
417                 signal_setup(signal_handler);
418
419         openlog(basename(program), option, LOG_DAEMON);
420
421         syslog(LOG_INFO, "%s version %s", program_name, program_version);
422
423         return 0;
424 }
425
426 void __connman_log_cleanup(gboolean backtrace)
427 {
428         syslog(LOG_INFO, "Exit");
429
430         closelog();
431
432         if (backtrace)
433                 signal_setup(SIG_DFL);
434
435         g_strfreev(enabled);
436 }