Blame bus/main.c

Packit Service 1d8f1c
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
Packit Service 1d8f1c
/* vim:set et sts=4: */
Packit Service 1d8f1c
/* ibus - The Input Bus
Packit Service 1d8f1c
 * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
Packit Service 1d8f1c
 * Copyright (C) 2013-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
Packit Service 1d8f1c
 * Copyright (C) 2008-2018 Red Hat, Inc.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * This library is free software; you can redistribute it and/or
Packit Service 1d8f1c
 * modify it under the terms of the GNU Lesser General Public
Packit Service 1d8f1c
 * License as published by the Free Software Foundation; either
Packit Service 1d8f1c
 * version 2.1 of the License, or (at your option) any later version.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * This library is distributed in the hope that it will be useful,
Packit Service 1d8f1c
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 1d8f1c
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 1d8f1c
 * Lesser General Public License for more details.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * You should have received a copy of the GNU Lesser General Public
Packit Service 1d8f1c
 * License along with this library; if not, write to the Free Software
Packit Service 1d8f1c
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
Packit Service 1d8f1c
 * USA
Packit Service 1d8f1c
 */
Packit Service 1d8f1c
#include <config.h>
Packit Service 1d8f1c
#include <fcntl.h>
Packit Service 1d8f1c
#include <glib.h>
Packit Service 1d8f1c
#include <gio/gio.h>
Packit Service 1d8f1c
#include <ibus.h>
Packit Service 1d8f1c
#include <locale.h>
Packit Service 1d8f1c
#include <pwd.h>
Packit Service 1d8f1c
#include <signal.h>
Packit Service 1d8f1c
#include <stdlib.h>
Packit Service 1d8f1c
#include <sys/types.h>
Packit Service 1d8f1c
#include <sys/stat.h>
Packit Service 1d8f1c
#include <unistd.h>
Packit Service 1d8f1c
Packit Service 1d8f1c
#include "global.h"
Packit Service 1d8f1c
#include "ibusimpl.h"
Packit Service 1d8f1c
#include "server.h"
Packit Service 1d8f1c
Packit Service 1d8f1c
static gboolean daemonize = FALSE;
Packit Service 1d8f1c
static gboolean single = FALSE;
Packit Service 1d8f1c
static gboolean xim = FALSE;
Packit Service 1d8f1c
static gboolean replace = FALSE;
Packit Service 1d8f1c
static gboolean restart = FALSE;
Packit Service 1d8f1c
static gchar *panel = "default";
Packit Service 1d8f1c
static gchar *emoji_extension = "default";
Packit Service 1d8f1c
static gchar *config = "default";
Packit Service 1d8f1c
static gchar *desktop = "gnome";
Packit Service 1d8f1c
Packit Service 1d8f1c
static gchar *panel_extension_disable_users[] = {
Packit Service 1d8f1c
    "gdm",
Packit Service 1d8f1c
    "liveuser"
Packit Service 1d8f1c
};
Packit Service 1d8f1c
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
show_version_and_quit (void)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_print ("%s - Version %s\n", g_get_application_name (), VERSION);
Packit Service 1d8f1c
    exit (EXIT_SUCCESS);
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static const GOptionEntry entries[] =
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    { "version",   'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, show_version_and_quit, "Show the application's version.", NULL },
Packit Service 1d8f1c
    { "daemonize", 'd', 0, G_OPTION_ARG_NONE,   &daemonize, "run ibus as background process.", NULL },
Packit Service 1d8f1c
    { "single",    's', 0, G_OPTION_ARG_NONE,   &single,    "do not execute panel and config module.", NULL },
Packit Service 1d8f1c
    { "xim",       'x', 0, G_OPTION_ARG_NONE,   &xim,       "execute ibus XIM server.", NULL },
Packit Service 1d8f1c
    { "desktop",   'n', 0, G_OPTION_ARG_STRING, &desktop,   "specify the name of desktop session. [default=gnome]", "name" },
Packit Service 1d8f1c
    { "panel",     'p', 0, G_OPTION_ARG_STRING, &panel,     "specify the cmdline of panel program. pass 'disable' not to start a panel program.", "cmdline" },
Packit Service 1d8f1c
    { "emoji-extension", 'E', 0, G_OPTION_ARG_STRING, &emoji_extension, "specify the cmdline of emoji extension program. pass 'disable' not to start an extension program.", "cmdline" },
Packit Service 1d8f1c
    { "config",    'c', 0, G_OPTION_ARG_STRING, &config,    "specify the cmdline of config program. pass 'disable' not to start a config program.", "cmdline" },
Packit Service 1d8f1c
    { "address",   'a', 0, G_OPTION_ARG_STRING, &g_address,   "specify the address of ibus daemon.", "address" },
Packit Service 1d8f1c
    { "replace",   'r', 0, G_OPTION_ARG_NONE,   &replace,   "if there is an old ibus-daemon is running, it will be replaced.", NULL },
Packit Service 1d8f1c
    { "cache",     't', 0, G_OPTION_ARG_STRING, &g_cache,   "specify the cache mode. [auto/refresh/none]", NULL },
Packit Service 1d8f1c
    { "timeout",   'o', 0, G_OPTION_ARG_INT,    &g_gdbus_timeout, "gdbus reply timeout in milliseconds. pass -1 to use the default timeout of gdbus.", "timeout [default is 15000]" },
Packit Service 1d8f1c
    { "mem-profile", 'm', 0, G_OPTION_ARG_NONE,   &g_mempro,   "enable memory profile, send SIGUSR2 to print out the memory profile.", NULL },
Packit Service 1d8f1c
    { "restart",     'R', 0, G_OPTION_ARG_NONE,   &restart,    "restart panel and config processes when they die.", NULL },
Packit Service 1d8f1c
    { "verbose",   'v', 0, G_OPTION_ARG_NONE,   &g_verbose,   "verbose.", NULL },
Packit Service 1d8f1c
    { NULL },
Packit Service 1d8f1c
};
Packit Service 1d8f1c
Packit Service 1d8f1c
/**
Packit Service 1d8f1c
 * execute_cmdline:
Packit Service 1d8f1c
 * @cmdline: An absolute path of the executable and its parameters, e.g.  "/usr/lib/ibus/ibus-x11 --kill-daemon".
Packit Service 1d8f1c
 * @returns: TRUE if both parsing cmdline and executing the command succeed.
Packit Service 1d8f1c
 *
Packit Service 1d8f1c
 * Execute cmdline. Child process's stdin, stdout, and stderr are attached to /dev/null.
Packit Service 1d8f1c
 * You don't have to handle SIGCHLD from the child process since glib will do.
Packit Service 1d8f1c
 */
Packit Service 1d8f1c
static gboolean
Packit Service 1d8f1c
execute_cmdline (const gchar *cmdline)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    g_assert (cmdline);
Packit Service 1d8f1c
Packit Service 1d8f1c
    gint argc = 0;
Packit Service 1d8f1c
    gchar **argv = NULL;
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
    if (!g_shell_parse_argv (cmdline, &argc, &argv, &error)) {
Packit Service 1d8f1c
        g_warning ("Can not parse cmdline `%s` exec: %s", cmdline, error->message);
Packit Service 1d8f1c
        g_error_free (error);
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    error = NULL;
Packit Service 1d8f1c
    gboolean retval = g_spawn_async (NULL, argv, NULL,
Packit Service 1d8f1c
                            G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
Packit Service 1d8f1c
                            NULL, NULL,
Packit Service 1d8f1c
                            NULL, &error);
Packit Service 1d8f1c
    g_strfreev (argv);
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!retval) {
Packit Service 1d8f1c
        g_warning ("Can not execute cmdline `%s`: %s", cmdline, error->message);
Packit Service 1d8f1c
        g_error_free (error);
Packit Service 1d8f1c
        return FALSE;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    return TRUE;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
#ifndef HAVE_DAEMON
Packit Service 1d8f1c
static void
Packit Service 1d8f1c
closeall (gint fd)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    gint fdlimit = sysconf(_SC_OPEN_MAX);
Packit Service 1d8f1c
Packit Service 1d8f1c
    while (fd < fdlimit) {
Packit Service 1d8f1c
      close(fd++);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
}
Packit Service 1d8f1c
Packit Service 1d8f1c
static gint
Packit Service 1d8f1c
daemon (gint nochdir, gint noclose)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    switch (fork()) {
Packit Service 1d8f1c
        case 0:  break;
Packit Service 1d8f1c
        case -1: return -1;
Packit Service 1d8f1c
        default: _exit(0);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (setsid() < 0) {
Packit Service 1d8f1c
      return -1;
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    switch (fork()) {
Packit Service 1d8f1c
        case 0:  break;
Packit Service 1d8f1c
        case -1: return -1;
Packit Service 1d8f1c
        default: _exit(0);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!nochdir) {
Packit Service 1d8f1c
      chdir("/");
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (!noclose) {
Packit Service 1d8f1c
        closeall(0);
Packit Service 1d8f1c
        open("/dev/null",O_RDWR);
Packit Service 1d8f1c
        dup(0); dup(0);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    return 0;
Packit Service 1d8f1c
}
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
gint
Packit Service 1d8f1c
main (gint argc, gchar **argv)
Packit Service 1d8f1c
{
Packit Service 1d8f1c
    int i;
Packit Service 1d8f1c
    const gchar *username = ibus_get_user_name ();
Packit Service 1d8f1c
Packit Service 1d8f1c
    setlocale (LC_ALL, "");
Packit Service 1d8f1c
Packit Service 1d8f1c
    GOptionContext *context = g_option_context_new ("- ibus daemon");
Packit Service 1d8f1c
    g_option_context_add_main_entries (context, entries, "ibus-daemon");
Packit Service 1d8f1c
Packit Service 1d8f1c
    g_argv = g_strdupv (argv);
Packit Service 1d8f1c
    GError *error = NULL;
Packit Service 1d8f1c
    if (!g_option_context_parse (context, &argc, &argv, &error)) {
Packit Service 1d8f1c
        g_printerr ("Option parsing failed: %s\n", error->message);
Packit Service 1d8f1c
	g_error_free (error);
Packit Service 1d8f1c
        exit (-1);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    if (g_gdbus_timeout < -1) {
Packit Service 1d8f1c
        g_printerr ("Bad timeout (must be >= -1): %d\n", g_gdbus_timeout);
Packit Service 1d8f1c
        exit (-1);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    if (g_mempro) {
Packit Service 1d8f1c
        g_warning ("--mem-profile no longer works with the GLib 2.46 or later");
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* check uid */
Packit Service 1d8f1c
    {
Packit Service 1d8f1c
        struct passwd *pwd = getpwuid (getuid ());
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (pwd == NULL || g_strcmp0 (pwd->pw_name, username) != 0) {
Packit Service 1d8f1c
            g_printerr ("Please run ibus-daemon with login user! Do not run ibus-daemon with sudo or su.\n");
Packit Service 1d8f1c
            exit (-1);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* daemonize process */
Packit Service 1d8f1c
    if (daemonize) {
Packit Service 1d8f1c
        if (daemon (1, 0) != 0) {
Packit Service 1d8f1c
            g_printerr ("Can not daemonize ibus.\n");
Packit Service 1d8f1c
            exit (-1);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* create a new process group. this is important to kill all of its children by SIGTERM at a time in bus_ibus_impl_destroy. */
Packit Service 1d8f1c
    setpgid (0, 0);
Packit Service 1d8f1c
Packit Service 1d8f1c
    ibus_init ();
Packit Service 1d8f1c
Packit Service 1d8f1c
    ibus_set_log_handler (g_verbose);
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* check if ibus-daemon is running in this session */
Packit Service 1d8f1c
    if (ibus_get_address () != NULL) {
Packit Service 1d8f1c
        IBusBus *bus = ibus_bus_new ();
Packit Service 1d8f1c
Packit Service 1d8f1c
        if (ibus_bus_is_connected (bus)) {
Packit Service 1d8f1c
            if (!replace) {
Packit Service 1d8f1c
                g_printerr ("current session already has an ibus-daemon.\n");
Packit Service 1d8f1c
                exit (-1);
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
            ibus_bus_exit (bus, FALSE);
Packit Service 1d8f1c
            while (ibus_bus_is_connected (bus)) {
Packit Service 1d8f1c
                g_main_context_iteration (NULL, TRUE);
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        g_object_unref (bus);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    bus_server_init ();
Packit Service 1d8f1c
    for (i = 0; i < G_N_ELEMENTS(panel_extension_disable_users); i++) {
Packit Service 1d8f1c
        if (!g_strcmp0 (username, panel_extension_disable_users[i]) != 0) {
Packit Service 1d8f1c
            emoji_extension = "disable";
Packit Service 1d8f1c
            break;
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
    if (!single) {
Packit Service 1d8f1c
        /* execute config component */
Packit Service 1d8f1c
        if (g_strcmp0 (config, "default") == 0) {
Packit Service 1d8f1c
            BusComponent *component;
Packit Service 1d8f1c
            component = bus_ibus_impl_lookup_component_by_name (
Packit Service 1d8f1c
                    BUS_DEFAULT_IBUS, IBUS_SERVICE_CONFIG);
Packit Service 1d8f1c
            if (component) {
Packit Service 1d8f1c
                bus_component_set_restart (component, restart);
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
            if (component == NULL || !bus_component_start (component, g_verbose)) {
Packit Service 1d8f1c
                g_printerr ("Can not execute default config program\n");
Packit Service 1d8f1c
                exit (-1);
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        } else if (g_strcmp0 (config, "disable") != 0 && g_strcmp0 (config, "") != 0) {
Packit Service 1d8f1c
            if (!execute_cmdline (config))
Packit Service 1d8f1c
                exit (-1);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
Packit Service 1d8f1c
        /* execute panel component */
Packit Service 1d8f1c
        if (g_strcmp0 (panel, "default") == 0) {
Packit Service 1d8f1c
            BusComponent *component;
Packit Service 1d8f1c
            component = bus_ibus_impl_lookup_component_by_name (
Packit Service 1d8f1c
                    BUS_DEFAULT_IBUS, IBUS_SERVICE_PANEL);
Packit Service 1d8f1c
            if (component) {
Packit Service 1d8f1c
                bus_component_set_restart (component, restart);
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
            if (component == NULL || !bus_component_start (component, g_verbose)) {
Packit Service 1d8f1c
                g_printerr ("Can not execute default panel program\n");
Packit Service 1d8f1c
                exit (-1);
Packit Service 1d8f1c
            }
Packit Service 1d8f1c
        } else if (g_strcmp0 (panel, "disable") != 0 && g_strcmp0 (panel, "") != 0) {
Packit Service 1d8f1c
            if (!execute_cmdline (panel))
Packit Service 1d8f1c
                exit (-1);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
#ifdef EMOJI_DICT
Packit Service 1d8f1c
    if (g_strcmp0 (emoji_extension, "default") == 0) {
Packit Service 1d8f1c
        BusComponent *component;
Packit Service 1d8f1c
        component = bus_ibus_impl_lookup_component_by_name (
Packit Service 1d8f1c
                BUS_DEFAULT_IBUS, IBUS_SERVICE_PANEL_EXTENSION);
Packit Service 1d8f1c
        if (component) {
Packit Service 1d8f1c
            bus_component_set_restart (component, restart);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
        if (component != NULL &&
Packit Service 1d8f1c
            !bus_component_start (component, g_verbose)) {
Packit Service 1d8f1c
            g_printerr ("Can not execute default panel program\n");
Packit Service 1d8f1c
            exit (-1);
Packit Service 1d8f1c
        }
Packit Service 1d8f1c
    } else if (g_strcmp0 (emoji_extension, "disable") != 0 &&
Packit Service 1d8f1c
               g_strcmp0 (emoji_extension, "") != 0) {
Packit Service 1d8f1c
        if (!execute_cmdline (emoji_extension))
Packit Service 1d8f1c
            exit (-1);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
#endif
Packit Service 1d8f1c
Packit Service 1d8f1c
    /* execute ibus xim server */
Packit Service 1d8f1c
    if (xim) {
Packit Service 1d8f1c
        if (!execute_cmdline (LIBEXECDIR "/ibus-x11 --kill-daemon"))
Packit Service 1d8f1c
            exit (-1);
Packit Service 1d8f1c
    }
Packit Service 1d8f1c
Packit Service 1d8f1c
    bus_server_run ();
Packit Service 1d8f1c
    return 0;
Packit Service 1d8f1c
}