Remove vconf key define which moved to vconf internal package
[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
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
52 static Server *_server = NULL;
53
54 static void __usage_info(const char *exec)
55 {
56         printf("Usage: %s [OPTION]... [PLUGIN_PATH]\n", exec);
57         printf("\n");
58         printf("  -T, --testload\t run with plugin load test mode and exit\n");
59         printf("  -h, --help\t\t display this help and exit\n");
60         printf("\n");
61 }
62
63 void tcore_log(enum tcore_log_type type, enum tcore_log_priority priority, const char *tag, const char *fmt, ...)
64 {
65         va_list ap;
66         char buf[1024];
67
68         switch (type) {
69         case TCORE_LOG_TYPE_RADIO: {
70                 if (priority >= TCORE_LOG_INFO) {
71                         va_start(ap, fmt);
72                         vsnprintf(buf, 1023, fmt, ap);
73                         va_end(ap);
74                         __dlog_print(LOG_ID_RADIO, priority, tag, buf);
75                 } else {
76                 #ifdef TIZEN_DEBUG_ENABLE
77                         va_start(ap, fmt);
78                         vsnprintf(buf, 1023, fmt, ap);
79                         va_end(ap);
80                         __dlog_print(LOG_ID_RADIO, priority, tag, buf);
81                 #endif
82                 }
83         } break;
84
85         case TCORE_LOG_TYPE_TIME_CHECK: {
86         #ifdef TIZEN_DEBUG_ENABLE /* User Mode should not log performance data */
87                 float a = 0.00, b = 0.00;
88                 int next = 0;
89                 FILE *fp = fopen("/proc/uptime", "r");
90                 g_return_if_fail(NULL != fp);
91
92                 if(fscanf(fp, "%f %f", &a, &b)){};
93                 fclose(fp);
94                 next = sprintf(buf, "[UPTIME] %f ", a);
95                 if (next < 0)
96                         return;
97
98                 va_start(ap, fmt);
99                 vsnprintf(buf + next, 1023 - next, fmt, ap);
100                 va_end(ap);
101                 __dlog_print(LOG_ID_RADIO, priority, tag, buf);
102         #endif
103         } break;
104
105         default:
106         break;
107         }
108 }
109
110 static void glib_log(const gchar *log_domain, GLogLevelFlags log_level,
111                 const gchar *msg, gpointer user_data)
112 {
113         NOTUSED(log_domain);
114         NOTUSED(log_level);
115         NOTUSED(user_data);
116
117         __dlog_print (LOG_ID_RADIO, DLOG_ERROR, "GLIB", msg);
118 }
119
120 #ifdef TIZEN_DEBUG_ENABLE
121 static void telephony_signal_handler(int signo)
122 {
123         if (!_server)
124                 return;
125
126         switch (signo) {
127         case SIGUSR1: {
128                 monitor_server_state(_server);
129         } break;
130
131         case SIGTERM: {
132                 tcore_server_exit(_server);
133         } break;
134
135         default: {
136                 warn("*~*~*~* Unhandled Signal: [%d] *~*~*~*", signo);
137         } break;
138         } /* end switch */
139
140         return;
141 }
142 #endif
143
144 static void __log_uptime()
145 {
146         float a = 0.00, b = 0.00;
147         FILE *fp = fopen("/proc/uptime", "r");
148         g_return_if_fail(NULL != fp);
149         info("scanned %d items", fscanf(fp, "%f %f", &a, &b));
150         info("proc uptime = %f idletime = %f\n", a, b);
151         fclose(fp);
152 }
153
154 static gboolean __init_plugin(TcorePlugin *plugin)
155 {
156         const struct tcore_plugin_define_desc *desc = tcore_plugin_get_description(plugin);
157
158         if (!desc || !desc->init)
159                 return FALSE;
160
161         if (!desc->init(plugin)) { /* TODO: Remove plugin from server */
162                 char *plugin_name = tcore_plugin_get_filename(plugin);
163                 if (NULL != plugin_name) {
164                         err("plugin(%s) init failed.", plugin_name);
165                         free(plugin_name);
166                 }
167                 return FALSE;
168         }
169
170         return TRUE;
171 }
172
173 static gboolean init_plugins(Server *s)
174 {
175         GSList *list = tcore_server_ref_plugins(s);
176
177         while (list != NULL) {
178                 if (G_UNLIKELY(FALSE == __init_plugin(list->data))) {
179                         list = g_slist_next(list);
180                         continue;
181                 }
182                 list = g_slist_next(list);
183         }
184
185         return TRUE;
186 }
187
188 static void *__load_plugin(const gchar *filename, struct tcore_plugin_define_desc **desc_out)
189 {
190         void *handle = NULL;
191         struct tcore_plugin_define_desc *desc = NULL;
192         struct stat stat_buf;
193         char file_date[27];
194
195         handle = dlopen(filename, RTLD_LAZY);
196         if (G_UNLIKELY(NULL == handle)) {
197                 err("fail to load '%s': %s", filename, dlerror());
198                 return NULL;
199         }
200
201         desc = dlsym(handle, "plugin_define_desc");
202         if (G_UNLIKELY(NULL == desc)) {
203                 err("fail to load symbol: %s", dlerror());
204                 dlclose(handle);
205                 return NULL;
206         }
207
208         dbg("%s plugin", desc->name);
209         dbg(" - path = %s", filename);
210         dbg(" - version = %d", desc->version);
211         dbg(" - priority = %d", desc->priority);
212
213         memset(&stat_buf, 0x00, sizeof(stat_buf));
214         memset(&file_date, '\0', sizeof(file_date));
215
216         if (0 == stat(filename, &stat_buf)) {
217                 if (NULL != ctime_r(&stat_buf.st_mtime, file_date)) {
218                         if (1 < strlen(file_date))
219                                 file_date[strlen(file_date)-1] = '\0';
220                         dbg(" - date = %s", file_date);
221                 }
222         }
223
224         if (G_LIKELY(desc->load)) {
225                 if (G_UNLIKELY(FALSE == desc->load())) {
226                         warn("false return from load(). skip this plugin");
227                         dlclose(handle);
228                         return NULL;
229                 }
230         }
231
232         if (NULL != desc_out)
233                 *desc_out = desc;
234
235         return handle;
236 }
237
238 static gboolean load_plugins(Server *s, const char *path, gboolean flag_test_load)
239 {
240         const gchar *file = NULL;
241         gchar *filename = NULL;
242         GDir *dir = NULL;
243         void *handle = NULL;
244         struct tcore_plugin_define_desc *desc = NULL;
245
246         if (!path || !s)
247                 return FALSE;
248
249         dir = g_dir_open(path, 0, NULL);
250         if (!dir)
251                 return FALSE;
252
253         while ((file = g_dir_read_name(dir)) != NULL) {
254                 if (g_str_has_prefix(file, "lib") == TRUE
255                         || g_str_has_suffix(file, ".so") == FALSE)
256                         continue;
257
258                 filename = g_build_filename(path, file, NULL);
259
260                 /* Load a plugin */
261                 if (G_UNLIKELY((handle = __load_plugin(filename, &desc)) == NULL)) {
262                         g_free(filename);
263                         continue;
264                 }
265
266                 /* Don't add to server if flag_test_load */
267                 if (flag_test_load) {
268                         dbg("success to load '%s'", filename);
269                         dlclose(handle);
270                         g_free(filename);
271                         continue;
272                 }
273
274                 tcore_server_add_plugin(s, tcore_plugin_new(s, desc, filename, handle));
275
276                 dbg("%s added", desc->name);
277                 g_free(filename);
278         }
279         g_dir_close(dir);
280
281         return TRUE;
282 }
283
284 int main(int argc, char *argv[])
285 {
286 #ifdef TIZEN_DEBUG_ENABLE
287         struct sigaction sigact;
288 #endif
289         Server *s = NULL;
290         gboolean flag_test_load = FALSE;
291         int opt = 0, opt_index = 0, ret_code = EXIT_SUCCESS;
292         int daemon_load_count = 0;
293         struct option options[] = {
294                 { "help", 0, 0, 0 },
295                 { "testload", 0, &flag_test_load, 1 },
296                 { 0, 0, 0, 0 }
297         };
298         const char *plugin_path = DEFAULT_PLUGINS_PATH;
299         char *tcore_ver = NULL;
300         struct sysinfo sys_info;
301
302         TIME_CHECK("Starting Telephony");
303
304         /* System Uptime */
305         if (0 == sysinfo(&sys_info))
306                 info("uptime: %ld secs", sys_info.uptime);
307         __log_uptime();
308
309         /* Version Info */
310         tcore_ver = tcore_util_get_version();
311         info("daemon version: %s", DAEMON_VERSION);
312         info("libtcore version: %s", tcore_ver);
313         free(tcore_ver);
314         info("glib version: %u.%u.%u", glib_major_version, glib_minor_version, glib_micro_version);
315
316         /* Telephony reset handling*/
317         vconf_get_int(VCONFKEY_TELEPHONY_DAEMON_LOAD_COUNT,&daemon_load_count);
318         daemon_load_count++;
319         vconf_set_int(VCONFKEY_TELEPHONY_DAEMON_LOAD_COUNT,daemon_load_count);
320         dbg("daemon load count = [%d]", daemon_load_count);
321
322 #ifdef TIZEN_DEBUG_ENABLE
323         /* Signal Registration */
324         sigact.sa_handler = telephony_signal_handler;
325         sigemptyset(&sigact.sa_mask);
326         sigact.sa_flags = 0;
327         if (sigaction(SIGTERM, &sigact, NULL) < 0)
328                 warn("sigaction(SIGTERM) failed.");
329         if (sigaction(SIGUSR1, &sigact, NULL) < 0)
330                 warn("sigaction(SIGUSR1) failed.");
331 #endif
332
333         /* Commandline option parser TODO: Replace with GOptionContext */
334         while (TRUE) {
335                 opt = getopt_long(argc, argv, "hT", options, &opt_index);
336
337                 if (-1 == opt)
338                         break;
339
340                 switch (opt) {
341                 case 0: {
342                         switch (opt_index) {
343                         case 0: {
344                                 __usage_info(argv[0]);
345                                 return 0;
346                         } break;
347                         default: {
348                                 warn("unhandled opt_index.");
349                         } break;
350                         } /* end switch */
351                 } break;
352
353                 case 'h': {
354                         __usage_info(argv[0]);
355                         return 0;
356                 } break;
357
358                 case 'T': {
359                         flag_test_load = TRUE;
360                 } break;
361                 default: {
362                         warn("unhandled opt case.");
363                 } break;
364                 } /* end switch */
365         }
366
367         if (optind < argc)
368                 plugin_path = argv[optind];
369
370         info("plugin_path: [%s]", plugin_path);
371
372 #if !GLIB_CHECK_VERSION(2, 35, 0)
373         g_type_init();
374 #endif
375 #if !GLIB_CHECK_VERSION(2, 31, 0)
376         g_thread_init(NULL);
377 #endif
378
379         s = tcore_server_new();
380         if (G_UNLIKELY(NULL == s)) {
381                 err("server_new failed.");
382                 ret_code = EXIT_FAILURE;
383                 goto END;
384         }
385         _server = s;
386
387         g_log_set_default_handler(glib_log, s);
388
389         /* Load Plugins */
390         if (G_UNLIKELY(FALSE == load_plugins(s, (const char *)plugin_path, flag_test_load))) {
391                 err("load_plugins failed.");
392                 ret_code = EXIT_FAILURE;
393                 goto END;
394         }
395
396         TIME_CHECK("Loading Plugins Complete");
397
398         if (flag_test_load) {
399                 ret_code = EXIT_SUCCESS;
400                 goto END;
401         }
402
403         /* Initialize Plugins */
404         if (G_UNLIKELY(FALSE == init_plugins(s))) {
405                 err("init_plugins failed.");
406                 ret_code = EXIT_FAILURE;
407                 goto END;
408         }
409
410         info("server mainloop start");
411         TIME_CHECK("Initializing Plugins Complete. Starting Daemon");
412
413         if (G_UNLIKELY(TCORE_RETURN_SUCCESS != tcore_server_run(s))) {
414                 err("server_run failed.");
415                 ret_code = EXIT_FAILURE;
416         }
417
418 END:
419         tcore_server_free(s); _server = NULL;
420         return ret_code;
421 }