~ubuntu-branches/ubuntu/trusty/gdm/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/ubuntu_dont_catch_sigsegv.patch/common/gdm-signal-handler.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha, Tim Lunn, Jeremy Bicha, Robert Ancell
  • Date: 2013-05-31 22:36:08 UTC
  • mfrom: (1.4.55)
  • Revision ID: package-import@ubuntu.com-20130531223608-33uo85niksee5460
Tags: 3.8.1.1-0ubuntu1
[ Tim Lunn ]
* New upstream release
* debian/patches/ubuntu_dont_catch_sigsegv.patch:
  - Dropped, obsolete
* debian/rules:
  - Don't rename gdm binary since that's already been
    done in the new version

[ Jeremy Bicha ]
* debian/control.in: Bump minimum glib
* debian/watch: Watch for unstable releases
* debian/patches/00git_logind_check.patch:
  - Dropped, applied in new release
* debian/patches/08_frequent-users_greeter.patch: Refreshed

[ Robert Ancell ]
* New upstream release
* debian/patches/ubuntu_daemon_autologin_tracking.patch:
* debian/patches/ubuntu_ensure_dirs.patch:
* debian/patches/ubuntu_slave-only-set-up-autologin.patch:
  - Applied upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
 
 *
3
 
 * Copyright (C) 2006 Red Hat, Inc.
4
 
 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 
 *
20
 
 */
21
 
 
22
 
#include "config.h"
23
 
 
24
 
#include <stdlib.h>
25
 
#include <stdio.h>
26
 
#include <fcntl.h>
27
 
#include <unistd.h>
28
 
#include <string.h>
29
 
#include <signal.h>
30
 
#if HAVE_EXECINFO_H
31
 
#include <execinfo.h>
32
 
#endif
33
 
#include <syslog.h>
34
 
#include <sys/wait.h>
35
 
#include <sys/stat.h>
36
 
 
37
 
#include <glib.h>
38
 
#include <glib/gi18n.h>
39
 
#include <glib/gstdio.h>
40
 
#include <glib-object.h>
41
 
 
42
 
#include "gdm-signal-handler.h"
43
 
 
44
 
#define GDM_SIGNAL_HANDLER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SIGNAL_HANDLER, GdmSignalHandlerPrivate))
45
 
 
46
 
typedef struct {
47
 
        int                  signal_number;
48
 
        GdmSignalHandlerFunc func;
49
 
        gpointer             data;
50
 
        guint                id;
51
 
} CallbackData;
52
 
 
53
 
struct GdmSignalHandlerPrivate
54
 
{
55
 
        GHashTable    *lookup;
56
 
        GHashTable    *id_lookup;
57
 
        GHashTable    *action_lookup;
58
 
        guint          next_id;
59
 
        GDestroyNotify fatal_func;
60
 
        gpointer       fatal_data;
61
 
};
62
 
 
63
 
static void     gdm_signal_handler_class_init   (GdmSignalHandlerClass *klass);
64
 
static void     gdm_signal_handler_init         (GdmSignalHandler      *signal_handler);
65
 
static void     gdm_signal_handler_finalize     (GObject               *object);
66
 
 
67
 
static gpointer signal_handler_object = NULL;
68
 
static int      signal_pipes[2];
69
 
static int      signals_blocked = 0;
70
 
static sigset_t signals_block_mask;
71
 
static sigset_t signals_oldmask;
72
 
 
73
 
G_DEFINE_TYPE (GdmSignalHandler, gdm_signal_handler, G_TYPE_OBJECT)
74
 
 
75
 
static void
76
 
block_signals_push (void)
77
 
{
78
 
        signals_blocked++;
79
 
 
80
 
        if (signals_blocked == 1) {
81
 
                /* Set signal mask */
82
 
                sigemptyset (&signals_block_mask);
83
 
                sigfillset (&signals_block_mask);
84
 
                sigprocmask (SIG_BLOCK, &signals_block_mask, &signals_oldmask);
85
 
        }
86
 
}
87
 
 
88
 
static void
89
 
block_signals_pop (void)
90
 
{
91
 
        signals_blocked--;
92
 
 
93
 
        if (signals_blocked == 0) {
94
 
                /* Set signal mask */
95
 
                sigprocmask (SIG_SETMASK, &signals_oldmask, NULL);
96
 
        }
97
 
}
98
 
 
99
 
static gboolean
100
 
signal_io_watch (GIOChannel       *ioc,
101
 
                 GIOCondition      condition,
102
 
                 GdmSignalHandler *handler)
103
 
{
104
 
        char     buf[256];
105
 
        gboolean is_fatal;
106
 
        gsize    bytes_read;
107
 
        int      i;
108
 
 
109
 
        block_signals_push ();
110
 
 
111
 
        g_io_channel_read_chars (ioc, buf, sizeof (buf), &bytes_read, NULL);
112
 
 
113
 
        is_fatal = FALSE;
114
 
 
115
 
        for (i = 0; i < bytes_read; i++) {
116
 
                int     signum;
117
 
                GSList *handlers;
118
 
                GSList *l;
119
 
 
120
 
                signum = (gint32)buf[i];
121
 
 
122
 
                g_debug ("GdmSignalHandler: handling signal %d", signum);
123
 
                handlers = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (signum));
124
 
 
125
 
                g_debug ("GdmSignalHandler: Found %u callbacks", g_slist_length (handlers));
126
 
                for (l = handlers; l != NULL; l = l->next) {
127
 
                        gboolean      res;
128
 
                        CallbackData *data;
129
 
 
130
 
                        data = g_hash_table_lookup (handler->priv->id_lookup, l->data);
131
 
                        if (data != NULL) {
132
 
                                if (data->func != NULL) {
133
 
                                        g_debug ("GdmSignalHandler: running %d handler: %p", signum, data->func);
134
 
                                        res = data->func (signum, data->data);
135
 
                                        if (! res) {
136
 
                                                is_fatal = TRUE;
137
 
                                        }
138
 
                                }
139
 
                        }
140
 
                }
141
 
        }
142
 
 
143
 
        block_signals_pop ();
144
 
 
145
 
        if (is_fatal) {
146
 
                if (handler->priv->fatal_func != NULL) {
147
 
                        g_debug ("GdmSignalHandler: Caught termination signal - calling fatal func");
148
 
                        handler->priv->fatal_func (handler->priv->fatal_data);
149
 
                } else {
150
 
                        g_debug ("GdmSignalHandler: Caught termination signal - exiting");
151
 
                        exit (1);
152
 
                }
153
 
 
154
 
                return FALSE;
155
 
        }
156
 
 
157
 
        g_debug ("GdmSignalHandler: Done handling signals");
158
 
 
159
 
        return TRUE;
160
 
}
161
 
 
162
 
static void
163
 
fallback_get_backtrace (void)
164
 
{
165
 
#ifdef HAVE_EXECINFO_H
166
 
        void *  frames[64];
167
 
        size_t  size;
168
 
        char ** strings;
169
 
        size_t  i;
170
 
 
171
 
        size = backtrace (frames, G_N_ELEMENTS (frames));
172
 
        if ((strings = backtrace_symbols (frames, size))) {
173
 
                syslog (LOG_CRIT, "******************* START ********************************");
174
 
                for (i = 0; i < size; i++) {
175
 
                        syslog (LOG_CRIT, "Frame %zd: %s", i, strings[i]);
176
 
                }
177
 
                free (strings);
178
 
                syslog (LOG_CRIT, "******************* END **********************************");
179
 
                return;
180
 
        }
181
 
#endif
182
 
        g_warning ("GDM crashed, but symbols couldn't be retrieved.");
183
 
}
184
 
 
185
 
 
186
 
static gboolean
187
 
crashlogger_get_backtrace (void)
188
 
{
189
 
        gboolean success = FALSE;
190
 
        int      pid;
191
 
 
192
 
        pid = fork ();
193
 
        if (pid > 0) {
194
 
                /* Wait for the child to finish */
195
 
                int estatus;
196
 
                if (waitpid (pid, &estatus, 0) != -1) {
197
 
                        /* Only succeed if the crashlogger succeeded */
198
 
                        if (WIFEXITED (estatus) && (WEXITSTATUS (estatus) == 0)) {
199
 
                                success = TRUE;
200
 
                        }
201
 
                }
202
 
        } else if (pid == 0) {
203
 
                /* Child process */
204
 
                execl (LIBEXECDIR "/gdm-crash-logger",
205
 
                       LIBEXECDIR "/gdm-crash-logger", NULL);
206
 
        }
207
 
 
208
 
        return success;
209
 
}
210
 
 
211
 
 
212
 
static void
213
 
gdm_signal_handler_backtrace (void)
214
 
{
215
 
        struct stat s;
216
 
        gboolean    fallback = TRUE;
217
 
 
218
 
        /* Try to use gdb via gdm-crash-logger if it exists, since
219
 
         * we get much better information out of it.  Otherwise
220
 
         * fall back to execinfo.
221
 
         */
222
 
        if (g_stat (LIBEXECDIR "/gdm-crash-logger", &s) == 0) {
223
 
                fallback = crashlogger_get_backtrace () ? FALSE : TRUE;
224
 
        }
225
 
 
226
 
        if (fallback) {
227
 
                fallback_get_backtrace ();
228
 
        }
229
 
}
230
 
 
231
 
static void
232
 
signal_handler (int signo)
233
 
{
234
 
        static int in_fatal = 0;
235
 
        int        ignore;
236
 
        guchar     signo_byte = signo;
237
 
 
238
 
        /* avoid loops */
239
 
        if (in_fatal > 0) {
240
 
                return;
241
 
        }
242
 
 
243
 
        ++in_fatal;
244
 
 
245
 
        switch (signo) {
246
 
        case SIGSEGV:
247
 
        case SIGBUS:
248
 
        case SIGILL:
249
 
        case SIGABRT:
250
 
        case SIGTRAP:
251
 
                gdm_signal_handler_backtrace ();
252
 
                exit (1);
253
 
                break;
254
 
        case SIGFPE:
255
 
        case SIGPIPE:
256
 
                /* let the fatal signals interrupt us */
257
 
                --in_fatal;
258
 
                gdm_signal_handler_backtrace ();
259
 
                ignore = write (signal_pipes [1], &signo_byte, 1);
260
 
                break;
261
 
        default:
262
 
                --in_fatal;
263
 
                ignore = write (signal_pipes [1], &signo_byte, 1);
264
 
                break;
265
 
        }
266
 
}
267
 
 
268
 
static void
269
 
catch_signal (GdmSignalHandler *handler,
270
 
              int               signal_number)
271
 
{
272
 
        struct sigaction  action;
273
 
        struct sigaction *old_action;
274
 
 
275
 
        g_debug ("GdmSignalHandler: Registering for %d signals", signal_number);
276
 
 
277
 
        action.sa_handler = signal_handler;
278
 
        sigemptyset (&action.sa_mask);
279
 
        action.sa_flags = 0;
280
 
 
281
 
        old_action = g_new0 (struct sigaction, 1);
282
 
 
283
 
        sigaction (signal_number, &action, old_action);
284
 
 
285
 
        g_hash_table_insert (handler->priv->action_lookup,
286
 
                             GINT_TO_POINTER (signal_number),
287
 
                             old_action);
288
 
}
289
 
 
290
 
static void
291
 
uncatch_signal (GdmSignalHandler *handler,
292
 
                int               signal_number)
293
 
{
294
 
        struct sigaction *old_action;
295
 
 
296
 
        g_debug ("GdmSignalHandler: Unregistering for %d signals", signal_number);
297
 
 
298
 
        old_action = g_hash_table_lookup (handler->priv->action_lookup,
299
 
                                          GINT_TO_POINTER (signal_number));
300
 
        g_hash_table_remove (handler->priv->action_lookup,
301
 
                             GINT_TO_POINTER (signal_number));
302
 
 
303
 
        sigaction (signal_number, old_action, NULL);
304
 
 
305
 
        g_free (old_action);
306
 
}
307
 
 
308
 
guint
309
 
gdm_signal_handler_add (GdmSignalHandler    *handler,
310
 
                        int                  signal_number,
311
 
                        GdmSignalHandlerFunc callback,
312
 
                        gpointer             data)
313
 
{
314
 
        CallbackData *cdata;
315
 
        GSList       *list;
316
 
 
317
 
        g_return_val_if_fail (GDM_IS_SIGNAL_HANDLER (handler), 0);
318
 
 
319
 
        cdata = g_new0 (CallbackData, 1);
320
 
        cdata->signal_number = signal_number;
321
 
        cdata->func = callback;
322
 
        cdata->data = data;
323
 
        cdata->id = handler->priv->next_id++;
324
 
 
325
 
        g_debug ("GdmSignalHandler: Adding handler %u: signum=%d %p", cdata->id, cdata->signal_number, cdata->func);
326
 
 
327
 
        if (g_hash_table_lookup (handler->priv->action_lookup, GINT_TO_POINTER (signal_number)) == NULL) {
328
 
                catch_signal (handler, signal_number);
329
 
        }
330
 
 
331
 
        /* ID lookup owns the CallbackData */
332
 
        g_hash_table_insert (handler->priv->id_lookup, GUINT_TO_POINTER (cdata->id), cdata);
333
 
 
334
 
        list = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (signal_number));
335
 
        list = g_slist_prepend (list, GUINT_TO_POINTER (cdata->id));
336
 
 
337
 
        g_hash_table_insert (handler->priv->lookup, GINT_TO_POINTER (signal_number), list);
338
 
 
339
 
        return cdata->id;
340
 
}
341
 
 
342
 
void
343
 
gdm_signal_handler_add_fatal (GdmSignalHandler *handler)
344
 
{
345
 
        g_return_if_fail (GDM_IS_SIGNAL_HANDLER (handler));
346
 
 
347
 
        gdm_signal_handler_add (handler, SIGILL, NULL, NULL);
348
 
        gdm_signal_handler_add (handler, SIGBUS, NULL, NULL);
349
 
        gdm_signal_handler_add (handler, SIGSEGV, NULL, NULL);
350
 
        gdm_signal_handler_add (handler, SIGABRT, NULL, NULL);
351
 
        gdm_signal_handler_add (handler, SIGTRAP, NULL, NULL);
352
 
}
353
 
 
354
 
static void
355
 
callback_data_free (CallbackData *d)
356
 
{
357
 
        g_free (d);
358
 
}
359
 
 
360
 
static void
361
 
gdm_signal_handler_remove_and_free_data (GdmSignalHandler *handler,
362
 
                                         CallbackData     *cdata)
363
 
{
364
 
        GSList *list;
365
 
 
366
 
        g_return_if_fail (GDM_IS_SIGNAL_HANDLER (handler));
367
 
 
368
 
        list = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (cdata->signal_number));
369
 
        list = g_slist_remove_all (list, GUINT_TO_POINTER (cdata->id));
370
 
        if (list == NULL) {
371
 
                uncatch_signal (handler, cdata->signal_number);
372
 
        }
373
 
 
374
 
        g_debug ("GdmSignalHandler: Removing handler %u: signum=%d %p", cdata->signal_number, cdata->id, cdata->func);
375
 
        /* put changed list back in */
376
 
        g_hash_table_insert (handler->priv->lookup, GINT_TO_POINTER (cdata->signal_number), list);
377
 
 
378
 
        g_hash_table_remove (handler->priv->id_lookup, GUINT_TO_POINTER (cdata->id));
379
 
}
380
 
 
381
 
void
382
 
gdm_signal_handler_remove (GdmSignalHandler    *handler,
383
 
                           guint                id)
384
 
{
385
 
        CallbackData *found;
386
 
 
387
 
        g_return_if_fail (GDM_IS_SIGNAL_HANDLER (handler));
388
 
 
389
 
        found = g_hash_table_lookup (handler->priv->id_lookup, GUINT_TO_POINTER (id));
390
 
        if (found != NULL) {
391
 
                gdm_signal_handler_remove_and_free_data (handler, found);
392
 
                found = NULL;
393
 
        }
394
 
}
395
 
 
396
 
static CallbackData *
397
 
find_callback_data_by_func (GdmSignalHandler    *handler,
398
 
                            guint                signal_number,
399
 
                            GdmSignalHandlerFunc callback,
400
 
                            gpointer             data)
401
 
{
402
 
        GSList       *list;
403
 
        GSList       *l;
404
 
        CallbackData *found;
405
 
 
406
 
        found = NULL;
407
 
 
408
 
        list = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (signal_number));
409
 
 
410
 
        for (l = list; l != NULL; l = l->next) {
411
 
                guint         id;
412
 
                CallbackData *d;
413
 
 
414
 
                id = GPOINTER_TO_UINT (l->data);
415
 
 
416
 
                d = g_hash_table_lookup (handler->priv->id_lookup, GUINT_TO_POINTER (id));
417
 
                if (d != NULL
418
 
                    && d->func == callback
419
 
                    && d->data == data) {
420
 
                        found = d;
421
 
                        break;
422
 
                }
423
 
        }
424
 
 
425
 
        return found;
426
 
}
427
 
 
428
 
void
429
 
gdm_signal_handler_remove_func (GdmSignalHandler    *handler,
430
 
                                guint                signal_number,
431
 
                                GdmSignalHandlerFunc callback,
432
 
                                gpointer             data)
433
 
{
434
 
        CallbackData *found;
435
 
 
436
 
        g_return_if_fail (GDM_IS_SIGNAL_HANDLER (handler));
437
 
 
438
 
        found = find_callback_data_by_func (handler, signal_number, callback, data);
439
 
 
440
 
        if (found != NULL) {
441
 
                gdm_signal_handler_remove_and_free_data (handler, found);
442
 
                found = NULL;
443
 
        }
444
 
 
445
 
        /* FIXME: once all handlers are removed deregister signum handler */
446
 
}
447
 
 
448
 
static void
449
 
gdm_signal_handler_class_init (GdmSignalHandlerClass *klass)
450
 
{
451
 
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
452
 
 
453
 
        object_class->finalize = gdm_signal_handler_finalize;
454
 
 
455
 
        g_type_class_add_private (klass, sizeof (GdmSignalHandlerPrivate));
456
 
}
457
 
 
458
 
static void
459
 
signal_list_free (GSList *list)
460
 
{
461
 
        g_slist_free (list);
462
 
}
463
 
 
464
 
void
465
 
gdm_signal_handler_set_fatal_func (GdmSignalHandler *handler,
466
 
                                   GDestroyNotify    func,
467
 
                                   gpointer          user_data)
468
 
{
469
 
        g_return_if_fail (GDM_IS_SIGNAL_HANDLER (handler));
470
 
 
471
 
        handler->priv->fatal_func = func;
472
 
        handler->priv->fatal_data = user_data;
473
 
}
474
 
 
475
 
static void
476
 
gdm_signal_handler_init (GdmSignalHandler *handler)
477
 
{
478
 
        GIOChannel *ioc;
479
 
 
480
 
        handler->priv = GDM_SIGNAL_HANDLER_GET_PRIVATE (handler);
481
 
 
482
 
        handler->priv->next_id = 1;
483
 
 
484
 
        handler->priv->lookup = g_hash_table_new (NULL, NULL);
485
 
        handler->priv->id_lookup = g_hash_table_new (NULL, NULL);
486
 
        handler->priv->action_lookup = g_hash_table_new (NULL, NULL);
487
 
 
488
 
        if (pipe (signal_pipes) == -1) {
489
 
                g_error ("Could not create pipe() for signal handling");
490
 
        }
491
 
        fcntl(signal_pipes[0], F_SETFD, FD_CLOEXEC);
492
 
        fcntl(signal_pipes[1], F_SETFD, FD_CLOEXEC);
493
 
 
494
 
        ioc = g_io_channel_unix_new (signal_pipes[0]);
495
 
        g_io_channel_set_flags (ioc, G_IO_FLAG_NONBLOCK, NULL);
496
 
        g_io_add_watch (ioc, G_IO_IN, (GIOFunc)signal_io_watch, handler);
497
 
        g_io_channel_set_close_on_unref (ioc, TRUE);
498
 
        g_io_channel_unref (ioc);
499
 
}
500
 
 
501
 
static void
502
 
gdm_signal_handler_finalize (GObject *object)
503
 
{
504
 
        GdmSignalHandler *handler;
505
 
        GList            *l;
506
 
 
507
 
        g_return_if_fail (object != NULL);
508
 
        g_return_if_fail (GDM_IS_SIGNAL_HANDLER (object));
509
 
 
510
 
        handler = GDM_SIGNAL_HANDLER (object);
511
 
 
512
 
        g_debug ("GdmSignalHandler: Finalizing signal handler");
513
 
 
514
 
        g_return_if_fail (handler->priv != NULL);
515
 
        for (l = g_hash_table_get_values (handler->priv->lookup);
516
 
             l != NULL; l = l->next) {
517
 
                signal_list_free ((GSList *) l->data);
518
 
        }
519
 
        g_hash_table_destroy (handler->priv->lookup);
520
 
        for (l = g_hash_table_get_values (handler->priv->id_lookup);
521
 
             l != NULL; l = l->next) {
522
 
                callback_data_free ((CallbackData *) l->data);
523
 
        }
524
 
        g_hash_table_destroy (handler->priv->id_lookup);
525
 
        for (l = g_hash_table_get_values (handler->priv->action_lookup);
526
 
             l != NULL; l = l->next) {
527
 
                g_free (l->data);
528
 
        }
529
 
        g_hash_table_destroy (handler->priv->action_lookup);
530
 
 
531
 
        close (signal_pipes [0]);
532
 
        close (signal_pipes [1]);
533
 
 
534
 
        G_OBJECT_CLASS (gdm_signal_handler_parent_class)->finalize (object);
535
 
}
536
 
 
537
 
GdmSignalHandler *
538
 
gdm_signal_handler_new (void)
539
 
{
540
 
        if (signal_handler_object != NULL) {
541
 
                g_object_ref (signal_handler_object);
542
 
        } else {
543
 
                signal_handler_object = g_object_new (GDM_TYPE_SIGNAL_HANDLER, NULL);
544
 
                g_object_add_weak_pointer (signal_handler_object,
545
 
                                           (gpointer *) &signal_handler_object);
546
 
        }
547
 
 
548
 
        return GDM_SIGNAL_HANDLER (signal_handler_object);
549
 
}