main.c 14.3 KB
Newer Older
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
3
 *
 * Copyright (C) 2006 Novell, Inc.
William Jon McCann's avatar
William Jon McCann committed
4
 * Copyright (C) 2008 Red Hat, Inc.
5
6
7
8
9
10
11
12
13
14
15
16
 *
 * 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
17
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
21

#include <config.h>

22
#include <libintl.h>
Tom Tromey's avatar
Tom Tromey committed
23
#include <signal.h>
24
#include <stdlib.h>
25
#include <string.h>
Ray Strode's avatar
Ray Strode committed
26
#include <locale.h>
27
28
#include <unistd.h>
#include <errno.h>
29

30
#include <glib/gi18n.h>
31
#include <glib.h>
32
#include <glib-unix.h>
Cosimo Cecchi's avatar
Cosimo Cecchi committed
33
#include <gio/gio.h>
34

35
#include "gdm-log.h"
36

Matthias Clasen's avatar
Matthias Clasen committed
37
#include "gsm-util.h"
38
#include "gsm-manager.h"
39
#include "gsm-session-fill.h"
40
#include "gsm-store.h"
41
#include "gsm-system.h"
42
#include "gsm-fail-whale.h"
43

44
45
46
47
#ifdef HAVE_SYSTEMD
#include <systemd/sd-journal.h>
#endif

48
49
#define GSM_DBUS_NAME "org.gnome.SessionManager"

50
51
static gboolean failsafe = FALSE;
static gboolean show_version = FALSE;
52
static gboolean debug = FALSE;
53
static gboolean please_fail = FALSE;
54
static gboolean disable_acceleration_check = FALSE;
Cosimo Cecchi's avatar
Cosimo Cecchi committed
55
56
static const char *session_name = NULL;
static GsmManager *manager = NULL;
57
static char *gl_renderer = NULL;
58

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
static GMainLoop *loop;

void
gsm_quit (void)
{
        g_main_loop_quit (loop);
}

static void
gsm_main (void)
{
        if (loop == NULL)
                loop = g_main_loop_new (NULL, TRUE);

        g_main_loop_run (loop);
}

76
static void
Cosimo Cecchi's avatar
Cosimo Cecchi committed
77
78
79
on_name_lost (GDBusConnection *connection,
              const char *name,
              gpointer    data)
80
{
Cosimo Cecchi's avatar
Cosimo Cecchi committed
81
        GsmManager *manager = (GsmManager *)data;
82
83

        if (connection == NULL) {
Cosimo Cecchi's avatar
Cosimo Cecchi committed
84
85
86
87
                g_warning ("Lost name on bus: %s", name);
                gsm_fail_whale_dialog_we_failed (TRUE, TRUE, NULL);
        } else {
                g_debug ("Calling name lost callback function");
88

Cosimo Cecchi's avatar
Cosimo Cecchi committed
89
90
91
92
93
94
95
                /*
                 * 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);
96

Cosimo Cecchi's avatar
Cosimo Cecchi committed
97
                gsm_quit ();
98
        }
99
100
}

101
static gboolean
102
term_or_int_signal_cb (gpointer data)
103
{
104
        GsmManager *manager = (GsmManager *)data;
105

106
107
        /* let the fatal signals interrupt us */
        g_debug ("Caught SIGINT/SIGTERM, shutting down normally.");
108

109
        gsm_manager_logout (manager, GSM_MANAGER_LOGOUT_MODE_FORCE, NULL);
110

111
112
        return FALSE;
}
113

114
115
116
117
118
119
120
static gboolean
sigusr2_cb (gpointer data)
{
        g_debug ("-------- MARK --------");
        return TRUE;
}

121
122
123
124
125
static gboolean
sigusr1_cb (gpointer data)
{
        gdm_log_toggle_debug ();
        return TRUE;
126
127
}

128
static void
Cosimo Cecchi's avatar
Cosimo Cecchi committed
129
create_manager (void)
130
{
Cosimo Cecchi's avatar
Cosimo Cecchi committed
131
        GsmStore *client_store;
132

Cosimo Cecchi's avatar
Cosimo Cecchi committed
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
        client_store = gsm_store_new ();
        manager = gsm_manager_new (client_store, failsafe);
        g_object_unref (client_store);

        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);
        g_unix_signal_add (SIGUSR2, sigusr2_cb, manager);

        if (IS_STRING_EMPTY (session_name)) {
                session_name = _gsm_manager_get_default_session (manager);
        }

        if (!gsm_session_fill (manager, session_name)) {
                gsm_fail_whale_dialog_we_failed (FALSE, TRUE, NULL);
        }
149

150
        _gsm_manager_set_renderer (manager, gl_renderer);
Cosimo Cecchi's avatar
Cosimo Cecchi committed
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
        gsm_manager_start (manager);
}

static void
on_bus_acquired (GDBusConnection *connection,
                 const char *name,
                 gpointer data)
{
        create_manager ();
}

static guint
acquire_name (void)
{
        return g_bus_own_name (G_BUS_TYPE_SESSION,
                               GSM_DBUS_NAME,
                               G_BUS_NAME_OWNER_FLAGS_NONE,
                               on_bus_acquired,
                               NULL,
                               on_name_lost,
                               NULL, NULL);
172
173
}

174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
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 */
192
        new_argv = g_malloc ((argc + 3) * sizeof (*argv));
193

194
195
        new_argv[0] = "dbus-launch";
        new_argv[1] = "--exit-with-session";
196
        for (i = 0; i < argc; i++) {
197
                new_argv[i + 2] = argv[i];
Ray Strode's avatar
Ray Strode committed
198
        }
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
        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;
}

214
215
216
217
218
219
static gboolean
check_gl (GError **error)
{
        int status;
        char *argv[] = { LIBEXECDIR "/gnome-session-check-accelerated", NULL };

220
221
222
223
224
        if (getenv ("DISPLAY") == NULL) {
                /* Not connected to X11, someone else will take care of checking GL */
                return TRUE;
        }

225
        if (!g_spawn_sync (NULL, (char **) argv, NULL, 0, NULL, NULL, &gl_renderer, NULL,
226
227
228
229
230
231
232
                           &status, error)) {
                return FALSE;
        }

        return g_spawn_check_exit_status (status, error);
}

233
234
235
236
237
238
239
static void
initialize_gio (void)
{
        char *disable_fuse = NULL;
        char *use_vfs = NULL;

        disable_fuse = g_strdup (g_getenv ("GVFS_DISABLE_FUSE"));
Ray Strode's avatar
Ray Strode committed
240
        use_vfs = g_strdup (g_getenv ("GIO_USE_VFS"));
241
242
243
244
245
246
247
248
249
250
251
252
253

        g_setenv ("GVFS_DISABLE_FUSE", "1", TRUE);
        g_setenv ("GIO_USE_VFS", "local", TRUE);
        g_vfs_get_default ();

        if (use_vfs) {
                g_setenv ("GIO_USE_VFS", use_vfs, TRUE);
                g_free (use_vfs);
        } else {
                g_unsetenv ("GIO_USE_VFS");
        }

        if (disable_fuse) {
Ray Strode's avatar
Ray Strode committed
254
                g_setenv ("GVFS_DISABLE_FUSE", use_vfs, TRUE);
255
256
257
258
259
260
                g_free (disable_fuse);
        } else {
                g_unsetenv ("GVFS_DISABLE_FUSE");
        }
}

261
int
262
main (int argc, char **argv)
263
{
264
        GError           *error = NULL;
265
        static char     **override_autostart_dirs = NULL;
Colin Walters's avatar
Colin Walters committed
266
        static char      *opt_session_name = NULL;
267
        const char       *debug_string = NULL;
268
        gboolean          gl_failed = FALSE;
Cosimo Cecchi's avatar
Cosimo Cecchi committed
269
        guint             name_owner_id;
270
        GOptionContext   *options;
271
        static GOptionEntry entries[] = {
272
                { "autostart", 'a', 0, G_OPTION_ARG_STRING_ARRAY, &override_autostart_dirs, N_("Override standard autostart directories"), N_("AUTOSTART_DIR") },
Colin Walters's avatar
Colin Walters committed
273
                { "session", 0, 0, G_OPTION_ARG_STRING, &opt_session_name, N_("Session to use"), N_("SESSION_NAME") },
274
275
276
                { "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 },
Matthias Clasen's avatar
Matthias Clasen committed
277
                /* Translators: the 'fail whale' is the black dialog we show when something goes seriously wrong */
278
                { "whale", 0, 0, G_OPTION_ARG_NONE, &please_fail, N_("Show the fail whale dialog for testing"), NULL },
279
                { "disable-acceleration-check", 0, 0, G_OPTION_ARG_NONE, &disable_acceleration_check, N_("Disable hardware acceleration check"), NULL },
280
281
                { NULL, 0, 0, 0, NULL, NULL, NULL }
        };
282

283
284
285
286
287
        /* Make sure that we have a session bus */
        if (!require_dbus_session (argc, argv, &error)) {
                gsm_util_init_error (TRUE, "%s", error->message);
        }

288
289
290
291
292
293
294
295
296
        /* From 3.14 GDM sets XDG_CURRENT_DESKTOP. For compatibility with
         * older versions of GDM,  other display managers, and startx,
         * set a fallback value if we don't find it set.
         */
        if (g_getenv ("XDG_CURRENT_DESKTOP") == NULL) {
            g_setenv("XDG_CURRENT_DESKTOP", "GNOME", TRUE);
            gsm_util_setenv ("XDG_CURRENT_DESKTOP", "GNOME");
        }

297
298
299
        /* Make sure we initialize gio in a way that does not autostart any daemon */
        initialize_gio ();

300
        setlocale (LC_ALL, "");
301
302
303
304
        bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
        textdomain (GETTEXT_PACKAGE);

305
306
307
        debug_string = g_getenv ("GNOME_SESSION_DEBUG");
        if (debug_string != NULL) {
                debug = rpmatch (debug_string) == TRUE || atoi (debug_string) == 1;
308
309
        }

310
        error = NULL;
311
312
313
        options = g_option_context_new (_(" - the GNOME session manager"));
        g_option_context_add_main_entries (options, entries, GETTEXT_PACKAGE);
        g_option_context_parse (options, &argc, &argv, &error);
314
        if (error != NULL) {
315
316
317
318
                g_warning ("%s", error->message);
                exit (1);
        }

319
320
        g_option_context_free (options);

321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
        /* Rebind stdout/stderr to the journal explicitly, so that
         * journald picks ups the nicer "gnome-session" as the program
         * name instead of whatever shell script GDM happened to use.
         */
#ifdef HAVE_SYSTEMD
        if (!debug) {
                int journalfd;

                journalfd = sd_journal_stream_fd (PACKAGE, LOG_INFO, 0);
                if (journalfd >= 0) {
                        dup2(journalfd, 1);
                        dup2(journalfd, 2);
                }
        }
#endif

337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
        gdm_log_init ();
        gdm_log_set_debug (debug);

        if (disable_acceleration_check) {
                g_debug ("hardware acceleration check is disabled");
        } else {
                /* Check GL, if it doesn't work out then force software fallback */
                if (!check_gl (&error)) {
                        gl_failed = TRUE;

                        g_debug ("hardware acceleration check failed: %s",
                                 error? error->message : "");
                        g_clear_error (&error);
                        if (g_getenv ("LIBGL_ALWAYS_SOFTWARE") == NULL) {
                                g_setenv ("LIBGL_ALWAYS_SOFTWARE", "1", TRUE);
                                if (!check_gl (&error)) {
                                        g_warning ("software acceleration check failed: %s",
                                                   error? error->message : "");
                                        g_clear_error (&error);
                                } else {
                                        gl_failed = FALSE;
                                }
                        }
                }
        }

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

368
369
        if (gl_failed) {
                gsm_fail_whale_dialog_we_failed (FALSE, TRUE, NULL);
370
                gsm_main ();
371
372
373
                exit (1);
        }

374
        if (please_fail) {
375
                gsm_fail_whale_dialog_we_failed (TRUE, TRUE, NULL);
376
                gsm_main ();
377
378
379
                exit (1);
        }

380
381
        gsm_util_export_activation_environment (NULL);

382
383
384
385
#ifdef HAVE_SYSTEMD
        gsm_util_export_user_environment (NULL);
#endif

386
387
388
389
390
391
        {
                gchar *ibus_path;

                ibus_path = g_find_program_in_path("ibus-daemon");

                if (ibus_path) {
392
393
394
395
396
397
398
399
400
                        const gchar *p;
                        p = g_getenv ("QT_IM_MODULE");
                        if (!p || !*p)
                                p = "ibus";
                        gsm_util_setenv ("QT_IM_MODULE", p);
                        p = g_getenv ("XMODIFIERS");
                        if (!p || !*p)
                                p = "@im=ibus";
                        gsm_util_setenv ("XMODIFIERS", p);
401
402
403
404
405
                }

                g_free (ibus_path);
        }

406
407
408
        /* Some third-party programs rely on GNOME_DESKTOP_SESSION_ID to
         * detect if GNOME is running. We keep this for compatibility reasons.
         */
409
        gsm_util_setenv ("GNOME_DESKTOP_SESSION_ID", "this-is-deprecated");
410

Florian Müllner's avatar
Florian Müllner committed
411
412
413
414
        /* We want to use the GNOME menus which has the designed categories.
         */
        gsm_util_setenv ("XDG_MENU_PREFIX", "gnome-");

415
416
417
418
419
420
421
422
423
424
425
426
        /* hack to fix keyring until we can reorder things in 3.20
         * https://bugzilla.gnome.org/show_bug.cgi?id=738205
         */
        if (g_strcmp0 (g_getenv ("XDG_SESSION_TYPE"), "wayland") == 0 &&
            g_getenv ("GSM_SKIP_SSH_AGENT_WORKAROUND") == NULL) {
                char *ssh_socket;

                ssh_socket = g_build_filename (g_get_user_runtime_dir (), "keyring", "ssh", NULL);
                gsm_util_setenv ("SSH_AUTH_SOCK", ssh_socket);
                g_free (ssh_socket);
        }

Cosimo Cecchi's avatar
Cosimo Cecchi committed
427
428
        gsm_util_set_autostart_dirs (override_autostart_dirs);
        session_name = opt_session_name;
429

430
431
432
433
434
435
436
        /* 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 ());

Cosimo Cecchi's avatar
Cosimo Cecchi committed
437
        name_owner_id  = acquire_name ();
438

439
        gsm_main ();
440

441
        g_clear_object (&manager);
442
        g_free (gl_renderer);
443

Cosimo Cecchi's avatar
Cosimo Cecchi committed
444
        g_bus_unown_name (name_owner_id);
445
446
        gdm_log_shutdown ();

447
        return 0;
448
}