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