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