[gdm] Add an X11 error trap mechanism



commit 23d5ed6b9ccbffbfb76e4551cce9051eea62cc52
Author: William Jon McCann <jmccann redhat com>
Date:   Wed Jun 16 18:41:49 2010 -0400

    Add an X11 error trap mechanism
    
    Copied from GDK

 daemon/Makefile.am                |    8 ++
 daemon/factory-slave-main.c       |    2 +
 daemon/gdm-slave.c                |    1 +
 daemon/gdm-xerrors.c              |  242 +++++++++++++++++++++++++++++++++++++
 daemon/gdm-xerrors.h              |   39 ++++++
 daemon/product-slave-main.c       |    2 +
 daemon/simple-slave-main.c        |    2 +
 daemon/xdmcp-chooser-slave-main.c |    2 +
 8 files changed, 298 insertions(+), 0 deletions(-)
---
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index fed212f..731a041 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -134,6 +134,8 @@ gdm_simple_slave_SOURCES = 		\
 	gdm-session-record.h		\
 	gdm-session-worker-job.c	\
 	gdm-session-worker-job.h	\
+	gdm-xerrors.h			\
+	gdm-xerrors.c			\
 	gdm-slave.c			\
 	gdm-slave.h			\
 	gdm-simple-slave.c		\
@@ -169,6 +171,8 @@ gdm_factory_slave_SOURCES = 		\
 	gdm-session-private.h		\
 	gdm-session-relay.c		\
 	gdm-session-relay.h		\
+	gdm-xerrors.h			\
+	gdm-xerrors.c			\
 	gdm-slave.c			\
 	gdm-slave.h			\
 	gdm-factory-slave.c		\
@@ -198,6 +202,8 @@ gdm_product_slave_SOURCES = 		\
 	gdm-session-record.h		\
 	gdm-session-worker-job.c	\
 	gdm-session-worker-job.h	\
+	gdm-xerrors.h			\
+	gdm-xerrors.c			\
 	gdm-slave.c			\
 	gdm-slave.h			\
 	gdm-product-slave.c		\
@@ -226,6 +232,8 @@ gdm_xdmcp_chooser_slave_SOURCES = 		\
 	gdm-welcome-session.h			\
 	gdm-chooser-session.c			\
 	gdm-chooser-session.h			\
+	gdm-xerrors.h				\
+	gdm-xerrors.c				\
 	gdm-slave.c				\
 	gdm-slave.h				\
 	gdm-xdmcp-chooser-slave.c		\
diff --git a/daemon/factory-slave-main.c b/daemon/factory-slave-main.c
index 8a99749..832dc4f 100644
--- a/daemon/factory-slave-main.c
+++ b/daemon/factory-slave-main.c
@@ -39,6 +39,7 @@
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
+#include "gdm-xerrors.h"
 #include "gdm-signal-handler.h"
 #include "gdm-log.h"
 #include "gdm-common.h"
@@ -197,6 +198,7 @@ main (int    argc,
                 goto out;
         }
 
+        gdm_xerrors_init ();
         gdm_log_init ();
 
         settings = gdm_settings_new ();
diff --git a/daemon/gdm-slave.c b/daemon/gdm-slave.c
index 4532758..b7a0c0c 100644
--- a/daemon/gdm-slave.c
+++ b/daemon/gdm-slave.c
@@ -47,6 +47,7 @@
 #include <X11/Xatom.h>
 
 #include "gdm-common.h"
+#include "gdm-xerrors.h"
 
 #include "gdm-slave.h"
 #include "gdm-slave-glue.h"
diff --git a/daemon/gdm-xerrors.c b/daemon/gdm-xerrors.c
new file mode 100644
index 0000000..90e6ad6
--- /dev/null
+++ b/daemon/gdm-xerrors.c
@@ -0,0 +1,242 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010 William Jon McCann <jmccann redhat com>
+ *
+ * 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 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.
+ *
+ */
+
+/* Most of this is derived from GTK+ (copyright GTK+ team) */
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "gdm-xerrors.h"
+
+typedef struct _GdmErrorTrap  GdmErrorTrap;
+
+struct _GdmErrorTrap
+{
+        int (*old_handler) (Display *, XErrorEvent *);
+        int error_warnings;
+        int error_code;
+};
+
+static int          gdm_x_error                  (Display     *display,
+                                                  XErrorEvent *error);
+static int          gdm_x_io_error               (Display     *display);
+
+/* Private variable declarations
+ */
+static GSList *gdm_error_traps = NULL;               /* List of error traps */
+static GSList *gdm_error_trap_free_list = NULL;      /* Free list */
+
+static int                _gdm_error_warnings = TRUE;
+static int                _gdm_error_code = 0;
+
+void
+gdm_xerrors_init (void)
+{
+        static gboolean initialized = FALSE;
+
+        if (initialized) {
+                return;
+        }
+
+        XSetErrorHandler (gdm_x_error);
+        XSetIOErrorHandler (gdm_x_io_error);
+        initialized = TRUE;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdm_x_error
+ *
+ *   The X error handling routine.
+ *
+ * Arguments:
+ *   "display" is the X display the error orignated from.
+ *   "error" is the XErrorEvent that we are handling.
+ *
+ * Results:
+ *   Either we were expecting some sort of error to occur,
+ *   in which case we set the "_gdm_error_code" flag, or this
+ *   error was unexpected, in which case we will print an
+ *   error message and exit. (Since trying to continue will
+ *   most likely simply lead to more errors).
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+gdm_x_error (Display     *display,
+             XErrorEvent *error)
+{
+        if (error->error_code) {
+                if (_gdm_error_warnings) {
+                        gchar buf[64];
+                        gchar *msg;
+
+                        XGetErrorText (display, error->error_code, buf, 63);
+
+                        msg =
+                                g_strdup_printf ("The program '%s' received an X Window System error.\n"
+                                                 "This probably reflects a bug in the program.\n"
+                                                 "The error was '%s'.\n"
+                                                 "  (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
+                                                 "  (Note to programmers: normally, X errors are reported asynchronously;\n"
+                                                 "   that is, you will receive the error a while after causing it.\n"
+                                                 "   To debug your program, run it with the --sync command line\n"
+                                                 "   option to change this behavior. You can then get a meaningful\n"
+                                                 "   backtrace from your debugger if you break on the gdm_x_error() function.)",
+                                                 g_get_prgname (),
+                                                 buf,
+                                                 error->serial,
+                                                 error->error_code,
+                                                 error->request_code,
+                                                 error->minor_code);
+
+#ifdef G_ENABLE_DEBUG
+                        g_error ("%s", msg);
+#else /* !G_ENABLE_DEBUG */
+                        g_fprintf (stderr, "%s\n", msg);
+
+                        exit (1);
+#endif /* G_ENABLE_DEBUG */
+                }
+                _gdm_error_code = error->error_code;
+        }
+
+        return 0;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdm_x_io_error
+ *
+ *   The X I/O error handling routine.
+ *
+ * Arguments:
+ *   "display" is the X display the error orignated from.
+ *
+ * Results:
+ *   An X I/O error basically means we lost our connection
+ *   to the X server. There is not much we can do to
+ *   continue, so simply print an error message and exit.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+gdm_x_io_error (Display *display)
+{
+        /* This is basically modelled after the code in XLib. We need
+         * an explicit error handler here, so we can disable our atexit()
+         * which would otherwise cause a nice segfault.
+         * We fprintf(stderr, instead of g_warning() because g_warning()
+         * could possibly be redirected to a dialog
+         */
+        if (errno == EPIPE) {
+                g_fprintf (stderr,
+                           "The application '%s' lost its connection to the display %s;\n"
+                           "most likely the X server was shut down or you killed/destroyed\n"
+                           "the application.\n",
+                           g_get_prgname (),
+                           display ? DisplayString (display) : "<unknown>");
+        } else {
+                g_fprintf (stderr, "%s: Fatal IO error %d (%s) on X server %s.\n",
+                           g_get_prgname (),
+                           errno, g_strerror (errno),
+                           display ? DisplayString (display) : "<unknown>");
+        }
+
+        exit(1);
+}
+
+/*************************************************************
+ * gdm_error_trap_push:
+ *     Push an error trap. X errors will be trapped until
+ *     the corresponding gdm_error_pop(), which will return
+ *     the error code, if any.
+ *   arguments:
+ *
+ *   results:
+ *************************************************************/
+
+void
+gdm_error_trap_push (void)
+{
+        GSList *node;
+        GdmErrorTrap *trap;
+
+        if (gdm_error_trap_free_list) {
+                node = gdm_error_trap_free_list;
+                gdm_error_trap_free_list = gdm_error_trap_free_list->next;
+        } else {
+                node = g_slist_alloc ();
+                node->data = g_new (GdmErrorTrap, 1);
+        }
+
+        node->next = gdm_error_traps;
+        gdm_error_traps = node;
+
+        trap = node->data;
+        trap->old_handler = XSetErrorHandler (gdm_x_error);
+        trap->error_code = _gdm_error_code;
+        trap->error_warnings = _gdm_error_warnings;
+
+        _gdm_error_code = 0;
+        _gdm_error_warnings = 0;
+}
+
+/*************************************************************
+ * gdm_error_trap_pop:
+ *     Pop an error trap added with gdm_error_push()
+ *   arguments:
+ *
+ *   results:
+ *     0, if no error occured, otherwise the error code.
+ *************************************************************/
+
+gint
+gdm_error_trap_pop (void)
+{
+        GSList *node;
+        GdmErrorTrap *trap;
+        gint result;
+
+        g_return_val_if_fail (gdm_error_traps != NULL, 0);
+
+        node = gdm_error_traps;
+        gdm_error_traps = gdm_error_traps->next;
+
+        node->next = gdm_error_trap_free_list;
+        gdm_error_trap_free_list = node;
+
+        result = _gdm_error_code;
+
+        trap = node->data;
+        _gdm_error_code = trap->error_code;
+        _gdm_error_warnings = trap->error_warnings;
+        XSetErrorHandler (trap->old_handler);
+
+        return result;
+}
diff --git a/daemon/gdm-xerrors.h b/daemon/gdm-xerrors.h
new file mode 100644
index 0000000..16efca3
--- /dev/null
+++ b/daemon/gdm-xerrors.h
@@ -0,0 +1,39 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* Metacity X error handling */
+
+/*
+ * Copyright (C) 2001 Havoc Pennington
+ *
+ * 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
+ * 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.
+ */
+
+#ifndef GDM_XERRORS_H
+#define GDM_XERRORS_H
+
+#include <glib.h>
+#include <X11/Xlib.h>
+
+typedef void (* GdmXErrorHandler) (Display     *dpy,
+                                   XErrorEvent *error,
+                                   gpointer     data);
+
+void      gdm_xerrors_init    (void);
+
+void      gdm_error_trap_push (void);
+gint      gdm_error_trap_pop  (void);
+
+#endif
diff --git a/daemon/product-slave-main.c b/daemon/product-slave-main.c
index b696ad2..7353f3a 100644
--- a/daemon/product-slave-main.c
+++ b/daemon/product-slave-main.c
@@ -39,6 +39,7 @@
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
+#include "gdm-xerrors.h"
 #include "gdm-signal-handler.h"
 #include "gdm-log.h"
 #include "gdm-common.h"
@@ -201,6 +202,7 @@ main (int    argc,
                 goto out;
         }
 
+        gdm_xerrors_init ();
         gdm_log_init ();
 
         settings = gdm_settings_new ();
diff --git a/daemon/simple-slave-main.c b/daemon/simple-slave-main.c
index e9d65ee..eed1742 100644
--- a/daemon/simple-slave-main.c
+++ b/daemon/simple-slave-main.c
@@ -39,6 +39,7 @@
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
+#include "gdm-xerrors.h"
 #include "gdm-signal-handler.h"
 #include "gdm-log.h"
 #include "gdm-common.h"
@@ -204,6 +205,7 @@ main (int    argc,
                 goto out;
         }
 
+        gdm_xerrors_init ();
         gdm_log_init ();
 
         settings = gdm_settings_new ();
diff --git a/daemon/xdmcp-chooser-slave-main.c b/daemon/xdmcp-chooser-slave-main.c
index a35c978..0b68af1 100644
--- a/daemon/xdmcp-chooser-slave-main.c
+++ b/daemon/xdmcp-chooser-slave-main.c
@@ -39,6 +39,7 @@
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
+#include "gdm-xerrors.h"
 #include "gdm-signal-handler.h"
 #include "gdm-log.h"
 #include "gdm-common.h"
@@ -203,6 +204,7 @@ main (int    argc,
                 goto out;
         }
 
+        gdm_xerrors_init ();
         gdm_log_init ();
 
         settings = gdm_settings_new ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]