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