Fix crash issue when SIGTERM happened
[platform/core/telephony/telephony-daemon.git] / src / main.c
1 /*
2  * telephony-daemon
3  *
4  * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
5  *
6  * Contact: Ja-young Gu <jygu@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #ifdef TIZEN_DEBUG_ENABLE
22 #include "monitor.h"
23 #endif
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <dlfcn.h>
30 #include <getopt.h>
31 #include <sys/stat.h>
32 #include <sys/sysinfo.h>
33
34 #include <glib.h>
35 #include <dlog.h>
36 #include <vconf.h>
37
38 #include <tcore.h>
39 #include <plugin.h>
40 #include <server.h>
41
42 #ifndef DAEMON_VERSION
43 #define DAEMON_VERSION "unknown"
44 #endif
45
46 #ifndef DEFAULT_PLUGINS_PATH
47 #define DEFAULT_PLUGINS_PATH "/usr/lib/telephony/plugins/"
48 #endif
49
50 #define NOTUSED(var) (var = var)
51 #define BUFFER_SIZE 1024
52
53 static Server *_server = NULL;
54
55 static void __usage_info(const char *exec)
56 {
57         info("Usage: %s [OPTION]... [PLUGIN_PATH]\n", exec);
58         info("\n");
59         info("  -T, --testload\t run with plugin load test mode and exit\n");
60         info("  -h, --help\t\t display this help and exit\n");
61         info("\n");
62 }
63
64 void tcore_log(enum tcore_log_type type, enum tcore_log_priority priority, const char *tag, const char *fmt, ...)
65 {
66         va_list ap;
67         char buf[BUFFER_SIZE];
68         int log_id = LOG_ID_RADIO;
69 #ifdef TIZEN_PROFILE_TV
70         log_id = LOG_ID_MAIN;
71         /* Increase log priority for debugging in TV profile */
72         priority = ((priority == TCORE_LOG_DEBUG) ? TCORE_LOG_INFO : priority);
73 #endif
74
75         switch (type) {
76         case TCORE_LOG_TYPE_RADIO: {
77                 if (priority >= TCORE_LOG_INFO) {
78                         va_start(ap, fmt);
79                         vsnprintf(buf, BUFFER_SIZE-1, fmt, ap);
80                         va_end(ap);
81                         __dlog_print(log_id, priority, tag, "%s", buf);
82                 } else {
83                 #ifdef TIZEN_DEBUG_ENABLE
84                         va_start(ap, fmt);
85                         vsnprintf(buf, BUFFER_SIZE-1, fmt, ap);
86                         va_end(ap);
87                         __dlog_print(log_id, priority, tag, "%s", buf);
88                 #endif
89                 }
90         } break;
91
92         case TCORE_LOG_TYPE_TIME_CHECK: {
93         #ifdef TIZEN_DEBUG_ENABLE /* User Mode should not log performance data */
94                 float a = 0.00, b = 0.00;
95                 int next = 0;
96                 FILE *fp = fopen("/proc/uptime", "r");
97                 if (NULL == fp) {
98                         err("fopen() failed");
99                         return;
100                 }
101                 if (fscanf(fp, "%f %f", &a, &b) != 1)
102                         next = snprintf(buf, BUFFER_SIZE, "[UPTIME] [Not Set] ");
103                 else
104                         next = snprintf(buf, BUFFER_SIZE, "[UPTIME] %f ", a);
105                 fclose(fp);
106                 if (next < 0)
107                         return;
108
109                 va_start(ap, fmt);
110                 vsnprintf(buf + next, (BUFFER_SIZE-1) - next, fmt, ap);
111                 va_end(ap);
112                 __dlog_print(log_id, priority, tag, "%s", buf);
113         #endif
114         } break;
115
116         default:
117         break;
118         }
119 }
120
121 static void glib_log(const gchar *log_domain, GLogLevelFlags log_level,
122                 const gchar *msg, gpointer user_data)
123 {
124         NOTUSED(log_domain);
125         NOTUSED(log_level);
126         NOTUSED(user_data);
127
128         __dlog_print(LOG_ID_RADIO, DLOG_ERROR, "GLIB", "%s", msg);
129 }
130
131 #ifdef TIZEN_DEBUG_ENABLE
132 static void telephony_signal_handler(int signo)
133 {
134         if (!_server)
135                 return;
136
137         switch (signo) {
138         case SIGUSR1: {
139                 monitor_server_state(_server);
140         } break;
141
142         case SIGTERM: {
143                 /* temporarily blocked for avoding crash happend on emulator TCT testing */
144                 //tcore_server_exit(_server);
145                 warn("*~*~*~* Ignore Signal: [SIGTERM] *~*~*~*");
146         } break;
147
148 #if defined(TIZEN_PROFILE_TV) || defined(TIZEN_PROFILE_IVI)
149         case SIGHUP: {
150                 warn("*~*~*~* Ignore Signal: [SIGHUP] *~*~*~*");
151         } break;
152 #endif
153
154         default: {
155                 warn("*~*~*~* Unhandled Signal: [%d] *~*~*~*", signo);
156         } break;
157         } /* end switch */
158
159         return;
160 }
161 #elif defined(TIZEN_PROFILE_TV) || defined(TIZEN_PROFILE_IVI)
162 static void telephony_signal_handler(int signo)
163 {
164         if (!_server)
165                 return;
166
167         switch (signo) {
168         case SIGHUP: {
169                 warn("*~*~*~* Ignore Signal: [SIGHUP] *~*~*~*");
170         } break;
171
172         default: {
173                 warn("*~*~*~* Unhandled Signal: [%d] *~*~*~*", signo);
174         } break;
175         } /* end switch */
176
177         return;
178 }
179 #endif
180
181 static void __log_uptime()
182 {
183         float a = 0.00, b = 0.00;
184         FILE *fp = fopen("/proc/uptime", "r");
185
186         if (NULL == fp) {
187                 err("fopen() failed");
188                 return;
189         }
190         info("scanned %d items", fscanf(fp, "%f %f", &a, &b));
191         info("proc uptime = %f idletime = %f\n", a, b);
192         fclose(fp);
193 }
194
195 static gboolean __init_plugin(TcorePlugin *plugin)
196 {
197         const struct tcore_plugin_define_desc *desc = tcore_plugin_get_description(plugin);
198
199         if (!desc || !desc->init)
200                 return FALSE;
201
202         if (!desc->init(plugin)) { /* TODO: Remove plugin from server */
203                 char *plugin_name = tcore_plugin_get_filename(plugin);
204                 if (NULL != plugin_name) {
205                         err("plugin(%s) init failed.", plugin_name);
206                         free(plugin_name);
207                 }
208                 return FALSE;
209         }
210
211         return TRUE;
212 }
213
214 static gboolean init_plugins(Server *s)
215 {
216         GSList *list = tcore_server_ref_plugins(s);
217
218         while (list != NULL) {
219                 if (G_UNLIKELY(FALSE == __init_plugin(list->data))) {
220                         list = g_slist_next(list);
221                         continue;
222                 }
223                 list = g_slist_next(list);
224         }
225
226         return TRUE;
227 }
228
229 static void *__load_plugin(const gchar *filename, struct tcore_plugin_define_desc **desc_out)
230 {
231         void *handle = NULL;
232         struct tcore_plugin_define_desc *desc = NULL;
233         struct stat stat_buf;
234         char file_date[27];
235
236         handle = dlopen(filename, RTLD_LAZY);
237         if (NULL == handle) {
238                 err("dlopen() failed:[%s]", filename);
239                 return NULL;
240         }
241
242         desc = dlsym(handle, "plugin_define_desc");
243         if (NULL == desc) {
244                 err("dlsym() failed:[%s]", "plugin_define_desc");
245                 dlclose(handle);
246                 return NULL;
247         }
248
249         dbg("%s plugin", desc->name);
250         dbg(" - path = %s", filename);
251         dbg(" - version = %d", desc->version);
252         dbg(" - priority = %d", desc->priority);
253
254         memset(&stat_buf, 0x00, sizeof(stat_buf));
255         memset(&file_date, '\0', sizeof(file_date));
256
257         if (0 == stat(filename, &stat_buf)) {
258                 if (NULL != ctime_r(&stat_buf.st_mtime, file_date)) {
259                         if (1 < strlen(file_date))
260                                 file_date[strlen(file_date)-1] = '\0';
261                         dbg(" - date = %s", file_date);
262                 }
263         }
264
265         if (G_LIKELY(desc->load)) {
266                 if (G_UNLIKELY(FALSE == desc->load())) {
267                         warn("false return from load(). skip this plugin");
268                         dlclose(handle);
269                         return NULL;
270                 }
271         }
272
273         if (NULL != desc_out)
274                 *desc_out = desc;
275
276         return handle;
277 }
278
279 static gboolean load_plugins(Server *s, const char *path, gboolean flag_test_load)
280 {
281         const gchar *file = NULL;
282         gchar *filename = NULL;
283         GDir *dir = NULL;
284         void *handle = NULL;
285         struct tcore_plugin_define_desc *desc = NULL;
286
287         if (!path || !s)
288                 return FALSE;
289
290         dir = g_dir_open(path, 0, NULL);
291         if (!dir)
292                 return FALSE;
293
294         while ((file = g_dir_read_name(dir)) != NULL) {
295                 if (g_str_has_prefix(file, "lib") == TRUE
296                         || g_str_has_suffix(file, ".so") == FALSE)
297                         continue;
298
299                 filename = g_build_filename(path, file, NULL);
300
301                 /* Load a plugin */
302                 handle = __load_plugin(filename, &desc);
303                 if (NULL == handle) {
304                         g_free(filename);
305                         continue;
306                 }
307
308                 /* Don't add to server if flag_test_load */
309                 if (flag_test_load) {
310                         dbg("success to load '%s'", filename);
311                         dlclose(handle);
312                         g_free(filename);
313                         continue;
314                 }
315
316                 tcore_server_add_plugin(s, tcore_plugin_new(s, desc, filename, handle));
317
318                 dbg("%s added", desc->name);
319                 g_free(filename);
320         }
321         g_dir_close(dir);
322
323         return TRUE;
324 }
325
326 int main(int argc, char *argv[])
327 {
328 #if defined(TIZEN_DEBUG_ENABLE) || defined(TIZEN_PROFILE_TV) || defined(TIZEN_PROFILE_IVI)
329         struct sigaction sigact;
330 #endif
331         Server *s = NULL;
332         gboolean flag_test_load = FALSE;
333         int opt = 0, opt_index = 0, ret_code = EXIT_SUCCESS;
334         int daemon_load_count = 0;
335         struct option options[] = {
336                 { "help", 0, 0, 0 },
337                 { "testload", 0, &flag_test_load, 1 },
338                 { 0, 0, 0, 0 }
339         };
340         const char *plugin_path = DEFAULT_PLUGINS_PATH;
341         char *tcore_ver = NULL;
342         struct sysinfo sys_info;
343
344         TIME_CHECK("Starting Telephony");
345
346         /* System Uptime */
347         if (0 == sysinfo(&sys_info))
348                 info("uptime: %ld secs", sys_info.uptime);
349         __log_uptime();
350
351         /* Version Info */
352         tcore_ver = tcore_util_get_version();
353         info("daemon version: [%s] libtcore version: [%s] glib version: [%u.%u.%u]",
354                 DAEMON_VERSION, tcore_ver, glib_major_version, glib_minor_version, glib_micro_version);
355         free(tcore_ver);
356         info("glib version: %u.%u.%u", glib_major_version, glib_minor_version, glib_micro_version);
357
358         /* Telephony reset handling*/
359         vconf_get_int(VCONFKEY_TELEPHONY_DAEMON_LOAD_COUNT, &daemon_load_count);
360         daemon_load_count++;
361         vconf_set_int(VCONFKEY_TELEPHONY_DAEMON_LOAD_COUNT, daemon_load_count);
362         info("daemon load count = [%d]", daemon_load_count);
363
364 #ifdef TIZEN_DEBUG_ENABLE
365         /* Signal Registration */
366         sigact.sa_handler = telephony_signal_handler;
367         sigemptyset(&sigact.sa_mask);
368         sigact.sa_flags = 0;
369         if (sigaction(SIGTERM, &sigact, NULL) < 0)
370                 warn("sigaction(SIGTERM) failed.");
371         if (sigaction(SIGUSR1, &sigact, NULL) < 0)
372                 warn("sigaction(SIGUSR1) failed.");
373 #if defined(TIZEN_PROFILE_TV) || defined(TIZEN_PROFILE_IVI)
374         /* SIGHUP should be ignored because cellular dongle ejection makes this signal */
375         if (sigaction(SIGHUP, &sigact, NULL) < 0)
376                 warn("sigaction(SIGHUP) failed.");
377 #endif
378 #elif defined(TIZEN_PROFILE_TV) || defined(TIZEN_PROFILE_IVI)
379         /* Signal Registration */
380         sigact.sa_handler = telephony_signal_handler;
381         sigemptyset(&sigact.sa_mask);
382         sigact.sa_flags = 0;
383         /* SIGHUP should be ignored because cellular dongle ejection makes this signal */
384         if (sigaction(SIGHUP, &sigact, NULL) < 0)
385                 warn("sigaction(SIGHUP) failed.");
386 #endif
387
388         if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
389                 err("Child process won't be auto reaped: [%d]", errno);
390
391         /* Commandline option parser TODO: Replace with GOptionContext */
392         while (TRUE) {
393                 opt = getopt_long(argc, argv, "hT", options, &opt_index);
394
395                 if (-1 == opt)
396                         break;
397
398                 switch (opt) {
399                 case 0: {
400                         switch (opt_index) {
401                         case 0: {
402                                 __usage_info(argv[0]);
403                                 return 0;
404                         } break;
405                         default: {
406                                 warn("unhandled opt_index.");
407                         } break;
408                         } /* end switch */
409                 } break;
410
411                 case 'h': {
412                         __usage_info(argv[0]);
413                         return 0;
414                 } break;
415
416                 case 'T': {
417                         flag_test_load = TRUE;
418                 } break;
419                 default: {
420                         warn("unhandled opt case.");
421                 } break;
422                 } /* end switch */
423         }
424
425         if (optind < argc)
426                 plugin_path = argv[optind];
427
428         info("plugin_path: [%s]", plugin_path);
429
430 #if !GLIB_CHECK_VERSION(2, 35, 0)
431         g_type_init();
432 #endif
433 #if !GLIB_CHECK_VERSION(2, 31, 0)
434         g_thread_init(NULL);
435 #endif
436
437         s = tcore_server_new();
438         if (G_UNLIKELY(NULL == s)) {
439                 err("server_new failed.");
440                 ret_code = EXIT_FAILURE;
441                 goto END;
442         }
443         _server = s;
444
445         g_log_set_default_handler(glib_log, s);
446
447         /* Load Plugins */
448         if (G_UNLIKELY(FALSE == load_plugins(s, (const char *)plugin_path, flag_test_load))) {
449                 err("load_plugins failed.");
450                 ret_code = EXIT_FAILURE;
451                 goto END;
452         }
453
454         TIME_CHECK("Loading Plugins Complete");
455
456         if (flag_test_load) {
457                 ret_code = EXIT_SUCCESS;
458                 goto END;
459         }
460
461         /* Initialize Plugins */
462         if (G_UNLIKELY(FALSE == init_plugins(s))) {
463                 err("init_plugins failed.");
464                 ret_code = EXIT_FAILURE;
465                 goto END;
466         }
467
468         info("server mainloop start");
469         TIME_CHECK("Initializing Plugins Complete. Starting Daemon");
470
471         if (G_UNLIKELY(TCORE_RETURN_SUCCESS != tcore_server_run(s))) {
472                 err("server_run failed.");
473                 ret_code = EXIT_FAILURE;
474         }
475
476 END:
477         tcore_server_free(s); _server = NULL;
478         return ret_code;
479 }