Implemented GetPhonebookInfo
[gsmd2.git] / src / main.c
blob9d2838a17c05dac86ec55005af5b5b5be3c29b62
1 /*
2 * main.c
4 * Copyright(C) 2007,2008 Ixonos Plc
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
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.
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., 59 Temple Place, Boston, MA 02111.
22 * Written by
23 * Jukka Honkela
24 * Yi Zheng
25 * Matti Katila
26 * Vesa Pikki
27 * Heikki Paajanen
30 /**
31 * @mainpage GSMD2
33 * \section intro Introduction
35 * This is the documentation of GSM daemon called GSMD2.
37 * \section install_sec Installation
39 * ...
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <signal.h>
47 #include <fcntl.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <syslog.h>
51 #include <dbus/dbus-glib-bindings.h>
52 #include <glib-object.h>
53 #include <glib/gquark.h>
54 #include <gmodule.h>
55 #include "modem_internal.h"
56 #include "dbus_objects.h"
58 #define USE_SYSLOG 1
59 #define RUNNING_DIR "/"
60 #define LOCK_FILE "/var/lock/LCK..gsmd2.lock"
62 #define DEFAULT_VENDOR "generic"
63 #define DEFAULT_SERIAL_PLUGIN "generic"
64 #define DEFAULT_DEVICE "/dev/ttyS2"
65 #define DEFAULT_CONFFILE "/etc/gsmd2/gsmd2.conf"
66 static gchar **devices = NULL;
67 static gchar *vendor = DEFAULT_VENDOR;
68 static gchar *serial_plugin = DEFAULT_SERIAL_PLUGIN;
69 static gchar *conffile = DEFAULT_CONFFILE;
70 static gboolean no_conf = FALSE; //Should the conf file be read
71 static gboolean no_cache = FALSE; //Should we cache values
72 static gboolean no_daemon = FALSE; //Should the process be daemon (FALSE)
73 //or a normal process (TRUE)
74 static gint interface_devices[INTERFACE_LAST] = {0};
76 //Command line parameters
77 static GOptionEntry options[] = {
78 { "conf", 'c',G_OPTION_FLAG_FILENAME , G_OPTION_ARG_STRING, &conffile,
79 "The configuration file to use. "
80 "The configuration file defaults to '" DEFAULT_CONFFILE "'.", NULL },
81 { "no-conf", 0, 0, G_OPTION_ARG_NONE, &no_conf,
82 "Do not try to read configuration file. "
83 "The configuration file is read by default.", NULL },
84 { "no-cache", 0, 0, G_OPTION_ARG_NONE, &no_cache,
85 "Do not cache any responses."
86 "The configuration file is read by default.", NULL },
87 { "device", 'd', 0, G_OPTION_ARG_STRING_ARRAY, &devices,
88 "The device of the modem. "
89 "The device defaults to '" DEFAULT_DEVICE "'.", NULL },
90 { "vendor", 'v', 0, G_OPTION_ARG_STRING, &vendor,
91 "The modem vendor. "
92 "The vendor defaults to '" DEFAULT_VENDOR "'.", NULL },
93 { "serial", 's', 0, G_OPTION_ARG_STRING, &serial_plugin,
94 "The serial plugin. "
95 "The vendor defaults to '" DEFAULT_SERIAL_PLUGIN "'.", NULL },
96 { "no-daemon", 'n', 0, G_OPTION_ARG_NONE, &no_daemon,
97 "Run without making this process a daemon"
98 "", NULL},
99 { "general_index",0, 0, G_OPTION_ARG_INT, &interface_devices[INTERFACE_GENERAL],
100 "Specify index of the the device to be used in general communication"
101 "", NULL},
102 { "call_index",0, 0, G_OPTION_ARG_INT, &interface_devices[INTERFACE_CALL],
103 "Specify the index of the device used in call interface's communication"
104 "", NULL},
105 { "device_index",0, 0, G_OPTION_ARG_INT, &interface_devices[INTERFACE_DEVICE],
106 "Specify the index of the device used in device interface's communication"
107 "", NULL},
108 { "network_index",0, 0, G_OPTION_ARG_INT, &interface_devices[INTERFACE_NETWORK],
109 "Specify the index of the device used in network interface's communication"
110 "", NULL},
111 { "pdp_index",0, 0, G_OPTION_ARG_INT, &interface_devices[INTERFACE_PDP],
112 "Specify the index of the device used in pdp interface's communication"
113 "", NULL},
114 { "sim_index",0, 0, G_OPTION_ARG_INT, &interface_devices[INTERFACE_SIM],
115 "Specify the index of the device used in sim interface's communication"
116 "", NULL},
117 { "sms_index",0, 0, G_OPTION_ARG_INT, &interface_devices[INTERFACE_SMS],
118 "Specify the index of the device used in sms interface's communication"
119 "", NULL},
120 { NULL }
123 GMainLoop *loop = NULL;
127 * @brief Wrapper to the syslog function
129 * @param priority priority of the message to log
130 * @param message message to log
132 void syslog_message(int priority, const char *message)
134 #ifdef USE_SYSLOG
135 syslog(priority, message);
136 #endif
140 * @brief Custom signal handler to SIGHUP,SIGTERM,SIGQUIT and SIGINT.
142 * - SIGHUP writes to syslog
143 * - SIGTEMR/SIGQUIT/SIGINT quits main loop and closes the log.
145 * @param sig signal to handle
147 void signal_handler(int sig)
149 switch (sig) {
150 case SIGHUP:
151 syslog_message(LOG_INFO, "SIGHUP signal catched");
152 break;
153 case SIGTERM:
154 case SIGQUIT:
155 case SIGINT: {
156 closelog();
157 if (loop && g_main_loop_is_running(loop))
158 g_main_loop_quit( loop );
159 syslog_message(LOG_INFO, "SIGTERM, SIGINT or SIGQUIT signal catched. Daemon stopped.");
160 exit(0);
162 break;
166 static
167 GKeyFile* gsmd_read_configuration_file(const gchar *file)
169 GKeyFile *conf = g_key_file_new();
170 GError *error = NULL;
171 gchar **string_list = NULL;
172 gchar *string = NULL;
173 gboolean bool = FALSE;
174 if( !g_key_file_load_from_file(conf, conffile, G_KEY_FILE_NONE, &error) ) {
175 g_warning("%s : %s", __func__, error->message);
176 g_error_free( error );
177 g_key_file_free( conf );
178 return NULL;
180 string_list = g_key_file_get_string_list(conf, "Default", "devices", NULL, NULL);
181 if( string_list ) {
182 if( !devices ) {
183 g_debug("%s : Using devices from %s", __func__, conffile);
184 devices = string_list;
185 string_list = NULL;
186 } else {
187 g_strfreev( string_list );
190 string = g_key_file_get_string(conf, "Default", "vendor",NULL);
191 if( string ) {
192 if( (gpointer)vendor == (gpointer)DEFAULT_VENDOR) {
193 g_debug("%s : Using vendor %s from %s", __func__, string, conffile);
194 vendor = string;
195 } else {
196 g_free( string );
200 string = g_key_file_get_string(conf, "Default", "serial",NULL);
201 if( string ) {
202 if( (gpointer)serial_plugin == (gpointer)DEFAULT_SERIAL_PLUGIN) {
203 g_debug("%s : Using serial plugin %s from %s", __func__, string, conffile);
204 serial_plugin = string;
205 } else {
206 g_free( string );
210 bool = g_key_file_get_boolean(conf, "Default", "no-daemon",&error);
211 if( error == NULL) {
212 g_debug("%s : no-daemon: %s", __func__, bool ? "yes": "no");
213 no_daemon = bool;
214 } else {
215 g_debug("%s : no-daemon error: %s", __func__, error->message);
216 g_error_free( error );
217 error = NULL;
219 bool = g_key_file_get_boolean(conf, "Default", "no-cache",&error);
220 if( error == NULL) {
221 g_debug("%s : no-cache: %s", __func__, bool ? "yes": "no");
222 no_cache = bool;
223 } else {
224 g_debug("%s : no-cache error: %s", __func__, error->message);
225 g_error_free( error );
226 error = NULL;
228 return conf;
232 * @brief Daemonizes the process.
235 void daemonize(void)
237 int i = 0;
238 int lock_file = 0;
239 char str[10];
241 #ifdef USE_SYSLOG
242 openlog("gsmd2", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
243 #endif
245 i = fork();
247 /* error in fork */
248 if (i < 0) {
249 syslog_message(LOG_ERR, "Can not fork process! Daemon not started.");
250 exit(1);
253 /* parent exits */
254 if (i > 0)
255 exit(0);
257 /* daemon must have own process group */
258 setsid();
260 /* close all open descriptors */
261 for (i=getdtablesize(); i>=0; --i)
262 close(i);
264 /* Redirect standard files to /dev/null */
265 freopen( "/dev/null", "r", stdin);
266 freopen( "/dev/null", "w", stdout);
267 freopen( "/dev/null", "w", stderr);
269 /* change running directory to "/" */
270 chdir(RUNNING_DIR);
271 lock_file = open(LOCK_FILE, O_RDWR|O_CREAT, 0640);
273 /* can't open lock file*/
274 if (lock_file < 0) {
275 syslog_message(LOG_ERR, "Can't open lock file");
276 exit(1);
279 /* can't lock */
280 if (lockf(lock_file, F_TLOCK, 0) < 0) {
281 syslog_message(LOG_ERR, "Can't set F_TLOCK to the lock file.");
282 syslog_message(LOG_ERR, "Daemon is probably already running!");
283 exit(0);
286 /* record program ID to lockfile */
287 sprintf(str, "%d\n", getpid());
288 write(lock_file, str, strlen(str));
290 /* set signal handlers */
291 signal(SIGCHLD, SIG_IGN);
292 signal(SIGTSTP, SIG_IGN);
293 signal(SIGTTOU, SIG_IGN);
294 signal(SIGTTIN, SIG_IGN);
295 signal(SIGHUP, signal_handler);
296 signal(SIGTERM, signal_handler);
297 signal(SIGQUIT, signal_handler);
298 signal(SIGINT, signal_handler);
300 syslog_message(LOG_INFO, "daemon is running successfully");
303 int main(int argc, char**argv)
305 GOptionContext *ctx = NULL;
306 GError *error = NULL;
307 ModemInterface* modem = NULL;
308 GKeyFile *conf = NULL;
309 if(!g_module_supported()) {
310 g_critical("%s : Current platform does not support GModule",__func__);
311 exit(1);
314 /* To be able to use GObjects or GType's */
315 g_type_init ();
317 //Parse commandline parameters
318 ctx = g_option_context_new(NULL);
319 g_option_context_add_main_entries (ctx, options, NULL);
321 if (!g_option_context_parse (ctx, &argc, &argv, &error)) {
322 g_print ("%s\n", error->message);
323 exit(1);
325 g_option_context_free(ctx);
327 if( !no_conf ) {
328 conf = gsmd_read_configuration_file(conffile);
329 if( !conf ) {
330 g_warning("%s : Failed to read configuration file '%s'", __func__, conffile);
334 //Check if we need to daemonize the process
335 if (!no_daemon) {
336 g_debug("demonizing");
337 daemonize();
340 //Create a main loop
341 loop = g_main_loop_new (NULL, FALSE);
342 if (!loop) {
343 g_warning("Loop was NULL");
344 exit (1);
347 //Create a new modem device
348 if (devices == NULL) {
349 devices = g_new0(char*,2);
350 devices[0] = DEFAULT_DEVICE;
353 modem = gsmd_modem_open (devices,
354 vendor,
355 serial_plugin,
356 no_cache,
357 conf,
358 &gsmd_dbus_initialize,
359 interface_devices);
360 g_free(devices);
363 if (!modem) {
364 g_warning ("cannot open modem\n");
365 exit (1);
368 //Start the main loop
369 g_main_loop_run (loop);
370 gsmd_modem_free (modem);
371 gsmd_dbus_uninitialize((DBusObjects*)modem->ipc_data);
374 return 0;