Fix SVACE issue for CID:24236, 31182
[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 #define _GNU_SOURCE
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <syslog.h>
33 #include <execinfo.h>
34 #include <dlfcn.h>
35
36 #include "connman.h"
37
38 static const char *program_exec;
39 static const char *program_path;
40
41 #if defined TIZEN_EXT
42 #include <sys/stat.h>
43 #include <sys/time.h>
44
45 #define LOG_FILE_PATH "/opt/usr/data/network/connman.log"
46 #define MAX_LOG_SIZE    1 * 1024 * 1024
47 #define MAX_LOG_COUNT   1
48
49 #define openlog __connman_log_open
50 #define closelog __connman_log_close
51 #define vsyslog __connman_log
52 #define syslog __connman_log_s
53
54 static FILE *log_file = NULL;
55
56 void __connman_log_open(const char *ident, int option, int facility)
57 {
58         if (!log_file)
59                 log_file = (FILE *)fopen(LOG_FILE_PATH, "a+");
60 }
61
62 void __connman_log_close(void)
63 {
64         fclose(log_file);
65         log_file = NULL;
66 }
67
68 static void __connman_log_update_file_revision(int rev)
69 {
70         int next_log_rev = 0;
71         char *log_file = NULL;
72         char *next_log_file = NULL;
73
74         next_log_rev = rev + 1;
75
76         log_file = g_strdup_printf("%s.%d", LOG_FILE_PATH, rev);
77         next_log_file = g_strdup_printf("%s.%d", LOG_FILE_PATH, next_log_rev);
78
79         if (next_log_rev >= MAX_LOG_COUNT)
80                 if (remove(next_log_file) != 0)
81                         __connman_log_s(LOG_INFO, "error: remove failed for %s", next_log_file);
82
83         if (access(next_log_file, F_OK) == 0)
84                 __connman_log_update_file_revision(next_log_rev);
85
86         if (rename(log_file, next_log_file) != 0)
87                 if (remove(log_file) != 0)
88                         __connman_log_s(LOG_INFO, "error: remove failed for %s", log_file);
89
90         g_free(log_file);
91         g_free(next_log_file);
92 }
93
94 static void __connman_log_make_backup(void)
95 {
96         const int rev = 0;
97         char *backup = NULL;
98
99         backup = g_strdup_printf("%s.%d", LOG_FILE_PATH, rev);
100
101         if (access(backup, F_OK) == 0)
102                 __connman_log_update_file_revision(rev);
103
104         if (rename(LOG_FILE_PATH, backup) != 0)
105                 if (remove(LOG_FILE_PATH) != 0)
106                         __connman_log_s(LOG_INFO, "error: remove failed for %s", LOG_FILE_PATH);
107
108         g_free(backup);
109 }
110
111 static void __connman_log_get_local_time(char *strtime, const int size)
112 {
113         struct timeval tv;
114         struct tm *local_ptm;
115         char buf[32];
116
117         gettimeofday(&tv, NULL);
118         local_ptm = localtime(&tv.tv_sec);
119
120         strftime(buf, sizeof(buf), "%m/%d %H:%M:%S", local_ptm);
121         snprintf(strtime, size, "%s.%03ld", buf, tv.tv_usec / 1000);
122 }
123
124 void __connman_log(const int log_priority, const char *format, va_list ap)
125 {
126         int log_size = 0;
127         struct stat buf;
128         char str[256];
129         char strtime[40];
130
131         if (!log_file)
132                 log_file = (FILE *)fopen(LOG_FILE_PATH, "a+");
133
134         if (!log_file)
135                 return;
136
137         fstat(fileno(log_file), &buf);
138         log_size = buf.st_size;
139
140         if (log_size >= MAX_LOG_SIZE) {
141                 fclose(log_file);
142                 log_file = NULL;
143
144                 __connman_log_make_backup();
145
146                 log_file = (FILE *)fopen(LOG_FILE_PATH, "a+");
147
148                 if (!log_file)
149                         return;
150         }
151
152         __connman_log_get_local_time(strtime, sizeof(strtime));
153
154         if (vsnprintf(str, sizeof(str), format, ap) > 0)
155                 fprintf(log_file, "%s %s\n", strtime, str);
156 }
157
158 void __connman_log_s(int log_priority, const char *format, ...)
159 {
160         va_list ap;
161
162         va_start(ap, format);
163
164         vsyslog(LOG_DEBUG, format, ap);
165
166         va_end(ap);
167 }
168 #endif
169
170 /**
171  * connman_info:
172  * @format: format string
173  * @Varargs: list of arguments
174  *
175  * Output general information
176  */
177 void connman_info(const char *format, ...)
178 {
179         va_list ap;
180
181         va_start(ap, format);
182
183         vsyslog(LOG_INFO, format, ap);
184
185         va_end(ap);
186 }
187
188 /**
189  * connman_warn:
190  * @format: format string
191  * @Varargs: list of arguments
192  *
193  * Output warning messages
194  */
195 void connman_warn(const char *format, ...)
196 {
197         va_list ap;
198
199         va_start(ap, format);
200
201         vsyslog(LOG_WARNING, format, ap);
202
203         va_end(ap);
204 }
205
206 /**
207  * connman_error:
208  * @format: format string
209  * @varargs: list of arguments
210  *
211  * Output error messages
212  */
213 void connman_error(const char *format, ...)
214 {
215         va_list ap;
216
217         va_start(ap, format);
218
219         vsyslog(LOG_ERR, format, ap);
220
221         va_end(ap);
222 }
223
224 /**
225  * connman_debug:
226  * @format: format string
227  * @varargs: list of arguments
228  *
229  * Output debug message
230  */
231 void connman_debug(const char *format, ...)
232 {
233         va_list ap;
234
235         va_start(ap, format);
236
237         vsyslog(LOG_DEBUG, format, ap);
238
239         va_end(ap);
240 }
241
242 static void print_backtrace(unsigned int offset)
243 {
244         void *frames[99];
245         size_t n_ptrs;
246         unsigned int i;
247         int outfd[2], infd[2];
248         int pathlen;
249         pid_t pid;
250
251         if (!program_exec)
252                 return;
253
254         pathlen = strlen(program_path);
255
256         n_ptrs = backtrace(frames, G_N_ELEMENTS(frames));
257         if (n_ptrs < offset)
258                 return;
259
260         if (pipe(outfd) < 0)
261                 return;
262
263         if (pipe(infd) < 0) {
264                 close(outfd[0]);
265                 close(outfd[1]);
266                 return;
267         }
268
269         pid = fork();
270         if (pid < 0) {
271                 close(outfd[0]);
272                 close(outfd[1]);
273                 close(infd[0]);
274                 close(infd[1]);
275                 return;
276         }
277
278         if (pid == 0) {
279                 close(outfd[1]);
280                 close(infd[0]);
281
282                 dup2(outfd[0], STDIN_FILENO);
283                 dup2(infd[1], STDOUT_FILENO);
284
285                 execlp("addr2line", "-C", "-f", "-e", program_exec, NULL);
286
287                 exit(EXIT_FAILURE);
288         }
289
290         close(outfd[0]);
291         close(infd[1]);
292
293         connman_error("++++++++ backtrace ++++++++");
294
295         for (i = offset; i < n_ptrs - 1; i++) {
296                 Dl_info info;
297                 char addr[20], buf[PATH_MAX * 2];
298                 int len, written;
299                 char *ptr, *pos;
300
301                 dladdr(frames[i], &info);
302
303                 len = snprintf(addr, sizeof(addr), "%p\n", frames[i]);
304                 if (len < 0)
305                         break;
306
307                 written = write(outfd[1], addr, len);
308                 if (written < 0)
309                         break;
310
311                 len = read(infd[0], buf, sizeof(buf) - 1);
312                 if (len < 0)
313                         break;
314
315                 buf[len] = '\0';
316
317                 pos = strchr(buf, '\n');
318                 *pos++ = '\0';
319
320                 if (strcmp(buf, "??") == 0) {
321                         connman_error("#%-2u %p in %s", i - offset,
322                                                 frames[i], info.dli_fname);
323                         continue;
324                 }
325
326                 ptr = strchr(pos, '\n');
327                 *ptr++ = '\0';
328
329                 if (strncmp(pos, program_path, pathlen) == 0)
330                         pos += pathlen + 1;
331
332                 connman_error("#%-2u %p in %s() at %s", i - offset,
333                                                 frames[i], buf, pos);
334         }
335
336         connman_error("+++++++++++++++++++++++++++");
337
338         kill(pid, SIGTERM);
339
340         close(outfd[1]);
341         close(infd[0]);
342 }
343
344 static void signal_handler(int signo)
345 {
346         connman_error("Aborting (signal %d) [%s]", signo, program_exec);
347
348         print_backtrace(2);
349
350         exit(EXIT_FAILURE);
351 }
352
353 static void signal_setup(sighandler_t handler)
354 {
355         struct sigaction sa;
356         sigset_t mask;
357
358         sigemptyset(&mask);
359         sa.sa_handler = handler;
360         sa.sa_mask = mask;
361         sa.sa_flags = 0;
362         sigaction(SIGBUS, &sa, NULL);
363         sigaction(SIGILL, &sa, NULL);
364         sigaction(SIGFPE, &sa, NULL);
365         sigaction(SIGSEGV, &sa, NULL);
366         sigaction(SIGABRT, &sa, NULL);
367         sigaction(SIGPIPE, &sa, NULL);
368 }
369
370 extern struct connman_debug_desc __start___debug[];
371 extern struct connman_debug_desc __stop___debug[];
372
373 static gchar **enabled = NULL;
374
375 static bool is_enabled(struct connman_debug_desc *desc)
376 {
377         int i;
378
379         if (!enabled)
380                 return false;
381
382         for (i = 0; enabled[i]; i++) {
383                 if (desc->name && g_pattern_match_simple(enabled[i],
384                                                         desc->name))
385                         return true;
386                 if (desc->file && g_pattern_match_simple(enabled[i],
387                                                         desc->file))
388                         return true;
389         }
390
391         return false;
392 }
393
394 void __connman_log_enable(struct connman_debug_desc *start,
395                                         struct connman_debug_desc *stop)
396 {
397         struct connman_debug_desc *desc;
398         const char *name = NULL, *file = NULL;
399
400         if (!start || !stop)
401                 return;
402
403         for (desc = start; desc < stop; desc++) {
404                 if (desc->flags & CONNMAN_DEBUG_FLAG_ALIAS) {
405                         file = desc->file;
406                         name = desc->name;
407                         continue;
408                 }
409
410                 if (file || name) {
411                         if (g_strcmp0(desc->file, file) == 0) {
412                                 if (!desc->name)
413                                         desc->name = name;
414                         } else
415                                 file = NULL;
416                 }
417
418                 if (is_enabled(desc))
419                         desc->flags |= CONNMAN_DEBUG_FLAG_PRINT;
420         }
421 }
422
423 int __connman_log_init(const char *program, const char *debug,
424                 gboolean detach, gboolean backtrace,
425                 const char *program_name, const char *program_version)
426 {
427         static char path[PATH_MAX];
428         int option = LOG_NDELAY | LOG_PID;
429
430         program_exec = program;
431         program_path = getcwd(path, sizeof(path));
432
433         if (debug)
434                 enabled = g_strsplit_set(debug, ":, ", 0);
435
436         __connman_log_enable(__start___debug, __stop___debug);
437
438         if (!detach)
439                 option |= LOG_PERROR;
440
441         if (backtrace)
442                 signal_setup(signal_handler);
443
444         openlog(basename(program), option, LOG_DAEMON);
445
446         syslog(LOG_INFO, "%s version %s", program_name, program_version);
447
448         return 0;
449 }
450
451 void __connman_log_cleanup(gboolean backtrace)
452 {
453         syslog(LOG_INFO, "Exit");
454
455         closelog();
456
457         if (backtrace)
458                 signal_setup(SIG_DFL);
459
460         g_strfreev(enabled);
461 }