summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am41
-rw-r--r--src/Makefile.in283
-rw-r--r--src/ck-event-logger.c420
-rw-r--r--src/ck-event-logger.h66
-rw-r--r--src/ck-log-event.c1284
-rw-r--r--src/ck-log-event.h148
-rw-r--r--src/ck-manager-glue.h51
-rw-r--r--src/ck-manager.c2013
-rw-r--r--src/ck-manager.h17
-rw-r--r--src/ck-manager.xml9
-rw-r--r--src/ck-marshal.c8
-rw-r--r--src/ck-run-programs.c230
-rw-r--r--src/ck-run-programs.h38
-rw-r--r--src/ck-seat-glue.h12
-rw-r--r--src/ck-seat.c158
-rw-r--r--src/ck-seat.h4
-rw-r--r--src/ck-session-glue.h14
-rw-r--r--src/ck-session-leader.c567
-rw-r--r--src/ck-session-leader.h97
-rw-r--r--src/ck-session.c107
-rw-r--r--src/ck-session.h3
-rw-r--r--src/ck-sysdeps-solaris.c45
-rw-r--r--src/ck-sysdeps-unix.c40
-rw-r--r--src/ck-vt-monitor.c61
-rw-r--r--src/main.c66
-rw-r--r--src/test-event-logger.c94
-rwxr-xr-xsrc/test-open-session-with-parameters2
27 files changed, 5236 insertions, 642 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3f142a3..8d5d83b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -10,6 +10,7 @@ INCLUDES = \
-I. \
-I$(srcdir) \
$(CONSOLE_KIT_CFLAGS) \
+ $(POLKIT_CFLAGS) \
$(DISABLE_DEPRECATED_CFLAGS) \
-DPREFIX=\""$(prefix)"\" \
-DBINDIR=\""$(bindir)"\" \
@@ -17,6 +18,7 @@ INCLUDES = \
-DLIBEXECDIR=\""$(libexecdir)"\" \
-DDATADIR=\""$(datadir)"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -DLOCALSTATEDIR=\""$(localstatedir)"\" \
-DCONSOLE_KIT_PID_FILE=\""$(CONSOLE_KIT_PID_FILE)"\" \
$(WARN_CFLAGS) \
$(DEBUG_CFLAGS) \
@@ -24,9 +26,15 @@ INCLUDES = \
$(NULL)
noinst_LTLIBRARIES = \
- libck.la \
+ libck.la \
+ libck-event-log.la \
$(NULL)
+libck_event_log_la_SOURCES = \
+ ck-log-event.h \
+ ck-log-event.c \
+ $(NULL)
+
libck_la_SOURCES = \
ck-sysdeps.h \
ck-sysdeps-unix.c \
@@ -94,10 +102,16 @@ console_kit_daemon_SOURCES = \
ck-job.c \
ck-seat.h \
ck-seat.c \
+ ck-session-leader.h \
+ ck-session-leader.c \
ck-session.h \
ck-session.c \
ck-log.h \
ck-log.c \
+ ck-run-programs.c \
+ ck-run-programs.h \
+ ck-event-logger.c \
+ ck-event-logger.h \
$(BUILT_SOURCES) \
$(NULL)
@@ -116,14 +130,31 @@ EXTRA_console_kit_daemon_SOURCES = \
console_kit_daemon_LDADD = \
$(CONSOLE_KIT_LIBS) \
+ $(POLKIT_LIBS) \
+ $(RBAC_LIBS) \
libck.la \
+ libck-event-log.la \
$(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) \
+ $(POLKIT_LIBS) \
+ $(RBAC_LIBS) \
+ libck-event-log.la \
+ $(NULL)
+
test_vt_monitor_SOURCES = \
ck-vt-monitor.h \
ck-vt-monitor.c \
@@ -132,6 +163,7 @@ test_vt_monitor_SOURCES = \
test_vt_monitor_LDADD = \
$(CONSOLE_KIT_LIBS) \
+ $(POLKIT_LIBS) \
libck.la \
$(NULL)
@@ -145,6 +177,7 @@ test_tty_idle_monitor_SOURCES = \
test_tty_idle_monitor_LDADD = \
$(CONSOLE_KIT_LIBS) \
+ $(POLKIT_LIBS) \
libck.la \
$(NULL)
@@ -163,3 +196,9 @@ CLEANFILES = $(BUILT_SOURCES)
MAINTAINERCLEANFILES = \
*~ \
Makefile.in
+
+install-data-local:
+ -mkdir -p $(DESTDIR)$(sysconfdir)/ConsoleKit/run-session.d
+ -mkdir -p $(DESTDIR)$(libdir)/ConsoleKit/run-session.d
+ -mkdir -p $(DESTDIR)$(localstatedir)/run/ConsoleKit
+ -mkdir -p $(DESTDIR)$(localstatedir)/log/ConsoleKit
diff --git a/src/Makefile.in b/src/Makefile.in
index 2e660af..7021cd8 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,8 +1,8 @@
-# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# Makefile.in generated by automake 1.10 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005 Free Software Foundation, Inc.
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -15,15 +15,11 @@
@SET_MAKE@
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
-top_builddir = ..
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-INSTALL = @INSTALL@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
@@ -50,8 +46,9 @@ host_triplet = @host@
@CK_COMPILE_FREEBSD_TRUE@ $(NULL)
sbin_PROGRAMS = console-kit-daemon$(EXEEXT) $(am__EXEEXT_1)
-noinst_PROGRAMS = test-tty-idle-monitor$(EXEEXT) \
- test-vt-monitor$(EXEEXT) $(am__EXEEXT_1)
+noinst_PROGRAMS = test-event-logger$(EXEEXT) \
+ test-tty-idle-monitor$(EXEEXT) test-vt-monitor$(EXEEXT) \
+ $(am__EXEEXT_1)
subdir = src
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -63,12 +60,15 @@ mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
+libck_event_log_la_LIBADD =
+am__objects_1 =
+am_libck_event_log_la_OBJECTS = ck-log-event.lo $(am__objects_1)
+libck_event_log_la_OBJECTS = $(am_libck_event_log_la_OBJECTS)
am__DEPENDENCIES_1 =
@CK_COMPILE_FREEBSD_TRUE@libck_la_DEPENDENCIES = \
@CK_COMPILE_FREEBSD_TRUE@ $(am__DEPENDENCIES_1)
am__libck_la_SOURCES_DIST = ck-sysdeps.h ck-sysdeps-unix.c \
ck-sysdeps-linux.c ck-sysdeps-solaris.c ck-sysdeps-freebsd.c
-am__objects_1 =
@CK_COMPILE_LINUX_TRUE@am__objects_2 = ck-sysdeps-linux.lo \
@CK_COMPILE_LINUX_TRUE@ $(am__objects_1)
@CK_COMPILE_SOLARIS_TRUE@am__objects_3 = ck-sysdeps-solaris.lo \
@@ -85,8 +85,10 @@ PROGRAMS = $(noinst_PROGRAMS) $(sbin_PROGRAMS)
am__console_kit_daemon_SOURCES_DIST = main.c ck-manager.h ck-manager.c \
ck-vt-monitor.h ck-vt-monitor.c ck-tty-idle-monitor.h \
ck-tty-idle-monitor.c ck-file-monitor.h ck-job.h ck-job.c \
- ck-seat.h ck-seat.c ck-session.h ck-session.c ck-log.h \
- ck-log.c ck-manager-glue.h ck-seat-glue.h ck-session-glue.h \
+ ck-seat.h ck-seat.c ck-session-leader.h ck-session-leader.c \
+ ck-session.h ck-session.c ck-log.h ck-log.c ck-run-programs.c \
+ ck-run-programs.h ck-event-logger.c ck-event-logger.h \
+ ck-manager-glue.h ck-seat-glue.h ck-session-glue.h \
ck-marshal.c ck-marshal.h ck-file-monitor-dummy.c \
ck-file-monitor-inotify.c
am__objects_5 = ck-marshal.$(OBJEXT) $(am__objects_1)
@@ -95,11 +97,19 @@ am__objects_5 = ck-marshal.$(OBJEXT) $(am__objects_1)
@ENABLE_INOTIFY_TRUE@ ck-file-monitor-inotify.$(OBJEXT)
am_console_kit_daemon_OBJECTS = main.$(OBJEXT) ck-manager.$(OBJEXT) \
ck-vt-monitor.$(OBJEXT) ck-tty-idle-monitor.$(OBJEXT) \
- ck-job.$(OBJEXT) ck-seat.$(OBJEXT) ck-session.$(OBJEXT) \
- ck-log.$(OBJEXT) $(am__objects_5) $(am__objects_1) \
- $(am__objects_6)
+ ck-job.$(OBJEXT) ck-seat.$(OBJEXT) ck-session-leader.$(OBJEXT) \
+ ck-session.$(OBJEXT) ck-log.$(OBJEXT) \
+ ck-run-programs.$(OBJEXT) ck-event-logger.$(OBJEXT) \
+ $(am__objects_5) $(am__objects_1) $(am__objects_6)
console_kit_daemon_OBJECTS = $(am_console_kit_daemon_OBJECTS)
-console_kit_daemon_DEPENDENCIES = $(am__DEPENDENCIES_1) libck.la \
+console_kit_daemon_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) libck.la \
+ libck-event-log.la $(am__DEPENDENCIES_1)
+am_test_event_logger_OBJECTS = ck-event-logger.$(OBJEXT) \
+ test-event-logger.$(OBJEXT) $(am__objects_1)
+test_event_logger_OBJECTS = $(am_test_event_logger_OBJECTS)
+test_event_logger_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) libck-event-log.la \
$(am__DEPENDENCIES_1)
am__test_tty_idle_monitor_SOURCES_DIST = ck-tty-idle-monitor.h \
ck-tty-idle-monitor.c ck-file-monitor.h \
@@ -109,46 +119,51 @@ am_test_tty_idle_monitor_OBJECTS = ck-tty-idle-monitor.$(OBJEXT) \
$(am__objects_6) test-tty-idle-monitor.$(OBJEXT) \
$(am__objects_1)
test_tty_idle_monitor_OBJECTS = $(am_test_tty_idle_monitor_OBJECTS)
-test_tty_idle_monitor_DEPENDENCIES = $(am__DEPENDENCIES_1) libck.la \
- $(am__DEPENDENCIES_1)
+test_tty_idle_monitor_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) libck.la $(am__DEPENDENCIES_1)
am_test_vt_monitor_OBJECTS = ck-vt-monitor.$(OBJEXT) \
test-vt-monitor.$(OBJEXT) $(am__objects_1)
test_vt_monitor_OBJECTS = $(am_test_vt_monitor_OBJECTS)
-test_vt_monitor_DEPENDENCIES = $(am__DEPENDENCIES_1) libck.la \
- $(am__DEPENDENCIES_1)
-DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+test_vt_monitor_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) libck.la $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
- $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
-LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
- $(AM_LDFLAGS) $(LDFLAGS) -o $@
-SOURCES = $(libck_la_SOURCES) $(EXTRA_libck_la_SOURCES) \
- $(console_kit_daemon_SOURCES) \
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libck_event_log_la_SOURCES) $(libck_la_SOURCES) \
+ $(EXTRA_libck_la_SOURCES) $(console_kit_daemon_SOURCES) \
$(EXTRA_console_kit_daemon_SOURCES) \
- $(test_tty_idle_monitor_SOURCES) $(test_vt_monitor_SOURCES)
-DIST_SOURCES = $(am__libck_la_SOURCES_DIST) $(EXTRA_libck_la_SOURCES) \
+ $(test_event_logger_SOURCES) $(test_tty_idle_monitor_SOURCES) \
+ $(test_vt_monitor_SOURCES)
+DIST_SOURCES = $(libck_event_log_la_SOURCES) \
+ $(am__libck_la_SOURCES_DIST) $(EXTRA_libck_la_SOURCES) \
$(am__console_kit_daemon_SOURCES_DIST) \
$(EXTRA_console_kit_daemon_SOURCES) \
+ $(test_event_logger_SOURCES) \
$(am__test_tty_idle_monitor_SOURCES_DIST) \
$(test_vt_monitor_SOURCES)
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
html-recursive info-recursive install-data-recursive \
- install-exec-recursive install-info-recursive \
- install-recursive installcheck-recursive installdirs-recursive \
- pdf-recursive ps-recursive uninstall-info-recursive \
- uninstall-recursive
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
ETAGS = etags
CTAGS = ctags
DIST_SUBDIRS = $(SUBDIRS)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
-AMDEP_FALSE = @AMDEP_FALSE@
-AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AR = @AR@
AUTOCONF = @AUTOCONF@
@@ -161,12 +176,6 @@ CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CK_BACKEND = @CK_BACKEND@
-CK_COMPILE_FREEBSD_FALSE = @CK_COMPILE_FREEBSD_FALSE@
-CK_COMPILE_FREEBSD_TRUE = @CK_COMPILE_FREEBSD_TRUE@
-CK_COMPILE_LINUX_FALSE = @CK_COMPILE_LINUX_FALSE@
-CK_COMPILE_LINUX_TRUE = @CK_COMPILE_LINUX_TRUE@
-CK_COMPILE_SOLARIS_FALSE = @CK_COMPILE_SOLARIS_FALSE@
-CK_COMPILE_SOLARIS_TRUE = @CK_COMPILE_SOLARIS_TRUE@
CONSOLE_KIT_CFLAGS = @CONSOLE_KIT_CFLAGS@
CONSOLE_KIT_LIBS = @CONSOLE_KIT_LIBS@
CONSOLE_KIT_PID_FILE = @CONSOLE_KIT_PID_FILE@
@@ -183,17 +192,11 @@ DBUS_SYS_DIR = @DBUS_SYS_DIR@
DEBUG_CFLAGS = @DEBUG_CFLAGS@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
-DOCBOOK_DOCS_ENABLED_FALSE = @DOCBOOK_DOCS_ENABLED_FALSE@
-DOCBOOK_DOCS_ENABLED_TRUE = @DOCBOOK_DOCS_ENABLED_TRUE@
ECHO = @ECHO@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
-ENABLE_INOTIFY_FALSE = @ENABLE_INOTIFY_FALSE@
-ENABLE_INOTIFY_TRUE = @ENABLE_INOTIFY_TRUE@
-ENABLE_PAM_MODULE_FALSE = @ENABLE_PAM_MODULE_FALSE@
-ENABLE_PAM_MODULE_TRUE = @ENABLE_PAM_MODULE_TRUE@
EXEEXT = @EXEEXT@
F77 = @F77@
FFLAGS = @FFLAGS@
@@ -203,8 +206,10 @@ GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
GREP = @GREP@
HAVE_PAM = @HAVE_PAM@
-HAVE_PAM_FALSE = @HAVE_PAM_FALSE@
-HAVE_PAM_TRUE = @HAVE_PAM_TRUE@
+HAVE_POLKIT = @HAVE_POLKIT@
+HISTORY_CFLAGS = @HISTORY_CFLAGS@
+HISTORY_LIBS = @HISTORY_LIBS@
+INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
@@ -221,9 +226,8 @@ LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
-MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
-MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
MKINSTALLDIRS = @MKINSTALLDIRS@
MSGFMT = @MSGFMT@
MSGFMT_OPTS = @MSGFMT_OPTS@
@@ -239,10 +243,13 @@ PAM_MODULE_DIR = @PAM_MODULE_DIR@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
POFILES = @POFILES@
+POLKIT_CFLAGS = @POLKIT_CFLAGS@
+POLKIT_LIBS = @POLKIT_LIBS@
POSUB = @POSUB@
PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
RANLIB = @RANLIB@
+RBAC_LIBS = @RBAC_LIBS@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
@@ -253,13 +260,14 @@ VERSION = @VERSION@
WARN_CFLAGS = @WARN_CFLAGS@
XGETTEXT = @XGETTEXT@
XMLTO = @XMLTO@
+Z_LIBS = @Z_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_F77 = @ac_ct_F77@
-am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
-am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
-am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
-am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -271,6 +279,7 @@ build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
+builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
@@ -298,8 +307,11 @@ program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = 1.7
NULL =
SUBDIRS = \
@@ -309,6 +321,7 @@ INCLUDES = \
-I. \
-I$(srcdir) \
$(CONSOLE_KIT_CFLAGS) \
+ $(POLKIT_CFLAGS) \
$(DISABLE_DEPRECATED_CFLAGS) \
-DPREFIX=\""$(prefix)"\" \
-DBINDIR=\""$(bindir)"\" \
@@ -316,6 +329,7 @@ INCLUDES = \
-DLIBEXECDIR=\""$(libexecdir)"\" \
-DDATADIR=\""$(datadir)"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -DLOCALSTATEDIR=\""$(localstatedir)"\" \
-DCONSOLE_KIT_PID_FILE=\""$(CONSOLE_KIT_PID_FILE)"\" \
$(WARN_CFLAGS) \
$(DEBUG_CFLAGS) \
@@ -323,9 +337,15 @@ INCLUDES = \
$(NULL)
noinst_LTLIBRARIES = \
- libck.la \
+ libck.la \
+ libck-event-log.la \
$(NULL)
+libck_event_log_la_SOURCES = \
+ ck-log-event.h \
+ ck-log-event.c \
+ $(NULL)
+
libck_la_SOURCES = ck-sysdeps.h ck-sysdeps-unix.c $(NULL) \
$(am__append_1) $(am__append_2) $(am__append_3)
@CK_COMPILE_FREEBSD_TRUE@libck_la_LIBADD = $(KVM_LIBS)
@@ -346,8 +366,10 @@ BUILT_SOURCES = \
console_kit_daemon_SOURCES = main.c ck-manager.h ck-manager.c \
ck-vt-monitor.h ck-vt-monitor.c ck-tty-idle-monitor.h \
ck-tty-idle-monitor.c ck-file-monitor.h ck-job.h ck-job.c \
- ck-seat.h ck-seat.c ck-session.h ck-session.c ck-log.h \
- ck-log.c $(BUILT_SOURCES) $(NULL) $(FILE_MONITOR_BACKEND)
+ ck-seat.h ck-seat.c ck-session-leader.h ck-session-leader.c \
+ ck-session.h ck-session.c ck-log.h ck-log.c ck-run-programs.c \
+ ck-run-programs.h ck-event-logger.c ck-event-logger.h \
+ $(BUILT_SOURCES) $(NULL) $(FILE_MONITOR_BACKEND)
@ENABLE_INOTIFY_FALSE@FILE_MONITOR_BACKEND = ck-file-monitor-dummy.c
@ENABLE_INOTIFY_TRUE@FILE_MONITOR_BACKEND = ck-file-monitor-inotify.c
EXTRA_console_kit_daemon_SOURCES = \
@@ -357,7 +379,23 @@ EXTRA_console_kit_daemon_SOURCES = \
console_kit_daemon_LDADD = \
$(CONSOLE_KIT_LIBS) \
+ $(POLKIT_LIBS) \
+ $(RBAC_LIBS) \
libck.la \
+ libck-event-log.la \
+ $(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) \
+ $(POLKIT_LIBS) \
+ $(RBAC_LIBS) \
+ libck-event-log.la \
$(NULL)
test_vt_monitor_SOURCES = \
@@ -368,6 +406,7 @@ test_vt_monitor_SOURCES = \
test_vt_monitor_LDADD = \
$(CONSOLE_KIT_LIBS) \
+ $(POLKIT_LIBS) \
libck.la \
$(NULL)
@@ -381,6 +420,7 @@ test_tty_idle_monitor_SOURCES = \
test_tty_idle_monitor_LDADD = \
$(CONSOLE_KIT_LIBS) \
+ $(POLKIT_LIBS) \
libck.la \
$(NULL)
@@ -442,8 +482,10 @@ clean-noinstLTLIBRARIES:
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
+libck-event-log.la: $(libck_event_log_la_OBJECTS) $(libck_event_log_la_DEPENDENCIES)
+ $(LINK) $(libck_event_log_la_OBJECTS) $(libck_event_log_la_LIBADD) $(LIBS)
libck.la: $(libck_la_OBJECTS) $(libck_la_DEPENDENCIES)
- $(LINK) $(libck_la_LDFLAGS) $(libck_la_OBJECTS) $(libck_la_LIBADD) $(LIBS)
+ $(LINK) $(libck_la_OBJECTS) $(libck_la_LIBADD) $(LIBS)
clean-noinstPROGRAMS:
@list='$(noinst_PROGRAMS)'; for p in $$list; do \
@@ -453,7 +495,7 @@ clean-noinstPROGRAMS:
done
install-sbinPROGRAMS: $(sbin_PROGRAMS)
@$(NORMAL_INSTALL)
- test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)"
+ test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
@list='$(sbin_PROGRAMS)'; for p in $$list; do \
p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
if test -f $$p \
@@ -481,13 +523,16 @@ clean-sbinPROGRAMS:
done
console-kit-daemon$(EXEEXT): $(console_kit_daemon_OBJECTS) $(console_kit_daemon_DEPENDENCIES)
@rm -f console-kit-daemon$(EXEEXT)
- $(LINK) $(console_kit_daemon_LDFLAGS) $(console_kit_daemon_OBJECTS) $(console_kit_daemon_LDADD) $(LIBS)
+ $(LINK) $(console_kit_daemon_OBJECTS) $(console_kit_daemon_LDADD) $(LIBS)
+test-event-logger$(EXEEXT): $(test_event_logger_OBJECTS) $(test_event_logger_DEPENDENCIES)
+ @rm -f test-event-logger$(EXEEXT)
+ $(LINK) $(test_event_logger_OBJECTS) $(test_event_logger_LDADD) $(LIBS)
test-tty-idle-monitor$(EXEEXT): $(test_tty_idle_monitor_OBJECTS) $(test_tty_idle_monitor_DEPENDENCIES)
@rm -f test-tty-idle-monitor$(EXEEXT)
- $(LINK) $(test_tty_idle_monitor_LDFLAGS) $(test_tty_idle_monitor_OBJECTS) $(test_tty_idle_monitor_LDADD) $(LIBS)
+ $(LINK) $(test_tty_idle_monitor_OBJECTS) $(test_tty_idle_monitor_LDADD) $(LIBS)
test-vt-monitor$(EXEEXT): $(test_vt_monitor_OBJECTS) $(test_vt_monitor_DEPENDENCIES)
@rm -f test-vt-monitor$(EXEEXT)
- $(LINK) $(test_vt_monitor_LDFLAGS) $(test_vt_monitor_OBJECTS) $(test_vt_monitor_LDADD) $(LIBS)
+ $(LINK) $(test_vt_monitor_OBJECTS) $(test_vt_monitor_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -495,13 +540,17 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-event-logger.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-file-monitor-dummy.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-file-monitor-inotify.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-log-event.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-manager.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-marshal.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-run-programs.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-seat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-session-leader.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-session.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-sysdeps-freebsd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-sysdeps-linux.Plo@am__quote@
@@ -510,26 +559,27 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-tty-idle-monitor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ck-vt-monitor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-event-logger.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-tty-idle-monitor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-vt-monitor.Po@am__quote@
.c.o:
-@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
.c.obj:
-@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
-@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
@@ -540,10 +590,6 @@ mostlyclean-libtool:
clean-libtool:
-rm -rf .libs _libs
-distclean-libtool:
- -rm -f libtool
-uninstall-info-am:
-
# This directory's subdirectories are mostly independent; you can cd
# into them and run `make' without going through this Makefile.
# To change the values of `make' variables: instead of editing Makefiles,
@@ -575,8 +621,7 @@ $(RECURSIVE_TARGETS):
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
fi; test -z "$$fail"
-mostlyclean-recursive clean-recursive distclean-recursive \
-maintainer-clean-recursive:
+$(RECURSIVE_CLEAN_TARGETS):
@failcom='exit 1'; \
for f in x $$MAKEFLAGS; do \
case $$f in \
@@ -677,22 +722,21 @@ distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
- @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
- topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
- list='$(DISTFILES)'; for file in $$list; do \
- case $$file in \
- $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
- $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
- esac; \
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
- dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
- if test "$$dir" != "$$file" && test "$$dir" != "."; then \
- dir="/$$dir"; \
- $(mkdir_p) "$(distdir)$$dir"; \
- else \
- dir=''; \
- fi; \
if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
@@ -706,7 +750,7 @@ distdir: $(DISTFILES)
list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test -d "$(distdir)/$$subdir" \
- || $(mkdir_p) "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
|| exit 1; \
distdir=`$(am__cd) $(distdir) && pwd`; \
top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
@@ -714,6 +758,8 @@ distdir: $(DISTFILES)
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$$top_distdir" \
distdir="$$distdir/$$subdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
distdir) \
|| exit 1; \
fi; \
@@ -725,7 +771,7 @@ all-am: Makefile $(LTLIBRARIES) $(PROGRAMS)
installdirs: installdirs-recursive
installdirs-am:
for dir in "$(DESTDIR)$(sbindir)"; do \
- test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) install-recursive
@@ -764,7 +810,7 @@ distclean: distclean-recursive
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
- distclean-libtool distclean-tags
+ distclean-tags
dvi: dvi-recursive
@@ -776,14 +822,22 @@ info: info-recursive
info-am:
-install-data-am:
+install-data-am: install-data-local
+
+install-dvi: install-dvi-recursive
install-exec-am: install-sbinPROGRAMS
+install-html: install-html-recursive
+
install-info: install-info-recursive
install-man:
+install-pdf: install-pdf-recursive
+
+install-ps: install-ps-recursive
+
installcheck-am:
maintainer-clean: maintainer-clean-recursive
@@ -804,24 +858,27 @@ ps: ps-recursive
ps-am:
-uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS
-
-uninstall-info: uninstall-info-recursive
-
-.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
- clean clean-generic clean-libtool clean-noinstLTLIBRARIES \
- clean-noinstPROGRAMS clean-recursive clean-sbinPROGRAMS ctags \
- ctags-recursive distclean distclean-compile distclean-generic \
- distclean-libtool distclean-recursive distclean-tags distdir \
- dvi dvi-am html html-am info info-am install install-am \
- install-data install-data-am install-exec install-exec-am \
- install-info install-info-am install-man install-sbinPROGRAMS \
- install-strip installcheck installcheck-am installdirs \
- installdirs-am maintainer-clean maintainer-clean-generic \
- maintainer-clean-recursive mostlyclean mostlyclean-compile \
- mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \
+uninstall-am: uninstall-sbinPROGRAMS
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
+ install-strip
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-generic clean-libtool \
+ clean-noinstLTLIBRARIES clean-noinstPROGRAMS \
+ clean-sbinPROGRAMS ctags ctags-recursive distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-data-local install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-sbinPROGRAMS install-strip \
+ installcheck installcheck-am installdirs installdirs-am \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
- uninstall-info-am uninstall-sbinPROGRAMS
+ uninstall-sbinPROGRAMS
ck-manager-glue.h: ck-manager.xml Makefile.am
@@ -837,6 +894,12 @@ ck-marshal.c: ck-marshal.list
ck-marshal.h: ck-marshal.list
@GLIB_GENMARSHAL@ $< --prefix=ck_marshal --header > $@
+
+install-data-local:
+ -mkdir -p $(DESTDIR)$(sysconfdir)/ConsoleKit/run-session.d
+ -mkdir -p $(DESTDIR)$(libdir)/ConsoleKit/run-session.d
+ -mkdir -p $(DESTDIR)$(localstatedir)/run/ConsoleKit
+ -mkdir -p $(DESTDIR)$(localstatedir)/log/ConsoleKit
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/src/ck-event-logger.c b/src/ck-event-logger.c
new file mode 100644
index 0000000..2fded87
--- /dev/null
+++ b/src/ck-event-logger.c
@@ -0,0 +1,420 @@
+/* -*- 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 <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"
+#include "ck-log-event.h"
+
+#define CK_EVENT_LOGGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_EVENT_LOGGER, CkEventLoggerPrivate))
+
+#define DEFAULT_LOG_FILENAME LOCALSTATEDIR "/log/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;
+}
+
+gboolean
+ck_event_logger_queue_event (CkEventLogger *event_logger,
+ CkLogEvent *event,
+ GError **error)
+{
+ CkLogEvent *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_log_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;
+ int res;
+ char *dirname;
+
+ /*
+ * Likely errors on rotate: ENFILE, ENOMEM, ENOSPC
+ */
+ flags = O_WRONLY | O_APPEND;
+#ifdef O_NOFOLLOW
+ flags |= O_NOFOLLOW;
+#endif
+
+ dirname = g_path_get_dirname (event_logger->priv->log_filename);
+ /* always make sure we have a directory */
+ errno = 0;
+ res = g_mkdir_with_parents (dirname,
+ S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ if (res < 0) {
+ g_warning ("Unable to create directory %s (%s)",
+ dirname,
+ g_strerror (errno));
+ g_free (dirname);
+ return FALSE;
+ }
+ g_free (dirname);
+
+retry:
+ errno = 0;
+ fd = g_open (event_logger->priv->log_filename, flags, 0600);
+ if (fd < 0) {
+ if (errno == ENOENT) {
+ fd = g_open (event_logger->priv->log_filename,
+ O_CREAT | O_EXCL | O_APPEND,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ 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->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;
+ }
+ event_logger->priv->fd = fd;
+
+ /* Set it to line buffering */
+ setlinebuf (event_logger->priv->file);
+
+ return TRUE;
+}
+
+static void
+reopen_file_stream (CkEventLogger *event_logger)
+{
+ close (event_logger->priv->fd);
+ fclose (event_logger->priv->file);
+
+ /* FIXME: retries */
+ open_log_file (event_logger);
+}
+
+static void
+check_file_stream (CkEventLogger *event_logger)
+{
+ int old_fd;
+ struct stat old_stats;
+ int new_fd;
+ struct stat new_stats;
+
+ old_fd = event_logger->priv->fd;
+ if (fstat (old_fd, &old_stats) != 0) {
+ g_warning ("Unable to stat file: %s",
+ g_strerror (errno));
+ reopen_file_stream (event_logger);
+ return;
+ }
+
+ new_fd = g_open (event_logger->priv->log_filename, O_RDONLY | O_NONBLOCK, 0600);
+ if (new_fd == -1 || fstat (new_fd, &new_stats) < 0) {
+ close (new_fd);
+ g_debug ("Unable to open or stat %s - will try to reopen", event_logger->priv->log_filename);
+ reopen_file_stream (event_logger);
+ return;
+ }
+ close (new_fd);
+
+ if (old_stats.st_ino != new_stats.st_ino || old_stats.st_dev != new_stats.st_dev) {
+ g_debug ("File %s has been replaced; writing to end of new file", event_logger->priv->log_filename);
+ reopen_file_stream (event_logger);
+ return;
+ }
+}
+
+static gboolean
+write_log_for_event (CkEventLogger *event_logger,
+ CkLogEvent *event)
+{
+ GString *str;
+
+ str = g_string_new (NULL);
+
+ ck_log_event_to_string (event, str);
+
+ g_debug ("Writing log for event: %s", str->str);
+ check_file_stream (event_logger);
+
+ 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));
+ }
+ } else {
+ g_warning ("Log file not open for writing");
+ }
+
+ g_string_free (str, TRUE);
+
+ return TRUE;
+}
+
+static void *
+writer_thread_start (CkEventLogger *event_logger)
+{
+ CkLogEvent *event;
+
+ while ((event = g_async_queue_pop (event_logger->priv->event_queue)) != NULL) {
+ write_log_for_event (event_logger, event);
+ ck_log_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..d4645f7
--- /dev/null
+++ b/src/ck-event-logger.h
@@ -0,0 +1,66 @@
+/* -*- 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>
+#include "ck-log-event.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_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,
+ CkLogEvent *event,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __CK_EVENT_LOGGER_H */
diff --git a/src/ck-log-event.c b/src/ck-log-event.c
new file mode 100644
index 0000000..7e8ce10
--- /dev/null
+++ b/src/ck-log-event.c
@@ -0,0 +1,1284 @@
+/* -*- 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 <string.h>
+
+#include <glib.h>
+
+#include "ck-log-event.h"
+
+static void
+event_seat_added_free (CkLogSeatAddedEvent *event)
+{
+ g_assert (event != NULL);
+
+ g_free (event->seat_id);
+ event->seat_id = NULL;
+}
+
+static void
+event_seat_removed_free (CkLogSeatRemovedEvent *event)
+{
+ g_assert (event != NULL);
+
+ g_free (event->seat_id);
+ event->seat_id = NULL;
+}
+
+static void
+event_system_stop_free (CkLogSystemStopEvent *event)
+{
+ g_assert (event != NULL);
+}
+
+static void
+event_system_restart_free (CkLogSystemRestartEvent *event)
+{
+ g_assert (event != NULL);
+}
+
+
+static void
+event_system_start_free (CkLogSystemStartEvent *event)
+{
+ g_assert (event != NULL);
+}
+
+static void
+event_seat_session_added_free (CkLogSeatSessionAddedEvent *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 (CkLogSeatSessionRemovedEvent *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 (CkLogSeatActiveSessionChangedEvent *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 (CkLogSeatDeviceAddedEvent *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 (CkLogSeatDeviceRemovedEvent *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 (CkLogSeatAddedEvent *event,
+ CkLogSeatAddedEvent *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 (CkLogSeatRemovedEvent *event,
+ CkLogSeatRemovedEvent *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_system_stop_copy (CkLogSystemStopEvent *event,
+ CkLogSystemStopEvent *event_copy)
+{
+ g_assert (event != NULL);
+ g_assert (event_copy != NULL);
+}
+
+static void
+event_system_restart_copy (CkLogSystemRestartEvent *event,
+ CkLogSystemRestartEvent *event_copy)
+{
+ g_assert (event != NULL);
+ g_assert (event_copy != NULL);
+}
+
+
+static void
+event_system_start_copy (CkLogSystemStartEvent *event,
+ CkLogSystemStartEvent *event_copy)
+{
+ g_assert (event != NULL);
+ g_assert (event_copy != NULL);
+}
+
+static void
+event_seat_session_added_copy (CkLogSeatSessionAddedEvent *event,
+ CkLogSeatSessionAddedEvent *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 (CkLogSeatSessionRemovedEvent *event,
+ CkLogSeatSessionRemovedEvent *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 (CkLogSeatActiveSessionChangedEvent *event,
+ CkLogSeatActiveSessionChangedEvent *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 (CkLogSeatDeviceAddedEvent *event,
+ CkLogSeatDeviceAddedEvent *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 (CkLogSeatDeviceRemovedEvent *event,
+ CkLogSeatDeviceRemovedEvent *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);
+}
+
+CkLogEvent *
+ck_log_event_copy (CkLogEvent *event)
+{
+ CkLogEvent *event_copy;
+
+ if (event == NULL) {
+ return NULL;
+ }
+
+ event_copy = g_new0 (CkLogEvent, 1);
+
+ event_copy->type = event->type;
+ event_copy->timestamp = event->timestamp;
+
+ switch (event->type) {
+ case CK_LOG_EVENT_SEAT_ADDED:
+ event_seat_added_copy ((CkLogSeatAddedEvent *) event,
+ (CkLogSeatAddedEvent *) event_copy);
+ break;
+ case CK_LOG_EVENT_SEAT_REMOVED:
+ event_seat_removed_copy ((CkLogSeatRemovedEvent *) event,
+ (CkLogSeatRemovedEvent *) event_copy);
+ break;
+ case CK_LOG_EVENT_SYSTEM_STOP:
+ event_system_stop_copy ((CkLogSystemStopEvent *) event,
+ (CkLogSystemStopEvent *) event_copy);
+ break;
+ case CK_LOG_EVENT_SYSTEM_RESTART:
+ event_system_restart_copy ((CkLogSystemRestartEvent *) event,
+ (CkLogSystemRestartEvent *) event_copy);
+ break;
+ case CK_LOG_EVENT_SYSTEM_START:
+ event_system_start_copy ((CkLogSystemStartEvent *) event,
+ (CkLogSystemStartEvent *) event_copy);
+ break;
+ case CK_LOG_EVENT_SEAT_SESSION_ADDED:
+ event_seat_session_added_copy ((CkLogSeatSessionAddedEvent *) event,
+ (CkLogSeatSessionAddedEvent *) event_copy);
+ break;
+ case CK_LOG_EVENT_SEAT_SESSION_REMOVED:
+ event_seat_session_removed_copy ((CkLogSeatSessionRemovedEvent *) event,
+ (CkLogSeatSessionRemovedEvent *) event_copy);
+ break;
+ case CK_LOG_EVENT_SEAT_DEVICE_ADDED:
+ event_seat_device_added_copy ((CkLogSeatDeviceAddedEvent *) event,
+ (CkLogSeatDeviceAddedEvent *) event_copy);
+ break;
+ case CK_LOG_EVENT_SEAT_DEVICE_REMOVED:
+ event_seat_device_removed_copy ((CkLogSeatDeviceRemovedEvent *) event,
+ (CkLogSeatDeviceRemovedEvent *) event_copy);
+ break;
+ case CK_LOG_EVENT_SEAT_ACTIVE_SESSION_CHANGED:
+ event_seat_active_session_changed_copy ((CkLogSeatActiveSessionChangedEvent *) event,
+ (CkLogSeatActiveSessionChangedEvent *) event_copy);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return event_copy;
+}
+
+void
+ck_log_event_free (CkLogEvent *event)
+{
+ switch (event->type) {
+ case CK_LOG_EVENT_SEAT_ADDED:
+ event_seat_added_free ((CkLogSeatAddedEvent *) event);
+ break;
+ case CK_LOG_EVENT_SEAT_REMOVED:
+ event_seat_removed_free ((CkLogSeatRemovedEvent *) event);
+ break;
+ case CK_LOG_EVENT_SYSTEM_STOP:
+ event_system_stop_free ((CkLogSystemStopEvent *) event);
+ break;
+ case CK_LOG_EVENT_SYSTEM_RESTART:
+ event_system_restart_free ((CkLogSystemRestartEvent *) event);
+ break;
+ case CK_LOG_EVENT_SYSTEM_START:
+ event_system_start_free ((CkLogSystemStartEvent *) event);
+ break;
+ case CK_LOG_EVENT_SEAT_SESSION_ADDED:
+ event_seat_session_added_free ((CkLogSeatSessionAddedEvent *) event);
+ break;
+ case CK_LOG_EVENT_SEAT_SESSION_REMOVED:
+ event_seat_session_removed_free ((CkLogSeatSessionRemovedEvent *) event);
+ break;
+ case CK_LOG_EVENT_SEAT_DEVICE_ADDED:
+ event_seat_device_added_free ((CkLogSeatDeviceAddedEvent *) event);
+ break;
+ case CK_LOG_EVENT_SEAT_DEVICE_REMOVED:
+ event_seat_device_removed_free ((CkLogSeatDeviceRemovedEvent *) event);
+ break;
+ case CK_LOG_EVENT_SEAT_ACTIVE_SESSION_CHANGED:
+ event_seat_active_session_changed_free ((CkLogSeatActiveSessionChangedEvent *) event);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ g_free (event);
+}
+
+static void
+add_log_for_seat_added (GString *str,
+ CkLogEvent *event)
+{
+ CkLogSeatAddedEvent *e;
+
+ e = (CkLogSeatAddedEvent *)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,
+ CkLogEvent *event)
+{
+ CkLogSeatRemovedEvent *e;
+
+ e = (CkLogSeatRemovedEvent *)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,
+ CkLogEvent *event)
+{
+ CkLogSeatSessionAddedEvent *e;
+
+ e = (CkLogSeatSessionAddedEvent *)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,
+ CkLogEvent *event)
+{
+ CkLogSeatSessionRemovedEvent *e;
+
+ e = (CkLogSeatSessionRemovedEvent *)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_system_stop (GString *str,
+ CkLogEvent *event)
+{
+ CkLogSystemStopEvent *e;
+
+ e = (CkLogSystemStopEvent *)event;
+}
+
+static void
+add_log_for_system_restart (GString *str,
+ CkLogEvent *event)
+{
+ CkLogSystemRestartEvent *e;
+
+ e = (CkLogSystemRestartEvent *)event;
+}
+
+
+static void
+add_log_for_system_start (GString *str,
+ CkLogEvent *event)
+{
+ CkLogSystemStartEvent *e;
+
+ e = (CkLogSystemStartEvent *)event;
+}
+
+static void
+add_log_for_seat_active_session_changed (GString *str,
+ CkLogEvent *event)
+{
+ CkLogSeatActiveSessionChangedEvent *e;
+
+ e = (CkLogSeatActiveSessionChangedEvent *)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,
+ CkLogEvent *event)
+{
+ CkLogSeatDeviceAddedEvent *e;
+
+ e = (CkLogSeatDeviceAddedEvent *)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,
+ CkLogEvent *event)
+{
+ CkLogSeatDeviceRemovedEvent *e;
+
+ e = (CkLogSeatDeviceRemovedEvent *)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 (CkLogEventType event_type)
+{
+ const char *str;
+ switch (event_type) {
+ case CK_LOG_EVENT_SEAT_ADDED:
+ str = "SEAT_ADDED";
+ break;
+ case CK_LOG_EVENT_SEAT_REMOVED:
+ str = "SEAT_REMOVED";
+ break;
+ case CK_LOG_EVENT_SYSTEM_STOP:
+ str = "SYSTEM_STOP";
+ break;
+ case CK_LOG_EVENT_SYSTEM_RESTART:
+ str = "SYSTEM_RESTART";
+ break;
+ case CK_LOG_EVENT_SYSTEM_START:
+ str = "SYSTEM_START";
+ break;
+ case CK_LOG_EVENT_SEAT_SESSION_ADDED:
+ str = "SEAT_SESSION_ADDED";
+ break;
+ case CK_LOG_EVENT_SEAT_SESSION_REMOVED:
+ str = "SEAT_SESSION_REMOVED";
+ break;
+ case CK_LOG_EVENT_SEAT_DEVICE_ADDED:
+ str = "SEAT_DEVICE_ADDED";
+ break;
+ case CK_LOG_EVENT_SEAT_DEVICE_REMOVED:
+ str = "SEAT_DEVICE_REMOVED";
+ break;
+ case CK_LOG_EVENT_SEAT_ACTIVE_SESSION_CHANGED:
+ str = "SEAT_ACTIVE_SESSION_CHANGED";
+ break;
+ default:
+ str = "UNKNOWN";
+ break;
+ }
+ return str;
+}
+
+static gboolean
+event_name_to_type (const char *event_name,
+ CkLogEventType *event_type)
+{
+ gboolean ret;
+
+ ret = TRUE;
+
+ if (strcmp (event_name, "SEAT_ADDED") == 0) {
+ *event_type = CK_LOG_EVENT_SEAT_ADDED;
+ } else if (strcmp (event_name, "SEAT_REMOVED") == 0) {
+ *event_type = CK_LOG_EVENT_SEAT_REMOVED;
+ } else if (strcmp (event_name, "SYSTEM_STOP") == 0) {
+ *event_type = CK_LOG_EVENT_SYSTEM_STOP;
+ } else if (strcmp (event_name, "SYSTEM_RESTART") == 0) {
+ *event_type = CK_LOG_EVENT_SYSTEM_RESTART;
+ } else if (strcmp (event_name, "SYSTEM_START") == 0) {
+ *event_type = CK_LOG_EVENT_SYSTEM_START;
+ } else if (strcmp (event_name, "SEAT_SESSION_ADDED") == 0) {
+ *event_type = CK_LOG_EVENT_SEAT_SESSION_ADDED;
+ } else if (strcmp (event_name, "SEAT_SESSION_REMOVED") == 0) {
+ *event_type = CK_LOG_EVENT_SEAT_SESSION_REMOVED;
+ } else if (strcmp (event_name, "SEAT_DEVICE_ADDED") == 0) {
+ *event_type = CK_LOG_EVENT_SEAT_DEVICE_ADDED;
+ } else if (strcmp (event_name, "SEAT_DEVICE_REMOVED") == 0) {
+ *event_type = CK_LOG_EVENT_SEAT_DEVICE_REMOVED;
+ } else if (strcmp (event_name, "SEAT_ACTIVE_SESSION_CHANGED") == 0) {
+ *event_type = CK_LOG_EVENT_SEAT_ACTIVE_SESSION_CHANGED;
+ } else {
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+static void
+add_log_for_any (GString *str,
+ CkLogEvent *event)
+{
+ g_string_append_printf (str,
+ "%lu.%03u type=%s :",
+ (gulong)event->timestamp.tv_sec,
+ (guint)(event->timestamp.tv_usec / 1000),
+ event_type_to_name (event->type));
+}
+
+void
+ck_log_event_to_string (CkLogEvent *event,
+ GString *str)
+{
+
+ add_log_for_any (str, event);
+
+ switch (event->type) {
+ case CK_LOG_EVENT_SEAT_ADDED:
+ add_log_for_seat_added (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_REMOVED:
+ add_log_for_seat_removed (str, event);
+ break;
+ case CK_LOG_EVENT_SYSTEM_STOP:
+ add_log_for_system_stop (str, event);
+ break;
+ case CK_LOG_EVENT_SYSTEM_RESTART:
+ add_log_for_system_restart (str, event);
+ break;
+ case CK_LOG_EVENT_SYSTEM_START:
+ add_log_for_system_start (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_SESSION_ADDED:
+ add_log_for_seat_session_added (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_SESSION_REMOVED:
+ add_log_for_seat_session_removed (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_DEVICE_ADDED:
+ add_log_for_seat_device_added (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_DEVICE_REMOVED:
+ add_log_for_seat_device_removed (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_ACTIVE_SESSION_CHANGED:
+ add_log_for_seat_active_session_changed (str, event);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static const char *
+skip_header (const char *str,
+ gssize len)
+{
+ char *r;
+ r = g_strstr_len (str,
+ len,
+ " : ");
+ if (r != NULL) {
+ r += 3;
+ }
+
+ return r;
+}
+
+static gboolean
+parse_value_as_ulong (const char *value,
+ gulong *intval)
+{
+ char *end_of_valid_int;
+ glong ulong_value;
+
+ ulong_value = strtoul (value, &end_of_valid_int, 10);
+
+ if (*value == '\0' || *end_of_valid_int != '\0') {
+ return FALSE;
+ }
+
+ *intval = ulong_value;
+
+ return TRUE;
+}
+
+static gboolean
+parse_log_for_seat_added (const GString *str,
+ CkLogEvent *event)
+{
+ gboolean ret;
+ const char *s;
+ GRegex *re;
+ GMatchInfo *match_info;
+ gboolean res;
+ GError *error;
+ char *tmp;
+ CkLogSeatAddedEvent *e;
+
+ re = NULL;
+ match_info = NULL;
+ ret = FALSE;
+
+ s = skip_header (str->str, str->len);
+ if (s == NULL) {
+ goto out;
+ }
+
+ error = NULL;
+ re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' seat-kind=(?P<sessionid>[0-9]*)", 0, 0, &error);
+ if (re == NULL) {
+ g_warning (error->message);
+ goto out;
+ }
+
+ g_regex_match (re, s, 0, &match_info);
+
+ res = g_match_info_matches (match_info);
+ if (! res) {
+ g_warning ("Unable to parse seat added event: %s", s);
+ goto out;
+ }
+
+ e = (CkLogSeatAddedEvent *)event;
+ e->seat_id = g_match_info_fetch_named (match_info, "seatid");
+
+ tmp = g_match_info_fetch_named (match_info, "seatkind");
+ if (tmp != NULL) {
+ gulong l;
+ if (parse_value_as_ulong (tmp, &l)) {
+ e->seat_kind = l;
+ }
+ }
+
+ ret = TRUE;
+ out:
+ if (match_info != NULL) {
+ g_match_info_free (match_info);
+ }
+ if (re != NULL) {
+ g_regex_unref (re);
+ }
+
+ return ret;
+}
+
+static gboolean
+parse_log_for_seat_removed (const GString *str,
+ CkLogEvent *event)
+{
+ gboolean ret;
+ const char *s;
+ GRegex *re;
+ GMatchInfo *match_info;
+ gboolean res;
+ GError *error;
+ char *tmp;
+ CkLogSeatRemovedEvent *e;
+
+ re = NULL;
+ match_info = NULL;
+ ret = FALSE;
+
+ s = skip_header (str->str, str->len);
+ if (s == NULL) {
+ goto out;
+ }
+
+ error = NULL;
+ re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' seat-kind=(?P<sessionid>[0-9]*)", 0, 0, &error);
+ if (re == NULL) {
+ g_warning (error->message);
+ goto out;
+ }
+
+ g_regex_match (re, s, 0, &match_info);
+
+ res = g_match_info_matches (match_info);
+ if (! res) {
+ g_warning ("Unable to parse seat removed event: %s", s);
+ goto out;
+ }
+
+ e = (CkLogSeatRemovedEvent *)event;
+ e->seat_id = g_match_info_fetch_named (match_info, "seatid");
+
+ tmp = g_match_info_fetch_named (match_info, "seatkind");
+ if (tmp != NULL) {
+ gulong l;
+ if (parse_value_as_ulong (tmp, &l)) {
+ e->seat_kind = l;
+ }
+ }
+
+ ret = TRUE;
+ out:
+ if (match_info != NULL) {
+ g_match_info_free (match_info);
+ }
+ if (re != NULL) {
+ g_regex_unref (re);
+ }
+
+ return ret;
+}
+
+static gboolean
+parse_log_for_system_stop (const GString *str,
+ CkLogEvent *event)
+{
+ gboolean ret;
+ const char *s;
+ CkLogSystemStopEvent *e;
+
+ ret = FALSE;
+
+ s = skip_header (str->str, str->len);
+ if (s == NULL) {
+ goto out;
+ }
+
+ e = (CkLogSystemStopEvent *)event;
+
+ ret = TRUE;
+ out:
+
+ return ret;
+}
+
+static gboolean
+parse_log_for_system_restart (const GString *str,
+ CkLogEvent *event)
+{
+ gboolean ret;
+ const char *s;
+ CkLogSystemRestartEvent *e;
+
+ ret = FALSE;
+
+ s = skip_header (str->str, str->len);
+ if (s == NULL) {
+ goto out;
+ }
+
+ e = (CkLogSystemRestartEvent *)event;
+
+ ret = TRUE;
+ out:
+
+ return ret;
+}
+
+static gboolean
+parse_log_for_system_start (const GString *str,
+ CkLogEvent *event)
+{
+ gboolean ret;
+ const char *s;
+ CkLogSystemStartEvent *e;
+
+ ret = FALSE;
+
+ s = skip_header (str->str, str->len);
+ if (s == NULL) {
+ goto out;
+ }
+
+ e = (CkLogSystemStartEvent *)event;
+
+ ret = TRUE;
+ out:
+
+ return ret;
+}
+
+static gboolean
+parse_log_for_seat_session_added (const GString *str,
+ CkLogEvent *event)
+{
+ gboolean ret;
+ const char *s;
+ GRegex *re;
+ GMatchInfo *match_info;
+ gboolean res;
+ GError *error;
+ char *tmp;
+ CkLogSeatSessionAddedEvent *e;
+
+ re = NULL;
+ match_info = NULL;
+ ret = FALSE;
+
+ s = skip_header (str->str, str->len);
+ if (s == NULL) {
+ goto out;
+ }
+
+ error = NULL;
+ re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' session-id='(?P<sessionid>[a-zA-Z0-9/]+)' session-type='(?P<sessiontype>[a-zA-Z0-9 ]*)' session-x11-display='(?P<sessionx11display>[0-9a-zA-Z.:]*)' session-x11-display-device='(?P<sessionx11displaydevice>[^']*)' session-display-device='(?P<sessiondisplaydevice>[^']*)' session-remote-host-name='(?P<sessionremovehostname>[^']*)' session-is-local=(?P<sessionislocal>[a-zA-Z]*) session-unix-user=(?P<sessionunixuser>[0-9]*) session-creation-time='(?P<sessioncreationtime>[^']*)'", 0, 0, &error);
+ if (re == NULL) {
+ g_warning (error->message);
+ goto out;
+ }
+
+ g_regex_match (re, s, 0, &match_info);
+
+ res = g_match_info_matches (match_info);
+ if (! res) {
+ g_warning ("Unable to parse session added event: %s", s);
+ goto out;
+ }
+
+ e = (CkLogSeatSessionAddedEvent *)event;
+ e->seat_id = g_match_info_fetch_named (match_info, "seatid");
+ e->session_id = g_match_info_fetch_named (match_info, "sessionid");
+ e->session_type = g_match_info_fetch_named (match_info, "sessiontype");
+ e->session_x11_display = g_match_info_fetch_named (match_info, "sessionx11display");
+ e->session_x11_display_device = g_match_info_fetch_named (match_info, "sessionx11displaydevice");
+ e->session_display_device = g_match_info_fetch_named (match_info, "sessiondisplaydevice");
+ e->session_remote_host_name = g_match_info_fetch_named (match_info, "sessionremotehostname");
+ e->session_creation_time = g_match_info_fetch_named (match_info, "sessioncreationtime");
+
+ tmp = g_match_info_fetch_named (match_info, "sessionislocal");
+ if (tmp != NULL && strcmp (tmp, "TRUE") == 0) {
+ e->session_is_local = TRUE;
+ } else {
+ e->session_is_local = FALSE;
+ }
+ g_free (tmp);
+
+ tmp = g_match_info_fetch_named (match_info, "sessionunixuser");
+ if (tmp != NULL) {
+ gulong l;
+ if (parse_value_as_ulong (tmp, &l)) {
+ e->session_unix_user = l;
+ }
+ }
+
+ ret = TRUE;
+ out:
+ if (match_info != NULL) {
+ g_match_info_free (match_info);
+ }
+ if (re != NULL) {
+ g_regex_unref (re);
+ }
+
+ return ret;
+}
+
+static gboolean
+parse_log_for_seat_session_removed (const GString *str,
+ CkLogEvent *event)
+{
+ gboolean ret;
+ const char *s;
+ GRegex *re;
+ GMatchInfo *match_info;
+ gboolean res;
+ GError *error;
+ char *tmp;
+ CkLogSeatSessionRemovedEvent *e;
+
+ re = NULL;
+ match_info = NULL;
+ ret = FALSE;
+
+ s = skip_header (str->str, str->len);
+ if (s == NULL) {
+ goto out;
+ }
+
+ error = NULL;
+ re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' session-id='(?P<sessionid>[a-zA-Z0-9/]+)' session-type='(?P<sessiontype>[a-zA-Z0-9 ]*)' session-x11-display='(?P<sessionx11display>[0-9a-zA-Z.:]*)' session-x11-display-device='(?P<sessionx11displaydevice>[^']*)' session-display-device='(?P<sessiondisplaydevice>[^']*)' session-remote-host-name='(?P<sessionremovehostname>[^']*)' session-is-local=(?P<sessionislocal>[a-zA-Z]*) session-unix-user=(?P<sessionunixuser>[0-9]*) session-creation-time='(?P<sessioncreationtime>[^']*)'", 0, 0, &error);
+ if (re == NULL) {
+ g_warning (error->message);
+ goto out;
+ }
+
+ g_regex_match (re, s, 0, &match_info);
+
+ res = g_match_info_matches (match_info);
+ if (! res) {
+ g_warning ("Unable to parse session removed event: %s", s);
+ goto out;
+ }
+
+ e = (CkLogSeatSessionRemovedEvent *)event;
+ e->seat_id = g_match_info_fetch_named (match_info, "seatid");
+ e->session_id = g_match_info_fetch_named (match_info, "sessionid");
+ e->session_type = g_match_info_fetch_named (match_info, "sessiontype");
+ e->session_x11_display = g_match_info_fetch_named (match_info, "sessionx11display");
+ e->session_x11_display_device = g_match_info_fetch_named (match_info, "sessionx11displaydevice");
+ e->session_display_device = g_match_info_fetch_named (match_info, "sessiondisplaydevice");
+ e->session_remote_host_name = g_match_info_fetch_named (match_info, "sessionremotehostname");
+ e->session_creation_time = g_match_info_fetch_named (match_info, "sessioncreationtime");
+
+ tmp = g_match_info_fetch_named (match_info, "sessionislocal");
+ if (tmp != NULL && strcmp (tmp, "TRUE") == 0) {
+ e->session_is_local = TRUE;
+ } else {
+ e->session_is_local = FALSE;
+ }
+ g_free (tmp);
+
+ tmp = g_match_info_fetch_named (match_info, "sessionunixuser");
+ if (tmp != NULL) {
+ gulong l;
+ if (parse_value_as_ulong (tmp, &l)) {
+ e->session_unix_user = l;
+ }
+ }
+
+ ret = TRUE;
+ out:
+ if (match_info != NULL) {
+ g_match_info_free (match_info);
+ }
+ if (re != NULL) {
+ g_regex_unref (re);
+ }
+
+ return ret;
+}
+
+static gboolean
+parse_log_for_seat_active_session_changed (const GString *str,
+ CkLogEvent *event)
+{
+ gboolean ret;
+ const char *s;
+ GRegex *re;
+ GMatchInfo *match_info;
+ gboolean res;
+ GError *error;
+ CkLogSeatActiveSessionChangedEvent *e;
+
+ re = NULL;
+ match_info = NULL;
+ ret = FALSE;
+
+ s = skip_header (str->str, str->len);
+ if (s == NULL) {
+ goto out;
+ }
+
+ error = NULL;
+ re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' session-id='(?P<sessionid>[a-zA-Z0-9/]*)'", 0, 0, &error);
+ if (re == NULL) {
+ g_warning (error->message);
+ goto out;
+ }
+
+ g_regex_match (re, s, 0, &match_info);
+
+ res = g_match_info_matches (match_info);
+ if (! res) {
+ g_warning ("Unable to parse session changed event: %s", s);
+ goto out;
+ }
+
+ e = (CkLogSeatActiveSessionChangedEvent *)event;
+ e->seat_id = g_match_info_fetch_named (match_info, "seatid");
+ e->session_id = g_match_info_fetch_named (match_info, "sessionid");
+
+ ret = TRUE;
+ out:
+ if (match_info != NULL) {
+ g_match_info_free (match_info);
+ }
+ if (re != NULL) {
+ g_regex_unref (re);
+ }
+
+ return ret;
+}
+
+static gboolean
+parse_log_for_seat_device_added (const GString *str,
+ CkLogEvent *event)
+{
+ gboolean ret;
+ const char *s;
+ GRegex *re;
+ GMatchInfo *match_info;
+ gboolean res;
+ GError *error;
+ CkLogSeatDeviceAddedEvent *e;
+
+ re = NULL;
+ match_info = NULL;
+ ret = FALSE;
+
+ s = skip_header (str->str, str->len);
+ if (s == NULL) {
+ goto out;
+ }
+
+ error = NULL;
+ re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' device-id='(?P<deviceid>[^']+)' device-type='(?P<devicetype>[^']+)'", 0, 0, &error);
+ if (re == NULL) {
+ g_warning (error->message);
+ goto out;
+ }
+
+ g_regex_match (re, s, 0, &match_info);
+
+ res = g_match_info_matches (match_info);
+ if (! res) {
+ g_warning ("Unable to parse device added event: %s", s);
+ goto out;
+ }
+
+ e = (CkLogSeatDeviceAddedEvent *)event;
+ e->seat_id = g_match_info_fetch_named (match_info, "seatid");
+ e->device_id = g_match_info_fetch_named (match_info, "deviceid");
+ e->device_type = g_match_info_fetch_named (match_info, "devicetype");
+
+ ret = TRUE;
+ out:
+ if (match_info != NULL) {
+ g_match_info_free (match_info);
+ }
+ if (re != NULL) {
+ g_regex_unref (re);
+ }
+
+ return ret;
+}
+
+static gboolean
+parse_log_for_seat_device_removed (const GString *str,
+ CkLogEvent *event)
+{
+ gboolean ret;
+ const char *s;
+ GRegex *re;
+ GMatchInfo *match_info;
+ gboolean res;
+ GError *error;
+ CkLogSeatDeviceRemovedEvent *e;
+
+ re = NULL;
+ match_info = NULL;
+ ret = FALSE;
+
+ s = skip_header (str->str, str->len);
+ if (s == NULL) {
+ goto out;
+ }
+
+ error = NULL;
+ re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' device-id='(?P<deviceid>[^']+)' device-type='(?P<devicetype>[^']+)'", 0, 0, &error);
+ if (re == NULL) {
+ g_warning (error->message);
+ goto out;
+ }
+
+ g_regex_match (re, s, 0, &match_info);
+
+ res = g_match_info_matches (match_info);
+ if (! res) {
+ g_warning ("Unable to parse device removed event: %s", s);
+ goto out;
+ }
+
+ e = (CkLogSeatDeviceRemovedEvent *)event;
+ e->seat_id = g_match_info_fetch_named (match_info, "seatid");
+ e->device_id = g_match_info_fetch_named (match_info, "deviceid");
+ e->device_type = g_match_info_fetch_named (match_info, "devicetype");
+
+ ret = TRUE;
+ out:
+ if (match_info != NULL) {
+ g_match_info_free (match_info);
+ }
+ if (re != NULL) {
+ g_regex_unref (re);
+ }
+
+ return ret;
+}
+
+static gboolean
+parse_log_for_any (const GString *str,
+ CkLogEvent *event)
+{
+ gboolean ret;
+ int res;
+ gulong sec;
+ guint frac;
+ char buf[32];
+
+ ret = FALSE;
+
+ res = sscanf (str->str, "%lu.%u type=%30s :",
+ &sec,
+ &frac,
+ buf);
+ if (res == 3) {
+ res = event_name_to_type (buf, &event->type);
+ if (! res) {
+ goto out;
+ }
+
+ event->timestamp.tv_sec = sec;
+ event->timestamp.tv_usec = 1000 * frac;
+
+ ret = TRUE;
+ }
+ out:
+ return ret;
+}
+
+gboolean
+ck_log_event_fill_from_string (CkLogEvent *event,
+ const GString *str)
+{
+ gboolean res;
+ gboolean ret;
+
+ g_return_val_if_fail (str != NULL, FALSE);
+
+ ret = FALSE;
+
+ res = parse_log_for_any (str, event);
+ if (! res) {
+ goto out;
+ }
+
+ switch (event->type) {
+ case CK_LOG_EVENT_SEAT_ADDED:
+ res = parse_log_for_seat_added (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_REMOVED:
+ res = parse_log_for_seat_removed (str, event);
+ break;
+ case CK_LOG_EVENT_SYSTEM_STOP:
+ res = parse_log_for_system_stop (str, event);
+ break;
+ case CK_LOG_EVENT_SYSTEM_RESTART:
+ res = parse_log_for_system_restart (str, event);
+ break;
+ case CK_LOG_EVENT_SYSTEM_START:
+ res = parse_log_for_system_start (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_SESSION_ADDED:
+ res = parse_log_for_seat_session_added (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_SESSION_REMOVED:
+ res = parse_log_for_seat_session_removed (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_DEVICE_ADDED:
+ res = parse_log_for_seat_device_added (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_DEVICE_REMOVED:
+ res = parse_log_for_seat_device_removed (str, event);
+ break;
+ case CK_LOG_EVENT_SEAT_ACTIVE_SESSION_CHANGED:
+ res = parse_log_for_seat_active_session_changed (str, event);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ if (! res) {
+ goto out;
+ }
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+CkLogEvent *
+ck_log_event_new_from_string (const GString *str)
+{
+ CkLogEvent *event;
+ gboolean res;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ event = g_new0 (CkLogEvent, 1);
+ res = ck_log_event_fill_from_string (event, str);
+ if (! res) {
+ g_free (event);
+ event = NULL;
+ }
+
+ return event;
+}
diff --git a/src/ck-log-event.h b/src/ck-log-event.h
new file mode 100644
index 0000000..149f49b
--- /dev/null
+++ b/src/ck-log-event.h
@@ -0,0 +1,148 @@
+/* -*- 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_LOG_EVENT_H
+#define __CK_LOG_EVENT_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ CK_LOG_EVENT_START = 0,
+ CK_LOG_EVENT_STOP,
+ CK_LOG_EVENT_SYSTEM_START,
+ CK_LOG_EVENT_SYSTEM_STOP,
+ CK_LOG_EVENT_SYSTEM_RESTART,
+ CK_LOG_EVENT_SYSTEM_RUNLEVEL_CHANGED,
+ CK_LOG_EVENT_SEAT_ADDED,
+ CK_LOG_EVENT_SEAT_REMOVED,
+ CK_LOG_EVENT_SEAT_SESSION_ADDED,
+ CK_LOG_EVENT_SEAT_SESSION_REMOVED,
+ CK_LOG_EVENT_SEAT_DEVICE_ADDED,
+ CK_LOG_EVENT_SEAT_DEVICE_REMOVED,
+ CK_LOG_EVENT_SEAT_ACTIVE_SESSION_CHANGED,
+} CkLogEventType;
+
+typedef struct
+{
+} CkLogSystemStopEvent;
+
+typedef struct
+{
+} CkLogSystemRestartEvent;
+
+typedef struct
+{
+} CkLogSystemStartEvent;
+
+typedef struct
+{
+ char *seat_id;
+ int seat_kind;
+} CkLogSeatAddedEvent;
+
+typedef struct
+{
+ char *seat_id;
+ int seat_kind;
+} CkLogSeatRemovedEvent;
+
+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;
+} CkLogSeatSessionAddedEvent;
+
+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;
+} CkLogSeatSessionRemovedEvent;
+
+typedef struct
+{
+ char *seat_id;
+ char *session_id;
+} CkLogSeatActiveSessionChangedEvent;
+
+typedef struct
+{
+ char *seat_id;
+ char *device_type;
+ char *device_id;
+} CkLogSeatDeviceAddedEvent;
+
+typedef struct
+{
+ char *seat_id;
+ char *device_type;
+ char *device_id;
+} CkLogSeatDeviceRemovedEvent;
+
+typedef struct
+{
+ union {
+ CkLogSystemRestartEvent system_start;
+ CkLogSystemStopEvent system_stop;
+ CkLogSystemRestartEvent system_restart;
+ CkLogSeatAddedEvent seat_added;
+ CkLogSeatRemovedEvent seat_removed;
+ CkLogSeatSessionAddedEvent seat_session_added;
+ CkLogSeatSessionRemovedEvent seat_session_removed;
+ CkLogSeatActiveSessionChangedEvent seat_active_session_changed;
+ CkLogSeatDeviceAddedEvent seat_device_added;
+ CkLogSeatDeviceRemovedEvent seat_device_removed;
+ } event;
+
+ GTimeVal timestamp;
+ CkLogEventType type;
+} CkLogEvent;
+
+CkLogEvent * ck_log_event_copy (CkLogEvent *event);
+void ck_log_event_free (CkLogEvent *event);
+
+CkLogEvent * ck_log_event_new_from_string (const GString *str);
+gboolean ck_log_event_fill_from_string (CkLogEvent *event,
+ const GString *str);
+
+void ck_log_event_to_string (CkLogEvent *event,
+ GString *str);
+
+G_END_DECLS
+
+#endif /* __CK_LOG_EVENT_H */
diff --git a/src/ck-manager-glue.h b/src/ck-manager-glue.h
index 0def872..b82aabc 100644
--- a/src/ck-manager-glue.h
+++ b/src/ck-manager-glue.h
@@ -53,7 +53,7 @@ G_BEGIN_DECLS
#endif /* !G_ENABLE_DEBUG */
-/* BOOLEAN:POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.2JLIYT:1) */
+/* BOOLEAN:POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.D3GI6T:1) */
extern void dbus_glib_marshal_ck_manager_BOOLEAN__POINTER_POINTER (GClosure *closure,
GValue *return_value,
guint n_param_values,
@@ -62,10 +62,10 @@ extern void dbus_glib_marshal_ck_manager_BOOLEAN__POINTER_POINTER (GClosure
gpointer marshal_data);
void
dbus_glib_marshal_ck_manager_BOOLEAN__POINTER_POINTER (GClosure *closure,
- GValue *return_value,
+ GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
- gpointer invocation_hint,
+ gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_POINTER) (gpointer data1,
@@ -100,11 +100,11 @@ dbus_glib_marshal_ck_manager_BOOLEAN__POINTER_POINTER (GClosure *closure,
g_value_set_boolean (return_value, v_return);
}
-/* NONE:UINT,POINTER (/tmp/dbus-binding-tool-c-marshallers.2JLIYT:2) */
+/* NONE:UINT,POINTER (/tmp/dbus-binding-tool-c-marshallers.D3GI6T:2) */
#define dbus_glib_marshal_ck_manager_VOID__UINT_POINTER g_cclosure_marshal_VOID__UINT_POINTER
#define dbus_glib_marshal_ck_manager_NONE__UINT_POINTER dbus_glib_marshal_ck_manager_VOID__UINT_POINTER
-/* NONE:STRING,POINTER (/tmp/dbus-binding-tool-c-marshallers.2JLIYT:3) */
+/* NONE:STRING,POINTER (/tmp/dbus-binding-tool-c-marshallers.D3GI6T:3) */
extern void dbus_glib_marshal_ck_manager_VOID__STRING_POINTER (GClosure *closure,
GValue *return_value,
guint n_param_values,
@@ -113,10 +113,10 @@ extern void dbus_glib_marshal_ck_manager_VOID__STRING_POINTER (GClosure *clo
gpointer marshal_data);
void
dbus_glib_marshal_ck_manager_VOID__STRING_POINTER (GClosure *closure,
- GValue *return_value,
+ GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
- gpointer invocation_hint,
+ gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef void (*GMarshalFunc_VOID__STRING_POINTER) (gpointer data1,
@@ -148,11 +148,11 @@ dbus_glib_marshal_ck_manager_VOID__STRING_POINTER (GClosure *closure,
}
#define dbus_glib_marshal_ck_manager_NONE__STRING_POINTER dbus_glib_marshal_ck_manager_VOID__STRING_POINTER
-/* NONE:POINTER (/tmp/dbus-binding-tool-c-marshallers.2JLIYT:4) */
+/* NONE:POINTER (/tmp/dbus-binding-tool-c-marshallers.D3GI6T:4) */
#define dbus_glib_marshal_ck_manager_VOID__POINTER g_cclosure_marshal_VOID__POINTER
#define dbus_glib_marshal_ck_manager_NONE__POINTER dbus_glib_marshal_ck_manager_VOID__POINTER
-/* NONE:BOXED,POINTER (/tmp/dbus-binding-tool-c-marshallers.2JLIYT:5) */
+/* NONE:BOXED,POINTER (/tmp/dbus-binding-tool-c-marshallers.D3GI6T:5) */
extern void dbus_glib_marshal_ck_manager_VOID__BOXED_POINTER (GClosure *closure,
GValue *return_value,
guint n_param_values,
@@ -161,10 +161,10 @@ extern void dbus_glib_marshal_ck_manager_VOID__BOXED_POINTER (GClosure *clos
gpointer marshal_data);
void
dbus_glib_marshal_ck_manager_VOID__BOXED_POINTER (GClosure *closure,
- GValue *return_value,
+ GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
- gpointer invocation_hint,
+ gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef void (*GMarshalFunc_VOID__BOXED_POINTER) (gpointer data1,
@@ -202,24 +202,27 @@ G_END_DECLS
#include <dbus/dbus-glib.h>
static const DBusGMethodInfo dbus_glib_ck_manager_methods[] = {
- { (GCallback) ck_manager_open_session, dbus_glib_marshal_ck_manager_NONE__POINTER, 0 },
- { (GCallback) ck_manager_open_session_with_parameters, dbus_glib_marshal_ck_manager_NONE__BOXED_POINTER, 65 },
- { (GCallback) ck_manager_close_session, dbus_glib_marshal_ck_manager_NONE__STRING_POINTER, 163 },
- { (GCallback) ck_manager_get_seats, dbus_glib_marshal_ck_manager_BOOLEAN__POINTER_POINTER, 240 },
- { (GCallback) ck_manager_get_session_for_cookie, dbus_glib_marshal_ck_manager_NONE__STRING_POINTER, 302 },
- { (GCallback) ck_manager_get_session_for_unix_process, dbus_glib_marshal_ck_manager_NONE__UINT_POINTER, 384 },
- { (GCallback) ck_manager_get_current_session, dbus_glib_marshal_ck_manager_NONE__POINTER, 468 },
- { (GCallback) ck_manager_get_sessions_for_unix_user, dbus_glib_marshal_ck_manager_NONE__UINT_POINTER, 537 },
- { (GCallback) ck_manager_get_sessions_for_user, dbus_glib_marshal_ck_manager_NONE__UINT_POINTER, 624 },
- { (GCallback) ck_manager_get_system_idle_hint, dbus_glib_marshal_ck_manager_BOOLEAN__POINTER_POINTER, 707 },
- { (GCallback) ck_manager_get_system_idle_since_hint, dbus_glib_marshal_ck_manager_BOOLEAN__POINTER_POINTER, 781 },
+ { (GCallback) ck_manager_restart, dbus_glib_marshal_ck_manager_NONE__POINTER, 0 },
+ { (GCallback) ck_manager_stop, dbus_glib_marshal_ck_manager_NONE__POINTER, 46 },
+ { (GCallback) ck_manager_open_session, dbus_glib_marshal_ck_manager_NONE__POINTER, 89 },
+ { (GCallback) ck_manager_open_session_with_parameters, dbus_glib_marshal_ck_manager_NONE__BOXED_POINTER, 154 },
+ { (GCallback) ck_manager_close_session, dbus_glib_marshal_ck_manager_NONE__STRING_POINTER, 252 },
+ { (GCallback) ck_manager_get_seats, dbus_glib_marshal_ck_manager_BOOLEAN__POINTER_POINTER, 329 },
+ { (GCallback) ck_manager_get_sessions, dbus_glib_marshal_ck_manager_BOOLEAN__POINTER_POINTER, 391 },
+ { (GCallback) ck_manager_get_session_for_cookie, dbus_glib_marshal_ck_manager_NONE__STRING_POINTER, 459 },
+ { (GCallback) ck_manager_get_session_for_unix_process, dbus_glib_marshal_ck_manager_NONE__UINT_POINTER, 541 },
+ { (GCallback) ck_manager_get_current_session, dbus_glib_marshal_ck_manager_NONE__POINTER, 625 },
+ { (GCallback) ck_manager_get_sessions_for_unix_user, dbus_glib_marshal_ck_manager_NONE__UINT_POINTER, 694 },
+ { (GCallback) ck_manager_get_sessions_for_user, dbus_glib_marshal_ck_manager_NONE__UINT_POINTER, 781 },
+ { (GCallback) ck_manager_get_system_idle_hint, dbus_glib_marshal_ck_manager_BOOLEAN__POINTER_POINTER, 864 },
+ { (GCallback) ck_manager_get_system_idle_since_hint, dbus_glib_marshal_ck_manager_BOOLEAN__POINTER_POINTER, 938 },
};
const DBusGObjectInfo dbus_glib_ck_manager_object_info = {
0,
dbus_glib_ck_manager_methods,
- 11,
-"org.freedesktop.ConsoleKit.Manager\0OpenSession\0A\0cookie\0O\0F\0N\0s\0\0org.freedesktop.ConsoleKit.Manager\0OpenSessionWithParameters\0A\0parameters\0I\0a(sv)\0cookie\0O\0F\0N\0s\0\0org.freedesktop.ConsoleKit.Manager\0CloseSession\0A\0cookie\0I\0s\0result\0O\0F\0N\0b\0\0org.freedesktop.ConsoleKit.Manager\0GetSeats\0S\0seats\0O\0F\0N\0ao\0\0org.freedesktop.ConsoleKit.Manager\0GetSessionForCookie\0A\0cookie\0I\0s\0ssid\0O\0F\0N\0o\0\0org.freedesktop.ConsoleKit.Manager\0GetSessionForUnixProcess\0A\0pid\0I\0u\0ssid\0O\0F\0N\0o\0\0org.freedesktop.ConsoleKit.Manager\0GetCurrentSession\0A\0ssid\0O\0F\0N\0o\0\0org.freedesktop.ConsoleKit.Manager\0GetSessionsForUnixUser\0A\0uid\0I\0u\0sessions\0O\0F\0N\0ao\0\0org.freedesktop.ConsoleKit.Manager\0GetSessionsForUser\0A\0uid\0I\0u\0sessions\0O\0F\0N\0ao\0\0org.freedesktop.ConsoleKit.Manager\0GetSystemIdleHint\0S\0idle_hint\0O\0F\0N\0b\0\0org.freedesktop.ConsoleKit.Manager\0GetSystemIdleSinceHint\0S\0iso8601_datetime\0O\0F\0N\0s\0\0\0",
+ 14,
+"org.freedesktop.ConsoleKit.Manager\0Restart\0A\0\0org.freedesktop.ConsoleKit.Manager\0Stop\0A\0\0org.freedesktop.ConsoleKit.Manager\0OpenSession\0A\0cookie\0O\0F\0N\0s\0\0org.freedesktop.ConsoleKit.Manager\0OpenSessionWithParameters\0A\0parameters\0I\0a(sv)\0cookie\0O\0F\0N\0s\0\0org.freedesktop.ConsoleKit.Manager\0CloseSession\0A\0cookie\0I\0s\0result\0O\0F\0N\0b\0\0org.freedesktop.ConsoleKit.Manager\0GetSeats\0S\0seats\0O\0F\0N\0ao\0\0org.freedesktop.ConsoleKit.Manager\0GetSessions\0S\0sessions\0O\0F\0N\0ao\0\0org.freedesktop.ConsoleKit.Manager\0GetSessionForCookie\0A\0cookie\0I\0s\0ssid\0O\0F\0N\0o\0\0org.freedesktop.ConsoleKit.Manager\0GetSessionForUnixProcess\0A\0pid\0I\0u\0ssid\0O\0F\0N\0o\0\0org.freedesktop.ConsoleKit.Manager\0GetCurrentSession\0A\0ssid\0O\0F\0N\0o\0\0org.freedesktop.ConsoleKit.Manager\0GetSessionsForUnixUser\0A\0uid\0I\0u\0sessions\0O\0F\0N\0ao\0\0org.freedesktop.ConsoleKit.Manager\0GetSessionsForUser\0A\0uid\0I\0u\0sessions\0O\0F\0N\0ao\0\0org.freedesktop.ConsoleKit.Manager\0GetSystemIdleHint\0S\0idle_hint\0O\0F\0N\0b\0\0org.freedesktop.ConsoleKit.Manager\0GetSystemIdleSinceHint\0S\0iso8601_datetime\0O\0F\0N\0s\0\0\0",
"org.freedesktop.ConsoleKit.Manager\0SeatAdded\0org.freedesktop.ConsoleKit.Manager\0SeatRemoved\0org.freedesktop.ConsoleKit.Manager\0SystemIdleHintChanged\0\0",
"\0"
};
diff --git a/src/ck-manager.c b/src/ck-manager.c
index 377cef0..bf4926f 100644
--- a/src/ck-manager.c
+++ b/src/ck-manager.c
@@ -28,45 +28,57 @@
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <errno.h>
+#include <pwd.h>
#include <glib.h>
#include <glib/gi18n.h>
+#include <glib/gstdio.h>
#include <glib-object.h>
#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
+#ifdef HAVE_POLKIT
+#include <polkit/polkit.h>
+#endif
+
+#ifdef ENABLE_RBAC_SHUTDOWN
+#include <auth_attr.h>
+#include <secdb.h>
+#endif
+
#include "ck-manager.h"
#include "ck-manager-glue.h"
#include "ck-seat.h"
+#include "ck-session-leader.h"
#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 "/log/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"
-#define CK_TYPE_PARAMETER_STRUCT (dbus_g_type_get_struct ("GValueArray", \
- G_TYPE_STRING, \
- G_TYPE_VALUE, \
- G_TYPE_INVALID))
-#define CK_TYPE_PARAMETER_LIST (dbus_g_type_get_collection ("GPtrArray", \
- CK_TYPE_PARAMETER_STRUCT))
struct CkManagerPrivate
{
+#ifdef HAVE_POLKIT
+ PolKitContext *pol_ctx;
+#endif
+
GHashTable *seats;
GHashTable *sessions;
GHashTable *leaders;
DBusGProxy *bus_proxy;
DBusGConnection *connection;
+ CkEventLogger *logger;
guint32 session_serial;
guint32 seat_serial;
@@ -75,18 +87,6 @@ struct CkManagerPrivate
GTimeVal system_idle_since_hint;
};
-
-typedef struct {
- int refcount;
- gboolean cancelled;
- uid_t uid;
- pid_t pid;
- char *service_name;
- char *ssid;
- char *cookie;
- GList *pending_jobs;
-} LeaderInfo;
-
enum {
SEAT_ADDED,
SEAT_REMOVED,
@@ -105,64 +105,136 @@ static gpointer manager_object = NULL;
G_DEFINE_TYPE (CkManager, ck_manager, G_TYPE_OBJECT)
static void
-remove_pending_job (CkJob *job)
+dump_state_seat_iter (char *id,
+ CkSeat *seat,
+ GKeyFile *key_file)
{
- if (job != NULL) {
- char *command;
-
- command = NULL;
- ck_job_get_command (job, &command);
- g_debug ("Removing pending job: %s", command);
- g_free (command);
-
- ck_job_cancel (job);
- g_object_unref (job);
- }
+ ck_seat_dump (seat, key_file);
}
static void
-_leader_info_free (LeaderInfo *info)
+dump_state_session_iter (char *id,
+ CkSession *session,
+ GKeyFile *key_file)
{
- g_debug ("Freeing leader info: %s", info->ssid);
-
- g_free (info->ssid);
- info->ssid = NULL;
- g_free (info->cookie);
- info->cookie = NULL;
- g_free (info->service_name);
- info->service_name = NULL;
-
- g_free (info);
+ ck_session_dump (session, key_file);
}
static void
-leader_info_cancel (LeaderInfo *info)
+dump_state_leader_iter (char *id,
+ CkSessionLeader *leader,
+ GKeyFile *key_file)
{
- if (info->pending_jobs != NULL) {
- g_list_foreach (info->pending_jobs, (GFunc)remove_pending_job, NULL);
- g_list_free (info->pending_jobs);
- info->pending_jobs = NULL;
+ ck_session_leader_dump (leader, key_file);
+}
+
+static gboolean
+do_dump (CkManager *manager,
+ int fd)
+{
+ char *str;
+ gsize str_len;
+ GKeyFile *key_file;
+ GError *error;
+ gboolean ret;
+
+ str = NULL;
+ error = NULL;
+ ret = FALSE;
+
+ key_file = g_key_file_new ();
+
+ g_hash_table_foreach (manager->priv->seats, (GHFunc) dump_state_seat_iter, key_file);
+ g_hash_table_foreach (manager->priv->sessions, (GHFunc) dump_state_session_iter, key_file);
+ g_hash_table_foreach (manager->priv->leaders, (GHFunc) dump_state_leader_iter, key_file);
+
+ str = g_key_file_to_data (key_file, &str_len, &error);
+ g_key_file_free (key_file);
+ if (str != NULL) {
+ ssize_t written;
+
+ written = 0;
+ while (written < str_len) {
+ ssize_t ret;
+ ret = write (fd, str + written, str_len - written);
+ if (ret < 0) {
+ if (errno == EAGAIN || errno == EINTR) {
+ continue;
+ } else {
+ g_warning ("Error writing state file: %s", strerror (errno));
+ goto out;
+ }
+ }
+ written += ret;
+ }
+ } else {
+ g_warning ("Couldn't construct state file: %s", error->message);
+ g_error_free (error);
}
- info->cancelled = TRUE;
+ ret = TRUE;
+
+out:
+ g_free (str);
+ return ret;
}
static void
-leader_info_unref (LeaderInfo *info)
+ck_manager_dump (CkManager *manager)
{
- /* Probably should use some kind of atomic op here */
- info->refcount -= 1;
- if (info->refcount == 0) {
- _leader_info_free (info);
+ int fd;
+ int res;
+ const char *filename = LOCALSTATEDIR "/run/ConsoleKit/database";
+ const char *filename_tmp = LOCALSTATEDIR "/run/ConsoleKit/database~";
+
+ if (manager == NULL) {
+ return;
}
-}
-static LeaderInfo *
-leader_info_ref (LeaderInfo *info)
-{
- info->refcount += 1;
+ /* always make sure we have a directory */
+ errno = 0;
+ res = g_mkdir_with_parents (LOCALSTATEDIR "/run/ConsoleKit",
+ S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ if (res < 0) {
+ g_warning ("Unable to create directory %s (%s)",
+ LOCALSTATEDIR "/run/ConsoleKit",
+ g_strerror (errno));
+ return;
+ }
+
+ fd = g_open (filename_tmp, O_CREAT | O_WRONLY, 0600);
+ if (fd == -1) {
+ g_warning ("Cannot create file %s: %s", filename_tmp, g_strerror (errno));
+ goto error;
+ }
+
+ if (! do_dump (manager, fd)) {
+ g_warning ("Cannot write to file %s", filename_tmp);
+ close (fd);
+ goto error;
+ }
+ again:
+ if (close (fd) != 0) {
+ if (errno == EINTR)
+ goto again;
+ else {
+ g_warning ("Cannot close fd for %s: %s", filename_tmp, g_strerror (errno));
+ goto error;
+ }
+ }
- return info;
+ if (g_rename (filename_tmp, filename) != 0) {
+ g_warning ("Cannot rename %s to %s: %s", filename_tmp, filename, g_strerror (errno));
+ goto error;
+ }
+
+ return;
+error:
+ /* For security reasons; unlink the existing file since it
+ contains outdated information */
+ if (g_unlink (filename) != 0) {
+ g_warning ("Cannot unlink %s: %s", filename, g_strerror (errno));
+ }
}
GQuark
@@ -176,6 +248,28 @@ ck_manager_error_quark (void)
return ret;
}
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+ck_manager_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (CK_MANAGER_ERROR_GENERAL, "GeneralError"),
+ ENUM_ENTRY (CK_MANAGER_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
+ { 0, 0, 0 }
+ };
+
+ g_assert (CK_MANAGER_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
+
+ etype = g_enum_register_static ("CkManagerError", values);
+ }
+
+ return etype;
+}
+
static guint32
get_next_session_serial (CkManager *manager)
{
@@ -277,6 +371,1140 @@ generate_seat_id (CkManager *manager)
return id;
}
+static const char *
+get_object_id_basename (const char *id)
+{
+ const char *base;
+
+ if (id != NULL && g_str_has_prefix (id, CK_DBUS_PATH "/")) {
+ base = id + strlen (CK_DBUS_PATH "/");
+ } else {
+ base = id;
+ }
+
+ return base;
+}
+
+static void
+log_seat_added_event (CkManager *manager,
+ CkSeat *seat)
+{
+ CkLogEvent event;
+ gboolean res;
+ GError *error;
+ char *sid;
+ CkSeatKind seat_kind;
+
+ memset (&event, 0, sizeof (CkLogEvent));
+
+ event.type = CK_LOG_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 = (char *)get_object_id_basename (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)
+{
+ CkLogEvent event;
+ gboolean res;
+ GError *error;
+ char *sid;
+ CkSeatKind seat_kind;
+
+ memset (&event, 0, sizeof (CkLogEvent));
+
+ event.type = CK_LOG_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 = (char *)get_object_id_basename (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_system_stop_event (CkManager *manager)
+{
+ CkLogEvent event;
+ gboolean res;
+ GError *error;
+
+ memset (&event, 0, sizeof (CkLogEvent));
+
+ event.type = CK_LOG_EVENT_SYSTEM_STOP;
+ g_get_current_time (&event.timestamp);
+
+ 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);
+ }
+
+ /* FIXME: in this case we should block and wait for log to flush */
+}
+
+static void
+log_system_restart_event (CkManager *manager)
+{
+ CkLogEvent event;
+ gboolean res;
+ GError *error;
+
+ memset (&event, 0, sizeof (CkLogEvent));
+
+ event.type = CK_LOG_EVENT_SYSTEM_RESTART;
+ g_get_current_time (&event.timestamp);
+
+ 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);
+ }
+
+ /* FIXME: in this case we should block and wait for log to flush */
+}
+
+static void
+log_seat_session_added_event (CkManager *manager,
+ CkSeat *seat,
+ const char *ssid)
+{
+ CkLogEvent event;
+ gboolean res;
+ GError *error;
+ char *sid;
+ CkSession *session;
+
+ memset (&event, 0, sizeof (CkLogEvent));
+
+ event.type = CK_LOG_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 = (char *)get_object_id_basename (sid);
+ event.event.seat_session_added.session_id = (char *)get_object_id_basename (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)
+{
+ CkLogEvent event;
+ gboolean res;
+ GError *error;
+ char *sid;
+ CkSession *session;
+
+ memset (&event, 0, sizeof (CkLogEvent));
+
+ event.type = CK_LOG_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 = (char *)get_object_id_basename (sid);
+ event.event.seat_session_removed.session_id = (char *)get_object_id_basename (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)
+{
+ CkLogEvent event;
+ gboolean res;
+ GError *error;
+ char *sid;
+
+ memset (&event, 0, sizeof (CkLogEvent));
+
+ event.type = CK_LOG_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 = (char *)get_object_id_basename (sid);
+ event.event.seat_active_session_changed.session_id = (char *)get_object_id_basename (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)
+{
+ CkLogEvent event;
+ gboolean res;
+ GError *error;
+ char *sid;
+ GValue val_struct = { 0, };
+ char *device_id;
+ char *device_type;
+
+ memset (&event, 0, sizeof (CkLogEvent));
+
+ event.type = CK_LOG_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 = (char *)get_object_id_basename (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)
+{
+ CkLogEvent event;
+ gboolean res;
+ GError *error;
+ char *sid;
+ GValue val_struct = { 0, };
+ char *device_id;
+ char *device_type;
+
+ memset (&event, 0, sizeof (CkLogEvent));
+
+ event.type = CK_LOG_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 = (char *)get_object_id_basename (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 char *
+get_cookie_for_pid (CkManager *manager,
+ guint pid)
+{
+ char *cookie;
+
+ /* FIXME: need a better way to get the cookie */
+
+ cookie = ck_unix_pid_get_env (pid, "XDG_SESSION_COOKIE");
+
+ return cookie;
+}
+
+static CkSession *
+get_session_for_unix_process (CkManager *manager,
+ guint pid)
+{
+ CkSessionLeader *leader;
+ CkSession *session;
+ char *cookie;
+
+ session = NULL;
+ leader = NULL;
+
+ cookie = get_cookie_for_pid (manager, pid);
+ if (cookie == NULL) {
+ goto out;
+ }
+
+ leader = g_hash_table_lookup (manager->priv->leaders, cookie);
+ if (leader == NULL) {
+ goto out;
+ }
+
+ session = g_hash_table_lookup (manager->priv->sessions, ck_session_leader_peek_session_id (leader));
+
+ out:
+ g_free (cookie);
+
+ return session;
+}
+
+#ifdef HAVE_POLKIT
+static PolKitSession *
+new_polkit_session_from_session (CkManager *manager,
+ CkSession *ck_session)
+{
+ PolKitSession *pk_session;
+ PolKitSeat *pk_seat;
+ uid_t uid;
+ gboolean is_active;
+ gboolean is_local;
+ char *sid;
+ char *ssid;
+ char *remote_host;
+
+ sid = NULL;
+ ssid = NULL;
+ remote_host = NULL;
+
+ ck_session_get_seat_id (ck_session, &sid, NULL);
+
+ g_object_get (ck_session,
+ "active", &is_active,
+ "is-local", &is_local,
+ "id", &ssid,
+ "unix-user", &uid,
+ "remote-host-name", &remote_host,
+ NULL);
+
+ pk_session = polkit_session_new ();
+ if (pk_session == NULL) {
+ goto out;
+ }
+ if (!polkit_session_set_uid (pk_session, uid)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!polkit_session_set_ck_objref (pk_session, ssid)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!polkit_session_set_ck_is_active (pk_session, is_active)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!polkit_session_set_ck_is_local (pk_session, is_local)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!is_local) {
+ if (!polkit_session_set_ck_remote_host (pk_session, remote_host)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+
+ }
+
+
+ pk_seat = polkit_seat_new ();
+ if (pk_seat == NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!polkit_seat_set_ck_objref (pk_seat, sid)) {
+ polkit_seat_unref (pk_seat);
+ pk_seat = NULL;
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ if (!polkit_seat_validate (pk_seat)) {
+ polkit_seat_unref (pk_seat);
+ pk_seat = NULL;
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+
+ if (!polkit_session_set_seat (pk_session, pk_seat)) {
+ polkit_seat_unref (pk_seat);
+ pk_seat = NULL;
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+ polkit_seat_unref (pk_seat); /* session object now owns this object */
+ pk_seat = NULL;
+
+ if (!polkit_session_validate (pk_session)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+
+out:
+ g_free (ssid);
+ g_free (sid);
+ g_free (remote_host);
+
+ return pk_session;
+}
+
+static PolKitCaller *
+new_polkit_caller_from_dbus_name (CkManager *manager,
+ const char *dbus_name)
+{
+ PolKitCaller *caller;
+ pid_t pid;
+ uid_t uid;
+ char *selinux_context;
+ PolKitSession *pk_session;
+ DBusMessage *message;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter sub_iter;
+ char *str;
+ int num_elems;
+ DBusConnection *con;
+ DBusError error;
+ CkSession *ck_session;
+
+ dbus_error_init (&error);
+
+ con = dbus_g_connection_get_connection (manager->priv->connection);
+
+ g_return_val_if_fail (con != NULL, NULL);
+ g_return_val_if_fail (dbus_name != NULL, NULL);
+
+ selinux_context = NULL;
+
+ caller = NULL;
+ ck_session = NULL;
+ pk_session = NULL;
+
+ uid = dbus_bus_get_unix_user (con, dbus_name, &error);
+ if (dbus_error_is_set (&error)) {
+ g_warning ("Could not get uid for connection: %s %s",
+ error.name,
+ error.message);
+ dbus_error_free (&error);
+ goto out;
+ }
+
+ message = dbus_message_new_method_call ("org.freedesktop.DBus",
+ "/org/freedesktop/DBus/Bus",
+ "org.freedesktop.DBus",
+ "GetConnectionUnixProcessID");
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &dbus_name);
+ reply = dbus_connection_send_with_reply_and_block (con, message, -1, &error);
+
+ if (reply == NULL || dbus_error_is_set (&error)) {
+ g_warning ("Error doing GetConnectionUnixProcessID on Bus: %s: %s",
+ error.name,
+ error.message);
+ dbus_message_unref (message);
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+ dbus_error_free (&error);
+ goto out;
+ }
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_get_basic (&iter, &pid);
+ dbus_message_unref (message);
+ dbus_message_unref (reply);
+
+ message = dbus_message_new_method_call ("org.freedesktop.DBus",
+ "/org/freedesktop/DBus/Bus",
+ "org.freedesktop.DBus",
+ "GetConnectionSELinuxSecurityContext");
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &dbus_name);
+ reply = dbus_connection_send_with_reply_and_block (con, message, -1, &error);
+ /* SELinux might not be enabled */
+ if (dbus_error_is_set (&error) &&
+ strcmp (error.name, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown") == 0) {
+ dbus_message_unref (message);
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+ dbus_error_init (&error);
+ } else if (reply == NULL || dbus_error_is_set (&error)) {
+ g_warning ("Error doing GetConnectionSELinuxSecurityContext on Bus: %s: %s", error.name, error.message);
+ dbus_message_unref (message);
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+ goto out;
+ } else {
+ /* TODO: verify signature */
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_recurse (&iter, &sub_iter);
+ dbus_message_iter_get_fixed_array (&sub_iter, (void *) &str, &num_elems);
+ if (str != NULL && num_elems > 0) {
+ selinux_context = g_strndup (str, num_elems);
+ }
+ dbus_message_unref (message);
+ dbus_message_unref (reply);
+ }
+
+ ck_session = get_session_for_unix_process (manager, pid);
+ if (ck_session == NULL) {
+ /* OK, this is not a catastrophe; just means the caller is not a
+ * member of any session or that ConsoleKit is not available..
+ */
+ goto not_in_session;
+ }
+
+ pk_session = new_polkit_session_from_session (manager, ck_session);
+ if (pk_session == NULL) {
+ g_warning ("Got a session but couldn't construct polkit session object!");
+ goto out;
+ }
+ if (!polkit_session_validate (pk_session)) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ goto out;
+ }
+
+not_in_session:
+
+ caller = polkit_caller_new ();
+ if (caller == NULL) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ goto out;
+ }
+
+ if (!polkit_caller_set_dbus_name (caller, dbus_name)) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+ if (!polkit_caller_set_uid (caller, uid)) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+ if (!polkit_caller_set_pid (caller, pid)) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+ if (selinux_context != NULL) {
+ if (!polkit_caller_set_selinux_context (caller, selinux_context)) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+ }
+ if (pk_session != NULL) {
+ if (!polkit_caller_set_ck_session (caller, pk_session)) {
+ if (pk_session != NULL) {
+ polkit_session_unref (pk_session);
+ pk_session = NULL;
+ }
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+ polkit_session_unref (pk_session); /* caller object now own this object */
+ pk_session = NULL;
+ }
+
+ if (!polkit_caller_validate (caller)) {
+ polkit_caller_unref (caller);
+ caller = NULL;
+ goto out;
+ }
+
+out:
+ g_free (selinux_context);
+
+ return caller;
+}
+
+static gboolean
+_check_polkit_for_action (CkManager *manager,
+ DBusGMethodInvocation *context,
+ const char *action)
+{
+ const char *sender;
+ GError *error;
+ DBusError dbus_error;
+ PolKitCaller *pk_caller;
+ PolKitAction *pk_action;
+ PolKitResult pk_result;
+
+ error = NULL;
+
+ g_debug ("constructing polkit data");
+
+ /* Check that caller is privileged */
+ sender = dbus_g_method_get_sender (context);
+ dbus_error_init (&dbus_error);
+
+ pk_caller = new_polkit_caller_from_dbus_name (manager, sender);
+ if (pk_caller == NULL) {
+ error = g_error_new (CK_MANAGER_ERROR,
+ CK_MANAGER_ERROR_GENERAL,
+ "Error getting information about caller: %s: %s",
+ dbus_error.name,
+ dbus_error.message);
+ dbus_error_free (&dbus_error);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ pk_action = polkit_action_new ();
+ polkit_action_set_action_id (pk_action, action);
+
+ g_debug ("checking if caller %s is authorized", sender);
+
+ /* this version crashes if error is used */
+ pk_result = polkit_context_is_caller_authorized (manager->priv->pol_ctx,
+ pk_action,
+ pk_caller,
+ TRUE,
+ NULL);
+ g_debug ("answer is: %s", (pk_result == POLKIT_RESULT_YES) ? "yes" : "no");
+
+ polkit_caller_unref (pk_caller);
+ polkit_action_unref (pk_action);
+
+ if (pk_result != POLKIT_RESULT_YES) {
+ error = g_error_new (CK_MANAGER_ERROR,
+ CK_MANAGER_ERROR_NOT_PRIVILEGED,
+ "Not privileged for action: %s",
+ action);
+ dbus_error_free (&dbus_error);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif
+
+/* adapted from PolicyKit */
+static gboolean
+get_caller_info (CkManager *manager,
+ const char *sender,
+ uid_t *calling_uid,
+ pid_t *calling_pid)
+{
+ gboolean res;
+ GError *error = NULL;
+
+ res = FALSE;
+
+ if (sender == NULL) {
+ goto out;
+ }
+
+ if (! dbus_g_proxy_call (manager->priv->bus_proxy, "GetConnectionUnixUser", &error,
+ G_TYPE_STRING, sender,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, calling_uid,
+ G_TYPE_INVALID)) {
+ g_debug ("GetConnectionUnixUser() failed: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ if (! dbus_g_proxy_call (manager->priv->bus_proxy, "GetConnectionUnixProcessID", &error,
+ G_TYPE_STRING, sender,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, calling_pid,
+ G_TYPE_INVALID)) {
+ g_debug ("GetConnectionUnixProcessID() failed: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ res = TRUE;
+
+ g_debug ("uid = %d", *calling_uid);
+ g_debug ("pid = %d", *calling_pid);
+
+out:
+ return res;
+}
+
+static char *
+get_user_name (uid_t uid)
+{
+ struct passwd *pwent;
+ char *name;
+
+ name = NULL;
+
+ pwent = getpwuid (uid);
+
+ if (pwent != NULL) {
+ name = g_strdup (pwent->pw_name);
+ }
+
+ return name;
+}
+
+static gboolean
+session_is_real_user (CkSession *session,
+ char **userp)
+{
+ int uid;
+ char *username;
+ char *session_type;
+ gboolean ret;
+
+ ret = FALSE;
+ session_type = NULL;
+ username = NULL;
+
+ session_type = NULL;
+
+ g_object_get (session,
+ "unix-user", &uid,
+ "session-type", session_type,
+ NULL);
+
+ username = get_user_name (uid);
+
+ /* filter out GDM user */
+ if (username != NULL && strcmp (username, "gdm") == 0) {
+ ret = FALSE;
+ goto out;
+ }
+
+ if (userp != NULL) {
+ *userp = g_strdup (username);
+ }
+
+ ret = TRUE;
+
+ out:
+ g_free (username);
+ g_free (session_type);
+
+ return ret;
+}
+
+static void
+collect_users (const char *ssid,
+ CkSession *session,
+ GHashTable *hash)
+{
+ char *username;
+
+ if (session_is_real_user (session, &username)) {
+ if (username != NULL) {
+ g_hash_table_insert (hash, username, NULL);
+ }
+ }
+}
+
+static guint
+get_system_num_users (CkManager *manager)
+{
+ guint num_users;
+ GHashTable *hash;
+
+ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ g_hash_table_foreach (manager->priv->sessions, (GHFunc)collect_users, hash);
+
+ num_users = g_hash_table_size (hash);
+
+ g_hash_table_destroy (hash);
+
+ g_debug ("found %u unique users", num_users);
+
+ return num_users;
+}
+
+#ifdef ENABLE_RBAC_SHUTDOWN
+static gboolean
+check_rbac_permissions (CkManager *manager,
+ DBusGMethodInvocation *context)
+{
+ const char *sender;
+ char *username;
+ gboolean res;
+ uid_t uid;
+ pid_t pid;
+
+ username = NULL;
+ sender = dbus_g_method_get_sender (context);
+ res = get_caller_info (manager,
+ sender,
+ &uid,
+ &pid);
+ if (!res) {
+ goto out;
+ }
+
+ username = get_user_name (uid);
+
+ if (username == NULL ||
+ !chkauthattr (RBAC_SHUTDOWN_KEY, username)) {
+ res = FALSE;
+ goto out;
+ }
+
+out:
+
+ if (res == TRUE) {
+ g_debug ("User %s has RBAC permission to stop/restart", username);
+ } else {
+ g_debug ("User %s does not have RBAC permission to stop/restart", username);
+ }
+
+ g_free (username);
+ return res;
+}
+#endif
+
+/*
+ Example:
+ dbus-send --system --dest=org.freedesktop.ConsoleKit \
+ --type=method_call --print-reply --reply-timeout=2000 \
+ /org/freedesktop/ConsoleKit/Manager \
+ org.freedesktop.ConsoleKit.Manager.Restart
+*/
+gboolean
+ck_manager_restart (CkManager *manager,
+ DBusGMethodInvocation *context)
+{
+ gboolean ret;
+ gboolean res;
+ const char *action;
+ GError *error;
+
+ ret = FALSE;
+
+ if (get_system_num_users (manager) > 1) {
+ action = "org.freedesktop.consolekit.system.restart-multiple-users";
+ } else {
+ action = "org.freedesktop.consolekit.system.restart";
+ }
+
+ g_debug ("ConsoleKit Restart: %s", action);
+
+#ifdef HAVE_POLKIT
+ res = _check_polkit_for_action (manager, context, action);
+ if (! res) {
+ goto out;
+ }
+#endif
+
+#ifdef ENABLE_RBAC_SHUTDOWN
+ if (! check_rbac_permissions (manager, context)) {
+ goto out;
+ }
+#endif
+
+ g_debug ("ConsoleKit preforming Restart: %s", action);
+
+ log_system_restart_event (manager);
+
+ error = NULL;
+ res = g_spawn_command_line_async (LIBDIR "/ConsoleKit/scripts/ck-system-restart",
+ &error);
+ if (! res) {
+ GError *new_error;
+
+ g_warning ("Unable to restart system: %s", error->message);
+
+ new_error = g_error_new (CK_MANAGER_ERROR,
+ CK_MANAGER_ERROR_GENERAL,
+ "Unable to restart system: %s", error->message);
+ dbus_g_method_return_error (context, new_error);
+ g_error_free (new_error);
+
+ g_error_free (error);
+ } else {
+ ret = TRUE;
+ dbus_g_method_return (context);
+ }
+
+ out:
+
+ return ret;
+}
+
+gboolean
+ck_manager_stop (CkManager *manager,
+ DBusGMethodInvocation *context)
+{
+ gboolean ret;
+ gboolean res;
+ const char *action;
+ GError *error;
+
+ ret = TRUE;
+
+ if (get_system_num_users (manager) > 1) {
+ action = "org.freedesktop.consolekit.system.stop-multiple-users";
+ } else {
+ action = "org.freedesktop.consolekit.system.stop";
+ }
+
+#ifdef HAVE_POLKIT
+ res = _check_polkit_for_action (manager, context, action);
+ if (! res) {
+ goto out;
+ }
+#endif
+
+#ifdef ENABLE_RBAC_SHUTDOWN
+ if (!check_rbac_permissions (manager, context))
+ goto out;
+#endif
+
+ g_debug ("Stopping system");
+
+ log_system_stop_event (manager);
+
+ error = NULL;
+ res = g_spawn_command_line_async (LIBDIR "/ConsoleKit/scripts/ck-system-stop",
+ &error);
+ if (! res) {
+ GError *new_error;
+
+ g_warning ("Unable to stop system: %s", error->message);
+
+ new_error = g_error_new (CK_MANAGER_ERROR,
+ CK_MANAGER_ERROR_GENERAL,
+ "Unable to stop system: %s", error->message);
+ dbus_g_method_return_error (context, new_error);
+ g_error_free (new_error);
+
+ g_error_free (error);
+ } else {
+ ret = TRUE;
+ dbus_g_method_return (context);
+ }
+
+ out:
+ return ret;
+}
+
+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
+on_seat_session_added (CkSeat *seat,
+ const char *ssid,
+ CkManager *manager)
+{
+ ck_manager_dump (manager);
+ log_seat_session_added_event (manager, seat, ssid);
+}
+
+static void
+on_seat_session_removed (CkSeat *seat,
+ const char *ssid,
+ CkManager *manager)
+{
+ ck_manager_dump (manager);
+ log_seat_session_removed_event (manager, seat, ssid);
+}
+
+static void
+on_seat_device_added (CkSeat *seat,
+ GValueArray *device,
+ CkManager *manager)
+{
+ ck_manager_dump (manager);
+ log_seat_device_added_event (manager, seat, device);
+}
+
+static void
+on_seat_device_removed (CkSeat *seat,
+ GValueArray *device,
+ CkManager *manager)
+{
+ ck_manager_dump (manager);
+ log_seat_device_removed_event (manager, seat, device);
+}
+
+static void
+connect_seat_signals (CkManager *manager,
+ CkSeat *seat)
+{
+ g_signal_connect (seat, "active-session-changed", G_CALLBACK (on_seat_active_session_changed), manager);
+ g_signal_connect (seat, "session-added", G_CALLBACK (on_seat_session_added), manager);
+ g_signal_connect (seat, "session-removed", G_CALLBACK (on_seat_session_removed), manager);
+ g_signal_connect (seat, "device-added", G_CALLBACK (on_seat_device_added), manager);
+ g_signal_connect (seat, "device-removed", G_CALLBACK (on_seat_device_removed), manager);
+}
+
+static void
+disconnect_seat_signals (CkManager *manager,
+ CkSeat *seat)
+{
+ g_signal_handlers_disconnect_by_func (seat, on_seat_active_session_changed, manager);
+ g_signal_handlers_disconnect_by_func (seat, on_seat_session_added, manager);
+ g_signal_handlers_disconnect_by_func (seat, on_seat_session_removed, manager);
+ g_signal_handlers_disconnect_by_func (seat, on_seat_device_added, manager);
+ g_signal_handlers_disconnect_by_func (seat, on_seat_device_removed, manager);
+}
+
static CkSeat *
add_new_seat (CkManager *manager,
CkSeatKind kind)
@@ -293,12 +1521,18 @@ add_new_seat (CkManager *manager,
goto out;
}
+ connect_seat_signals (manager, seat);
+
g_hash_table_insert (manager->priv->seats, sid, seat);
g_debug ("Added seat: %s kind:%d", sid, kind);
+ ck_manager_dump (manager);
+
g_signal_emit (manager, signals [SEAT_ADDED], 0, sid);
+ log_seat_added_event (manager, seat);
+
out:
return seat;
}
@@ -307,19 +1541,49 @@ static void
remove_seat (CkManager *manager,
CkSeat *seat)
{
- char *sid;
+ char *sid;
+ char *orig_sid;
+ CkSeat *orig_seat;
+ gboolean res;
sid = NULL;
ck_seat_get_id (seat, &sid, NULL);
+ /* Need to get the original key/value */
+ res = g_hash_table_lookup_extended (manager->priv->seats,
+ sid,
+ (gpointer *)&orig_sid,
+ (gpointer *)&orig_seat);
+ if (! res) {
+ g_debug ("Seat %s is not attached", sid);
+ goto out;
+ }
+
+ /* Remove the seat from the list but don't call
+ * unref until the signal is emitted */
+ g_hash_table_steal (manager->priv->seats, sid);
+
+ disconnect_seat_signals (manager, orig_seat);
+
if (sid != NULL) {
g_hash_table_remove (manager->priv->seats, sid);
}
+ ck_manager_dump (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) {
+ g_object_unref (orig_seat);
+ }
+ g_free (orig_sid);
+
+ out:
g_free (sid);
}
@@ -384,51 +1648,6 @@ find_seat_for_session (CkManager *manager,
return seat;
}
-/* adapted from PolicyKit */
-static gboolean
-get_caller_info (CkManager *manager,
- const char *sender,
- uid_t *calling_uid,
- pid_t *calling_pid)
-{
- gboolean res;
- GError *error = NULL;
-
- res = FALSE;
-
- if (sender == NULL) {
- goto out;
- }
-
- if (! dbus_g_proxy_call (manager->priv->bus_proxy, "GetConnectionUnixUser", &error,
- G_TYPE_STRING, sender,
- G_TYPE_INVALID,
- G_TYPE_UINT, calling_uid,
- G_TYPE_INVALID)) {
- g_debug ("GetConnectionUnixUser() failed: %s", error->message);
- g_error_free (error);
- goto out;
- }
-
- if (! dbus_g_proxy_call (manager->priv->bus_proxy, "GetConnectionUnixProcessID", &error,
- G_TYPE_STRING, sender,
- G_TYPE_INVALID,
- G_TYPE_UINT, calling_pid,
- G_TYPE_INVALID)) {
- g_debug ("GetConnectionUnixProcessID() failed: %s", error->message);
- g_error_free (error);
- goto out;
- }
-
- res = TRUE;
-
- g_debug ("uid = %d", *calling_uid);
- g_debug ("pid = %d", *calling_pid);
-
-out:
- return res;
-}
-
static gboolean
manager_set_system_idle_hint (CkManager *manager,
gboolean idle_hint)
@@ -552,16 +1771,21 @@ ck_manager_get_system_idle_since_hint (CkManager *manager,
}
static void
-open_session_for_leader_info (CkManager *manager,
- LeaderInfo *leader_info,
- const GPtrArray *parameters,
- DBusGMethodInvocation *context)
+open_session_for_leader (CkManager *manager,
+ CkSessionLeader *leader,
+ const GPtrArray *parameters,
+ DBusGMethodInvocation *context)
{
CkSession *session;
CkSeat *seat;
+ const char *ssid;
+ const char *cookie;
+
+ ssid = ck_session_leader_peek_session_id (leader);
+ cookie = ck_session_leader_peek_cookie (leader);
- session = ck_session_new_with_parameters (leader_info->ssid,
- leader_info->cookie,
+ session = ck_session_new_with_parameters (ssid,
+ cookie,
parameters);
if (session == NULL) {
@@ -576,7 +1800,9 @@ open_session_for_leader_info (CkManager *manager,
return;
}
- g_hash_table_insert (manager->priv->sessions, g_strdup (leader_info->ssid), g_object_ref (session));
+ g_hash_table_insert (manager->priv->sessions,
+ g_strdup (ssid),
+ g_object_ref (session));
/* Add to seat */
seat = find_seat_for_session (manager, session);
@@ -597,247 +1823,55 @@ open_session_for_leader_info (CkManager *manager,
g_object_unref (session);
- dbus_g_method_return (context, leader_info->cookie);
+ dbus_g_method_return (context, cookie);
}
static void
-verify_and_open_session_for_leader_info (CkManager *manager,
- LeaderInfo *leader_info,
- const GPtrArray *parameters,
- DBusGMethodInvocation *context)
+verify_and_open_session_for_leader (CkManager *manager,
+ CkSessionLeader *leader,
+ const GPtrArray *parameters,
+ DBusGMethodInvocation *context)
{
/* for now don't bother verifying since we protect OpenSessionWithParameters */
- open_session_for_leader_info (manager,
- leader_info,
- parameters,
- context);
-}
-
-static void
-add_param_int (GPtrArray *parameters,
- const char *key,
- const char *value)
-{
- GValue val = { 0, };
- GValue param_val = { 0, };
- int num;
-
- num = atoi (value);
-
- g_value_init (&val, G_TYPE_INT);
- g_value_set_int (&val, num);
- g_value_init (&param_val, CK_TYPE_PARAMETER_STRUCT);
- g_value_take_boxed (&param_val,
- dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT));
- dbus_g_type_struct_set (&param_val,
- 0, key,
- 1, &val,
- G_MAXUINT);
- g_value_unset (&val);
-
- g_ptr_array_add (parameters, g_value_get_boxed (&param_val));
-}
-
-static void
-add_param_boolean (GPtrArray *parameters,
- const char *key,
- const char *value)
-{
- GValue val = { 0, };
- GValue param_val = { 0, };
- gboolean b;
-
- if (value != NULL && strcmp (value, "true") == 0) {
- b = TRUE;
- } else {
- b = FALSE;
- }
-
- g_value_init (&val, G_TYPE_BOOLEAN);
- g_value_set_boolean (&val, b);
- g_value_init (&param_val, CK_TYPE_PARAMETER_STRUCT);
- g_value_take_boxed (&param_val,
- dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT));
- dbus_g_type_struct_set (&param_val,
- 0, key,
- 1, &val,
- G_MAXUINT);
- g_value_unset (&val);
-
- g_ptr_array_add (parameters, g_value_get_boxed (&param_val));
+ open_session_for_leader (manager,
+ leader,
+ parameters,
+ context);
}
static void
-add_param_string (GPtrArray *parameters,
- const char *key,
- const char *value)
-{
- GValue val = { 0, };
- GValue param_val = { 0, };
-
- g_value_init (&val, G_TYPE_STRING);
- g_value_set_string (&val, value);
-
- g_value_init (&param_val, CK_TYPE_PARAMETER_STRUCT);
- g_value_take_boxed (&param_val,
- dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT));
-
- dbus_g_type_struct_set (&param_val,
- 0, key,
- 1, &val,
- G_MAXUINT);
- g_value_unset (&val);
-
- g_ptr_array_add (parameters, g_value_get_boxed (&param_val));
-}
-
-typedef void (* CkAddParamFunc) (GPtrArray *arr,
- const char *key,
- const char *value);
-
-static struct {
- char *key;
- CkAddParamFunc func;
-} parse_ops[] = {
- { "display-device", add_param_string },
- { "x11-display-device", add_param_string },
- { "x11-display", add_param_string },
- { "remote-host-name", add_param_string },
- { "session-type", add_param_string },
- { "is-local", add_param_boolean },
- { "unix-user", add_param_int },
-};
-
-static GPtrArray *
-parse_output (const char *output)
+collect_parameters_cb (CkSessionLeader *leader,
+ GPtrArray *parameters,
+ DBusGMethodInvocation *context,
+ CkManager *manager)
{
- GPtrArray *parameters;
- char **lines;
- int i;
- int j;
-
- lines = g_strsplit (output, "\n", -1);
- if (lines == NULL) {
- return NULL;
- }
-
- parameters = g_ptr_array_sized_new (10);
-
- for (i = 0; lines[i] != NULL; i++) {
- char **vals;
-
- vals = g_strsplit (lines[i], " = ", 2);
- if (vals == NULL || vals[0] == NULL) {
- g_strfreev (vals);
- continue;
- }
-
- for (j = 0; j < G_N_ELEMENTS (parse_ops); j++) {
- if (strcmp (vals[0], parse_ops[j].key) == 0) {
- parse_ops[j].func (parameters, vals[0], vals[1]);
- break;
- }
- }
- g_strfreev (vals);
- }
-
- g_strfreev (lines);
-
- return parameters;
-}
-
-typedef struct {
- CkManager *manager;
- LeaderInfo *leader_info;
- DBusGMethodInvocation *context;
-} JobData;
-
-static void
-job_data_free (JobData *data)
-{
- leader_info_unref (data->leader_info);
- g_free (data);
-}
-
-static void
-parameters_free (GPtrArray *parameters)
-{
- int i;
-
- for (i = 0; i < parameters->len; i++) {
- gpointer data;
- data = g_ptr_array_index (parameters, i);
- if (data != NULL) {
- g_boxed_free (CK_TYPE_PARAMETER_STRUCT, data);
- }
- }
-
- g_ptr_array_free (parameters, TRUE);
-}
-
-static void
-job_completed (CkJob *job,
- int status,
- JobData *data)
-{
- g_debug ("Job status: %d", status);
- if (status == 0) {
- char *output;
- GPtrArray *parameters;
-
- output = NULL;
- ck_job_get_stdout (job, &output);
- g_debug ("Job output: %s", output);
-
- parameters = parse_output (output);
- g_free (output);
-
- verify_and_open_session_for_leader_info (data->manager,
- data->leader_info,
- parameters,
- data->context);
- parameters_free (parameters);
+ if (parameters == NULL) {
+ GError *error;
+ error = g_error_new (CK_MANAGER_ERROR,
+ CK_MANAGER_ERROR_GENERAL,
+ "Unable to get information about the calling process");
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
}
- /* remove job from queue */
- data->leader_info->pending_jobs = g_list_remove (data->leader_info->pending_jobs, job);
-
- g_signal_handlers_disconnect_by_func (job, job_completed, data);
- g_object_unref (job);
+ verify_and_open_session_for_leader (manager,
+ leader,
+ parameters,
+ context);
}
static void
-generate_session_for_leader_info (CkManager *manager,
- LeaderInfo *leader_info,
- DBusGMethodInvocation *context)
+generate_session_for_leader (CkManager *manager,
+ CkSessionLeader *leader,
+ DBusGMethodInvocation *context)
{
- GError *local_error;
- char *command;
- gboolean res;
- CkJob *job;
- JobData *data;
-
- command = g_strdup_printf ("%s --uid %u --pid %u",
- LIBEXECDIR "/ck-collect-session-info",
- leader_info->uid,
- leader_info->pid);
- job = ck_job_new ();
- ck_job_set_command (job, command);
- g_free (command);
-
- data = g_new0 (JobData, 1);
- data->manager = manager;
- data->leader_info = leader_info_ref (leader_info);
- data->context = context;
- g_signal_connect_data (job,
- "completed",
- G_CALLBACK (job_completed),
- data,
- (GClosureNotify)job_data_free,
- 0);
+ gboolean res;
- local_error = NULL;
- res = ck_job_execute (job, &local_error);
+ res = ck_session_leader_collect_parameters (leader,
+ context,
+ (CkSessionLeaderDoneFunc)collect_parameters_cb,
+ manager);
if (! res) {
GError *error;
error = g_error_new (CK_MANAGER_ERROR,
@@ -845,19 +1879,7 @@ generate_session_for_leader_info (CkManager *manager,
"Unable to get information about the calling process");
dbus_g_method_return_error (context, error);
g_error_free (error);
-
- if (local_error != NULL) {
- g_debug ("stat on pid %d failed: %s", leader_info->pid, local_error->message);
- g_error_free (local_error);
- }
-
- g_object_unref (job);
-
- return;
}
-
- /* Add job to queue */
- leader_info->pending_jobs = g_list_prepend (leader_info->pending_jobs, job);
}
static gboolean
@@ -866,12 +1888,14 @@ create_session_for_sender (CkManager *manager,
const GPtrArray *parameters,
DBusGMethodInvocation *context)
{
- pid_t pid;
- uid_t uid;
- gboolean res;
- char *cookie;
- char *ssid;
- LeaderInfo *leader_info;
+ pid_t pid;
+ uid_t uid;
+ gboolean res;
+ char *cookie;
+ char *ssid;
+ CkSessionLeader *leader;
+
+ g_debug ("CkManager: create session for sender: %s", sender);
res = get_caller_info (manager,
sender,
@@ -892,27 +1916,27 @@ create_session_for_sender (CkManager *manager,
g_debug ("Creating new session ssid: %s", ssid);
- leader_info = g_new0 (LeaderInfo, 1);
- leader_info->uid = uid;
- leader_info->pid = pid;
- leader_info->service_name = g_strdup (sender);
- leader_info->ssid = g_strdup (ssid);
- leader_info->cookie = g_strdup (cookie);
+ leader = ck_session_leader_new ();
+ ck_session_leader_set_uid (leader, uid);
+ ck_session_leader_set_pid (leader, pid);
+ ck_session_leader_set_service_name (leader, sender);
+ ck_session_leader_set_session_id (leader, ssid);
+ ck_session_leader_set_cookie (leader, cookie);
/* need to store the leader info first so the pending request can be revoked */
g_hash_table_insert (manager->priv->leaders,
- g_strdup (leader_info->cookie),
- leader_info_ref (leader_info));
+ g_strdup (cookie),
+ g_object_ref (leader));
if (parameters == NULL) {
- generate_session_for_leader_info (manager,
- leader_info,
- context);
+ generate_session_for_leader (manager,
+ leader,
+ context);
} else {
- verify_and_open_session_for_leader_info (manager,
- leader_info,
- parameters,
- context);
+ verify_and_open_session_for_leader (manager,
+ leader,
+ parameters,
+ context);
}
g_free (cookie);
@@ -933,18 +1957,20 @@ ck_manager_get_session_for_cookie (CkManager *manager,
const char *cookie,
DBusGMethodInvocation *context)
{
- gboolean res;
- char *sender;
- uid_t calling_uid;
- pid_t calling_pid;
- CkProcessStat *stat;
- char *ssid;
- CkSession *session;
- LeaderInfo *leader_info;
- GError *local_error;
+ gboolean res;
+ char *sender;
+ uid_t calling_uid;
+ pid_t calling_pid;
+ CkProcessStat *stat;
+ char *ssid;
+ CkSession *session;
+ CkSessionLeader *leader;
+ GError *local_error;
ssid = NULL;
+ g_debug ("CkManager: get session for cookie");
+
sender = dbus_g_method_get_sender (context);
res = get_caller_info (manager,
@@ -984,8 +2010,8 @@ ck_manager_get_session_for_cookie (CkManager *manager,
/* FIXME: should we restrict this by uid? */
ck_process_stat_free (stat);
- leader_info = g_hash_table_lookup (manager->priv->leaders, cookie);
- if (leader_info == NULL) {
+ leader = g_hash_table_lookup (manager->priv->leaders, cookie);
+ if (leader == NULL) {
GError *error;
error = g_error_new (CK_MANAGER_ERROR,
CK_MANAGER_ERROR_GENERAL,
@@ -995,7 +2021,7 @@ ck_manager_get_session_for_cookie (CkManager *manager,
return FALSE;
}
- session = g_hash_table_lookup (manager->priv->sessions, leader_info->ssid);
+ session = g_hash_table_lookup (manager->priv->sessions, ck_session_leader_peek_session_id (leader));
if (session == NULL) {
GError *error;
error = g_error_new (CK_MANAGER_ERROR,
@@ -1015,19 +2041,6 @@ ck_manager_get_session_for_cookie (CkManager *manager,
return TRUE;
}
-static char *
-get_cookie_for_pid (CkManager *manager,
- guint pid)
-{
- char *cookie;
-
- /* FIXME: need a better way to get the cookie */
-
- cookie = ck_unix_pid_get_env (pid, "XDG_SESSION_COOKIE");
-
- return cookie;
-}
-
/*
Example:
dbus-send --system --dest=org.freedesktop.ConsoleKit \
@@ -1044,12 +2057,12 @@ ck_manager_get_session_for_unix_process (CkManager *manager,
char *sender;
uid_t calling_uid;
pid_t calling_pid;
- CkProcessStat *stat;
char *cookie;
- GError *error;
sender = dbus_g_method_get_sender (context);
+ g_debug ("CkManager: get session for unix process: %u", pid);
+
res = get_caller_info (manager,
sender,
&calling_uid,
@@ -1066,27 +2079,12 @@ ck_manager_get_session_for_unix_process (CkManager *manager,
return FALSE;
}
- error = NULL;
- res = ck_process_stat_new_for_unix_pid (calling_pid, &stat, &error);
- if (! res) {
- GError *error;
- g_debug ("stat on pid %d failed", calling_pid);
- error = g_error_new (CK_MANAGER_ERROR,
- CK_MANAGER_ERROR_GENERAL,
- _("Unable to lookup information about calling process '%d'"),
- calling_pid);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return FALSE;
- }
-
- /* FIXME: check stuff? */
-
- ck_process_stat_free (stat);
-
cookie = get_cookie_for_pid (manager, pid);
if (cookie == NULL) {
GError *error;
+
+ g_debug ("CkManager: unable to lookup session for unix process: %u", pid);
+
error = g_error_new (CK_MANAGER_ERROR,
CK_MANAGER_ERROR_GENERAL,
_("Unable to lookup session information for process '%d'"),
@@ -1120,6 +2118,8 @@ ck_manager_get_current_session (CkManager *manager,
sender = dbus_g_method_get_sender (context);
+ g_debug ("CkManager: get current session");
+
res = get_caller_info (manager,
sender,
&calling_uid,
@@ -1175,43 +2175,59 @@ remove_session_for_cookie (CkManager *manager,
const char *cookie,
GError **error)
{
- CkSession *session;
- LeaderInfo *leader_info;
- char *ssid;
- char *sid;
+ CkSession *orig_session;
+ char *orig_ssid;
+ CkSessionLeader *leader;
+ char *sid;
+ gboolean res;
+ gboolean ret;
+
+ ret = FALSE;
+ orig_ssid = NULL;
+ orig_session = NULL;
g_debug ("Removing session for cookie: %s", cookie);
- leader_info = g_hash_table_lookup (manager->priv->leaders, cookie);
+ leader = g_hash_table_lookup (manager->priv->leaders, cookie);
- if (leader_info == NULL) {
+ if (leader == NULL) {
g_set_error (error,
CK_MANAGER_ERROR,
CK_MANAGER_ERROR_GENERAL,
"Unable to find session for cookie");
- return FALSE;
+ goto out;
}
- session = g_hash_table_lookup (manager->priv->sessions, leader_info->ssid);
- if (session == NULL) {
+ /* Need to get the original key/value */
+ res = g_hash_table_lookup_extended (manager->priv->sessions,
+ ck_session_leader_peek_session_id (leader),
+ (gpointer *)&orig_ssid,
+ (gpointer *)&orig_session);
+ if (! res) {
g_set_error (error,
CK_MANAGER_ERROR,
CK_MANAGER_ERROR_GENERAL,
"Unable to find session for cookie");
- return FALSE;
+ goto out;
}
- ssid = g_strdup (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 */
- ck_session_get_seat_id (session, &sid, NULL);
+ sid = NULL;
+ ck_session_get_seat_id (orig_session, &sid, NULL);
if (sid != NULL) {
CkSeat *seat;
seat = g_hash_table_lookup (manager->priv->seats, sid);
if (seat != NULL) {
CkSeatKind kind;
- ck_seat_remove_session (seat, session, NULL);
+ ck_seat_remove_session (seat, orig_session, NULL);
kind = CK_SEAT_KIND_STATIC;
/* if dynamic seat has no sessions then remove it */
@@ -1221,15 +2237,25 @@ remove_session_for_cookie (CkManager *manager,
}
}
}
+ g_free (sid);
- g_hash_table_remove (manager->priv->sessions, ssid);
+ /* Remove the session from the list but don't call
+ * unref until we are done with it */
+ g_hash_table_steal (manager->priv->sessions,
+ ck_session_leader_peek_session_id (leader));
- g_free (sid);
- g_free (ssid);
+ ck_manager_dump (manager);
manager_update_system_idle_hint (manager);
- return TRUE;
+ ret = TRUE;
+ out:
+ if (orig_session != NULL) {
+ g_object_unref (orig_session);
+ }
+ g_free (orig_ssid);
+
+ return ret;
}
static gboolean
@@ -1239,7 +2265,7 @@ paranoia_check_is_cookie_owner (CkManager *manager,
pid_t calling_pid,
GError **error)
{
- LeaderInfo *leader_info;
+ CkSessionLeader *leader;
if (cookie == NULL) {
g_set_error (error,
@@ -1249,8 +2275,8 @@ paranoia_check_is_cookie_owner (CkManager *manager,
return FALSE;
}
- leader_info = g_hash_table_lookup (manager->priv->leaders, cookie);
- if (leader_info == NULL) {
+ leader = g_hash_table_lookup (manager->priv->leaders, cookie);
+ if (leader == NULL) {
g_set_error (error,
CK_MANAGER_ERROR,
CK_MANAGER_ERROR_GENERAL,
@@ -1258,7 +2284,7 @@ paranoia_check_is_cookie_owner (CkManager *manager,
return FALSE;
}
- if (leader_info->uid != calling_uid) {
+ if (ck_session_leader_get_uid (leader) != calling_uid) {
g_set_error (error,
CK_MANAGER_ERROR,
CK_MANAGER_ERROR_GENERAL,
@@ -1268,7 +2294,7 @@ paranoia_check_is_cookie_owner (CkManager *manager,
}
/* do we want to restrict to the same process? */
- if (leader_info->pid != calling_pid) {
+ if (ck_session_leader_get_pid (leader) != calling_pid) {
g_set_error (error,
CK_MANAGER_ERROR,
CK_MANAGER_ERROR_GENERAL,
@@ -1341,15 +2367,18 @@ typedef struct {
static gboolean
remove_leader_for_connection (const char *cookie,
- LeaderInfo *info,
+ CkSessionLeader *leader,
RemoveLeaderData *data)
{
- g_assert (info != NULL);
+ const char *name;
+
+ g_assert (leader != NULL);
g_assert (data->service_name != NULL);
- if (strcmp (info->service_name, data->service_name) == 0) {
+ name = ck_session_leader_peek_service_name (leader);
+ if (strcmp (name, data->service_name) == 0) {
remove_session_for_cookie (data->manager, cookie, NULL);
- leader_info_cancel (info);
+ ck_session_leader_cancel (leader);
return TRUE;
}
@@ -1389,11 +2418,65 @@ bus_name_owner_changed (DBusGProxy *bus_proxy,
service_name, old_service_name, new_service_name);
}
+#ifdef HAVE_POLKIT
+static gboolean
+pk_io_watch_have_data (GIOChannel *channel,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ int fd;
+ PolKitContext *pk_context = user_data;
+
+ fd = g_io_channel_unix_get_fd (channel);
+ polkit_context_io_func (pk_context, fd);
+ return TRUE;
+}
+
+static int
+pk_io_add_watch (PolKitContext *pk_context,
+ int fd)
+{
+ guint id = 0;
+ GIOChannel *channel;
+
+ channel = g_io_channel_unix_new (fd);
+ if (channel == NULL) {
+ goto out;
+ }
+
+ id = g_io_add_watch (channel, G_IO_IN, pk_io_watch_have_data, pk_context);
+ if (id == 0) {
+ g_io_channel_unref (channel);
+ goto out;
+ }
+ g_io_channel_unref (channel);
+
+out:
+ return id;
+}
+
+static void
+pk_io_remove_watch (PolKitContext *pk_context,
+ int watch_id)
+{
+ g_source_remove (watch_id);
+}
+#endif
+
static gboolean
register_manager (CkManager *manager)
{
GError *error = NULL;
+#ifdef HAVE_POLKIT
+ manager->priv->pol_ctx = polkit_context_new ();
+ polkit_context_set_io_watch_functions (manager->priv->pol_ctx, pk_io_add_watch, pk_io_remove_watch);
+ if (! polkit_context_init (manager->priv->pol_ctx, NULL)) {
+ g_critical ("cannot initialize libpolkit");
+ return FALSE;
+ }
+#endif
+
error = NULL;
manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
if (manager->priv->connection == NULL) {
@@ -1464,6 +2547,7 @@ ck_manager_class_init (CkManagerClass *klass)
1, G_TYPE_BOOLEAN);
dbus_g_object_type_install_info (CK_TYPE_MANAGER, &dbus_glib_ck_manager_object_info);
+ dbus_g_error_domain_register (CK_MANAGER_ERROR, NULL, CK_MANAGER_TYPE_ERROR);
g_type_class_add_private (klass, sizeof (CkManagerPrivate));
}
@@ -1547,6 +2631,31 @@ ck_manager_get_seats (CkManager *manager,
}
static void
+listify_session_ids (char *id,
+ CkSession *session,
+ GPtrArray **array)
+{
+ g_ptr_array_add (*array, g_strdup (id));
+}
+
+gboolean
+ck_manager_get_sessions (CkManager *manager,
+ GPtrArray **sessions,
+ GError **error)
+{
+ g_return_val_if_fail (CK_IS_MANAGER (manager), FALSE);
+
+ if (sessions == NULL) {
+ return FALSE;
+ }
+
+ *sessions = g_ptr_array_new ();
+ g_hash_table_foreach (manager->priv->sessions, (GHFunc)listify_session_ids, sessions);
+
+ return TRUE;
+}
+
+static void
add_seat_for_file (CkManager *manager,
const char *filename)
{
@@ -1562,11 +2671,17 @@ add_seat_for_file (CkManager *manager,
return;
}
+ connect_seat_signals (manager, seat);
+
g_hash_table_insert (manager->priv->seats, sid, seat);
g_debug ("Added seat: %s", sid);
+ ck_manager_dump (manager);
+
g_signal_emit (manager, signals [SEAT_ADDED], 0, sid);
+
+ log_seat_added_event (manager, seat);
}
static gboolean
@@ -1627,7 +2742,9 @@ ck_manager_init (CkManager *manager)
manager->priv->leaders = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
- (GDestroyNotify) leader_info_unref);
+ (GDestroyNotify) g_object_unref);
+
+ manager->priv->logger = ck_event_logger_new (LOG_FILE);
create_seats (manager);
}
@@ -1647,7 +2764,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/ck-manager.h b/src/ck-manager.h
index a6fd670..45910b7 100644
--- a/src/ck-manager.h
+++ b/src/ck-manager.h
@@ -58,11 +58,16 @@ typedef struct
typedef enum
{
- CK_MANAGER_ERROR_GENERAL
+ CK_MANAGER_ERROR_GENERAL,
+ CK_MANAGER_ERROR_NOT_PRIVILEGED,
+ CK_MANAGER_NUM_ERRORS
} CkManagerError;
#define CK_MANAGER_ERROR ck_manager_error_quark ()
+GType ck_manager_error_get_type (void);
+#define CK_MANAGER_TYPE_ERROR (ck_manager_error_get_type ())
+
GQuark ck_manager_error_quark (void);
GType ck_manager_get_type (void);
@@ -70,9 +75,19 @@ CkManager * ck_manager_new (void);
/* unprivileged methods */
+
+/* System actions */
+gboolean ck_manager_stop (CkManager *manager,
+ DBusGMethodInvocation *context);
+gboolean ck_manager_restart (CkManager *manager,
+ DBusGMethodInvocation *context);
+
/* Authoritative properties */
gboolean ck_manager_open_session (CkManager *manager,
DBusGMethodInvocation *context);
+gboolean ck_manager_get_sessions (CkManager *manager,
+ GPtrArray **sessions,
+ GError **error);
gboolean ck_manager_get_seats (CkManager *manager,
GPtrArray **seats,
GError **error);
diff --git a/src/ck-manager.xml b/src/ck-manager.xml
index f40d6d5..0ca74fa 100644
--- a/src/ck-manager.xml
+++ b/src/ck-manager.xml
@@ -1,6 +1,12 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/org/freedesktop/ConsoleKit/Manager">
<interface name="org.freedesktop.ConsoleKit.Manager">
+ <method name="Restart">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ </method>
+ <method name="Stop">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ </method>
<method name="OpenSession">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="cookie" direction="out" type="s"/>
@@ -18,6 +24,9 @@
<method name="GetSeats">
<arg name="seats" direction="out" type="ao"/>
</method>
+ <method name="GetSessions">
+ <arg name="sessions" direction="out" type="ao"/>
+ </method>
<method name="GetSessionForCookie">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="cookie" direction="in" type="s"/>
diff --git a/src/ck-marshal.c b/src/ck-marshal.c
index 6b77b77..8b08794 100644
--- a/src/ck-marshal.c
+++ b/src/ck-marshal.c
@@ -51,10 +51,10 @@
/* VOID:UINT,STRING (ck-marshal.list:1) */
void
ck_marshal_VOID__UINT_STRING (GClosure *closure,
- GValue *return_value,
+ GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
- gpointer invocation_hint,
+ gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef void (*GMarshalFunc_VOID__UINT_STRING) (gpointer data1,
@@ -88,10 +88,10 @@ ck_marshal_VOID__UINT_STRING (GClosure *closure,
/* BOOLEAN:POINTER (ck-marshal.list:2) */
void
ck_marshal_BOOLEAN__POINTER (GClosure *closure,
- GValue *return_value,
+ GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
- gpointer invocation_hint,
+ gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer data1,
diff --git a/src/ck-run-programs.c b/src/ck-run-programs.c
new file mode 100644
index 0000000..f9d62c7
--- /dev/null
+++ b/src/ck-run-programs.c
@@ -0,0 +1,230 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 David Zeuthen <david@fubar.dk>
+ *
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include "ck-run-programs.h"
+
+/* The number of wall-clock seconds a program is allowed to run before we kill it */
+#define TIMEOUT_SECONDS 15
+
+/* Guaranteed by POSIX; see 'man environ' for details */
+extern char **environ;
+
+typedef struct {
+ int refcount;
+
+ char *path;
+
+ gboolean child_is_running;
+ guint watch_id;
+ guint timeout_id;
+ GPid pid;
+} ChildData;
+
+static ChildData *
+_child_data_new (void)
+{
+ ChildData *cd;
+
+ cd = g_new0 (ChildData, 1);
+ cd->refcount = 1;
+ g_debug ("Allocated ChildData %p", cd);
+
+ return cd;
+}
+
+static ChildData *
+_child_data_ref (ChildData *cd)
+{
+ cd->refcount++;
+ return cd;
+}
+
+
+static void
+_child_data_unref (ChildData *cd)
+{
+ cd->refcount--;
+ if (cd->refcount == 0) {
+ g_free (cd->path);
+ g_free (cd);
+ g_debug ("Freeing ChildData %p", cd);
+ }
+}
+
+
+static void
+_child_watch (GPid pid,
+ int status,
+ ChildData *cd)
+{
+ g_debug ("In _child_watch for pid %d", pid);
+
+ g_spawn_close_pid (pid);
+ g_source_remove (cd->timeout_id);
+
+ cd->child_is_running = FALSE;
+
+ _child_data_unref (cd);
+}
+
+static gboolean
+_child_timeout (ChildData *cd)
+{
+ /* The program we ran timed out; this is a bug in the program */
+ g_warning ("The program %s didn't exit within %d seconds; killing it", cd->path, TIMEOUT_SECONDS);
+
+ kill (cd->pid, SIGTERM);
+
+ cd->child_is_running = FALSE;
+ return FALSE;
+}
+
+/**
+ * ck_run_programs:
+ * @dirpath: Path to a directory containing programs to run
+ * @action: Argument to pass to each program
+ * @extra_env: Extra environment to pass
+ *
+ * Synchronously run all scripts with suffix .ck in the given
+ * directory.
+ */
+void
+ck_run_programs (const char *dirpath,
+ const char *action,
+ char **extra_env)
+{
+ GDir *dir;
+ GError *error;
+ const char *name;
+ char **env_for_child;
+ int environ_len;
+ int extra_env_len;
+ int n;
+ int m;
+
+ g_return_if_fail (dirpath != NULL);
+ g_return_if_fail (action != NULL);
+
+ g_debug ("Running programs in %s for action %s", dirpath, action);
+
+ /* Construct an environment consisting of the existing and the given environment */
+ environ_len = environ != NULL ? g_strv_length (environ) : 0;
+ extra_env_len = extra_env != NULL ? g_strv_length (extra_env) : 0;
+ env_for_child = g_new0 (char *, environ_len + extra_env_len + 2);
+ m = 0;
+ for (n = 0; n < environ_len; n++) {
+ env_for_child [m++] = g_strdup (environ[n]);
+ }
+ for (n = 0; n < extra_env_len; n++) {
+ env_for_child [m++] = g_strdup (extra_env[n]);
+ }
+ env_for_child[m] = NULL;
+
+ error = NULL;
+
+ dir = g_dir_open (dirpath, 0, &error);
+ if (dir == NULL) {
+ /* This is unexpected; it means ConsoleKit isn't properly installed */
+ g_warning ("Unable to open directory %s: %s", dirpath, error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ while ((name = g_dir_read_name (dir)) != NULL) {
+ char *child_argv[3];
+ ChildData *cd;
+ gboolean res;
+
+ if (!g_str_has_suffix (name, ".ck"))
+ continue;
+
+ child_argv[0] = g_strdup_printf ("%s/%s", dirpath, name);
+ child_argv[1] = (char *) action;
+ child_argv[2] = NULL;
+
+ error = NULL;
+ cd = _child_data_new ();
+ cd->path = g_strdup (child_argv[0]);
+
+ /* The ChildData instance is also unreffed in _child_watch; we only ref
+ * it here to prevent cd from being destroyed while checking it in
+ * the mainloop
+ */
+ _child_data_ref (cd);
+
+ res = g_spawn_async (NULL,
+ child_argv,
+ env_for_child,
+ G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL,
+ NULL,
+ &cd->pid,
+ &error);
+ if (! res) {
+ /* This is unexpected; it means the program to run isn't installed correctly */
+ g_warning ("Unable to spawn %s: %s", child_argv[0], error->message);
+ g_error_free (error);
+ _child_data_unref (cd);
+ _child_data_unref (cd);
+ goto out_loop;
+ }
+ cd->child_is_running = TRUE;
+
+ g_debug ("Waiting for child with pid %d", cd->pid);
+
+ cd->watch_id = g_child_watch_add (cd->pid,
+ (GChildWatchFunc)_child_watch,
+ cd);
+ cd->timeout_id = g_timeout_add (TIMEOUT_SECONDS * 1000,
+ (GSourceFunc)_child_timeout,
+ cd);
+
+ /* run the mainloop; this allows the main daemon to
+ * continue serving clients (including the program we
+ * just launched) */
+ while (cd->child_is_running) {
+ g_main_context_iteration (NULL, TRUE);
+ }
+
+ g_debug ("Done waiting for child with pid %d", cd->pid);
+ _child_data_unref (cd);
+
+ out_loop:
+ g_free (child_argv[0]);
+ }
+out:
+ g_strfreev (env_for_child);
+}
diff --git a/src/ck-run-programs.h b/src/ck-run-programs.h
new file mode 100644
index 0000000..77cdf48
--- /dev/null
+++ b/src/ck-run-programs.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 David Zeuthen <david@fubar.dk>
+ *
+ * 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_RUN_PROGRAMS_H
+#define __CK_RUN_PROGRAMS_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include "ck-session.h"
+
+G_BEGIN_DECLS
+
+void ck_run_programs (const char *dirpath, const char *action, char **extra_env);
+
+void ck_session_run_programs (CkSession *session, const char *action);
+
+
+G_END_DECLS
+
+#endif /* __CK_RUN_PROGRAMS_H */
diff --git a/src/ck-seat-glue.h b/src/ck-seat-glue.h
index d6cbca1..264ba13 100644
--- a/src/ck-seat-glue.h
+++ b/src/ck-seat-glue.h
@@ -53,7 +53,7 @@ G_BEGIN_DECLS
#endif /* !G_ENABLE_DEBUG */
-/* BOOLEAN:POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.33NIYT:1) */
+/* BOOLEAN:POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.G1XI6T:1) */
extern void dbus_glib_marshal_ck_seat_BOOLEAN__POINTER_POINTER (GClosure *closure,
GValue *return_value,
guint n_param_values,
@@ -62,10 +62,10 @@ extern void dbus_glib_marshal_ck_seat_BOOLEAN__POINTER_POINTER (GClosure *cl
gpointer marshal_data);
void
dbus_glib_marshal_ck_seat_BOOLEAN__POINTER_POINTER (GClosure *closure,
- GValue *return_value,
+ GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
- gpointer invocation_hint,
+ gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_POINTER) (gpointer data1,
@@ -100,7 +100,7 @@ dbus_glib_marshal_ck_seat_BOOLEAN__POINTER_POINTER (GClosure *closure,
g_value_set_boolean (return_value, v_return);
}
-/* NONE:BOXED,POINTER (/tmp/dbus-binding-tool-c-marshallers.33NIYT:2) */
+/* NONE:BOXED,POINTER (/tmp/dbus-binding-tool-c-marshallers.G1XI6T:2) */
extern void dbus_glib_marshal_ck_seat_VOID__BOXED_POINTER (GClosure *closure,
GValue *return_value,
guint n_param_values,
@@ -109,10 +109,10 @@ extern void dbus_glib_marshal_ck_seat_VOID__BOXED_POINTER (GClosure *closure
gpointer marshal_data);
void
dbus_glib_marshal_ck_seat_VOID__BOXED_POINTER (GClosure *closure,
- GValue *return_value,
+ GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
- gpointer invocation_hint,
+ gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef void (*GMarshalFunc_VOID__BOXED_POINTER) (gpointer data1,
diff --git a/src/ck-seat.c b/src/ck-seat.c
index e04b569..009452e 100644
--- a/src/ck-seat.c
+++ b/src/ck-seat.c
@@ -42,12 +42,14 @@
#include "ck-session.h"
#include "ck-vt-monitor.h"
+#include "ck-run-programs.h"
#define CK_SEAT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SEAT, CkSeatPrivate))
#define CK_DBUS_PATH "/org/freedesktop/ConsoleKit"
#define CK_DBUS_NAME "org.freedesktop.ConsoleKit"
+#define NONULL_STRING(x) ((x) != NULL ? (x) : "")
struct CkSeatPrivate
{
@@ -122,17 +124,37 @@ ck_seat_get_active_session (CkSeat *seat,
char **ssid,
GError **error)
{
+ gboolean ret;
+ char *session_id;
+
g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
+ g_debug ("CkSeat: get active session");
+ session_id = NULL;
+ ret = FALSE;
if (seat->priv->active_session != NULL) {
- ck_session_get_id (seat->priv->active_session, ssid, NULL);
+ gboolean res;
+ res = ck_session_get_id (seat->priv->active_session, &session_id, NULL);
+ if (res) {
+ ret = TRUE;
+ }
+ } else {
+ g_debug ("CkSeat: seat has no active session");
+ }
+
+ if (! ret) {
+ g_set_error (error,
+ CK_SEAT_ERROR,
+ CK_SEAT_ERROR_GENERAL,
+ "%s", "Seat has no active session");
} else {
if (ssid != NULL) {
- *ssid = NULL;
+ *ssid = g_strdup (session_id);
}
}
- return TRUE;
+ g_free (session_id);
+ return ret;
}
typedef struct
@@ -200,8 +222,11 @@ _seat_activate_session (CkSeat *seat,
goto out;
}
- ck_session_get_display_device (session, &device, NULL);
-
+ device = NULL;
+ ck_session_get_x11_display_device (session, &device, NULL);
+ if (device == NULL) {
+ ck_session_get_display_device (session, &device, NULL);
+ }
res = ck_get_console_num_from_device (device, &num);
if (! res) {
GError *error;
@@ -264,6 +289,8 @@ ck_seat_activate_session (CkSeat *seat,
session = NULL;
+ g_debug ("Trying to activate session: %s", ssid);
+
if (ssid != NULL) {
session = g_hash_table_lookup (seat->priv->sessions, ssid);
}
@@ -473,7 +500,7 @@ change_active_session (CkSeat *seat,
ck_session_set_active (session, TRUE, NULL);
}
- g_debug ("Active session changed: %s", ssid);
+ g_debug ("Active session changed: %s", ssid ? ssid : "(null)");
g_signal_emit (seat, signals [ACTIVE_SESSION_CHANGED], 0, ssid);
@@ -527,8 +554,11 @@ ck_seat_remove_session (CkSeat *seat,
CkSession *session,
GError **error)
{
- char *ssid;
- gboolean ret;
+ char *ssid;
+ char *orig_ssid;
+ CkSession *orig_session;
+ gboolean res;
+ gboolean ret;
g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
@@ -536,7 +566,12 @@ ck_seat_remove_session (CkSeat *seat,
ssid = NULL;
ck_session_get_id (session, &ssid, NULL);
- if (g_hash_table_lookup (seat->priv->sessions, ssid) == NULL) {
+ /* Need to get the original key/value */
+ res = g_hash_table_lookup_extended (seat->priv->sessions,
+ ssid,
+ (gpointer *)&orig_ssid,
+ (gpointer *)&orig_session);
+ if (! res) {
g_debug ("Session %s is not attached to seat %s", ssid, seat->priv->id);
g_set_error (error,
CK_SEAT_ERROR,
@@ -547,15 +582,23 @@ ck_seat_remove_session (CkSeat *seat,
g_signal_handlers_disconnect_by_func (session, session_activate, seat);
- g_debug ("Emitting removed signal: %s", ssid);
+ /* Remove the session from the list but don't call
+ * unref until the signal is emitted */
+ g_hash_table_steal (seat->priv->sessions, ssid);
- g_signal_emit (seat, signals [SESSION_REMOVED], 0, ssid);
+ ck_session_run_programs (session, "session_removed");
- g_hash_table_remove (seat->priv->sessions, ssid);
+ g_debug ("Emitting session-removed: %s", ssid);
+ g_signal_emit (seat, signals [SESSION_REMOVED], 0, ssid);
/* try to change the active session */
maybe_update_active_session (seat);
+ if (orig_session != NULL) {
+ g_object_unref (orig_session);
+ }
+ g_free (orig_ssid);
+
ret = TRUE;
out:
g_free (ssid);
@@ -581,6 +624,8 @@ ck_seat_add_session (CkSeat *seat,
g_signal_connect_object (session, "activate", G_CALLBACK (session_activate), seat, 0);
/* FIXME: attach to property notify signals? */
+ ck_session_run_programs (session, "session_added");
+
g_debug ("Emitting added signal: %s", ssid);
g_signal_emit (seat, signals [SESSION_ADDED], 0, ssid);
@@ -637,7 +682,6 @@ ck_seat_add_device (CkSeat *seat,
g_ptr_array_add (seat->priv->devices, g_boxed_copy (CK_TYPE_DEVICE, device));
g_debug ("Emitting device added signal");
-
g_signal_emit (seat, signals [DEVICE_ADDED], 0, device);
return TRUE;
@@ -653,7 +697,6 @@ ck_seat_remove_device (CkSeat *seat,
/* FIXME: check if already present */
if (0) {
g_debug ("Emitting device removed signal");
-
g_signal_emit (seat, signals [DEVICE_REMOVED], 0, device);
}
@@ -1103,3 +1146,90 @@ ck_seat_new_from_file (const char *sid,
return seat;
}
+
+static void
+dump_seat_session_iter (char *id,
+ CkSession *session,
+ GString *str)
+{
+ char *session_id;
+ GError *error;
+
+ error = NULL;
+ if (! ck_session_get_id (session, &session_id, &error)) {
+ g_warning ("Cannot get session id from seat: %s", error->message);
+ g_error_free (error);
+ } else {
+ if (str->len > 0) {
+ g_string_append_c (str, ' ');
+ }
+ g_string_append (str, session_id);
+ g_free (session_id);
+ }
+}
+
+void
+ck_seat_dump (CkSeat *seat,
+ GKeyFile *key_file)
+{
+ char *group_name;
+ GString *str;
+ char *s;
+ int n;
+
+ group_name = g_strdup_printf ("Seat %s", seat->priv->id);
+
+ g_key_file_set_integer (key_file, group_name, "kind", seat->priv->kind);
+
+ str = g_string_new (NULL);
+ g_hash_table_foreach (seat->priv->sessions, (GHFunc) dump_seat_session_iter, str);
+ s = g_string_free (str, FALSE);
+ g_key_file_set_string (key_file, group_name, "sessions", s);
+ g_free (s);
+
+ str = g_string_new (NULL);
+ if (seat->priv->devices != NULL) {
+ for (n = 0; n < seat->priv->devices->len; n++) {
+ int m;
+ GValueArray *va;
+
+ va = seat->priv->devices->pdata[n];
+
+ if (str->len > 0)
+ g_string_append_c (str, ' ');
+ for (m = 0; m < va->n_values; m++) {
+ if (m > 0)
+ g_string_append_c (str, ':');
+ g_string_append (str, g_value_get_string ((const GValue *) &((va->values)[m])));
+ }
+
+ g_debug ("foo %d", va->n_values);
+ }
+ }
+ s = g_string_free (str, FALSE);
+ g_key_file_set_string (key_file, group_name, "devices", s);
+ g_free (s);
+
+
+ if (seat->priv->active_session != NULL) {
+ char *session_id;
+ GError *error;
+
+ error = NULL;
+ if (! ck_session_get_id (seat->priv->active_session, &session_id, &error)) {
+ g_warning ("Cannot get session id for active session on seat %s: %s",
+ seat->priv->id,
+ error->message);
+ g_error_free (error);
+ } else {
+ g_key_file_set_string (key_file,
+ group_name,
+ "active_session",
+ NONULL_STRING (session_id));
+ g_free (session_id);
+ }
+ }
+
+ g_free (group_name);
+}
+
diff --git a/src/ck-seat.h b/src/ck-seat.h
index 63ab3d5..5977781 100644
--- a/src/ck-seat.h
+++ b/src/ck-seat.h
@@ -90,6 +90,10 @@ CkSeat * ck_seat_new_from_file (const char *sid,
CkSeat * ck_seat_new_with_devices (const char *sid,
CkSeatKind kind,
GPtrArray *devices);
+
+void ck_seat_dump (CkSeat *seat,
+ GKeyFile *key_file);
+
gboolean ck_seat_get_kind (CkSeat *seat,
CkSeatKind *kind,
GError **error);
diff --git a/src/ck-session-glue.h b/src/ck-session-glue.h
index cabded2..c06173f 100644
--- a/src/ck-session-glue.h
+++ b/src/ck-session-glue.h
@@ -53,7 +53,7 @@ G_BEGIN_DECLS
#endif /* !G_ENABLE_DEBUG */
-/* BOOLEAN:POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.8HEIYT:1) */
+/* BOOLEAN:POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.P39I6T:1) */
extern void dbus_glib_marshal_ck_session_BOOLEAN__POINTER_POINTER (GClosure *closure,
GValue *return_value,
guint n_param_values,
@@ -62,10 +62,10 @@ extern void dbus_glib_marshal_ck_session_BOOLEAN__POINTER_POINTER (GClosure
gpointer marshal_data);
void
dbus_glib_marshal_ck_session_BOOLEAN__POINTER_POINTER (GClosure *closure,
- GValue *return_value,
+ GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
- gpointer invocation_hint,
+ gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_POINTER) (gpointer data1,
@@ -100,7 +100,7 @@ dbus_glib_marshal_ck_session_BOOLEAN__POINTER_POINTER (GClosure *closure,
g_value_set_boolean (return_value, v_return);
}
-/* NONE:BOOLEAN,POINTER (/tmp/dbus-binding-tool-c-marshallers.8HEIYT:2) */
+/* NONE:BOOLEAN,POINTER (/tmp/dbus-binding-tool-c-marshallers.P39I6T:2) */
extern void dbus_glib_marshal_ck_session_VOID__BOOLEAN_POINTER (GClosure *closure,
GValue *return_value,
guint n_param_values,
@@ -109,10 +109,10 @@ extern void dbus_glib_marshal_ck_session_VOID__BOOLEAN_POINTER (GClosure *cl
gpointer marshal_data);
void
dbus_glib_marshal_ck_session_VOID__BOOLEAN_POINTER (GClosure *closure,
- GValue *return_value,
+ GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
- gpointer invocation_hint,
+ gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef void (*GMarshalFunc_VOID__BOOLEAN_POINTER) (gpointer data1,
@@ -144,7 +144,7 @@ dbus_glib_marshal_ck_session_VOID__BOOLEAN_POINTER (GClosure *closure,
}
#define dbus_glib_marshal_ck_session_NONE__BOOLEAN_POINTER dbus_glib_marshal_ck_session_VOID__BOOLEAN_POINTER
-/* NONE:POINTER (/tmp/dbus-binding-tool-c-marshallers.8HEIYT:3) */
+/* NONE:POINTER (/tmp/dbus-binding-tool-c-marshallers.P39I6T:3) */
#define dbus_glib_marshal_ck_session_VOID__POINTER g_cclosure_marshal_VOID__POINTER
#define dbus_glib_marshal_ck_session_NONE__POINTER dbus_glib_marshal_ck_session_VOID__POINTER
diff --git a/src/ck-session-leader.c b/src/ck-session-leader.c
new file mode 100644
index 0000000..756feac
--- /dev/null
+++ b/src/ck-session-leader.c
@@ -0,0 +1,567 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006-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 <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "ck-session-leader.h"
+#include "ck-job.h"
+
+#define CK_SESSION_LEADER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SESSION_LEADER, CkSessionLeaderPrivate))
+
+#define CK_TYPE_PARAMETER_STRUCT (dbus_g_type_get_struct ("GValueArray", \
+ G_TYPE_STRING, \
+ G_TYPE_VALUE, \
+ G_TYPE_INVALID))
+#define CK_TYPE_PARAMETER_LIST (dbus_g_type_get_collection ("GPtrArray", \
+ CK_TYPE_PARAMETER_STRUCT))
+
+struct CkSessionLeaderPrivate
+{
+ char *id;
+ uid_t uid;
+ pid_t pid;
+ char *service_name;
+ char *session_id;
+ char *cookie;
+ GList *pending_jobs;
+ gboolean cancelled;
+};
+
+enum {
+ PROP_0,
+};
+
+static void ck_session_leader_class_init (CkSessionLeaderClass *klass);
+static void ck_session_leader_init (CkSessionLeader *session_leader);
+static void ck_session_leader_finalize (GObject *object);
+
+G_DEFINE_TYPE (CkSessionLeader, ck_session_leader, G_TYPE_OBJECT)
+
+GQuark
+ck_session_leader_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("ck_session_leader_error");
+ }
+
+ return ret;
+}
+
+static void
+remove_pending_job (CkJob *job)
+{
+ if (job != NULL) {
+ char *command;
+
+ command = NULL;
+ ck_job_get_command (job, &command);
+ g_debug ("Removing pending job: %s", command);
+ g_free (command);
+
+ ck_job_cancel (job);
+ g_object_unref (job);
+ }
+}
+
+void
+ck_session_leader_cancel (CkSessionLeader *leader)
+{
+ g_return_if_fail (CK_IS_SESSION_LEADER (leader));
+
+ if (leader->priv->pending_jobs != NULL) {
+ g_list_foreach (leader->priv->pending_jobs, (GFunc)remove_pending_job, NULL);
+ g_list_free (leader->priv->pending_jobs);
+ leader->priv->pending_jobs = NULL;
+ }
+
+ leader->priv->cancelled = TRUE;
+}
+
+
+static void
+add_param_int (GPtrArray *parameters,
+ const char *key,
+ const char *value)
+{
+ GValue val = { 0, };
+ GValue param_val = { 0, };
+ int num;
+
+ num = atoi (value);
+
+ g_value_init (&val, G_TYPE_INT);
+ g_value_set_int (&val, num);
+ g_value_init (&param_val, CK_TYPE_PARAMETER_STRUCT);
+ g_value_take_boxed (&param_val,
+ dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT));
+ dbus_g_type_struct_set (&param_val,
+ 0, key,
+ 1, &val,
+ G_MAXUINT);
+ g_value_unset (&val);
+
+ g_ptr_array_add (parameters, g_value_get_boxed (&param_val));
+}
+
+static void
+add_param_boolean (GPtrArray *parameters,
+ const char *key,
+ const char *value)
+{
+ GValue val = { 0, };
+ GValue param_val = { 0, };
+ gboolean b;
+
+ if (value != NULL && strcmp (value, "true") == 0) {
+ b = TRUE;
+ } else {
+ b = FALSE;
+ }
+
+ g_value_init (&val, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&val, b);
+ g_value_init (&param_val, CK_TYPE_PARAMETER_STRUCT);
+ g_value_take_boxed (&param_val,
+ dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT));
+ dbus_g_type_struct_set (&param_val,
+ 0, key,
+ 1, &val,
+ G_MAXUINT);
+ g_value_unset (&val);
+
+ g_ptr_array_add (parameters, g_value_get_boxed (&param_val));
+}
+
+static void
+add_param_string (GPtrArray *parameters,
+ const char *key,
+ const char *value)
+{
+ GValue val = { 0, };
+ GValue param_val = { 0, };
+
+ g_value_init (&val, G_TYPE_STRING);
+ g_value_set_string (&val, value);
+
+ g_value_init (&param_val, CK_TYPE_PARAMETER_STRUCT);
+ g_value_take_boxed (&param_val,
+ dbus_g_type_specialized_construct (CK_TYPE_PARAMETER_STRUCT));
+
+ dbus_g_type_struct_set (&param_val,
+ 0, key,
+ 1, &val,
+ G_MAXUINT);
+ g_value_unset (&val);
+
+ g_ptr_array_add (parameters, g_value_get_boxed (&param_val));
+}
+
+typedef void (* CkAddParamFunc) (GPtrArray *arr,
+ const char *key,
+ const char *value);
+
+static struct {
+ char *key;
+ CkAddParamFunc func;
+} parse_ops[] = {
+ { "display-device", add_param_string },
+ { "x11-display-device", add_param_string },
+ { "x11-display", add_param_string },
+ { "remote-host-name", add_param_string },
+ { "session-type", add_param_string },
+ { "is-local", add_param_boolean },
+ { "unix-user", add_param_int },
+};
+
+static GPtrArray *
+parse_output (const char *output)
+{
+ GPtrArray *parameters;
+ char **lines;
+ int i;
+ int j;
+
+ lines = g_strsplit (output, "\n", -1);
+ if (lines == NULL) {
+ return NULL;
+ }
+
+ parameters = g_ptr_array_sized_new (10);
+
+ for (i = 0; lines[i] != NULL; i++) {
+ char **vals;
+
+ vals = g_strsplit (lines[i], " = ", 2);
+ if (vals == NULL || vals[0] == NULL) {
+ g_strfreev (vals);
+ continue;
+ }
+
+ for (j = 0; j < G_N_ELEMENTS (parse_ops); j++) {
+ if (strcmp (vals[0], parse_ops[j].key) == 0) {
+ parse_ops[j].func (parameters, vals[0], vals[1]);
+ break;
+ }
+ }
+ g_strfreev (vals);
+ }
+
+ g_strfreev (lines);
+
+ return parameters;
+}
+
+
+static void
+parameters_free (GPtrArray *parameters)
+{
+ int i;
+
+ for (i = 0; i < parameters->len; i++) {
+ gpointer data;
+ data = g_ptr_array_index (parameters, i);
+ if (data != NULL) {
+ g_boxed_free (CK_TYPE_PARAMETER_STRUCT, data);
+ }
+ }
+
+ g_ptr_array_free (parameters, TRUE);
+}
+
+typedef struct {
+ CkSessionLeader *leader;
+ CkSessionLeaderDoneFunc done_cb;
+ gpointer user_data;
+ DBusGMethodInvocation *context;
+} JobData;
+
+static void
+job_completed (CkJob *job,
+ int status,
+ JobData *data)
+{
+ g_debug ("Job status: %d", status);
+ if (status == 0) {
+ char *output;
+ GPtrArray *parameters;
+
+ output = NULL;
+ ck_job_get_stdout (job, &output);
+ g_debug ("Job output: %s", output);
+
+ parameters = parse_output (output);
+ g_free (output);
+
+ data->done_cb (data->leader,
+ parameters,
+ data->context,
+ data->user_data);
+ parameters_free (parameters);
+ } else {
+ data->done_cb (data->leader,
+ NULL,
+ data->context,
+ data->user_data);
+ }
+
+ /* remove job from queue */
+ data->leader->priv->pending_jobs = g_list_remove (data->leader->priv->pending_jobs, job);
+
+ g_signal_handlers_disconnect_by_func (job, job_completed, data);
+ g_object_unref (job);
+}
+
+static void
+job_data_free (JobData *data)
+{
+ g_free (data);
+}
+
+gboolean
+ck_session_leader_collect_parameters (CkSessionLeader *session_leader,
+ DBusGMethodInvocation *context,
+ CkSessionLeaderDoneFunc done_cb,
+ gpointer user_data)
+{
+ GError *local_error;
+ char *command;
+ gboolean res;
+ gboolean ret;
+ CkJob *job;
+ JobData *data;
+
+ ret = FALSE;
+
+ data = g_new0 (JobData, 1);
+ data->leader = session_leader;
+ data->done_cb = done_cb;
+ data->user_data = user_data;
+ data->context = context;
+
+ command = g_strdup_printf ("%s --uid %u --pid %u",
+ LIBEXECDIR "/ck-collect-session-info",
+ session_leader->priv->uid,
+ session_leader->priv->pid);
+ job = ck_job_new ();
+ ck_job_set_command (job, command);
+ g_free (command);
+
+ g_signal_connect_data (job,
+ "completed",
+ G_CALLBACK (job_completed),
+ data,
+ (GClosureNotify)job_data_free,
+ 0);
+
+ local_error = NULL;
+ res = ck_job_execute (job, &local_error);
+ if (! res) {
+ if (local_error != NULL) {
+ g_debug ("stat on pid %d failed: %s", session_leader->priv->pid, local_error->message);
+ g_error_free (local_error);
+ }
+
+ g_object_unref (job);
+
+ goto out;
+ }
+
+ /* Add job to queue */
+ session_leader->priv->pending_jobs = g_list_prepend (session_leader->priv->pending_jobs, job);
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
+
+const char *
+ck_session_leader_peek_session_id (CkSessionLeader *session_leader)
+{
+ g_return_val_if_fail (CK_IS_SESSION_LEADER (session_leader), NULL);
+ return session_leader->priv->session_id;
+}
+
+const char *
+ck_session_leader_peek_cookie (CkSessionLeader *session_leader)
+{
+ g_return_val_if_fail (CK_IS_SESSION_LEADER (session_leader), NULL);
+ return session_leader->priv->cookie;
+}
+
+const char *
+ck_session_leader_peek_service_name (CkSessionLeader *session_leader)
+{
+ g_return_val_if_fail (CK_IS_SESSION_LEADER (session_leader), NULL);
+ return session_leader->priv->service_name;
+}
+
+uid_t
+ck_session_leader_get_uid (CkSessionLeader *session_leader)
+{
+ g_return_val_if_fail (CK_IS_SESSION_LEADER (session_leader), -1);
+ return session_leader->priv->uid;
+}
+
+pid_t
+ck_session_leader_get_pid (CkSessionLeader *session_leader)
+{
+ g_return_val_if_fail (CK_IS_SESSION_LEADER (session_leader), -1);
+ return session_leader->priv->pid;
+}
+
+void
+ck_session_leader_set_pid (CkSessionLeader *session_leader,
+ pid_t pid)
+{
+ g_return_if_fail (CK_IS_SESSION_LEADER (session_leader));
+ session_leader->priv->pid = pid;
+}
+
+void
+ck_session_leader_set_uid (CkSessionLeader *session_leader,
+ uid_t uid)
+{
+ g_return_if_fail (CK_IS_SESSION_LEADER (session_leader));
+ session_leader->priv->uid = uid;
+}
+
+void
+ck_session_leader_set_session_id (CkSessionLeader *session_leader,
+ const char *session_id)
+{
+ g_return_if_fail (CK_IS_SESSION_LEADER (session_leader));
+ g_free (session_leader->priv->session_id);
+ session_leader->priv->session_id = g_strdup (session_id);
+}
+
+void
+ck_session_leader_set_cookie (CkSessionLeader *session_leader,
+ const char *cookie)
+{
+ g_return_if_fail (CK_IS_SESSION_LEADER (session_leader));
+ g_free (session_leader->priv->cookie);
+ session_leader->priv->cookie = g_strdup (cookie);
+}
+
+void
+ck_session_leader_set_service_name (CkSessionLeader *session_leader,
+ const char *service_name)
+{
+ g_return_if_fail (CK_IS_SESSION_LEADER (session_leader));
+ g_free (session_leader->priv->service_name);
+ session_leader->priv->service_name = g_strdup (service_name);
+}
+
+static void
+ck_session_leader_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ CkSessionLeader *self;
+
+ self = CK_SESSION_LEADER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+ck_session_leader_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ CkSessionLeader *self;
+
+ self = CK_SESSION_LEADER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+ck_session_leader_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ CkSessionLeader *session_leader;
+ CkSessionLeaderClass *klass;
+
+ klass = CK_SESSION_LEADER_CLASS (g_type_class_peek (CK_TYPE_SESSION_LEADER));
+
+ session_leader = CK_SESSION_LEADER (G_OBJECT_CLASS (ck_session_leader_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ return G_OBJECT (session_leader);
+}
+
+static void
+ck_session_leader_class_init (CkSessionLeaderClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructor = ck_session_leader_constructor;
+ object_class->get_property = ck_session_leader_get_property;
+ object_class->set_property = ck_session_leader_set_property;
+ object_class->finalize = ck_session_leader_finalize;
+
+ g_type_class_add_private (klass, sizeof (CkSessionLeaderPrivate));
+}
+
+static void
+ck_session_leader_init (CkSessionLeader *session_leader)
+{
+ session_leader->priv = CK_SESSION_LEADER_GET_PRIVATE (session_leader);
+}
+
+static void
+ck_session_leader_finalize (GObject *object)
+{
+ CkSessionLeader *session_leader;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (CK_IS_SESSION_LEADER (object));
+
+ session_leader = CK_SESSION_LEADER (object);
+
+ g_return_if_fail (session_leader->priv != NULL);
+
+ g_free (session_leader->priv->session_id);
+ session_leader->priv->session_id = NULL;
+ g_free (session_leader->priv->cookie);
+ session_leader->priv->cookie = NULL;
+ g_free (session_leader->priv->service_name);
+ session_leader->priv->service_name = NULL;
+
+ G_OBJECT_CLASS (ck_session_leader_parent_class)->finalize (object);
+}
+
+CkSessionLeader *
+ck_session_leader_new (void)
+{
+ GObject *object;
+
+ object = g_object_new (CK_TYPE_SESSION_LEADER,
+ NULL);
+
+ return CK_SESSION_LEADER (object);
+}
+
+void
+ck_session_leader_dump (CkSessionLeader *session_leader,
+ GKeyFile *key_file)
+{
+ char *group_name;
+
+ group_name = g_strdup_printf ("SessionLeader %s", session_leader->priv->session_id);
+ g_key_file_set_string (key_file, group_name, "session", session_leader->priv->session_id);
+ g_key_file_set_integer (key_file, group_name, "uid", session_leader->priv->uid);
+ g_key_file_set_integer (key_file, group_name, "pid", session_leader->priv->pid);
+ g_key_file_set_string (key_file, group_name, "cookie", session_leader->priv->cookie);
+ g_key_file_set_string (key_file, group_name, "service_name", session_leader->priv->service_name);
+
+ g_free (group_name);
+}
diff --git a/src/ck-session-leader.h b/src/ck-session-leader.h
new file mode 100644
index 0000000..4eb8857
--- /dev/null
+++ b/src/ck-session-leader.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006-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_SESSION_LEADER_H
+#define __CK_SESSION_LEADER_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+G_BEGIN_DECLS
+
+#define CK_TYPE_SESSION_LEADER (ck_session_leader_get_type ())
+#define CK_SESSION_LEADER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CK_TYPE_SESSION_LEADER, CkSessionLeader))
+#define CK_SESSION_LEADER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CK_TYPE_SESSION_LEADER, CkSessionLeaderClass))
+#define CK_IS_SESSION_LEADER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CK_TYPE_SESSION_LEADER))
+#define CK_IS_SESSION_LEADER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CK_TYPE_SESSION_LEADER))
+#define CK_SESSION_LEADER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CK_TYPE_SESSION_LEADER, CkSessionLeaderClass))
+
+typedef struct CkSessionLeaderPrivate CkSessionLeaderPrivate;
+
+typedef struct
+{
+ GObject parent;
+ CkSessionLeaderPrivate *priv;
+} CkSessionLeader;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+} CkSessionLeaderClass;
+
+typedef enum
+{
+ CK_SESSION_LEADER_ERROR_GENERAL
+} CkSessionLeaderError;
+
+#define CK_SESSION_LEADER_ERROR ck_session_leader_error_quark ()
+
+typedef void (* CkSessionLeaderDoneFunc) (CkSessionLeader *session_leader,
+ GPtrArray *parameters,
+ DBusGMethodInvocation *context,
+ gpointer data);
+
+GQuark ck_session_leader_error_quark (void);
+GType ck_session_leader_get_type (void);
+CkSessionLeader * ck_session_leader_new (void);
+
+void ck_session_leader_set_pid (CkSessionLeader *session_leader,
+ pid_t pid);
+void ck_session_leader_set_uid (CkSessionLeader *session_leader,
+ uid_t uid);
+void ck_session_leader_set_session_id (CkSessionLeader *session_leader,
+ const char *session_id);
+void ck_session_leader_set_cookie (CkSessionLeader *session_leader,
+ const char *cookie);
+void ck_session_leader_set_service_name (CkSessionLeader *session_leader,
+ const char *sender);
+
+const char * ck_session_leader_peek_session_id (CkSessionLeader *session_leader);
+const char * ck_session_leader_peek_cookie (CkSessionLeader *session_leader);
+const char * ck_session_leader_peek_service_name (CkSessionLeader *session_leader);
+uid_t ck_session_leader_get_uid (CkSessionLeader *session_leader);
+pid_t ck_session_leader_get_pid (CkSessionLeader *session_leader);
+
+
+gboolean ck_session_leader_collect_parameters (CkSessionLeader *session_leader,
+ DBusGMethodInvocation *context,
+ CkSessionLeaderDoneFunc done_cb,
+ gpointer data);
+void ck_session_leader_cancel (CkSessionLeader *session_leader);
+
+void ck_session_leader_dump (CkSessionLeader *session_leader,
+ GKeyFile *key_file);
+
+
+G_END_DECLS
+
+#endif /* __CK_SESSION_LEADER_H */
diff --git a/src/ck-session.c b/src/ck-session.c
index f136333..d9e32be 100644
--- a/src/ck-session.c
+++ b/src/ck-session.c
@@ -40,12 +40,15 @@
#include "ck-session.h"
#include "ck-session-glue.h"
#include "ck-marshal.h"
+#include "ck-run-programs.h"
#define CK_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SESSION, CkSessionPrivate))
#define CK_DBUS_PATH "/org/freedesktop/ConsoleKit"
#define CK_DBUS_NAME "org.freedesktop.ConsoleKit"
+#define NONULL_STRING(x) ((x) != NULL ? (x) : "")
+
#define IDLE_TIME_SECS 60
struct CkSessionPrivate
@@ -394,6 +397,7 @@ ck_session_set_active (CkSession *session,
if (session->priv->active != active) {
session->priv->active = active;
+ ck_session_run_programs (session, "session_active_changed");
g_signal_emit (session, signals [ACTIVE_CHANGED], 0, active);
}
@@ -1206,3 +1210,106 @@ ck_session_new_with_parameters (const char *ssid,
return CK_SESSION (object);
}
+
+void
+ck_session_run_programs (CkSession *session,
+ const char *action)
+{
+ int n;
+ char *extra_env[11]; /* be sure to adjust this as needed */
+
+ n = 0;
+
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_ID=%s", session->priv->id);
+ if (session->priv->session_type != NULL) {
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_TYPE=%s", session->priv->session_type);
+ }
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_SEAT_ID=%s", session->priv->seat_id);
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_USER_UID=%d", session->priv->uid);
+ if (session->priv->display_device != NULL && strlen (session->priv->display_device) > 0) {
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_DISPLAY_DEVICE=%s", session->priv->display_device);
+ }
+ if (session->priv->x11_display_device != NULL && strlen (session->priv->x11_display_device) > 0) {
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_X11_DISPLAY_DEVICE=%s", session->priv->x11_display_device);
+ }
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_X11_DISPLAY=%s",
+ session->priv->x11_display ? session->priv->x11_display : "");
+ if (session->priv->remote_host_name != NULL && strlen (session->priv->remote_host_name) > 0) {
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_REMOTE_HOST_NAME=%s", session->priv->remote_host_name);
+ }
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_IS_ACTIVE=%s", session->priv->active ? "true" : "false");
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_IS_LOCAL=%s", session->priv->is_local ? "true" : "false");
+ extra_env[n++] = NULL;
+
+ ck_run_programs (SYSCONFDIR "/ConsoleKit/run-session.d", action, extra_env);
+ ck_run_programs (LIBDIR "/ConsoleKit/run-session.d", action, extra_env);
+
+ for (n = 0; extra_env[n] != NULL; n++) {
+ g_free (extra_env[n]);
+ }
+}
+
+void
+ck_session_dump (CkSession *session,
+ GKeyFile *key_file)
+{
+ char *s;
+ char *group_name;
+
+ group_name = g_strdup_printf ("Session %s", session->priv->id);
+ g_key_file_set_integer (key_file, group_name, "uid", session->priv->uid);
+ g_key_file_set_string (key_file,
+ group_name,
+ "seat",
+ NONULL_STRING (session->priv->seat_id));
+ g_key_file_set_string (key_file,
+ group_name,
+ "cookie",
+ NONULL_STRING (session->priv->cookie));
+ if (session->priv->session_type != NULL) {
+ g_key_file_set_string (key_file,
+ group_name,
+ "type",
+ NONULL_STRING (session->priv->session_type));
+ }
+ if (session->priv->display_device != NULL && strlen (session->priv->display_device) > 0) {
+ g_key_file_set_string (key_file,
+ group_name,
+ "display_device",
+ NONULL_STRING (session->priv->display_device));
+ }
+ if (session->priv->x11_display_device != NULL && strlen (session->priv->x11_display_device) > 0) {
+ g_key_file_set_string (key_file,
+ group_name,
+ "x11_display_device",
+ NONULL_STRING (session->priv->x11_display_device));
+ }
+ if (session->priv->x11_display != NULL && strlen (session->priv->x11_display) > 0) {
+ g_key_file_set_string (key_file,
+ group_name,
+ "x11_display",
+ NONULL_STRING (session->priv->x11_display));
+ }
+ if (session->priv->remote_host_name != NULL && strlen (session->priv->remote_host_name) > 0) {
+ g_key_file_set_string (key_file,
+ group_name,
+ "remote_host_name",
+ NONULL_STRING (session->priv->remote_host_name));
+ }
+ g_key_file_set_string (key_file,
+ group_name,
+ "remote_host_name",
+ NONULL_STRING (session->priv->remote_host_name));
+ g_key_file_set_boolean (key_file, group_name, "is_active", session->priv->active);
+ g_key_file_set_boolean (key_file, group_name, "is_local", session->priv->is_local);
+
+ s = g_time_val_to_iso8601 (&(session->priv->creation_time));
+ g_key_file_set_string (key_file,
+ group_name,
+ "creation_time",
+ NONULL_STRING (s));
+ g_free (s);
+
+ g_free (group_name);
+}
+
diff --git a/src/ck-session.h b/src/ck-session.h
index fea3a71..8c5c00e 100644
--- a/src/ck-session.h
+++ b/src/ck-session.h
@@ -74,6 +74,9 @@ CkSession * ck_session_new_with_parameters (const char *ss
const char *cookie,
const GPtrArray *parameters);
+void ck_session_dump (CkSession *session,
+ GKeyFile *key_file);
+
gboolean ck_session_set_active (CkSession *session,
gboolean active,
GError **error);
diff --git a/src/ck-sysdeps-solaris.c b/src/ck-sysdeps-solaris.c
index 9cfec2e..87bf4fd 100644
--- a/src/ck-sysdeps-solaris.c
+++ b/src/ck-sysdeps-solaris.c
@@ -30,6 +30,10 @@
#include <sys/stat.h>
#include <sys/ioctl.h>
+#ifdef HAVE_SYS_VT_H
+#include <sys/vt.h>
+#endif
+
#define DEV_ENCODE(M,m) ( \
( (M&0xfff) << 8) | ( (m&0xfff00) << 12) | (m&0xff) \
)
@@ -173,16 +177,30 @@ stat2proc (pid_t pid,
snprintf (P->tty_text, sizeof P->tty_text, "%3d,%-3d", tty_maj, tty_min);
+ if (tty_maj == 15) {
+ snprintf (P->tty_text, sizeof P->tty_text, "/dev/vt/%u", tty_min);
+ }
if (tty_maj == 24) {
- snprintf (P->tty_text, sizeof P->tty_text, "pts/%-3u", tty_min);
+ snprintf (P->tty_text, sizeof P->tty_text, "/dev/pts/%u", tty_min);
}
if (P->tty == NO_TTY_VALUE) {
+#ifdef HAVE_SYS_VT_H
memcpy (P->tty_text, " ? ", 8);
+#else
+ /*
+ * This is a bit of a hack. On Solaris, pre-VT integration, the
+ * Xorg process is not assigned a TTY. So, just assign the value
+ * to "/dev/console" if running without VT support. This will
+ * allow people using Solaris pre-VT integration to use
+ * ConsoleKit.
+ */
+ memcpy (P->tty_text, "/dev/console", 12);
+#endif
}
if (P->tty == DEV_ENCODE(0,0)) {
- memcpy (P->tty_text, "console", 8);
+ memcpy (P->tty_text, "/dev/console", 12);
}
if (P->pid != pid) {
@@ -256,7 +274,7 @@ ck_unix_pid_get_env_hash (pid_t pid)
if (skip_prefix != NULL) {
char **vals;
- vals = g_strsplit (buf, "=", 2);
+ vals = g_strsplit (skip_prefix + 1, "=", 2);
if (vals != NULL) {
g_hash_table_insert (hash,
g_strdup (vals[0]),
@@ -360,7 +378,7 @@ ck_get_max_num_consoles (guint *num)
error = NULL;
svcprop_stdout = NULL;
status = 0;
- res = g_spawn_command_line_sync ("/usr/bin/svcprop -p options/vtnodecount vtdaemon",
+ res = g_spawn_command_line_sync ("/usr/bin/svcprop -p options/nodecount vtdaemon",
&svcprop_stdout,
NULL,
&status,
@@ -395,7 +413,10 @@ ck_get_console_device_for_num (guint num)
{
char *device;
- device = g_strdup_printf ("/dev/vt/%u", num);
+ if (num == 1)
+ device = g_strdup_printf ("/dev/console", num);
+ else
+ device = g_strdup_printf ("/dev/vt/%u", num);
return device;
}
@@ -414,7 +435,9 @@ ck_get_console_num_from_device (const char *device,
return FALSE;
}
- if (sscanf (device, "/dev/vt/%u", &n) == 1) {
+ if (strcmp (device, "/dev/console") == 0) {
+ *num = 1;
+ } else if (sscanf (device, "/dev/vt/%u", &n) == 1) {
ret = TRUE;
}
@@ -432,6 +455,8 @@ ck_get_active_console_num (int console_fd,
gboolean ret;
int res;
guint active;
+
+#ifdef VT_GETSTATE
struct vt_stat stat;
g_assert (console_fd != -1);
@@ -464,6 +489,14 @@ ck_get_active_console_num (int console_fd,
if (num != NULL) {
*num = active;
}
+#else
+ /*
+ * If not using VT, not really an active number, but return 1,
+ * which maps to "/dev/console".
+ */
+ ret = TRUE;
+ *num = 1;
+#endif
return ret;
}
diff --git a/src/ck-sysdeps-unix.c b/src/ck-sysdeps-unix.c
index 0001b6b..e4ab16b 100644
--- a/src/ck-sysdeps-unix.c
+++ b/src/ck-sysdeps-unix.c
@@ -33,10 +33,13 @@
#ifdef __linux__
#include <linux/kd.h>
+#endif
+
+#ifdef HAVE_SYS_VT_H
#include <sys/vt.h>
#endif
-#ifdef __FreeBSD__
+#if HAVE_SYS_CONSIO_H
#include <sys/consio.h>
#endif
@@ -124,15 +127,15 @@ gboolean
ck_fd_is_a_console (int fd)
{
#ifdef __linux__
- char arg = 0;
+ struct vt_stat vts;
#elif defined(__FreeBSD__)
int vers;
#endif
int kb_ok;
+ errno = 0;
#ifdef __linux__
- kb_ok = (ioctl (fd, KDGKBTYPE, &arg) == 0
- && ((arg == KB_101) || (arg == KB_84)));
+ kb_ok = (ioctl (fd, VT_GETSTATE, &vts) == 0);
#elif defined(__FreeBSD__)
kb_ok = (ioctl (fd, CONS_GETVERS, &vers) == 0);
#else
@@ -193,6 +196,11 @@ ck_get_a_console_fd (void)
goto done;
}
+ fd = open_a_console ("/dev/tty0");
+ if (fd >= 0) {
+ goto done;
+ }
+
#ifdef _PATH_CONSOLE
fd = open_a_console (_PATH_CONSOLE);
if (fd >= 0) {
@@ -252,11 +260,15 @@ ck_wait_for_active_console_num (int console_fd,
again:
ret = FALSE;
- g_debug ("VT_WAITACTIVE for vt %d", num);
errno = 0;
+#ifdef VT_WAITACTIVE
+ g_debug ("VT_WAITACTIVE for vt %d", num);
res = ioctl (console_fd, VT_WAITACTIVE, num);
-
- g_debug ("VT_WAITACTIVE for vt %d returned %d", num, ret);
+ g_debug ("VT_WAITACTIVE for vt %d returned %d", num, res);
+#else
+ res = ERROR;
+ errno = ENOTSUP;
+#endif
if (res == ERROR) {
const char *errmsg;
@@ -268,6 +280,8 @@ ck_wait_for_active_console_num (int console_fd,
num,
errmsg);
goto again;
+ } else if (errno == ENOTSUP) {
+ g_debug ("Console activation not supported on this system");
} else {
g_warning ("Error waiting for native console %d activation: %s",
num,
@@ -294,11 +308,21 @@ ck_activate_console_num (int console_fd,
ret = FALSE;
errno = 0;
+#ifdef VT_ACTIVATE
res = ioctl (console_fd, VT_ACTIVATE, num);
+#else
+ res = ERROR;
+ errno = ENOTSUP;
+#endif
+
if (res == 0) {
ret = TRUE;
} else {
- g_warning ("Unable to activate console: %s", g_strerror (errno));
+ if (errno == ENOTSUP) {
+ g_debug ("Console activation not supported on this system");
+ } else {
+ g_warning ("Unable to activate console: %s", g_strerror (errno));
+ }
}
return ret;
diff --git a/src/ck-vt-monitor.c b/src/ck-vt-monitor.c
index 59d3d1c..d21026b 100644
--- a/src/ck-vt-monitor.c
+++ b/src/ck-vt-monitor.c
@@ -40,6 +40,12 @@
#include "ck-sysdeps.h"
#include "ck-marshal.h"
+#if defined (__sun) && defined (HAVE_SYS_VT_H)
+#include <sys/vt.h>
+#include <signal.h>
+#include <stropts.h>
+#endif
+
#ifndef ERROR
#define ERROR -1
#endif
@@ -157,6 +163,44 @@ ck_vt_monitor_get_active (CkVtMonitor *vt_monitor,
return TRUE;
}
+#if defined (__sun) && defined (HAVE_SYS_VT_H)
+static void
+handle_vt_active (void)
+{
+ struct vt_stat state;
+ guint num;
+ CkVtMonitor *vt_monitor = CK_VT_MONITOR (vt_object);
+
+ g_return_if_fail (CK_IS_VT_MONITOR (vt_monitor));
+
+ /*
+ * state.v_active value: [1 .. N]
+ *
+ * VT device file VT #
+ *
+ * /dev/console --- VT #1
+ * /dev/vt/2 --- VT #2
+ * /dev/vt/3 --- VT #3
+ * /dev/vt/N --- VT #4
+ */
+ if (ioctl (vt_monitor->priv->vfd, VT_GETSTATE, &state) != -1) {
+ num = state.v_active;
+ } else {
+ g_debug ("Fails to ioctl VT_GETSTATE");
+ }
+
+ if (vt_monitor->priv->active_num != num) {
+ g_debug ("Changing active VT: %d", num);
+
+ vt_monitor->priv->active_num = num;
+
+ g_signal_emit (vt_monitor, signals [ACTIVE_CHANGED], 0, num);
+ } else {
+ g_debug ("VT activated but already active: %d", num);
+ }
+}
+#endif
+
static void
change_active_num (CkVtMonitor *vt_monitor,
guint num)
@@ -338,6 +382,22 @@ vt_add_watches (CkVtMonitor *vt_monitor)
int i;
gint32 current_num;
+#if defined (__sun) && !defined (HAVE_SYS_VT_H)
+ /* Best to do nothing if VT is not supported */
+#elif defined (__sun) && defined (HAVE_SYS_VT_H)
+ /*
+ * Solaris supports synchronous event notification in STREAMS.
+ * Applications that open the virtual console device can
+ * get a asynchronous notification of VT switching by setting
+ * the S_MSG flag in an I_SETSIG STREAMS ioctl. Such processes
+ * receive a SIGPOLL signal when a VT switching succeeds.
+ */
+ struct sigaction act;
+ act.sa_handler = handle_vt_active;
+ sigaction (SIGPOLL, &act, NULL);
+
+ ioctl (vt_monitor->priv->vfd, I_SETSIG, S_MSG);
+#else
G_LOCK (hash_lock);
current_num = vt_monitor->priv->active_num;
@@ -365,6 +425,7 @@ vt_add_watches (CkVtMonitor *vt_monitor)
}
G_UNLOCK (hash_lock);
+#endif
}
static void
diff --git a/src/main.c b/src/main.c
index 11b6f2e..adc0d71 100644
--- a/src/main.c
+++ b/src/main.c
@@ -252,6 +252,42 @@ setup_debug_log (gboolean debug)
setup_debug_log_signals ();
}
+static void
+create_pid_file (void)
+{
+ char *dirname;
+ int res;
+ int pf;
+ ssize_t written;
+ char pid[9];
+
+ /* remove old pid file */
+ unlink (CONSOLE_KIT_PID_FILE);
+
+ dirname = g_path_get_dirname (CONSOLE_KIT_PID_FILE);
+ errno = 0;
+ res = g_mkdir_with_parents (dirname,
+ S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ if (res < 0) {
+ g_warning ("Unable to create directory %s (%s)",
+ dirname,
+ g_strerror (errno));
+ }
+ g_free (dirname);
+
+ /* make a new pid file */
+ if ((pf = open (CONSOLE_KIT_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) {
+ snprintf (pid, sizeof (pid), "%lu\n", (long unsigned) getpid ());
+ written = write (pf, pid, strlen (pid));
+ close (pf);
+ g_atexit (delete_pid);
+ } else {
+ g_warning ("Unable to write pid file %s: %s",
+ CONSOLE_KIT_PID_FILE,
+ g_strerror (errno));
+ }
+}
+
int
main (int argc,
char **argv)
@@ -261,11 +297,9 @@ main (int argc,
GOptionContext *context;
DBusGProxy *bus_proxy;
DBusGConnection *connection;
+ GError *error;
int ret;
- int pf;
- ssize_t written;
- char pid[9];
-
+ gboolean res;
static gboolean debug = FALSE;
static gboolean no_daemon = FALSE;
static gboolean do_timed_exit = FALSE;
@@ -289,10 +323,21 @@ main (int argc,
exit (1);
}
+ if (debug) {
+ g_setenv ("G_DEBUG", "fatal_criticals", FALSE);
+ g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
+ }
+
context = g_option_context_new (_("Console kit daemon"));
g_option_context_add_main_entries (context, entries, NULL);
- g_option_context_parse (context, &argc, &argv, NULL);
+ error = NULL;
+ res = g_option_context_parse (context, &argc, &argv, &error);
g_option_context_free (context);
+ if (! res) {
+ g_warning (error->message);
+ g_error_free (error);
+ goto out;
+ }
if (! no_daemon && daemon (0, 0)) {
g_error ("Could not daemonize: %s", g_strerror (errno));
@@ -318,16 +363,7 @@ main (int argc,
g_debug ("initializing console-kit-daemon %s", VERSION);
- /* remove old pid file */
- unlink (CONSOLE_KIT_PID_FILE);
-
- /* make a new pid file */
- if ((pf = open (CONSOLE_KIT_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) {
- snprintf (pid, sizeof (pid), "%lu\n", (long unsigned) getpid ());
- written = write (pf, pid, strlen (pid));
- close (pf);
- g_atexit (delete_pid);
- }
+ create_pid_file ();
manager = ck_manager_new ();
diff --git a/src/test-event-logger.c b/src/test-event-logger.c
new file mode 100644
index 0000000..e3d7db0
--- /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)
+{
+ CkLogEvent event;
+ GError *error;
+ gboolean res;
+
+ memset (&event, 0, sizeof (CkLogEvent));
+
+ event.type = CK_LOG_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;
+}
diff --git a/src/test-open-session-with-parameters b/src/test-open-session-with-parameters
index e9e3358..ce622ce 100755
--- a/src/test-open-session-with-parameters
+++ b/src/test-open-session-with-parameters
@@ -15,7 +15,7 @@ manager_obj = bus.get_object ('org.freedesktop.ConsoleKit', '/org/freedesktop/Co
manager = dbus.Interface (manager_obj, 'org.freedesktop.ConsoleKit.Manager')
params = dbus.Array ([], signature = "sv")
-params.append (("user", dbus.Variant (730)))
+params.append (("unix-user", dbus.Variant (730)))
params.append (("session-type", dbus.Variant ("gnome-session")))
#params.append (("x11-display", dbus.Variant (":0.0")))
params.append (("display-device", dbus.Variant ("/dev/tty8")))