Release 0.0.3
[profile/ivi/gsignond.git] / src / daemon / plugins / plugind / 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 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 int main (int argc, char **argv)
95 {
96     GError *error = NULL;
97     GMainLoop *main_loop = NULL;
98     GOptionContext *opt_context = NULL;
99     gchar **plugin_args = NULL;
100     gint up_signal = -1;
101     gint in_fd = 0, out_fd = 1;
102     GOptionEntry opt_entries[] = {
103         {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &plugin_args,
104                 "Plugin Args", NULL},
105         {NULL}
106     };
107
108     /* Duplicates stdin,stdout,stderr descriptors and point the descriptors
109      * to /dev/null to avoid anyone writing to descriptors before initial
110      * "plugind-is-ready" notification is sent to gsignond
111      * */
112     in_fd = dup(0);
113     if (in_fd == -1) {
114         WARN ("Failed to dup stdin : %s(%d)", strerror(errno), errno);
115         in_fd = 0;
116     }
117     if (!freopen("/dev/null", "r+", stdin)) {
118         WARN ("Unable to redirect stdin to /dev/null");
119     }
120
121     out_fd = dup(1);
122     if (out_fd == -1) {
123         WARN ("Failed to dup stdout : %s(%d)", strerror(errno), errno);
124         out_fd = 1;
125     }
126
127     /* Reattach stderr to stdout */
128     dup2 (2, 1);
129
130 #if !GLIB_CHECK_VERSION (2, 36, 0)
131     g_type_init ();
132 #endif
133
134     opt_context = g_option_context_new ("<plugin_path> <plugin_name>");
135     g_option_context_set_summary (opt_context, "gSSO helper plugin daemon");
136     g_option_context_add_main_entries (opt_context, opt_entries, NULL);
137     g_option_context_set_ignore_unknown_options (opt_context, TRUE);
138     g_option_context_parse (opt_context, &argc, &argv, &error);
139     g_option_context_free (opt_context);
140     if (error) {
141         WARN ("Error in arguments parsing: %s", error->message);
142         g_error_free (error);
143     }
144     if (!plugin_args || !plugin_args[0] || !plugin_args[1]) {
145         WARN ("plugin path or plugin type missing");
146         if (write (out_fd, "0", sizeof(char)) == -1)
147             WARN ("Unable to write down notification to stdout");
148         if (in_fd != 0) close (in_fd);
149         if (out_fd != 1) close (out_fd);
150         if (plugin_args) g_strfreev(plugin_args);
151         return -1;
152     }
153
154     _daemon = gsignond_plugin_daemon_new (plugin_args[0], plugin_args[1], in_fd,
155             out_fd);
156     g_strfreev(plugin_args);
157     if (_daemon == NULL) {
158         if (write (out_fd, "0", sizeof(char)) == -1)
159             WARN ("Unable to write down notification to stdout");
160         if (in_fd != 0) close (in_fd);
161         if (out_fd != 1) close (out_fd);
162         return -1;
163     }
164
165     main_loop = g_main_loop_new (NULL, FALSE);
166     g_object_weak_ref (G_OBJECT (_daemon), _on_daemon_closed, main_loop);
167     _install_sighandlers (main_loop);
168
169     /* Notification for gsignond that plugind is up and ready */
170     up_signal = write (out_fd, "1", sizeof(char));
171
172     if (up_signal == -1) {
173         g_main_loop_unref (main_loop);
174         g_object_unref (_daemon);
175         return -1;
176     }
177
178     DBG ("Entering main event loop");
179
180     g_main_loop_run (main_loop);
181
182     if(_daemon) {
183         g_object_unref (_daemon);
184     }
185
186     if (main_loop) {
187         g_main_loop_unref (main_loop);
188     }
189
190     return 0;
191 }