main.c 11.8 KB
Newer Older
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 3
 *
 * Copyright (C) 2006 Novell, Inc.
4
 * Copyright (C) 2008 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
20
 */
21 22 23

#include <config.h>

24
#include <libintl.h>
25
#include <signal.h>
26
#include <stdlib.h>
27
#include <string.h>
28 29
#include <unistd.h>
#include <errno.h>
30

31
#include <glib/gi18n.h>
32
#include <glib.h>
33
#include <gtk/gtk.h>
34

35 36
#include <glib-unix.h>

37 38 39 40 41
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-bindings.h>
#include <dbus/dbus-glib-lowlevel.h>

42
#include "gdm-log.h"
43

44
#include "gsm-util.h"
45
#include "gsm-manager.h"
46
#include "gsm-session-fill.h"
47
#include "gsm-store.h"
48
#include "gsm-system.h"
49
#include "gsm-fail-whale.h"
50

51 52
#define GSM_DBUS_NAME "org.gnome.SessionManager"

53 54
static gboolean failsafe = FALSE;
static gboolean show_version = FALSE;
55
static gboolean debug = FALSE;
56
static gboolean please_fail = FALSE;
57

58 59 60 61
static DBusGProxy *bus_proxy = NULL;

static void shutdown_cb (gpointer data);

62 63 64 65 66 67 68 69 70
static void
on_bus_name_lost (DBusGProxy *bus_proxy,
                  const char *name,
                  gpointer    data)
{
        g_warning ("Lost name on bus: %s, exiting", name);
        exit (1);
}

71 72 73
static gboolean
acquire_name_on_proxy (DBusGProxy *bus_proxy,
                       const char *name)
74
{
75 76 77 78 79 80
        GError     *error;
        guint       result;
        gboolean    res;
        gboolean    ret;

        ret = FALSE;
81

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
        if (bus_proxy == NULL) {
                goto out;
        }

        error = NULL;
        res = dbus_g_proxy_call (bus_proxy,
                                 "RequestName",
                                 &error,
                                 G_TYPE_STRING, name,
                                 G_TYPE_UINT, 0,
                                 G_TYPE_INVALID,
                                 G_TYPE_UINT, &result,
                                 G_TYPE_INVALID);
        if (! res) {
                if (error != NULL) {
                        g_warning ("Failed to acquire %s: %s", name, error->message);
                        g_error_free (error);
                } else {
                        g_warning ("Failed to acquire %s", name);
                }
                goto out;
        }

        if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
                if (error != NULL) {
                        g_warning ("Failed to acquire %s: %s", name, error->message);
                        g_error_free (error);
                } else {
                        g_warning ("Failed to acquire %s", name);
                }
                goto out;
        }

115 116 117 118 119 120 121 122 123 124 125 126
        /* register for name lost */
        dbus_g_proxy_add_signal (bus_proxy,
                                 "NameLost",
                                 G_TYPE_STRING,
                                 G_TYPE_INVALID);
        dbus_g_proxy_connect_signal (bus_proxy,
                                     "NameLost",
                                     G_CALLBACK (on_bus_name_lost),
                                     NULL,
                                     NULL);


127 128 129 130 131 132 133 134 135 136 137 138 139
        ret = TRUE;

 out:
        return ret;
}

static gboolean
acquire_name (void)
{
        GError          *error;
        DBusGConnection *connection;

        error = NULL;
140
        connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
141 142
        if (connection == NULL) {
                gsm_util_init_error (TRUE,
143
                                     "Could not connect to session bus: %s",
144
                                     error->message);
145
                return FALSE;
146 147
        }

148 149 150 151 152 153 154 155 156
        bus_proxy = dbus_g_proxy_new_for_name_owner (connection,
                                                     DBUS_SERVICE_DBUS,
                                                     DBUS_PATH_DBUS,
                                                     DBUS_INTERFACE_DBUS,
                                                     &error);
        if (error != NULL) {
                gsm_util_init_error (TRUE,
                                     "Could not connect to session bus: %s",
                                     error->message);
157
                return FALSE;
158 159
        }

160 161
        if (! acquire_name_on_proxy (bus_proxy, GSM_DBUS_NAME) ) {
                gsm_util_init_error (TRUE,
162 163
                                     "%s",
                                     "Could not acquire name on session bus");
164
                return FALSE;
165 166 167
        }

        return TRUE;
168 169
}

170
static gboolean
171
term_or_int_signal_cb (gpointer data)
172
{
173
        GsmManager *manager = (GsmManager *)data;
174

175 176
        /* let the fatal signals interrupt us */
        g_debug ("Caught SIGINT/SIGTERM, shutting down normally.");
177

178
        gsm_manager_logout (manager, GSM_MANAGER_LOGOUT_MODE_FORCE, NULL);
179

180 181
        return FALSE;
}
182

183 184 185 186 187 188 189
static gboolean
sigusr2_cb (gpointer data)
{
        g_debug ("-------- MARK --------");
        return TRUE;
}

190 191 192 193 194
static gboolean
sigusr1_cb (gpointer data)
{
        gdm_log_toggle_debug ();
        return TRUE;
195 196
}

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
static void
shutdown_cb (gpointer data)
{
        GsmManager *manager = (GsmManager *)data;
        g_debug ("Calling shutdown callback function");

        /*
         * When the signal handler gets a shutdown signal, it calls
         * this function to inform GsmManager to not restart
         * applications in the off chance a handler is already queued
         * to dispatch following the below call to gtk_main_quit.
         */
        gsm_manager_set_phase (manager, GSM_MANAGER_PHASE_EXIT);

        gtk_main_quit ();
}

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
static gboolean
require_dbus_session (int      argc,
                      char   **argv,
                      GError **error)
{
        char **new_argv;
        int    i;

        if (g_getenv ("DBUS_SESSION_BUS_ADDRESS"))
                return TRUE;

        /* Just a sanity check to prevent infinite recursion if
         * dbus-launch fails to set DBUS_SESSION_BUS_ADDRESS 
         */
        g_return_val_if_fail (!g_str_has_prefix (argv[0], "dbus-launch"),
                              TRUE);

        /* +2 for our new arguments, +1 for NULL */
        new_argv = g_malloc (argc + 3 * sizeof (*argv));
233

234 235
        new_argv[0] = "dbus-launch";
        new_argv[1] = "--exit-with-session";
236
        for (i = 0; i < argc; i++) {
237
                new_argv[i + 2] = argv[i];
238
	}
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
        new_argv[i + 2] = NULL;
        
        if (!execvp ("dbus-launch", new_argv)) {
                g_set_error (error, 
                             G_SPAWN_ERROR,
                             G_SPAWN_ERROR_FAILED,
                             "No session bus and could not exec dbus-launch: %s",
                             g_strerror (errno));
                return FALSE;
        }

        /* Should not be reached */
        return TRUE;
}

254
int
255
main (int argc, char **argv)
256
{
257 258 259 260
        GError           *error;
        char             *display_str;
        GsmManager       *manager;
        GsmStore         *client_store;
261
        static char     **override_autostart_dirs = NULL;
262 263
        static char      *opt_session_name = NULL;
        const char       *session_name;
264
        static GOptionEntry entries[] = {
265
                { "autostart", 'a', 0, G_OPTION_ARG_STRING_ARRAY, &override_autostart_dirs, N_("Override standard autostart directories"), N_("AUTOSTART_DIR") },
266
                { "session", 0, 0, G_OPTION_ARG_STRING, &opt_session_name, N_("Session to use"), N_("SESSION_NAME") },
267 268 269
                { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, N_("Enable debugging code"), NULL },
                { "failsafe", 'f', 0, G_OPTION_ARG_NONE, &failsafe, N_("Do not load user-specified applications"), NULL },
                { "version", 0, 0, G_OPTION_ARG_NONE, &show_version, N_("Version of this application"), NULL },
270
                /* Translators: the 'fail whale' is the black dialog we show when something goes seriously wrong */
271
                { "whale", 0, 0, G_OPTION_ARG_NONE, &please_fail, N_("Show the fail whale dialog for testing"), NULL },
272 273
                { NULL, 0, 0, 0, NULL, NULL, NULL }
        };
274

275 276 277 278 279
        /* Make sure that we have a session bus */
        if (!require_dbus_session (argc, argv, &error)) {
                gsm_util_init_error (TRUE, "%s", error->message);
        }

280 281 282 283 284 285 286 287 288 289
        bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
        textdomain (GETTEXT_PACKAGE);

        error = NULL;
        gtk_init_with_args (&argc, &argv,
                            (char *) _(" - the GNOME session manager"),
                            entries, GETTEXT_PACKAGE,
                            &error);
        if (error != NULL) {
290 291 292 293 294 295
                g_warning ("%s", error->message);
                exit (1);
        }

        if (show_version) {
                g_print ("%s %s\n", argv [0], VERSION);
296
                exit (0);
297 298
        }

299
        if (please_fail) {
300
                gsm_fail_whale_dialog_we_failed (TRUE, TRUE, NULL);
301 302 303 304
                gtk_main ();
                exit (1);
        }

305 306 307
        gdm_log_init ();
        gdm_log_set_debug (debug);

308 309 310 311
        /* Set DISPLAY explicitly for all our children, in case --display
         * was specified on the command line.
         */
        display_str = gdk_get_display ();
312
        gsm_util_setenv ("DISPLAY", display_str);
313 314
        g_free (display_str);

315 316 317
        /* Some third-party programs rely on GNOME_DESKTOP_SESSION_ID to
         * detect if GNOME is running. We keep this for compatibility reasons.
         */
318
        gsm_util_setenv ("GNOME_DESKTOP_SESSION_ID", "this-is-deprecated");
319

320 321 322 323
        /* We want to use the GNOME menus which has the designed categories.
         */
        gsm_util_setenv ("XDG_MENU_PREFIX", "gnome-");

324
        client_store = gsm_store_new ();
325

326 327 328 329 330 331 332
        /* Talk to logind before acquiring a name, since it does synchronous
         * calls at initialization time that invoke a main loop and if we
         * already owned a name, then we would service too early during
         * that main loop.
         */
        g_object_unref (gsm_get_system ());

333 334 335 336 337
        if (!acquire_name ()) {
                gsm_fail_whale_dialog_we_failed (TRUE, TRUE, NULL);
                gtk_main ();
                exit (1);
        }
338

339
        manager = gsm_manager_new (client_store, failsafe);
340

341 342 343 344 345
        g_signal_connect_object (bus_proxy,
                                 "destroy",
                                 G_CALLBACK (shutdown_cb),
                                 manager,
                                 G_CONNECT_SWAPPED);
346

347 348 349
        g_unix_signal_add (SIGTERM, term_or_int_signal_cb, manager);
        g_unix_signal_add (SIGINT, term_or_int_signal_cb, manager);
        g_unix_signal_add (SIGUSR1, sigusr1_cb, manager);
350
        g_unix_signal_add (SIGUSR2, sigusr2_cb, manager);
351

352
        if (IS_STRING_EMPTY (opt_session_name))
353
                session_name = _gsm_manager_get_default_session (manager);
354 355
        else
                session_name = opt_session_name;
356

357 358 359
        gsm_util_set_autostart_dirs (override_autostart_dirs);

        if (!gsm_session_fill (manager, session_name)) {
360
                gsm_fail_whale_dialog_we_failed (FALSE, TRUE, NULL);
361
        }
362 363 364 365 366

        gsm_manager_start (manager);

        gtk_main ();

367 368 369
        g_clear_object (&manager);
        g_clear_object (&client_store);
        g_clear_object (&bus_proxy);
370

371 372
        gdm_log_shutdown ();

373
        return 0;
374
}