Remove block call in ibus-daemon, and use async call instead and clean up code.
[platform/upstream/ibus.git] / bus / main.c
1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* ibus - The Input Bus
4  * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
5  * Copyright (C) 2008-2010 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 #include <config.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <pwd.h>
28 #include <stdlib.h>
29 #include <locale.h>
30 #include <signal.h>
31 #include <glib.h>
32 #include <gio/gio.h>
33 #include <ibus.h>
34 #include "server.h"
35 #include "ibusimpl.h"
36
37 gchar **g_argv = NULL;
38
39 static gboolean daemonize = FALSE;
40 static gboolean single = FALSE;
41 static gboolean xim = FALSE;
42 static gboolean replace = FALSE;
43 static gboolean restart = FALSE;
44 static gchar *panel = "default";
45 static gchar *config = "default";
46 static gchar *desktop = "gnome";
47 gchar *g_address = "unix:tmpdir=/tmp";
48 gchar *g_cache = "auto";
49 gboolean g_mempro = FALSE;
50 gboolean g_verbose = FALSE;
51 gint   g_dbus_timeout = 5000;
52 #ifdef G_THREADS_ENABLED
53 gint   g_monitor_timeout = 0;
54 #endif
55
56 static void
57 show_version_and_quit (void)
58 {
59     g_print ("%s - Version %s\n", g_get_application_name (), VERSION);
60     exit (EXIT_SUCCESS);
61 }
62
63 static const GOptionEntry entries[] =
64 {
65     { "version",   'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, show_version_and_quit, "Show the application's version.", NULL },
66     { "daemonize", 'd', 0, G_OPTION_ARG_NONE,   &daemonize, "run ibus as background process.", NULL },
67     { "single",    's', 0, G_OPTION_ARG_NONE,   &single,    "do not execute panel and config module.", NULL },
68     { "xim",       'x', 0, G_OPTION_ARG_NONE,   &xim,       "execute ibus XIM server.", NULL },
69     { "desktop",   'n', 0, G_OPTION_ARG_STRING, &desktop,   "specify the name of desktop session. [default=gnome]", "name" },
70     { "panel",     'p', 0, G_OPTION_ARG_STRING, &panel,     "specify the cmdline of panel program. pass 'disable' not to start a panel program.", "cmdline" },
71     { "config",    'c', 0, G_OPTION_ARG_STRING, &config,    "specify the cmdline of config program. pass 'disable' not to start a config program.", "cmdline" },
72     { "address",   'a', 0, G_OPTION_ARG_STRING, &g_address,   "specify the address of ibus daemon.", "address" },
73     { "replace",   'r', 0, G_OPTION_ARG_NONE,   &replace,   "if there is an old ibus-daemon is running, it will be replaced.", NULL },
74     { "cache",     't', 0, G_OPTION_ARG_STRING, &g_cache,   "specify the cache mode. [auto/refresh/none]", NULL },
75     { "timeout",   'o', 0, G_OPTION_ARG_INT,    &g_dbus_timeout, "dbus reply timeout in milliseconds.", "timeout [default is 2000]" },
76 #ifdef G_THREADS_ENABLED
77     { "monitor-timeout", 'j', 0, G_OPTION_ARG_INT,    &g_monitor_timeout, "timeout of poll changes of engines in seconds. 0 to disable it. ", "timeout [default is 0]" },
78 #endif
79     { "mem-profile", 'm', 0, G_OPTION_ARG_NONE,   &g_mempro,   "enable memory profile, send SIGUSR2 to print out the memory profile.", NULL },
80     { "restart",     'R', 0, G_OPTION_ARG_NONE,   &restart,    "restart panel and config processes when they die.", NULL },
81     { "verbose",   'v', 0, G_OPTION_ARG_NONE,   &g_verbose,   "verbose.", NULL },
82     { NULL },
83 };
84
85 /**
86  * execute_cmdline:
87  * @cmdline: An absolute path of the executable and its parameters, e.g.  "/usr/lib/ibus/ibus-x11 --kill-daemon".
88  * @returns: TRUE if both parsing cmdline and executing the command succeed.
89  *
90  * Execute cmdline. Child process's stdin, stdout, and stderr are attached to /dev/null.
91  * You don't have to handle SIGCHLD from the child process since glib will do.
92  */
93 static gboolean
94 execute_cmdline (const gchar *cmdline)
95 {
96     g_assert (cmdline);
97
98     gint argc = 0;
99     gchar **argv = NULL;
100     GError *error = NULL;
101     if (!g_shell_parse_argv (cmdline, &argc, &argv, &error)) {
102         g_warning ("Can not parse cmdline `%s` exec: %s", cmdline, error->message);
103         g_error_free (error);
104         return FALSE;
105     }
106
107     error = NULL;
108     gboolean retval = g_spawn_async (NULL, argv, NULL,
109                             G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
110                             NULL, NULL,
111                             NULL, &error);
112     g_strfreev (argv);
113
114     if (!retval) {
115         g_warning ("Can not execute cmdline `%s`: %s", cmdline, error->message);
116         g_error_free (error);
117         return FALSE;
118     }
119
120     return TRUE;
121 }
122
123 #ifndef HAVE_DAEMON
124 static void
125 closeall (gint fd)
126 {
127     gint fdlimit = sysconf(_SC_OPEN_MAX);
128
129     while (fd < fdlimit) {
130       close(fd++);
131     }
132 }
133
134 static gint
135 daemon (gint nochdir, gint noclose)
136 {
137     switch (fork()) {
138         case 0:  break;
139         case -1: return -1;
140         default: _exit(0);
141     }
142
143     if (setsid() < 0) {
144       return -1;
145     }
146
147     switch (fork()) {
148         case 0:  break;
149         case -1: return -1;
150         default: _exit(0);
151     }
152
153     if (!nochdir) {
154       chdir("/");
155     }
156
157     if (!noclose) {
158         closeall(0);
159         open("/dev/null",O_RDWR);
160         dup(0); dup(0);
161     }
162     return 0;
163 }
164 #endif
165
166 /*
167  * _sig_usr2_handler:
168  * @sig: the signal number, which is usually SIGUSR2.
169  *
170  * A signal handler for SIGUSR2 signal. Dump a summary of memory usage to stderr.
171  */
172 static void
173 _sig_usr2_handler (int sig)
174 {
175     g_mem_profile ();
176 }
177
178 gint
179 main (gint argc, gchar **argv)
180 {
181     setlocale (LC_ALL, "");
182
183     GOptionContext *context = g_option_context_new ("- ibus daemon");
184     g_option_context_add_main_entries (context, entries, "ibus-daemon");
185
186     g_argv = g_strdupv (argv);
187     GError *error = NULL;
188     if (!g_option_context_parse (context, &argc, &argv, &error)) {
189         g_printerr ("Option parsing failed: %s\n", error->message);
190         g_error_free (error);
191         exit (-1);
192     }
193
194     if (g_mempro) {
195         g_mem_set_vtable (glib_mem_profiler_table);
196         signal (SIGUSR2, _sig_usr2_handler);
197     }
198
199     /* check uid */
200     {
201         const gchar *username = ibus_get_user_name ();
202         uid_t uid = getuid ();
203         struct passwd *pwd = getpwuid (uid);
204
205         if (pwd == NULL || g_strcmp0 (pwd->pw_name, username) != 0) {
206             g_printerr ("Please run ibus-daemon with login user! Do not run ibus-daemon with sudo or su.\n");
207             exit (-1);
208         }
209     }
210
211     /* daemonize process */
212     if (daemonize) {
213         if (daemon (1, 0) != 0) {
214             g_printerr ("Can not daemonize ibus.\n");
215             exit (-1);
216         }
217     }
218
219     /* create a new process group. this is important to kill all of its children by SIGTERM at a time in bus_ibus_impl_destroy. */
220     setpgid (0, 0);
221
222     ibus_init ();
223
224 #ifdef G_THREADS_ENABLED
225     g_thread_init (NULL);
226 #endif
227     ibus_set_log_handler (g_verbose);
228
229     /* check if ibus-daemon is running in this session */
230     if (ibus_get_address () != NULL) {
231         IBusBus *bus = ibus_bus_new ();
232
233         if (ibus_bus_is_connected (bus)) {
234             if (!replace) {
235                 g_printerr ("current session already has an ibus-daemon.\n");
236                 exit (-1);
237             }
238             ibus_bus_exit (bus, FALSE);
239             while (ibus_bus_is_connected (bus)) {
240                 g_main_context_iteration (NULL, TRUE);
241             }
242         }
243         g_object_unref (bus);
244     }
245
246     bus_server_init ();
247     if (!single) {
248         /* execute config component */
249         if (g_strcmp0 (config, "default") == 0) {
250             BusComponent *component;
251             component = bus_registry_lookup_component_by_name (BUS_DEFAULT_REGISTRY, IBUS_SERVICE_CONFIG);
252             if (component) {
253                 bus_component_set_restart (component, restart);
254             }
255             if (component == NULL || !bus_component_start (component, g_verbose)) {
256                 g_printerr ("Can not execute default config program\n");
257                 exit (-1);
258             }
259         } else if (g_strcmp0 (config, "disable") != 0 && g_strcmp0 (config, "") != 0) {
260             if (!execute_cmdline (config))
261                 exit (-1);
262         }
263
264         /* execute panel component */
265         if (g_strcmp0 (panel, "default") == 0) {
266             BusComponent *component;
267             component = bus_registry_lookup_component_by_name (BUS_DEFAULT_REGISTRY, IBUS_SERVICE_PANEL);
268             if (component) {
269                 bus_component_set_restart (component, restart);
270             }
271             if (component == NULL || !bus_component_start (component, g_verbose)) {
272                 g_printerr ("Can not execute default panel program\n");
273                 exit (-1);
274             }
275         } else if (g_strcmp0 (panel, "disable") != 0 && g_strcmp0 (panel, "") != 0) {
276             if (!execute_cmdline (panel))
277                 exit (-1);
278         }
279     }
280
281     /* execute ibus xim server */
282     if (xim) {
283         if (!execute_cmdline (LIBEXECDIR "/ibus-x11 --kill-daemon"))
284             exit (-1);
285     }
286
287     bus_server_run ();
288     return 0;
289 }