diff options
| author | William Jon McCann <mccann@jhu.edu> | 2007-10-16 16:40:44 -0400 | 
|---|---|---|
| committer | William Jon McCann <mccann@jhu.edu> | 2007-10-16 16:40:44 -0400 | 
| commit | 0011a7aa94a9dbb00a322a1c08d5ac6a6dfdc21c (patch) | |
| tree | bd0037bbcab650ed23b1484ae031d96c55c0e8b4 /src | |
| parent | a0a1ff87b1f4c93c147d5222a164138cb83ba149 (diff) | |
add event logging capability
This adds the ability to log events to a history file.  One idea
is to be able to provide wtmp like functionality.  The next step
is to add a seat-aware "last" command.  This will be very useful
for creating graphical logins that remember the most recent/frequent
logins.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 13 | ||||
| -rw-r--r-- | src/ck-event-logger.c | 828 | ||||
| -rw-r--r-- | src/ck-event-logger.h | 161 | ||||
| -rw-r--r-- | src/ck-manager.c | 340 | ||||
| -rw-r--r-- | src/test-event-logger.c | 94 | 
5 files changed, 1430 insertions, 6 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index d72ec35..54e37cb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -101,6 +101,8 @@ console_kit_daemon_SOURCES =	\  	ck-log.c		\  	ck-run-programs.c	\  	ck-run-programs.h	\ +	ck-event-logger.c	\ +	ck-event-logger.h	\  	$(BUILT_SOURCES)	\  	$(NULL) @@ -123,10 +125,21 @@ console_kit_daemon_LDADD =	\  	$(NULL)  noinst_PROGRAMS = 			\ +	test-event-logger		\  	test-tty-idle-monitor		\  	test-vt-monitor			\  	$(NULL) +test_event_logger_SOURCES = 		\ +	ck-event-logger.h		\ +	ck-event-logger.c		\ +	test-event-logger.c 		\ +	$(NULL) + +test_event_logger_LDADD =		\ +	$(CONSOLE_KIT_LIBS)		\ +	$(NULL) +  test_vt_monitor_SOURCES = 		\  	ck-vt-monitor.h			\  	ck-vt-monitor.c			\ diff --git a/src/ck-event-logger.c b/src/ck-event-logger.c new file mode 100644 index 0000000..b9e41ee --- /dev/null +++ b/src/ck-event-logger.c @@ -0,0 +1,828 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * 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. + * + */ + +#include "config.h" + +#define _GNU_SOURCE             /* For O_NOFOLLOW */ + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib/gstdio.h> +#include <glib-object.h> + +#include "ck-event-logger.h" + +#define CK_EVENT_LOGGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_EVENT_LOGGER, CkEventLoggerPrivate)) + +#define DEFAULT_LOG_FILENAME LOCALSTATEDIR "/run/ConsoleKit/history" + +struct CkEventLoggerPrivate +{ +        int              fd; +        FILE            *file; +        GThread         *writer_thread; +        GAsyncQueue     *event_queue; +        char            *log_filename; +}; + +enum { +        PROP_0, +        PROP_LOG_FILENAME +}; + +static void     ck_event_logger_class_init  (CkEventLoggerClass *klass); +static void     ck_event_logger_init        (CkEventLogger      *event_logger); +static void     ck_event_logger_finalize    (GObject            *object); + +G_DEFINE_TYPE (CkEventLogger, ck_event_logger, G_TYPE_OBJECT) + +GQuark +ck_event_logger_error_quark (void) +{ +        static GQuark ret = 0; +        if (ret == 0) { +                ret = g_quark_from_static_string ("ck_event_logger_error"); +        } + +        return ret; +} + +static void +event_seat_added_free (CkEventLoggerSeatAddedEvent *event) +{ +        g_assert (event != NULL); + +        g_free (event->seat_id); +        event->seat_id = NULL; +} + +static void +event_seat_removed_free (CkEventLoggerSeatRemovedEvent *event) +{ +        g_assert (event != NULL); + +        g_free (event->seat_id); +        event->seat_id = NULL; +} + +static void +event_seat_session_added_free (CkEventLoggerSeatSessionAddedEvent *event) +{ +        g_assert (event != NULL); + +        g_free (event->seat_id); +        event->seat_id = NULL; + +        g_free (event->session_id); +        event->session_id = NULL; +        g_free (event->session_type); +        event->session_type = NULL; +        g_free (event->session_x11_display); +        event->session_x11_display = NULL; +        g_free (event->session_x11_display_device); +        event->session_x11_display_device = NULL; +        g_free (event->session_display_device); +        event->session_display_device = NULL; +        g_free (event->session_remote_host_name); +        event->session_remote_host_name = NULL; +        g_free (event->session_creation_time); +        event->session_creation_time = NULL; +} + +static void +event_seat_session_removed_free (CkEventLoggerSeatSessionRemovedEvent *event) +{ +        g_assert (event != NULL); + +        g_free (event->seat_id); +        event->seat_id = NULL; + +        g_free (event->session_id); +        event->session_id = NULL; +        g_free (event->session_type); +        event->session_type = NULL; +        g_free (event->session_x11_display); +        event->session_x11_display = NULL; +        g_free (event->session_x11_display_device); +        event->session_x11_display_device = NULL; +        g_free (event->session_display_device); +        event->session_display_device = NULL; +        g_free (event->session_remote_host_name); +        event->session_remote_host_name = NULL; +        g_free (event->session_creation_time); +        event->session_creation_time = NULL; +} + +static void +event_seat_active_session_changed_free (CkEventLoggerSeatActiveSessionChangedEvent *event) +{ +        g_assert (event != NULL); + +        g_free (event->seat_id); +        event->seat_id = NULL; + +        g_free (event->session_id); +        event->session_id = NULL; +} + +static void +event_seat_device_added_free (CkEventLoggerSeatDeviceAddedEvent *event) +{ +        g_assert (event != NULL); + +        g_free (event->seat_id); +        event->seat_id = NULL; +        g_free (event->device_id); +        event->device_id = NULL; +        g_free (event->device_type); +        event->device_type = NULL; +} + +static void +event_seat_device_removed_free (CkEventLoggerSeatDeviceRemovedEvent *event) +{ +        g_assert (event != NULL); + +        g_free (event->seat_id); +        event->seat_id = NULL; +        g_free (event->device_id); +        event->device_id = NULL; +        g_free (event->device_type); +        event->device_type = NULL; +} + +static void +event_seat_added_copy (CkEventLoggerSeatAddedEvent *event, +                       CkEventLoggerSeatAddedEvent *event_copy) +{ +        g_assert (event != NULL); +        g_assert (event_copy != NULL); + +        event_copy->seat_id = g_strdup (event->seat_id); +        event_copy->seat_kind = event->seat_kind; +} + +static void +event_seat_removed_copy (CkEventLoggerSeatRemovedEvent *event, +                         CkEventLoggerSeatRemovedEvent *event_copy) +{ +        g_assert (event != NULL); +        g_assert (event_copy != NULL); + +        event_copy->seat_id = g_strdup (event->seat_id); +        event_copy->seat_kind = event->seat_kind; +} + +static void +event_seat_session_added_copy (CkEventLoggerSeatSessionAddedEvent *event, +                               CkEventLoggerSeatSessionAddedEvent *event_copy) +{ +        g_assert (event != NULL); +        g_assert (event_copy != NULL); + +        event_copy->seat_id = g_strdup (event->seat_id); +        event_copy->session_id = g_strdup (event->session_id); +        event_copy->session_type = g_strdup (event->session_type); +        event_copy->session_x11_display = g_strdup (event->session_x11_display); +        event_copy->session_x11_display_device = g_strdup (event->session_x11_display_device); +        event_copy->session_display_device = g_strdup (event->session_display_device); +        event_copy->session_remote_host_name = g_strdup (event->session_remote_host_name); +        event_copy->session_is_local = event->session_is_local; +        event_copy->session_unix_user = event->session_unix_user; +        event_copy->session_creation_time = g_strdup (event->session_creation_time); +} + +static void +event_seat_session_removed_copy (CkEventLoggerSeatSessionRemovedEvent *event, +                                 CkEventLoggerSeatSessionRemovedEvent *event_copy) +{ +        g_assert (event != NULL); +        g_assert (event_copy != NULL); + +        event_copy->seat_id = g_strdup (event->seat_id); +        event_copy->session_id = g_strdup (event->session_id); +        event_copy->session_type = g_strdup (event->session_type); +        event_copy->session_x11_display = g_strdup (event->session_x11_display); +        event_copy->session_x11_display_device = g_strdup (event->session_x11_display_device); +        event_copy->session_display_device = g_strdup (event->session_display_device); +        event_copy->session_remote_host_name = g_strdup (event->session_remote_host_name); +        event_copy->session_is_local = event->session_is_local; +        event_copy->session_unix_user = event->session_unix_user; +        event_copy->session_creation_time = g_strdup (event->session_creation_time); +} + +static void +event_seat_active_session_changed_copy (CkEventLoggerSeatActiveSessionChangedEvent *event, +                                        CkEventLoggerSeatActiveSessionChangedEvent *event_copy) +{ +        g_assert (event != NULL); +        g_assert (event_copy != NULL); + +        event_copy->seat_id = g_strdup (event->seat_id); +        event_copy->session_id = g_strdup (event->session_id); +} + +static void +event_seat_device_added_copy (CkEventLoggerSeatDeviceAddedEvent *event, +                              CkEventLoggerSeatDeviceAddedEvent *event_copy) +{ +        g_assert (event != NULL); +        g_assert (event_copy != NULL); + +        event_copy->seat_id = g_strdup (event->seat_id); +        event_copy->device_id = g_strdup (event->device_id); +        event_copy->device_type = g_strdup (event->device_type); +} + +static void +event_seat_device_removed_copy (CkEventLoggerSeatDeviceRemovedEvent *event, +                                CkEventLoggerSeatDeviceRemovedEvent *event_copy) +{ +        g_assert (event != NULL); +        g_assert (event_copy != NULL); + +        event_copy->seat_id = g_strdup (event->seat_id); +        event_copy->device_id = g_strdup (event->device_id); +        event_copy->device_type = g_strdup (event->device_type); +} + +CkEventLoggerEvent * +ck_event_logger_event_copy (CkEventLoggerEvent *event) +{ +        CkEventLoggerEvent *event_copy; + +        if (event == NULL) { +                return NULL; +        } + +        event_copy = g_new0 (CkEventLoggerEvent, 1); + +        event_copy->type = event->type; +        event_copy->timestamp = event->timestamp; + +        switch (event->type) { +        case CK_EVENT_LOGGER_EVENT_SEAT_ADDED: +                event_seat_added_copy ((CkEventLoggerSeatAddedEvent *) event, +                                       (CkEventLoggerSeatAddedEvent *) event_copy); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_REMOVED: +                event_seat_removed_copy ((CkEventLoggerSeatRemovedEvent *) event, +                                         (CkEventLoggerSeatRemovedEvent *) event_copy); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_SESSION_ADDED: +                event_seat_session_added_copy ((CkEventLoggerSeatSessionAddedEvent *) event, +                                               (CkEventLoggerSeatSessionAddedEvent *) event_copy); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_SESSION_REMOVED: +                event_seat_session_removed_copy ((CkEventLoggerSeatSessionRemovedEvent *) event, +                                                 (CkEventLoggerSeatSessionRemovedEvent *) event_copy); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_ADDED: +                event_seat_device_added_copy ((CkEventLoggerSeatDeviceAddedEvent *) event, +                                              (CkEventLoggerSeatDeviceAddedEvent *) event_copy); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_REMOVED: +                event_seat_device_removed_copy ((CkEventLoggerSeatDeviceRemovedEvent *) event, +                                                (CkEventLoggerSeatDeviceRemovedEvent *) event_copy); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_ACTIVE_SESSION_CHANGED: +                event_seat_active_session_changed_copy ((CkEventLoggerSeatActiveSessionChangedEvent *) event, +                                                        (CkEventLoggerSeatActiveSessionChangedEvent *) event_copy); +                break; +        default: +                g_assert_not_reached (); +                break; +        } + +        return event_copy; +} + +void +ck_event_logger_event_free (CkEventLoggerEvent *event) +{ +        switch (event->type) { +        case CK_EVENT_LOGGER_EVENT_SEAT_ADDED: +                event_seat_added_free ((CkEventLoggerSeatAddedEvent *) event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_REMOVED: +                event_seat_removed_free ((CkEventLoggerSeatRemovedEvent *) event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_SESSION_ADDED: +                event_seat_session_added_free ((CkEventLoggerSeatSessionAddedEvent *) event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_SESSION_REMOVED: +                event_seat_session_removed_free ((CkEventLoggerSeatSessionRemovedEvent *) event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_ADDED: +                event_seat_device_added_free ((CkEventLoggerSeatDeviceAddedEvent *) event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_REMOVED: +                event_seat_device_removed_free ((CkEventLoggerSeatDeviceRemovedEvent *) event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_ACTIVE_SESSION_CHANGED: +                event_seat_active_session_changed_free ((CkEventLoggerSeatActiveSessionChangedEvent *) event); +                break; +        default: +                g_assert_not_reached (); +                break; +        } + +        g_free (event); +} + +gboolean +ck_event_logger_queue_event (CkEventLogger      *event_logger, +                             CkEventLoggerEvent *event, +                             GError            **error) +{ +        CkEventLoggerEvent *event_copy; +        gboolean            ret; + +        g_return_val_if_fail (CK_IS_EVENT_LOGGER (event_logger), FALSE); +        g_return_val_if_fail (event != NULL, FALSE); + +        event_copy = ck_event_logger_event_copy (event); + +        g_async_queue_push (event_logger->priv->event_queue, +                            event_copy); + +        ret = TRUE; + +        return ret; +} + +/* Adapted from auditd auditd-event.c */ +static gboolean +open_log_file (CkEventLogger *event_logger) +{ +        int flags; +        int fd; + +        /* +         * Likely errors on rotate: ENFILE, ENOMEM, ENOSPC +         */ +        flags = O_WRONLY | O_APPEND; +#ifdef O_NOFOLLOW +        flags |= O_NOFOLLOW; +#endif + +retry: +        fd = g_open (event_logger->priv->log_filename, flags, 0600); +        if (fd < 0) { +                if (errno == ENOENT) { +                        /* FIXME: should we just skip if file doesn't exist? */ +                        fd = g_open (event_logger->priv->log_filename, +                                     O_CREAT | O_EXCL | O_APPEND, +                                     S_IRUSR | S_IWUSR | S_IRGRP); +                        if (fd < 0) { +                                g_warning ("Couldn't create log file %s (%s)", +                                           event_logger->priv->log_filename, +                                           g_strerror (errno)); +                                return FALSE; +                        } + +                        close (fd); +                        fd = g_open (event_logger->priv->log_filename, flags, 0600); +                } else if (errno == ENFILE) { +                        /* All system descriptors used, try again... */ +                        goto retry; +                } +                if (fd < 0) { +                        g_warning ("Couldn't open log file %s (%s)", +                                   event_logger->priv->log_filename, +                                   g_strerror (errno)); +                        return FALSE; +                } +        } + +        if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) { +                close (fd); +                g_warning ("Error setting log file CLOEXEC flag (%s)", +                           g_strerror (errno)); +                return FALSE; +        } + +        fchown (fd, 0, 0); + +        event_logger->priv->fd = fd; +        event_logger->priv->file = fdopen (fd, "a"); + +        if (event_logger->priv->file == NULL) { +                g_warning ("Error setting up log descriptor (%s)", +                           g_strerror (errno)); +                close (fd); +                return FALSE; +        } + +        /* Set it to line buffering */ +        setlinebuf (event_logger->priv->file); + +        return TRUE; +} + +static void +add_log_for_seat_added (GString            *str, +                        CkEventLoggerEvent *event) +{ +        CkEventLoggerSeatAddedEvent *e; + +        e = (CkEventLoggerSeatAddedEvent *)event; +        g_string_append_printf (str, +                                " seat-id=%s seat-kind=%d", +                                e->seat_id, +                                e->seat_kind); +} + +static void +add_log_for_seat_removed (GString            *str, +                          CkEventLoggerEvent *event) +{ +        CkEventLoggerSeatRemovedEvent *e; + +        e = (CkEventLoggerSeatRemovedEvent *)event; +        g_string_append_printf (str, +                                " seat-id=%s seat-kind=%d", +                                e->seat_id, +                                e->seat_kind); +} + +static void +add_log_for_seat_session_added (GString            *str, +                                CkEventLoggerEvent *event) +{ +        CkEventLoggerSeatSessionAddedEvent *e; + +        e = (CkEventLoggerSeatSessionAddedEvent *)event; +        g_string_append_printf (str, +                                " seat-id='%s' session-id='%s' session-type='%s' session-x11-display='%s' session-x11-display-device='%s' session-display-device='%s' session-remote-host-name='%s' session-is-local=%s session-unix-user=%u session-creation-time='%s'", +                                e->seat_id ? e->seat_id : "", +                                e->session_id ? e->session_id : "", +                                e->session_type ? e->session_type : "", +                                e->session_x11_display ? e->session_x11_display : "", +                                e->session_x11_display_device ? e->session_x11_display_device : "", +                                e->session_display_device ? e->session_display_device : "", +                                e->session_remote_host_name ? e->session_remote_host_name : "", +                                e->session_is_local ? "TRUE" : "FALSE", +                                e->session_unix_user, +                                e->session_creation_time ? e->session_creation_time : ""); +} + +static void +add_log_for_seat_session_removed (GString            *str, +                                  CkEventLoggerEvent *event) +{ +        CkEventLoggerSeatSessionRemovedEvent *e; + +        e = (CkEventLoggerSeatSessionRemovedEvent *)event; +        g_string_append_printf (str, +                                " seat-id='%s' session-id='%s' session-type='%s' session-x11-display='%s' session-x11-display-device='%s' session-display-device='%s' session-remote-host-name='%s' session-is-local=%s session-unix-user=%u session-creation-time='%s'", +                                e->seat_id ? e->seat_id : "", +                                e->session_id ? e->session_id : "", +                                e->session_type ? e->session_type : "", +                                e->session_x11_display ? e->session_x11_display : "", +                                e->session_x11_display_device ? e->session_x11_display_device : "", +                                e->session_display_device ? e->session_display_device : "", +                                e->session_remote_host_name ? e->session_remote_host_name : "", +                                e->session_is_local ? "TRUE" : "FALSE", +                                e->session_unix_user, +                                e->session_creation_time ? e->session_creation_time : ""); +} + +static void +add_log_for_seat_active_session_changed (GString            *str, +                                         CkEventLoggerEvent *event) +{ +        CkEventLoggerSeatActiveSessionChangedEvent *e; + +        e = (CkEventLoggerSeatActiveSessionChangedEvent *)event; +        g_string_append_printf (str, +                                " seat-id='%s' session-id='%s'", +                                e->seat_id ? e->seat_id : "", +                                e->session_id ? e->session_id : ""); +} + +static void +add_log_for_seat_device_added (GString            *str, +                               CkEventLoggerEvent *event) +{ +        CkEventLoggerSeatDeviceAddedEvent *e; + +        e = (CkEventLoggerSeatDeviceAddedEvent *)event; +        g_string_append_printf (str, +                                " seat-id='%s' device-id='%s' device-type='%s'", +                                e->seat_id ? e->seat_id : "", +                                e->device_id ? e->device_id : "", +                                e->device_type ? e->device_type : ""); +} + +static void +add_log_for_seat_device_removed (GString            *str, +                                 CkEventLoggerEvent *event) +{ +        CkEventLoggerSeatDeviceRemovedEvent *e; + +        e = (CkEventLoggerSeatDeviceRemovedEvent *)event; +        g_string_append_printf (str, +                                " seat-id='%s' device-id='%s' device-type='%s'", +                                e->seat_id ? e->seat_id : "", +                                e->device_id ? e->device_id : "", +                                e->device_type ? e->device_type : ""); +} + +static const char * +event_type_to_name (int event_type) +{ +        const char *str; +        switch (event_type) { +        case CK_EVENT_LOGGER_EVENT_SEAT_ADDED: +                str = "SEAT_ADDED"; +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_REMOVED: +                str = "SEAT_REMOVED"; +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_SESSION_ADDED: +                str = "SEAT_SESSION_ADDED"; +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_SESSION_REMOVED: +                str = "SEAT_SESSION_REMOVED"; +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_ADDED: +                str = "SEAT_DEVICE_ADDED"; +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_REMOVED: +                str = "SEAT_DEVICE_REMOVED"; +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_ACTIVE_SESSION_CHANGED: +                str = "SEAT_ACTIVE_SESSION_CHANGED"; +                break; +        default: +                str = "UNKNOWN"; +                break; +        } +        return str; +} + +static void +add_log_for_any (GString            *str, +                 CkEventLoggerEvent *event) +{ +        char *tstr; + +        tstr = g_time_val_to_iso8601 (&event->timestamp); + +        g_string_append_printf (str, +                                "%s type=%s", +                                tstr, +                                event_type_to_name (event->type)); +        g_free (tstr); +} + +static gboolean +write_log_for_event (CkEventLogger      *event_logger, +                     CkEventLoggerEvent *event) +{ +        GString *str; + +        str = g_string_new (NULL); + +        add_log_for_any (str, event); + +        switch (event->type) { +        case CK_EVENT_LOGGER_EVENT_SEAT_ADDED: +                add_log_for_seat_added (str, event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_REMOVED: +                add_log_for_seat_removed (str, event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_SESSION_ADDED: +                add_log_for_seat_session_added (str, event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_SESSION_REMOVED: +                add_log_for_seat_session_removed (str, event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_ADDED: +                add_log_for_seat_device_added (str, event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_REMOVED: +                add_log_for_seat_device_removed (str, event); +                break; +        case CK_EVENT_LOGGER_EVENT_SEAT_ACTIVE_SESSION_CHANGED: +                add_log_for_seat_active_session_changed (str, event); +                break; +        default: +                g_assert_not_reached (); +                break; +        } + +        g_debug ("Writing log for event: %s", str->str); + +        if (event_logger->priv->file != NULL) { +                int rc; + +                rc = fprintf (event_logger->priv->file, "%s\n", str->str); +                if (rc < 0) { +                        g_warning ("Record was not written to disk (%s)", +                                   g_strerror (errno)); +                } +        } + +        g_string_free (str, TRUE); + +        return TRUE; +} + +static void * +writer_thread_start (CkEventLogger *event_logger) +{ +        CkEventLoggerEvent *event; + +        while ((event = g_async_queue_pop (event_logger->priv->event_queue)) != NULL) { +                write_log_for_event (event_logger, event); +                ck_event_logger_event_free (event); +        } + +        g_thread_exit (NULL); +        return NULL; +} + +static void +create_writer_thread (CkEventLogger *event_logger) +{ +        GError *error; + +        g_debug ("Creating thread for log writing"); + +        error = NULL; +        event_logger->priv->writer_thread = g_thread_create_full ((GThreadFunc)writer_thread_start, +                                                                  event_logger, +                                                                  65536, +                                                                  FALSE, +                                                                  TRUE, +                                                                  G_THREAD_PRIORITY_NORMAL, +                                                                  &error); +        if (event_logger->priv->writer_thread == NULL) { +                g_debug ("Unable to create thread: %s", error->message); +                g_error_free (error); +        } +} + +static GObject * +ck_event_logger_constructor (GType                  type, +                             guint                  n_construct_properties, +                             GObjectConstructParam *construct_properties) +{ +        CkEventLogger      *event_logger; +        CkEventLoggerClass *klass; + +        klass = CK_EVENT_LOGGER_CLASS (g_type_class_peek (CK_TYPE_EVENT_LOGGER)); + +        event_logger = CK_EVENT_LOGGER (G_OBJECT_CLASS (ck_event_logger_parent_class)->constructor (type, +                                                                                                    n_construct_properties, +                                                                                                    construct_properties)); + +        if (open_log_file (event_logger)) { +                create_writer_thread (event_logger); +        } + +        return G_OBJECT (event_logger); +} + +static void +_ck_event_logger_set_log_filename (CkEventLogger  *event_logger, +                                   const char     *filename) +{ +        g_free (event_logger->priv->log_filename); +        event_logger->priv->log_filename = g_strdup (filename); +} + +static void +ck_event_logger_set_property (GObject            *object, +                              guint               prop_id, +                              const GValue       *value, +                              GParamSpec         *pspec) +{ +        CkEventLogger *self; + +        self = CK_EVENT_LOGGER (object); + +        switch (prop_id) { +        case PROP_LOG_FILENAME: +                _ck_event_logger_set_log_filename (self, g_value_get_string (value)); +                break; +        default: +                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +                break; +        } +} + +static void +ck_event_logger_get_property (GObject    *object, +                              guint       prop_id, +                              GValue     *value, +                              GParamSpec *pspec) +{ +        CkEventLogger *self; + +        self = CK_EVENT_LOGGER (object); + +        switch (prop_id) { +        case PROP_LOG_FILENAME: +                g_value_set_string (value, self->priv->log_filename); +                break; +        default: +                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +                break; +        } +} + +static void +ck_event_logger_class_init (CkEventLoggerClass *klass) +{ +        GObjectClass   *object_class = G_OBJECT_CLASS (klass); + +        object_class->finalize = ck_event_logger_finalize; +        object_class->constructor = ck_event_logger_constructor; +        object_class->get_property = ck_event_logger_get_property; +        object_class->set_property = ck_event_logger_set_property; + +        g_object_class_install_property (object_class, +                                         PROP_LOG_FILENAME, +                                         g_param_spec_string ("log-filename", +                                                              "log-filename", +                                                              "log-filename", +                                                              DEFAULT_LOG_FILENAME, +                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + +        g_type_class_add_private (klass, sizeof (CkEventLoggerPrivate)); +} + +static void +ck_event_logger_init (CkEventLogger *event_logger) +{ +        event_logger->priv = CK_EVENT_LOGGER_GET_PRIVATE (event_logger); + +        event_logger->priv->event_queue = g_async_queue_new (); +} + +static void +ck_event_logger_finalize (GObject *object) +{ +        CkEventLogger *event_logger; + +        g_return_if_fail (object != NULL); +        g_return_if_fail (CK_IS_EVENT_LOGGER (object)); + +        event_logger = CK_EVENT_LOGGER (object); + +        g_return_if_fail (event_logger->priv != NULL); + +        if (event_logger->priv->event_queue != NULL) { +                g_async_queue_unref (event_logger->priv->event_queue); +        } + +        if (event_logger->priv->fd != -1) { +                close (event_logger->priv->fd); +        } + +        g_free (event_logger->priv->log_filename); + +        G_OBJECT_CLASS (ck_event_logger_parent_class)->finalize (object); +} + +CkEventLogger * +ck_event_logger_new (const char *filename) +{ +        GObject *object; + +        object = g_object_new (CK_TYPE_EVENT_LOGGER, +                               "log-filename", filename, +                               NULL); + +        return CK_EVENT_LOGGER (object); +} diff --git a/src/ck-event-logger.h b/src/ck-event-logger.h new file mode 100644 index 0000000..c49136e --- /dev/null +++ b/src/ck-event-logger.h @@ -0,0 +1,161 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * 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 __CK_EVENT_LOGGER_H +#define __CK_EVENT_LOGGER_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define CK_TYPE_EVENT_LOGGER         (ck_event_logger_get_type ()) +#define CK_EVENT_LOGGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), CK_TYPE_EVENT_LOGGER, CkEventLogger)) +#define CK_EVENT_LOGGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), CK_TYPE_EVENT_LOGGER, CkEventLoggerClass)) +#define CK_IS_EVENT_LOGGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), CK_TYPE_EVENT_LOGGER)) +#define CK_IS_EVENT_LOGGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), CK_TYPE_EVENT_LOGGER)) +#define CK_EVENT_LOGGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CK_TYPE_EVENT_LOGGER, CkEventLoggerClass)) + +typedef struct CkEventLoggerPrivate CkEventLoggerPrivate; + +typedef struct +{ +        GObject               parent; +        CkEventLoggerPrivate *priv; +} CkEventLogger; + +typedef struct +{ +        GObjectClass   parent_class; +} CkEventLoggerClass; + +typedef enum +{ +        CK_EVENT_LOGGER_EVENT_START = 0, +        CK_EVENT_LOGGER_EVENT_STOP, +        CK_EVENT_LOGGER_EVENT_SYSTEM_SHUTDOWN, +        CK_EVENT_LOGGER_EVENT_SYSTEM_RUNLEVEL_CHANGED, +        CK_EVENT_LOGGER_EVENT_SEAT_ADDED, +        CK_EVENT_LOGGER_EVENT_SEAT_REMOVED, +        CK_EVENT_LOGGER_EVENT_SEAT_SESSION_ADDED, +        CK_EVENT_LOGGER_EVENT_SEAT_SESSION_REMOVED, +        CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_ADDED, +        CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_REMOVED, +        CK_EVENT_LOGGER_EVENT_SEAT_ACTIVE_SESSION_CHANGED, +} CkEventLoggerEventType; + +typedef struct +{ +        char *seat_id; +        int   seat_kind; +} CkEventLoggerSeatAddedEvent; + +typedef struct +{ +        char *seat_id; +        int   seat_kind; +} CkEventLoggerSeatRemovedEvent; + +typedef struct +{ +        char    *seat_id; +        char    *session_id; +        char    *session_type; +        char    *session_x11_display; +        char    *session_x11_display_device; +        char    *session_display_device; +        char    *session_remote_host_name; +        gboolean session_is_local; +        guint    session_unix_user; +        char    *session_creation_time; +} CkEventLoggerSeatSessionAddedEvent; + +typedef struct +{ +        char    *seat_id; +        char    *session_id; +        char    *session_type; +        char    *session_x11_display; +        char    *session_x11_display_device; +        char    *session_display_device; +        char    *session_remote_host_name; +        gboolean session_is_local; +        guint    session_unix_user; +        char    *session_creation_time; +} CkEventLoggerSeatSessionRemovedEvent; + +typedef struct +{ +        char    *seat_id; +        char    *session_id; +} CkEventLoggerSeatActiveSessionChangedEvent; + +typedef struct +{ +        char *seat_id; +        char *device_type; +        char *device_id; +} CkEventLoggerSeatDeviceAddedEvent; + +typedef struct +{ +        char *seat_id; +        char *device_type; +        char *device_id; +} CkEventLoggerSeatDeviceRemovedEvent; + +typedef struct +{ +        union { +                CkEventLoggerSeatAddedEvent seat_added; +                CkEventLoggerSeatRemovedEvent seat_removed; +                CkEventLoggerSeatSessionAddedEvent seat_session_added; +                CkEventLoggerSeatSessionRemovedEvent seat_session_removed; +                CkEventLoggerSeatActiveSessionChangedEvent seat_active_session_changed; +                CkEventLoggerSeatDeviceAddedEvent seat_device_added; +                CkEventLoggerSeatDeviceRemovedEvent seat_device_removed; +        } event; + +        GTimeVal               timestamp; +        CkEventLoggerEventType type; +} CkEventLoggerEvent; + + +typedef enum +{ +         CK_EVENT_LOGGER_ERROR_GENERAL +} CkEventLoggerError; + +#define CK_EVENT_LOGGER_ERROR ck_event_logger_error_quark () + +GQuark               ck_event_logger_error_quark         (void); +GType                ck_event_logger_get_type            (void); +CkEventLogger      * ck_event_logger_new                 (const char         *filename); + +gboolean             ck_event_logger_queue_event         (CkEventLogger      *event_logger, +                                                          CkEventLoggerEvent *event, +                                                          GError            **error); + +CkEventLoggerEvent * ck_event_logger_event_copy          (CkEventLoggerEvent *event); +void                 ck_event_logger_event_free          (CkEventLoggerEvent *event); + + +G_END_DECLS + +#endif /* __CK_EVENT_LOGGER_H */ diff --git a/src/ck-manager.c b/src/ck-manager.c index 74d488c..b3f1b63 100644 --- a/src/ck-manager.c +++ b/src/ck-manager.c @@ -44,13 +44,14 @@  #include "ck-session.h"  #include "ck-job.h"  #include "ck-marshal.h" +#include "ck-event-logger.h"  #include "ck-sysdeps.h"  #define CK_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_MANAGER, CkManagerPrivate)) -#define CK_SEAT_DIR SYSCONFDIR "/ConsoleKit/seats.d" - +#define CK_SEAT_DIR          SYSCONFDIR "/ConsoleKit/seats.d" +#define LOG_FILE             LOCALSTATEDIR "/run/ConsoleKit/history"  #define CK_DBUS_PATH         "/org/freedesktop/ConsoleKit"  #define CK_MANAGER_DBUS_PATH CK_DBUS_PATH "/Manager"  #define CK_MANAGER_DBUS_NAME "org.freedesktop.ConsoleKit.Manager" @@ -69,6 +70,7 @@ struct CkManagerPrivate          DBusGProxy      *bus_proxy;          DBusGConnection *connection; +        CkEventLogger   *logger;          guint32          session_serial;          guint32          seat_serial; @@ -389,11 +391,312 @@ generate_seat_id (CkManager *manager)  }  static void +log_seat_added_event (CkManager  *manager, +                      CkSeat     *seat) +{ +        CkEventLoggerEvent event; +        gboolean           res; +        GError            *error; +        char              *sid; +        CkSeatKind         seat_kind; + +        memset (&event, 0, sizeof (CkEventLoggerEvent)); + +        event.type = CK_EVENT_LOGGER_EVENT_SEAT_ADDED; +        g_get_current_time (&event.timestamp); + +        sid = NULL; +        ck_seat_get_id (seat, &sid, NULL); +        ck_seat_get_kind (seat, &seat_kind, NULL); + +        event.event.seat_added.seat_id = sid; +        event.event.seat_added.seat_kind = (int)seat_kind; + +        error = NULL; +        res = ck_event_logger_queue_event (manager->priv->logger, &event, &error); +        if (! res) { +                g_debug ("Unable to log event: %s", error->message); +                g_error_free (error); +        } + +        g_free (sid); +} + +static void +log_seat_removed_event (CkManager  *manager, +                        CkSeat     *seat) +{ +        CkEventLoggerEvent event; +        gboolean           res; +        GError            *error; +        char              *sid; +        CkSeatKind         seat_kind; + +        memset (&event, 0, sizeof (CkEventLoggerEvent)); + +        event.type = CK_EVENT_LOGGER_EVENT_SEAT_REMOVED; +        g_get_current_time (&event.timestamp); + +        sid = NULL; +        ck_seat_get_id (seat, &sid, NULL); +        ck_seat_get_kind (seat, &seat_kind, NULL); + +        event.event.seat_removed.seat_id = sid; +        event.event.seat_removed.seat_kind = (int)seat_kind; + +        error = NULL; +        res = ck_event_logger_queue_event (manager->priv->logger, &event, &error); +        if (! res) { +                g_debug ("Unable to log event: %s", error->message); +                g_error_free (error); +        } + +        g_free (sid); +} + +static void +log_seat_session_added_event (CkManager  *manager, +                              CkSeat     *seat, +                              const char *ssid) +{ +        CkEventLoggerEvent event; +        gboolean           res; +        GError            *error; +        char              *sid; +        CkSession         *session; + +        memset (&event, 0, sizeof (CkEventLoggerEvent)); + +        event.type = CK_EVENT_LOGGER_EVENT_SEAT_SESSION_ADDED; +        g_get_current_time (&event.timestamp); + +        sid = NULL; +        ck_seat_get_id (seat, &sid, NULL); + +        event.event.seat_session_added.seat_id = sid; +        event.event.seat_session_added.session_id = (char *)ssid; + +        session = g_hash_table_lookup (manager->priv->sessions, ssid); +        if (session != NULL) { +                g_object_get (session, +                              "session-type", &event.event.seat_session_added.session_type, +                              "x11-display", &event.event.seat_session_added.session_x11_display, +                              "x11-display-device", &event.event.seat_session_added.session_x11_display_device, +                              "display-device", &event.event.seat_session_added.session_display_device, +                              "remote-host-name", &event.event.seat_session_added.session_remote_host_name, +                              "is-local", &event.event.seat_session_added.session_is_local, +                              "unix-user", &event.event.seat_session_added.session_unix_user, +                              NULL); +                ck_session_get_creation_time (session, &event.event.seat_session_added.session_creation_time, NULL); +                g_debug ("Got uid: %u", event.event.seat_session_added.session_unix_user); +        } else { +        } + +        error = NULL; +        res = ck_event_logger_queue_event (manager->priv->logger, &event, &error); +        if (! res) { +                g_debug ("Unable to log event: %s", error->message); +                g_error_free (error); +        } + +        g_free (sid); + +        g_free (event.event.seat_session_added.session_type); +        g_free (event.event.seat_session_added.session_x11_display); +        g_free (event.event.seat_session_added.session_x11_display_device); +        g_free (event.event.seat_session_added.session_display_device); +        g_free (event.event.seat_session_added.session_remote_host_name); +        g_free (event.event.seat_session_added.session_creation_time); +} + +static void +log_seat_session_removed_event (CkManager  *manager, +                                CkSeat     *seat, +                                const char *ssid) +{ +        CkEventLoggerEvent event; +        gboolean           res; +        GError            *error; +        char              *sid; +        CkSession         *session; + +        memset (&event, 0, sizeof (CkEventLoggerEvent)); + +        event.type = CK_EVENT_LOGGER_EVENT_SEAT_SESSION_REMOVED; +        g_get_current_time (&event.timestamp); + +        sid = NULL; +        ck_seat_get_id (seat, &sid, NULL); + +        event.event.seat_session_removed.seat_id = sid; +        event.event.seat_session_removed.session_id = (char *)ssid; + +        session = g_hash_table_lookup (manager->priv->sessions, ssid); +        if (session != NULL) { +                g_object_get (session, +                              "session-type", &event.event.seat_session_removed.session_type, +                              "x11-display", &event.event.seat_session_removed.session_x11_display, +                              "x11-display-device", &event.event.seat_session_removed.session_x11_display_device, +                              "display-device", &event.event.seat_session_removed.session_display_device, +                              "remote-host-name", &event.event.seat_session_removed.session_remote_host_name, +                              "is-local", &event.event.seat_session_removed.session_is_local, +                              "unix-user", &event.event.seat_session_removed.session_unix_user, +                              NULL); +                ck_session_get_creation_time (session, &event.event.seat_session_removed.session_creation_time, NULL); +                g_debug ("Got uid: %u", event.event.seat_session_removed.session_unix_user); +        } + +        error = NULL; +        res = ck_event_logger_queue_event (manager->priv->logger, &event, &error); +        if (! res) { +                g_debug ("Unable to log event: %s", error->message); +                g_error_free (error); +        } + +        g_free (sid); + +        g_free (event.event.seat_session_removed.session_type); +        g_free (event.event.seat_session_removed.session_x11_display); +        g_free (event.event.seat_session_removed.session_x11_display_device); +        g_free (event.event.seat_session_removed.session_display_device); +        g_free (event.event.seat_session_removed.session_remote_host_name); +        g_free (event.event.seat_session_removed.session_creation_time); +} + +static void +log_seat_active_session_changed_event (CkManager  *manager, +                                       CkSeat     *seat, +                                       const char *ssid) +{ +        CkEventLoggerEvent event; +        gboolean           res; +        GError            *error; +        char              *sid; + +        memset (&event, 0, sizeof (CkEventLoggerEvent)); + +        event.type = CK_EVENT_LOGGER_EVENT_SEAT_ACTIVE_SESSION_CHANGED; +        g_get_current_time (&event.timestamp); + +        sid = NULL; +        ck_seat_get_id (seat, &sid, NULL); + +        event.event.seat_active_session_changed.seat_id = sid; +        event.event.seat_active_session_changed.session_id = (char *)ssid; + +        error = NULL; +        res = ck_event_logger_queue_event (manager->priv->logger, &event, &error); +        if (! res) { +                g_debug ("Unable to log event: %s", error->message); +                g_error_free (error); +        } + +        g_free (sid); +} + +static void +log_seat_device_added_event (CkManager   *manager, +                             CkSeat      *seat, +                             GValueArray *device) +{ +        CkEventLoggerEvent event; +        gboolean           res; +        GError            *error; +        char              *sid; +        GValue             val_struct = { 0, }; +        char              *device_id; +        char              *device_type; + +        memset (&event, 0, sizeof (CkEventLoggerEvent)); + +        event.type = CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_ADDED; +        g_get_current_time (&event.timestamp); + +        sid = NULL; +        device_type = NULL; +        device_id = NULL; + +        ck_seat_get_id (seat, &sid, NULL); + +        g_value_init (&val_struct, CK_TYPE_DEVICE); +        g_value_set_static_boxed (&val_struct, device); +        res = dbus_g_type_struct_get (&val_struct, +                                      0, &device_type, +                                      1, &device_id, +                                      G_MAXUINT); + +        event.event.seat_device_added.seat_id = sid; + +        event.event.seat_device_added.device_id = device_id; +        event.event.seat_device_added.device_type = device_type; + +        error = NULL; +        res = ck_event_logger_queue_event (manager->priv->logger, &event, &error); +        if (! res) { +                g_debug ("Unable to log event: %s", error->message); +                g_error_free (error); +        } + +        g_free (sid); +        g_free (device_type); +        g_free (device_id); +} + +static void +log_seat_device_removed_event (CkManager   *manager, +                               CkSeat      *seat, +                               GValueArray *device) +{ +        CkEventLoggerEvent event; +        gboolean           res; +        GError            *error; +        char              *sid; +        GValue             val_struct = { 0, }; +        char              *device_id; +        char              *device_type; + +        memset (&event, 0, sizeof (CkEventLoggerEvent)); + +        event.type = CK_EVENT_LOGGER_EVENT_SEAT_DEVICE_REMOVED; +        g_get_current_time (&event.timestamp); + +        sid = NULL; +        device_type = NULL; +        device_id = NULL; + +        ck_seat_get_id (seat, &sid, NULL); + +        g_value_init (&val_struct, CK_TYPE_DEVICE); +        g_value_set_static_boxed (&val_struct, device); +        res = dbus_g_type_struct_get (&val_struct, +                                      0, &device_type, +                                      1, &device_id, +                                      G_MAXUINT); + +        event.event.seat_device_removed.seat_id = sid; + +        event.event.seat_device_removed.device_id = device_id; +        event.event.seat_device_removed.device_type = device_type; + +        error = NULL; +        res = ck_event_logger_queue_event (manager->priv->logger, &event, &error); +        if (! res) { +                g_debug ("Unable to log event: %s", error->message); +                g_error_free (error); +        } + +        g_free (sid); +        g_free (device_type); +        g_free (device_id); +} + +static void  on_seat_active_session_changed (CkSeat     *seat,                                  const char *ssid,                                  CkManager  *manager)  {          ck_manager_dump (manager); +        log_seat_active_session_changed_event (manager, seat, ssid);  }  static void @@ -402,6 +705,7 @@ on_seat_session_added (CkSeat     *seat,                         CkManager  *manager)  {          ck_manager_dump (manager); +        log_seat_session_added_event (manager, seat, ssid);  }  static void @@ -410,6 +714,7 @@ on_seat_session_removed (CkSeat     *seat,                           CkManager  *manager)  {          ck_manager_dump (manager); +        log_seat_session_removed_event (manager, seat, ssid);  }  static void @@ -418,6 +723,7 @@ on_seat_device_added (CkSeat      *seat,                        CkManager   *manager)  {          ck_manager_dump (manager); +        log_seat_device_added_event (manager, seat, device);  }  static void @@ -426,6 +732,7 @@ on_seat_device_removed (CkSeat      *seat,                          CkManager   *manager)  {          ck_manager_dump (manager); +        log_seat_device_removed_event (manager, seat, device);  }  static void @@ -476,6 +783,8 @@ add_new_seat (CkManager *manager,          g_signal_emit (manager, signals [SEAT_ADDED], 0, sid); +        log_seat_added_event (manager, seat); +   out:          return seat;  } @@ -517,6 +826,8 @@ remove_seat (CkManager *manager,          g_debug ("Emitting seat-removed: %s", sid);          g_signal_emit (manager, signals [SEAT_REMOVED], 0, sid); +        log_seat_removed_event (manager, orig_seat); +          g_debug ("Removed seat: %s", sid);          if (orig_seat != NULL) { @@ -1416,9 +1727,12 @@ remove_session_for_cookie (CkManager  *manager,                  goto out;          } -        /* Remove the session from the list but don't call -         * unref until the removed from seats */ -        g_hash_table_steal (manager->priv->sessions, leader_info->ssid); +        /* Must keep a reference to the session in the manager until +         * all events for seats are cleared.  So don't remove +         * or steal the session from the master list until +         * it is removed from all seats.  Otherwise, event logging +         * for seat removals doesn't work. +         */          /* remove from seat */          sid = NULL; @@ -1441,6 +1755,10 @@ remove_session_for_cookie (CkManager  *manager,          }          g_free (sid); +        /* Remove the session from the list but don't call +         * unref until we are done with it */ +        g_hash_table_steal (manager->priv->sessions, leader_info->ssid); +          ck_manager_dump (manager);          manager_update_system_idle_hint (manager); @@ -1794,6 +2112,8 @@ add_seat_for_file (CkManager  *manager,          ck_manager_dump (manager);          g_signal_emit (manager, signals [SEAT_ADDED], 0, sid); + +        log_seat_added_event (manager, seat);  }  static gboolean @@ -1856,6 +2176,8 @@ ck_manager_init (CkManager *manager)                                                          g_free,                                                          (GDestroyNotify) leader_info_unref); +        manager->priv->logger = ck_event_logger_new (LOG_FILE); +          create_seats (manager);  } @@ -1874,7 +2196,13 @@ ck_manager_finalize (GObject *object)          g_hash_table_destroy (manager->priv->seats);          g_hash_table_destroy (manager->priv->sessions);          g_hash_table_destroy (manager->priv->leaders); -        g_object_unref (manager->priv->bus_proxy); +        if (manager->priv->bus_proxy != NULL) { +                g_object_unref (manager->priv->bus_proxy); +        } + +        if (manager->priv->logger != NULL) { +                g_object_unref (manager->priv->logger); +        }          G_OBJECT_CLASS (ck_manager_parent_class)->finalize (object);  } diff --git a/src/test-event-logger.c b/src/test-event-logger.c new file mode 100644 index 0000000..cc5d80b --- /dev/null +++ b/src/test-event-logger.c @@ -0,0 +1,94 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * 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. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <pwd.h> +#include <string.h> +#include <errno.h> + +#include <locale.h> + +#include <glib.h> + +#include "ck-event-logger.h" + +static gboolean +write_to_log (CkEventLogger    *logger) +{ +        CkEventLoggerEvent event; +        GError            *error; +        gboolean           res; + +        memset (&event, 0, sizeof (CkEventLoggerEvent)); + +        event.type = CK_EVENT_LOGGER_EVENT_SEAT_SESSION_ADDED; +        g_get_current_time (&event.timestamp); + +        event.event.seat_session_added.session_id = "Session1"; + +        error = NULL; +        res = ck_event_logger_queue_event (logger, &event, &error); +        if (! res) { +                g_warning ("Unable to queue event: %s", error->message); +                g_error_free (error); +        } + +        return TRUE; +} + +int +main (int argc, char **argv) +{ +        GMainLoop        *loop; +        CkEventLogger    *logger; +        char             *filename; + +        if (! g_thread_supported ()) { +                g_thread_init (NULL); +        } +        g_type_init (); + +        filename = g_build_filename (g_get_tmp_dir (), "ck-logger-test.log", NULL); + +        g_message ("Testing the event logger.\n  Should write messages to: %s", filename); +        logger = ck_event_logger_new (filename); +        g_free (filename); + +        g_timeout_add (1000, (GSourceFunc)write_to_log, logger); + +        loop = g_main_loop_new (NULL, FALSE); + +        g_main_loop_run (loop); + +        g_object_unref (logger); + +        g_main_loop_unref (loop); + +        return 0; +}  | 
