Release 0.0.3
[profile/ivi/gsignond.git] / src / gplugind / main.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of gsignond
5  *
6  * Copyright (C) 2013-2014 Intel Corporation.
7  *
8  * Contact: Imran Zaman <imran.zaman@intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25
26 #include <config.h>
27 #include <errno.h>
28 #include <signal.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <glib-unix.h>
32 #include <glib.h>
33 #include <gio/gio.h>
34 #include <sys/prctl.h>
35
36 #include "gsignond/gsignond-log.h"
37 #include "daemon/dbus/gsignond-dbus.h"
38 #include "gsignond-plugin-daemon.h"
39
40 static GSignondPluginDaemon *_daemon = NULL;
41 static guint _sig_source_id[3];
42
43 static void
44 _on_daemon_closed (gpointer data, GObject *server)
45 {
46     _daemon = NULL;
47     DBG ("Daemon closed");
48     if (data) g_main_loop_quit ((GMainLoop *)data);
49 }
50
51 static gboolean
52 _handle_quit_signal (gpointer user_data)
53 {
54     GMainLoop *ml = (GMainLoop *) user_data;
55
56     g_return_val_if_fail (ml != NULL, FALSE);
57     DBG ("Received quit signal");
58     if (ml) g_main_loop_quit (ml);
59
60     return FALSE;
61 }
62
63 static void 
64 _install_sighandlers (GMainLoop *main_loop)
65 {
66     GSource *source = NULL;
67     GMainContext *ctx = g_main_loop_get_context (main_loop);
68
69     source = g_unix_signal_source_new (SIGTERM);
70     g_source_set_callback (source,
71                            _handle_quit_signal,
72                            main_loop,
73                            NULL);
74     _sig_source_id[0] = g_source_attach (source, ctx);
75
76     source = g_unix_signal_source_new (SIGINT);
77     g_source_set_callback (source,
78                            _handle_quit_signal,
79                            main_loop,
80                            NULL);
81     _sig_source_id[1] = g_source_attach (source, ctx);
82
83     source = g_unix_signal_source_new (SIGHUP);
84     g_source_set_callback (source,
85                            _handle_quit_signal,
86                            main_loop,
87                            NULL);
88     _sig_source_id[2] = g_source_attach (source, ctx);
89
90     if (prctl(PR_SET_PDEATHSIG, SIGHUP))
91         WARN ("failed to set parent death signal");
92 }
93
94 static void _list_plugins()
95 {
96     const gchar *plugin_path = GSIGNOND_GPLUGINS_DIR;
97
98 #   ifdef ENABLE_DEBUG
99     const gchar *env_val = g_getenv("SSO_GPLUGINS_DIR");
100     if (env_val)
101         plugin_path = env_val;
102 #   endif
103     GDir* plugin_dir = g_dir_open(plugin_path, 0, NULL);
104     if (plugin_dir == NULL) {
105         return;
106     }
107
108     while (1) {
109         const gchar* plugin_soname = g_dir_read_name(plugin_dir);
110         if (plugin_soname == NULL)
111             break;
112         if (g_str_has_prefix(plugin_soname, "lib") &&
113             g_str_has_suffix(plugin_soname, ".so")) {
114             gchar* plugin_name = g_strndup(plugin_soname+3,
115                 strlen(plugin_soname) - 6);
116             g_print("%s\n", plugin_name);
117             g_free(plugin_name);
118         }
119     }
120     g_dir_close(plugin_dir);
121 }
122
123 int main (int argc, char **argv)
124 {
125     GError *error = NULL;
126     GMainLoop *main_loop = NULL;
127     GOptionContext *opt_context = NULL;
128     gint in_fd = 0, out_fd = 1;
129
130     gboolean list_plugins = FALSE;
131     gchar* plugin_name = NULL;
132     GOptionEntry main_entries[] =
133     {
134         { "list-plugins", 0, 0, G_OPTION_ARG_NONE, &list_plugins, "List available plugins", NULL},
135         { "load-plugin", 0, 0, G_OPTION_ARG_STRING, &plugin_name, "Load a plugin and start a d-bus connection with it on stdio channel", "name"},
136         { NULL }
137     };
138
139     opt_context = g_option_context_new ("gSSO glib plugin loader");
140     g_option_context_add_main_entries (opt_context, main_entries, NULL);
141
142     if (!g_option_context_parse (opt_context, &argc, &argv, &error)) {
143         WARN ("option parsing failed: %s\n", error->message);
144         g_error_free(error);
145         g_option_context_free(opt_context);
146         return -1;
147     }
148     g_option_context_free(opt_context);
149
150     if (list_plugins) {
151         _list_plugins();
152         return 0;
153     }
154
155     if (!plugin_name) {
156         g_print("Use --help to list command line options\n");
157         return -1;
158     }
159
160
161     /* Duplicates stdin,stdout,stderr descriptors and point the descriptors
162      * to /dev/null to avoid anyone writing to descriptors before initial
163      * "plugind-is-ready" notification is sent to gsignond
164      * */
165     in_fd = dup(0);
166     if (in_fd == -1) {
167         WARN ("Failed to dup stdin : %s(%d)", strerror(errno), errno);
168         in_fd = 0;
169     }
170     if (!freopen("/dev/null", "r+", stdin)) {
171         WARN ("Unable to redirect stdin to /dev/null");
172     }
173
174     out_fd = dup(1);
175     if (out_fd == -1) {
176         WARN ("Failed to dup stdout : %s(%d)", strerror(errno), errno);
177         out_fd = 1;
178     }
179
180     /* Reattach stderr to stdout */
181     dup2 (2, 1);
182
183 #if !GLIB_CHECK_VERSION (2, 36, 0)
184     g_type_init ();
185 #endif
186
187     const gchar *plugin_path = GSIGNOND_GPLUGINS_DIR;
188 #   ifdef ENABLE_DEBUG
189     const gchar *env_val = g_getenv("SSO_GPLUGINS_DIR");
190     if (env_val)
191         plugin_path = env_val;
192 #   endif
193     gchar* filename = g_module_build_path (plugin_path, plugin_name);
194
195     _daemon = gsignond_plugin_daemon_new (filename, plugin_name, in_fd,
196             out_fd);
197     g_free(filename);
198     g_free(plugin_name);
199     if (_daemon == NULL) {
200         return -1;
201     }
202
203     main_loop = g_main_loop_new (NULL, FALSE);
204     g_object_weak_ref (G_OBJECT (_daemon), _on_daemon_closed, main_loop);
205     _install_sighandlers (main_loop);
206
207     DBG ("Entering main event loop");
208
209     g_main_loop_run (main_loop);
210
211     if(_daemon) {
212         g_object_unref (_daemon);
213     }
214
215     if (main_loop) {
216         g_main_loop_unref (main_loop);
217     }
218
219     return 0;
220 }