Upgrade ofono to 1.11 and merge to 2.0alpha
[profile/ivi/ofono.git] / src / log.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2008-2011  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 "ofono.h"
37
38 static const char *program_exec;
39 static const char *program_path;
40
41 /**
42  * ofono_info:
43  * @format: format string
44  * @Varargs: list of arguments
45  *
46  * Output general information
47  */
48 void ofono_info(const char *format, ...)
49 {
50         va_list ap;
51
52         va_start(ap, format);
53
54         vsyslog(LOG_INFO, format, ap);
55
56         va_end(ap);
57 }
58
59 /**
60  * ofono_warn:
61  * @format: format string
62  * @Varargs: list of arguments
63  *
64  * Output warning messages
65  */
66 void ofono_warn(const char *format, ...)
67 {
68         va_list ap;
69
70         va_start(ap, format);
71
72         vsyslog(LOG_WARNING, format, ap);
73
74         va_end(ap);
75 }
76
77 /**
78  * ofono_error:
79  * @format: format string
80  * @varargs: list of arguments
81  *
82  * Output error messages
83  */
84 void ofono_error(const char *format, ...)
85 {
86         va_list ap;
87
88         va_start(ap, format);
89
90         vsyslog(LOG_ERR, format, ap);
91
92         va_end(ap);
93 }
94
95 /**
96  * ofono_debug:
97  * @format: format string
98  * @varargs: list of arguments
99  *
100  * Output debug message
101  *
102  * The actual output of the debug message is controlled via a command line
103  * switch. If not enabled, these messages will be ignored.
104  */
105 void ofono_debug(const char *format, ...)
106 {
107         va_list ap;
108
109         va_start(ap, format);
110
111         vsyslog(LOG_DEBUG, format, ap);
112
113         va_end(ap);
114 }
115
116 static void print_backtrace(unsigned int offset)
117 {
118         void *frames[99];
119         size_t n_ptrs;
120         unsigned int i;
121         int outfd[2], infd[2];
122         int pathlen;
123         pid_t pid;
124
125         if (program_exec == NULL)
126                 return;
127
128         pathlen = strlen(program_path);
129
130         n_ptrs = backtrace(frames, G_N_ELEMENTS(frames));
131         if (n_ptrs < offset)
132                 return;
133
134         if (pipe(outfd) < 0)
135                 return;
136
137         if (pipe(infd) < 0) {
138                 close(outfd[0]);
139                 close(outfd[1]);
140                 return;
141         }
142
143         pid = fork();
144         if (pid < 0) {
145                 close(outfd[0]);
146                 close(outfd[1]);
147                 close(infd[0]);
148                 close(infd[1]);
149                 return;
150         }
151
152         if (pid == 0) {
153                 close(outfd[1]);
154                 close(infd[0]);
155
156                 dup2(outfd[0], STDIN_FILENO);
157                 dup2(infd[1], STDOUT_FILENO);
158
159                 execlp("addr2line", "-C", "-f", "-e", program_exec, NULL);
160
161                 exit(EXIT_FAILURE);
162         }
163
164         close(outfd[0]);
165         close(infd[1]);
166
167         ofono_error("++++++++ backtrace ++++++++");
168
169         for (i = offset; i < n_ptrs - 1; i++) {
170                 Dl_info info;
171                 char addr[20], buf[PATH_MAX * 2];
172                 int len, written;
173                 char *ptr, *pos;
174
175                 dladdr(frames[i], &info);
176
177                 len = snprintf(addr, sizeof(addr), "%p\n", frames[i]);
178                 if (len < 0)
179                         break;
180
181                 written = write(outfd[1], addr, len);
182                 if (written < 0)
183                         break;
184
185                 len = read(infd[0], buf, sizeof(buf));
186                 if (len < 0)
187                         break;
188
189                 buf[len] = '\0';
190
191                 pos = strchr(buf, '\n');
192                 *pos++ = '\0';
193
194                 if (strcmp(buf, "??") == 0) {
195                         ofono_error("#%-2u %p in %s", i - offset,
196                                                 frames[i], info.dli_fname);
197                         continue;
198                 }
199
200                 ptr = strchr(pos, '\n');
201                 *ptr++ = '\0';
202
203                 if (strncmp(pos, program_path, pathlen) == 0)
204                         pos += pathlen + 1;
205
206                 ofono_error("#%-2u %p in %s() at %s", i - offset,
207                                                 frames[i], buf, pos);
208         }
209
210         ofono_error("+++++++++++++++++++++++++++");
211
212         kill(pid, SIGTERM);
213
214         close(outfd[1]);
215         close(infd[0]);
216 }
217
218 static void signal_handler(int signo)
219 {
220         ofono_error("Aborting (signal %d) [%s]", signo, program_exec);
221
222         print_backtrace(2);
223
224         exit(EXIT_FAILURE);
225 }
226
227 static void signal_setup(sighandler_t handler)
228 {
229         struct sigaction sa;
230         sigset_t mask;
231
232         sigemptyset(&mask);
233         sa.sa_handler = handler;
234         sa.sa_mask = mask;
235         sa.sa_flags = 0;
236         sigaction(SIGBUS, &sa, NULL);
237         sigaction(SIGILL, &sa, NULL);
238         sigaction(SIGFPE, &sa, NULL);
239         sigaction(SIGSEGV, &sa, NULL);
240         sigaction(SIGABRT, &sa, NULL);
241         sigaction(SIGPIPE, &sa, NULL);
242 }
243
244 extern struct ofono_debug_desc __start___debug[];
245 extern struct ofono_debug_desc __stop___debug[];
246
247 static gchar **enabled = NULL;
248
249 static ofono_bool_t is_enabled(struct ofono_debug_desc *desc)
250 {
251         int i;
252
253         if (enabled == NULL)
254                 return FALSE;
255
256         for (i = 0; enabled[i] != NULL; i++) {
257                 if (desc->name != NULL && g_pattern_match_simple(enabled[i],
258                                                         desc->name) == TRUE)
259                         return TRUE;
260                 if (desc->file != NULL && g_pattern_match_simple(enabled[i],
261                                                         desc->file) == TRUE)
262                         return TRUE;
263         }
264
265         return FALSE;
266 }
267
268 void __ofono_log_enable(struct ofono_debug_desc *start,
269                                         struct ofono_debug_desc *stop)
270 {
271         struct ofono_debug_desc *desc;
272         const char *name = NULL, *file = NULL;
273
274         if (start == NULL || stop == NULL)
275                 return;
276
277         for (desc = start; desc < stop; desc++) {
278                 if (file != NULL || name != NULL) {
279                         if (g_strcmp0(desc->file, file) == 0) {
280                                 if (desc->name == NULL)
281                                         desc->name = name;
282                         } else
283                                 file = NULL;
284                 }
285
286                 if (is_enabled(desc) == TRUE)
287                         desc->flags |= OFONO_DEBUG_FLAG_PRINT;
288         }
289 }
290
291 int __ofono_log_init(const char *program, const char *debug,
292                                                 ofono_bool_t detach)
293 {
294         static char path[PATH_MAX];
295         int option = LOG_NDELAY | LOG_PID;
296
297         program_exec = program;
298         program_path = getcwd(path, sizeof(path));
299
300         if (debug != NULL)
301                 enabled = g_strsplit_set(debug, ":, ", 0);
302
303         __ofono_log_enable(__start___debug, __stop___debug);
304
305         if (detach == FALSE)
306                 option |= LOG_PERROR;
307
308         signal_setup(signal_handler);
309
310         openlog(basename(program), option, LOG_DAEMON);
311
312         syslog(LOG_INFO, "oFono version %s", VERSION);
313
314         return 0;
315 }
316
317 void __ofono_log_cleanup(void)
318 {
319         syslog(LOG_INFO, "Exit");
320
321         closelog();
322
323         signal_setup(SIG_DFL);
324
325         g_strfreev(enabled);
326 }