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