[Fix][src/service] Add 'fall through' comment when break statement is not needed
[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
44 #define LOG_FILE_PATH "/opt/usr/data/network/connman.log"
45 #define MAX_LOG_SIZE    1 * 1024 * 1024
46 #define MAX_LOG_COUNT   15
47
48 #define openlog __connman_log_open
49 #define closelog __connman_log_close
50 #define vsyslog __connman_log
51 #define syslog __connman_log_s
52
53 static FILE *log_file = NULL;
54
55 void __connman_log_open(const char *ident, int option, int facility)
56 {
57         if (!log_file)
58                 log_file = (FILE *)fopen(LOG_FILE_PATH, "a+");
59 }
60
61 void __connman_log_close(void)
62 {
63         fclose(log_file);
64         log_file = NULL;
65 }
66
67 static void __connman_log_update_file_revision(int rev)
68 {
69         int next_log_rev = 0;
70         char *log_file = NULL;
71         char *next_log_file = NULL;
72
73         next_log_rev = rev + 1;
74
75         log_file = g_strdup_printf("%s.%d", LOG_FILE_PATH, rev);
76         next_log_file = g_strdup_printf("%s.%d", LOG_FILE_PATH, next_log_rev);
77
78         if (next_log_rev >= MAX_LOG_COUNT)
79                 if (remove(next_log_file) != 0)
80                         goto error;
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 error:
89         g_free(log_file);
90         g_free(next_log_file);
91 }
92
93 static int __connman_log_make_backup(void)
94 {
95         const int rev = 0;
96         char *backup = NULL;
97         int ret = 0;
98
99         backup = g_strdup_printf("%s.%d", LOG_FILE_PATH, rev);
100
101         if (access(backup, F_OK) == 0)
102                 __connman_log_update_file_revision(rev);
103
104         if (rename(LOG_FILE_PATH, backup) != 0)
105                 if (remove(LOG_FILE_PATH) != 0)
106                         ret = -1;
107
108         g_free(backup);
109         return ret;
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         if (fstat(fileno(log_file), &buf) < 0) {
139                 fclose(log_file);
140                 log_file = NULL;
141                 return;
142         }
143
144         log_size = buf.st_size;
145
146         if (log_size >= MAX_LOG_SIZE) {
147                 fclose(log_file);
148                 log_file = NULL;
149
150                 if (__connman_log_make_backup() != 0)
151                         return;
152
153                 log_file = (FILE *)fopen(LOG_FILE_PATH, "a+");
154
155                 if (!log_file)
156                         return;
157         }
158
159         __connman_log_get_local_time(strtime, sizeof(strtime));
160
161         if (vsnprintf(str, sizeof(str), format, ap) > 0)
162                 fprintf(log_file, "%s %s\n", strtime, str);
163 }
164
165 void __connman_log_s(int log_priority, const char *format, ...)
166 {
167         va_list ap;
168
169         va_start(ap, format);
170
171         vsyslog(LOG_DEBUG, format, ap);
172
173         va_end(ap);
174 }
175 #endif
176
177 /* This makes sure we always have a __debug section. */
178 CONNMAN_DEBUG_DEFINE(dummy);
179
180 /**
181  * connman_info:
182  * @format: format string
183  * @Varargs: list of arguments
184  *
185  * Output general information
186  */
187 void connman_info(const char *format, ...)
188 {
189         va_list ap;
190
191         va_start(ap, format);
192
193         vsyslog(LOG_INFO, format, ap);
194
195         va_end(ap);
196 }
197
198 /**
199  * connman_warn:
200  * @format: format string
201  * @Varargs: list of arguments
202  *
203  * Output warning messages
204  */
205 void connman_warn(const char *format, ...)
206 {
207         va_list ap;
208
209         va_start(ap, format);
210
211         vsyslog(LOG_WARNING, format, ap);
212
213         va_end(ap);
214 }
215
216 /**
217  * connman_error:
218  * @format: format string
219  * @varargs: list of arguments
220  *
221  * Output error messages
222  */
223 void connman_error(const char *format, ...)
224 {
225         va_list ap;
226
227         va_start(ap, format);
228
229         vsyslog(LOG_ERR, format, ap);
230
231         va_end(ap);
232 }
233
234 /**
235  * connman_debug:
236  * @format: format string
237  * @varargs: list of arguments
238  *
239  * Output debug message
240  */
241 void connman_debug(const char *format, ...)
242 {
243         va_list ap;
244
245         va_start(ap, format);
246
247         vsyslog(LOG_DEBUG, format, ap);
248
249         va_end(ap);
250 }
251
252 static void signal_handler(int signo)
253 {
254         connman_error("Aborting (signal %d) [%s]", signo, program_exec);
255
256         print_backtrace(program_path, program_exec, 2);
257
258         exit(EXIT_FAILURE);
259 }
260
261 static void signal_setup(sighandler_t handler)
262 {
263         struct sigaction sa;
264         sigset_t mask;
265
266         sigemptyset(&mask);
267         sa.sa_handler = handler;
268         sa.sa_mask = mask;
269         sa.sa_flags = 0;
270         sigaction(SIGBUS, &sa, NULL);
271         sigaction(SIGILL, &sa, NULL);
272         sigaction(SIGFPE, &sa, NULL);
273         sigaction(SIGSEGV, &sa, NULL);
274         sigaction(SIGABRT, &sa, NULL);
275         sigaction(SIGPIPE, &sa, NULL);
276 }
277
278 extern struct connman_debug_desc __start___debug[];
279 extern struct connman_debug_desc __stop___debug[];
280
281 static gchar **enabled = NULL;
282
283 static bool is_enabled(struct connman_debug_desc *desc)
284 {
285         int i;
286
287         if (!enabled)
288                 return false;
289
290         for (i = 0; enabled[i]; i++) {
291                 if (desc->name && g_pattern_match_simple(enabled[i],
292                                                         desc->name))
293                         return true;
294                 if (desc->file && g_pattern_match_simple(enabled[i],
295                                                         desc->file))
296                         return true;
297         }
298
299         return false;
300 }
301
302 void __connman_log_enable(struct connman_debug_desc *start,
303                                         struct connman_debug_desc *stop)
304 {
305         struct connman_debug_desc *desc;
306         const char *name = NULL, *file = NULL;
307
308         if (!start || !stop)
309                 return;
310
311         for (desc = start; desc < stop; desc++) {
312                 if (desc->flags & CONNMAN_DEBUG_FLAG_ALIAS) {
313                         file = desc->file;
314                         name = desc->name;
315                         continue;
316                 }
317
318                 if (file || name) {
319                         if (g_strcmp0(desc->file, file) == 0) {
320                                 if (!desc->name)
321                                         desc->name = name;
322                         } else
323                                 file = NULL;
324                 }
325
326                 if (is_enabled(desc))
327                         desc->flags |= CONNMAN_DEBUG_FLAG_PRINT;
328         }
329 }
330
331 int __connman_log_init(const char *program, const char *debug,
332                 gboolean detach, gboolean backtrace,
333                 const char *program_name, const char *program_version)
334 {
335         static char path[PATH_MAX];
336         int option = LOG_NDELAY | LOG_PID;
337
338         program_exec = program;
339         program_path = getcwd(path, sizeof(path));
340
341         if (debug)
342                 enabled = g_strsplit_set(debug, ":, ", 0);
343
344         __connman_log_enable(__start___debug, __stop___debug);
345
346         if (!detach)
347                 option |= LOG_PERROR;
348
349         if (backtrace)
350                 signal_setup(signal_handler);
351
352         openlog(basename(program), option, LOG_DAEMON);
353
354         syslog(LOG_INFO, "%s version %s", program_name, program_version);
355
356         return 0;
357 }
358
359 void __connman_log_cleanup(gboolean backtrace)
360 {
361         syslog(LOG_INFO, "Exit");
362
363         closelog();
364
365         if (backtrace)
366                 signal_setup(SIG_DFL);
367
368         g_strfreev(enabled);
369 }