17903105 M7: Display device hotplug support - Interface to start/kill X sessions s11u3_09
authorhenryzh <henry.zhao@oracle.com>
Mon, 13 Oct 2014 15:22:07 -0700
changeset 1417 f97e1099346b
parent 1416 e0f6ec7d26e9
child 1418 b4b80fd490b1
17903105 M7: Display device hotplug support - Interface to start/kill X sessions
open-src/app/Makefile
open-src/app/dsession/Makefile
open-src/app/dsession/sun-src/Makefile
open-src/app/dsession/sun-src/dsession.c
open-src/app/dsession/sun-src/dsession.man
pkg/manifests/x11-session-dsession.p5m
--- a/open-src/app/Makefile	Wed Oct 01 15:49:37 2014 -0700
+++ b/open-src/app/Makefile	Mon Oct 13 15:22:07 2014 -0700
@@ -1,6 +1,6 @@
 # Makefile for X Consolidation Open Source Application modules
 #
-# Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
 #
 # Permission is hereby granted, free of charge, to any person obtaining a
 # copy of this software and associated documentation files (the "Software"),
@@ -124,6 +124,7 @@
 	xwud \
 
 OS_SUBDIRS_sparc = $(OS_SUBDIRS_common) \
+	dsession \
 	gfx-utils
 
 OS_SUBDIRS_i386 = $(OS_SUBDIRS_common) \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/open-src/app/dsession/Makefile	Mon Oct 13 15:22:07 2014 -0700
@@ -0,0 +1,64 @@
+###############################################################################
+#
+# dsession - utility for managing dynamic sessions
+#
+# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+#
+
+# Package name used in tarballs
+MODULE_NAME=dsession
+
+# Version number (used in path names)
+MODULE_VERSION=1.0.0
+
+# No upstream sources, only local sources
+SOURCE_TARBALL_NAME=NONE
+SOURCE_TARBALL_NAME_SET=yes
+SOURCE_TARGETS =
+ADDITIONAL_SOURCE_DIR=sun-src
+
+# Dates to show in Oracle copyright notice in pkg license file
+# Earliest & latest of the copyrights in the Oracle files in this pkg
+ORACLE_COPYRIGHT_YEARS = 2014
+
+# pkg(5) name we deliver the files in (override default)
+MODULE_PKGNAME=x11/session/$(MODULE_NAME)
+MODULE_PKGNAME_SET=yes
+
+# ARC cases that covered this module
+# PSARC/2014/217 M7 fail-over and hotplug 
+MODULE_ARC_CASES = PSARC/2014/217
+
+# Man pages to apply Sun footer to & attributes to list
+SUNTOUCHED_MANPAGES= # None
+MODULE_STABILITY=Volatile
+
+# No configure script to run
+CONFIGURE_TARGETS=
+CONFIGURE_TARGETS_SET=yes
+
+# Since we don't have a configure script, pass configure flags to make
+MODULE_BUILD_MAKEFLAGS=$(CONFIG_ENV) PREFIX=$(MODULE_PREFIX)
+MODULE_INSTALL_MAKEFLAGS=$(CONFIG_ENV) PREFIX=$(MODULE_PREFIX)
+
+include ../Makefile.inc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/open-src/app/dsession/sun-src/Makefile	Mon Oct 13 15:22:07 2014 -0700
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+
+SRCS = dsession.c
+OBJS = $(SRCS:.c=.o)
+LIBS = -lpciaccess 
+
+dsession: $(OBJS)
+	$(LD) -o $@ $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS)
+
+install: dsession
+	mkdir -p $(DESTDIR)$(PREFIX)/lib/ConsoleKit
+	$(INSTALL) -m 0544 dsession $(DESTDIR)$(PREFIX)/lib/ConsoleKit
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/open-src/app/dsession/sun-src/dsession.c	Mon Oct 13 15:22:07 2014 -0700
@@ -0,0 +1,1812 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files(the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice(including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <sys/stat.h>
+#include <sys/shm.h>
+#include <sys/ipc.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <dirent.h>
+#include <synch.h>
+#include <signal.h>
+#include <libgen.h>
+#include <X11/Xos.h>
+#include "pciaccess.h"
+#include "xorg/xf86Pci.h"
+
+
+#define MAX_DISP_DEV	8
+#define IS_VGA(c) \
+	(((c) & 0x00ffff00) \
+	== ((PCI_CLASS_DISPLAY << 16) | (PCI_SUBCLASS_DISPLAY_VGA << 8)))
+#define RETRY_COUNT	30
+#define ALL		255
+#define MAX_EARGC	8
+#define FTOK_FILE	"/usr/lib/ConsoleKit/dsession"
+#define FTOK_ID		'H'
+#define SESSION_SIZE	64
+#define TYPE_SIZE	16
+
+typedef struct {
+	char	session_id[SESSION_SIZE];
+	Bool	open;
+	char	busid[64];
+	char	dev_path[PATH_MAX];
+	int	display;
+	char	status[TYPE_SIZE];
+	char	usr_session[SESSION_SIZE];
+	pid_t	server_pid;
+} dsession_mgr_t;
+
+typedef struct {
+	char	session_id[SESSION_SIZE];
+	Bool	open;
+	int	display;
+	char	session_type[TYPE_SIZE];
+	char	display_type[TYPE_SIZE];
+} ck_session_t;
+
+typedef struct {
+	dsession_mgr_t	dsession_table[MAX_DISP_DEV];
+	mutex_t		lock;
+} shared_mem_t;
+
+static struct pci_device_iterator * iter;
+static struct pci_device * dev;
+static struct sol_device_private {
+	    struct pci_device	base;
+	    const char		*device_string;
+	};
+#define DEV_PATH(dev)	(((struct sol_device_private *) dev)->device_string)
+
+static char 		*program_name;
+static dsession_mgr_t	dsession_mgr_table[MAX_DISP_DEV];
+static int		disp_num = 0;
+static ck_session_t	ck_sessions[MAX_DISP_DEV * 2];
+static int   		num_sessions = 0;
+static char		device[PATH_MAX];
+static void		*shm_addr = NULL;
+static key_t		shm_key;
+static int		shmid;
+static Bool		debug = FALSE;
+
+#define lock		(((shared_mem_t *) shm_addr)->lock)
+#define shm_table	(((shared_mem_t *) shm_addr)->dsession_table)
+
+
+static Bool
+cmd_exec(char *cmd, char *output, size_t size)
+{
+    pid_t pid;
+    int   p_fd[2];
+    char  *token;
+    char  string[MAX_EARGC + 1][64];
+    char  *eargv[MAX_EARGC + 1];
+    int   i;
+
+    if (debug)
+	printf("run cmd: %s\n", cmd);
+
+    /* parse cmd */
+    memset(eargv, 0, sizeof (eargv));
+    i = -1;
+
+    token = strtok(cmd, " ");
+
+    /* walk through other tokens */
+    while (token != NULL) {
+	if (++i == MAX_EARGC) {
+	    fprintf(stderr, "cmd_exec: arguments exceed limit\n");
+
+	    return FALSE;
+	}
+
+	strlcpy(string[i], token, sizeof (string[i]));
+	eargv[i] = string[i];
+
+	token = strtok(NULL, " ");
+    }
+
+    if (i == -1) {
+	fprintf(stderr, "cmd_exec: cmd parsing error\n");
+
+	return FALSE;
+    }
+
+    if (pipe(p_fd) != 0) {
+	fprintf(stderr, "cmd_exec command %s: ", eargv[0]);
+	perror("unable to pipe");
+
+	return FALSE;
+    }
+
+    if ((pid = fork()) == -1) {
+	fprintf(stderr, "cmd_exec command %s: ", eargv[0]);
+	perror("can not fork");
+
+	close(p_fd[0]);
+	close(p_fd[1]);
+
+	return FALSE;
+
+    } else if (pid == 0) {
+	/* child process */
+	close(p_fd[0]);
+
+	if (p_fd[1] != 1) {
+	    if (dup2(p_fd[1], 1) < 0) {
+		fprintf(stderr, "cmd_exec command %s: ", eargv[0]);
+		perror("child failed to reopen stdout");
+
+		return FALSE;
+	    }
+
+	    close(p_fd[1]);
+	}
+
+	execv(eargv[0], eargv);
+
+	fprintf(stderr, "cmd_exec command %s: ", eargv[0]);
+	perror("fail to exec"); 	/* shouldn't be reached */
+
+	_exit(1);
+
+    } else {
+	/* parent process */
+	FILE  *fd;
+	Bool  done = FALSE;
+	char  *buf;
+	int   status;
+	int   len;
+
+	close(p_fd[1]);
+	fd = fdopen(p_fd[0], "r");
+
+	if (output && (size > 0)) {
+	    buf = malloc(size);
+
+	    while (fgets(buf, size, fd) != NULL) {
+		/* only need one line from read */
+		if (!done) {
+		    strlcpy(output, buf, size);
+		    done = TRUE;
+		}
+	    }
+
+	    if ((len = strlen(output)) > 0) {
+		if (output[len - 1] == '\n')
+		    output[len - 1] = 0;
+
+		else
+		    output[len] = 0;
+	    }
+
+	} else {
+	    buf = malloc(256);
+
+	    while (fgets(buf, 256, fd) != NULL);
+	}
+
+	free(buf);
+
+	close(p_fd[0]);
+
+	if (waitpid(pid, &status, 0) != pid) {
+	    fprintf(stderr, "cmd_exec command %s: ", eargv[0]);
+	    perror("error waiting for child process");
+
+	    return FALSE;
+
+	} else if (WIFSIGNALED(status)) {
+	    fprintf(stderr, "cmd_exec command %s: ", eargv[0]);
+	    fprintf(stderr, "child exited with signal %d\n",
+		    WTERMSIG(status));
+
+	    return FALSE;
+
+	} else if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)) {
+	    return TRUE;
+
+	} else {
+	    fprintf(stderr, "cmd_exec command %s: ", eargv[0]);
+	    fprintf(stderr, "child exited abnormally\n");
+
+	    return FALSE;
+	}
+    }
+}
+
+static void
+get_dsession_mgr_table(void)
+{
+    int i;
+
+    memcpy(dsession_mgr_table, shm_table, sizeof (dsession_mgr_table));
+
+    for (i = 0; i < MAX_DISP_DEV; i++) {
+	if (!dsession_mgr_table[i].dev_path[0])
+	    break;
+    }
+
+    if (i == 0)
+	printf("warning: no entry in dsession table\n");
+
+    disp_num = i;
+}
+
+
+static void
+print_mgr_table_entry(int index)
+{
+    printf("%s:\n", dsession_mgr_table[index].session_id);
+
+    if (dsession_mgr_table[index].open)
+	printf("\topen = %s\n", "TRUE");
+
+    else
+	printf("\topen = %s\n", "FALSE");
+
+    if (dsession_mgr_table[index].busid[0])
+	printf("\tbusid = %s\n", dsession_mgr_table[index].busid);
+
+    else
+	printf("\tbusid = %s\n", "NULL");
+
+    if (dsession_mgr_table[index].dev_path[0])
+	printf("\tdev_path = %s\n", dsession_mgr_table[index].dev_path);
+
+    else
+	printf("\tdev_path = %s\n", "NULL");
+
+    if (dsession_mgr_table[index].display == -1)
+	printf("\tdisplay = :\n");
+
+    else
+	printf("\tdisplay = :%d\n", dsession_mgr_table[index].display);
+
+    if (dsession_mgr_table[index].status[0])
+	printf("\tstatus = %s\n", dsession_mgr_table[index].status);
+
+    else
+	printf("\tstatus = %s\n", "UNKNOWN");
+
+    if (dsession_mgr_table[index].usr_session[0])
+	printf("\tuser_session_id = %s\n",
+		dsession_mgr_table[index].usr_session);
+
+    fflush(stdout);
+}
+
+static Bool
+print_mgr_table(Bool all)
+{
+    int  i;
+
+    if (all) {
+	for (i = 0; i < disp_num; i++)
+	    print_mgr_table_entry(i);
+
+    } else {
+	for (i = 0; i < disp_num; i++) {
+	    if (strcmp(dsession_mgr_table[i].dev_path, device) == 0)
+		break;
+	}
+
+	if (i != disp_num)
+	    print_mgr_table_entry(i);
+
+	else {
+	    fprintf(stderr, "device not in the table\n");
+
+	    return FALSE;
+	}
+    }
+
+    return TRUE;
+}
+
+static int
+get_sessions(char *session)
+{
+    pid_t  pid;
+    int    p_fd[2];
+
+    if (pipe(p_fd) != 0) {
+	perror("get_sessions: unable to pipe");
+
+	return -1;
+    }
+
+    if ((pid = fork()) == -1) {
+	perror("get_sessions: can not fork");
+
+	close(p_fd[0]);
+	close(p_fd[1]);
+
+	return -1;
+
+    } else if (pid == 0) {
+	/* child process */
+	close(p_fd[0]);
+
+	if (p_fd[1] != 1) {
+	    if (dup2(p_fd[1], 1) < 0) {
+		perror("get_sessions: child failed to reopen stdout");
+
+		return -1;
+	    }
+
+	    close(p_fd[1]);
+	}
+
+	if (strcmp(session, "all") == 0)
+	    execl("/usr/bin/ck-list-sessions", "ck-list-sessions", "-a",
+		    NULL);
+
+	else
+	    execl("/usr/bin/ck-list-sessions", "ck-list-sessions", "-s",
+		    session, NULL);
+
+	perror("get_sessions: fail to exec"); 	/* shouldn't be reached */
+
+	_exit(1);
+
+    } else {
+	/* parent process */
+	FILE  *fd;
+	char  buf[BUFSIZ];
+	int   session_num;
+	int   status;
+	Bool  discard = FALSE;
+	Bool  ret = TRUE;
+
+	close(p_fd[1]);
+	fd = fdopen(p_fd[0], "r");
+	session_num = -1;
+
+	memset(ck_sessions, 0, sizeof (ck_sessions));
+
+	while (fgets(buf, BUFSIZ, fd) != NULL) {
+	    size_t  bufsize = strlen(buf);
+
+	    if (discard)
+		continue;
+
+	    if (buf[0] != '\t') {
+		/* session id */
+		if (++session_num > (MAX_DISP_DEV * 2 - 1)) {
+		    fprintf(stderr, "max session number exceeded.\n");
+
+		    discard = TRUE;
+		    ret = FALSE;
+
+		    continue;
+		}
+
+		if (bufsize && (buf[bufsize - 1] == '\n')) {
+		    buf[bufsize - 1] = 0;
+		    bufsize--;
+		}
+
+		if (bufsize && (buf[bufsize - 1] == ':'))
+		    buf[bufsize - 1] = 0;
+
+		strlcpy(ck_sessions[session_num].session_id, buf,
+			SESSION_SIZE);
+
+	    } else {
+		/* session body */
+		if (bufsize && (buf[bufsize - 1] == '\n'))
+		    buf[bufsize - 1] = 0;
+
+		if (strncmp(buf, "\topen = ", sizeof ("\topen = ") - 1) == 0) {
+		    if (strncmp(&buf[sizeof ("\topen = ") - 1], "'TRUE'",
+			    sizeof ("'TRUE'") - 1) == 0)
+			ck_sessions[session_num].open = TRUE;
+
+		    else if (strncmp(&buf[sizeof ("\topen = ") - 1], "'FALSE'",
+			    sizeof ("'FALSE'") - 1) == 0)
+			ck_sessions[session_num].open = FALSE;
+
+		} else if (strncmp(buf, "\tx11-display = ",
+			sizeof ("\tx11-display = ") - 1) == 0) {
+		    int disp;
+
+		    if (strncmp(&buf[sizeof ("\tx11-display = ") - 1], "''",
+			    sizeof ("''") - 1) == 0)
+			ck_sessions[session_num].display = -1;
+
+		    else {
+		        if (sscanf(buf, "\tx11-display = ':%d'",
+				&disp) == 1)
+			    ck_sessions[session_num].display = disp;
+		    }
+
+		} else if (strncmp(buf, "\tsession-type = ",
+			sizeof ("\tsession-type = ") - 1) == 0) {
+		    char type[TYPE_SIZE];
+
+		    if (strncmp(&buf[sizeof ("\tsession-type = ") - 1], "''",
+			    sizeof ("''") - 1) == 0)
+			ck_sessions[session_num].session_type[0] = 0;
+
+		    else {
+			if (sscanf(buf, "\tsession-type = '%16[^']",
+				type) == 1)
+			    strlcpy(ck_sessions[session_num].session_type,
+				    type, TYPE_SIZE);
+		    }
+
+		} else if (strncmp(buf, "\tdisplay-type = ",
+			sizeof ("\tdisplay-type = ") - 1) == 0) {
+		    char type[TYPE_SIZE];
+
+		    if (strncmp(&buf[sizeof ("\tdisplay-type = ") - 1], "''",
+			    sizeof ("''") - 1) == 0)
+			ck_sessions[session_num].display_type[0] = 0;
+
+		    else {
+			if (sscanf(buf, "\tdisplay-type = '%16[^']",
+				type) == 1)
+			    strlcpy(ck_sessions[session_num].display_type,
+				    type, TYPE_SIZE);
+		    }
+
+		} else
+		    /* ignore */
+		    continue;
+	    }
+	}
+
+	close(p_fd[0]);
+
+	if (waitpid(pid, &status, 0) != pid) {
+	    perror("get_sessions: error waiting for child process");
+
+	    return -1;
+
+	} else if (WIFSIGNALED(status)) {
+	    fprintf(stderr, "get_sessions: child exited with signal %d\n",
+		    WTERMSIG(status));
+
+            return -1;
+
+	} else if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)) {
+	    if (ret) {
+		if (debug) {
+		    if (strcmp(session, "all") == 0)
+			printf("get_sessions(all): %d sessions found\n",
+				session_num + 1);
+		    else
+			printf("get_sessions(single): %d sessions found\n",
+				session_num + 1);
+		}
+
+	 	return session_num + 1;
+
+	    } else
+		return -1;
+
+	} else {
+	    fprintf(stderr, "get_sessions: child exited abnormally\n");
+
+	    return -1;
+
+	}
+    }
+}
+
+static int
+find_session_in_list(char *session_id)
+{
+    int i;
+
+    if (!session_id)
+	return -1;
+
+    for (i = 0; i < num_sessions; i++) {
+	if (strcmp(ck_sessions[i].session_id, session_id) == 0)
+	    return i;
+    }
+
+    return -1;
+}
+
+
+static Bool
+probe_and_print_dev(void)
+{
+    if (pci_system_init() != 0) {
+	fprintf(stderr, "can't do pci system init\n");
+
+	return FALSE;
+    }
+
+    iter = pci_slot_match_iterator_create(NULL);
+
+    while ((dev = pci_device_next(iter)) != NULL) {
+	pci_device_probe(dev);
+
+	if (IS_VGA(dev->device_class)) {
+	    if (DEV_PATH(dev))
+		printf("/devices%s\n", DEV_PATH(dev));
+
+	}
+    }
+
+    pci_iterator_destroy(iter);
+    pci_system_cleanup();
+
+    return TRUE;
+}
+
+static Bool
+set_server_pid(int i)
+{
+    char  output[16];
+    long  pid;
+    char  display[8];
+
+    if (dsession_mgr_table[i].display != -1)
+	snprintf(display, sizeof (display), ":%d",
+		dsession_mgr_table[i].display);
+
+    else
+	return FALSE;
+
+    setenv("DISPLAY", display, 1);
+
+    memset(output, 0, sizeof (output));
+
+    if (cmd_exec("/usr/lib/ck-get-x11-server-pid", output,
+	    sizeof (output)) && output[0]) {
+	if (sscanf(output, "%ld", &pid) == 1) {
+	    dsession_mgr_table[i].server_pid = (pid_t) pid;
+
+	    if (debug)
+		printf("server pid %ld set for display :%d\n",
+			(long) dsession_mgr_table[i].server_pid,
+			dsession_mgr_table[i].display);
+
+	    return TRUE;
+
+	} else
+	    return FALSE;
+    }
+
+    return FALSE;
+}
+
+static Bool
+verify_and_set(char *type, int index)
+{
+
+    Bool verified = FALSE;
+    int  count = 0;
+    Bool allsessions;
+    int  i, j;
+    char *session_id;
+
+    if (index == ALL)
+	/* called from init() or fini() */
+	allsessions = TRUE;
+
+    else {
+	allsessions = FALSE;
+	session_id = dsession_mgr_table[index].session_id;
+    }
+
+    if (strcmp(type, "delete") == 0) {
+	while (!verified && (count++ < RETRY_COUNT)) {
+	    Bool   no_server_pid = FALSE;
+
+	    usleep(2000000);
+	    if (allsessions) {
+		/* delete all sessions, only when called from fini() */
+		if ((num_sessions = get_sessions("all")) == -1)
+		    return FALSE;
+
+		verified = TRUE;
+
+		for (i = 0; i < disp_num; i++) {
+		    pid_t server_pid = dsession_mgr_table[i].server_pid;
+
+		    if (strcmp(dsession_mgr_table[i].session_id, "Deleted")
+			    != 0) {
+			if ((find_session_in_list(
+				dsession_mgr_table[i].session_id)) == -1) {
+			    /*
+			     * session closed, also need to verify server
+			     * termination before exiting
+			     */
+			    if (server_pid != -1) {
+				if (kill(server_pid, 0)) {
+				    if (debug)
+					printf("server %ld terminated\n",
+						(long) server_pid);
+
+				} else
+				    verified = FALSE;
+
+			    } else
+				no_server_pid = TRUE;
+
+			    if (verified) {
+			        dsession_mgr_table[i].open = FALSE;
+
+			        strlcpy(dsession_mgr_table[i].session_id,
+					"Deleted", SESSION_SIZE);
+			        strlcpy(dsession_mgr_table[i].status,
+					"REMOVED", TYPE_SIZE);
+			    }
+
+			} else {
+			    verified = FALSE;
+
+			    if (count == (RETRY_COUNT - 5) &&
+				    (server_pid != -1)) {
+
+				errno = 0;
+				if ((kill(server_pid, SIGTERM) == -1) &&
+					(errno != ESRCH))
+				    perror("kill server failed");
+
+				else if (debug)
+				    printf("server %ld killed\n",
+					    (long) server_pid);
+			    }
+			}
+		    }
+		}
+
+		if (verified && no_server_pid)
+		    /*
+		     * add a delay if server's termination cannot be
+		     * verified
+		     */
+		    usleep(4000000);
+
+	    } else {
+		/* delete single session */
+		pid_t server_pid = dsession_mgr_table[index].server_pid;
+
+		if (get_sessions(session_id) == 0) {
+		    /*
+		     * session closed, also need to verify server
+		     * termination before exiting
+		     */
+		    if (server_pid != -1) {
+			if (kill(server_pid, 0)) {
+			    if (debug)
+				printf("server %ld terminated\n",
+					(long) server_pid);
+
+			    verified = TRUE;
+			}
+
+		    } else  {
+		        /*
+			 * add a delay if server's termination cannot be
+			 * verified
+			 */
+			usleep(4000000);
+			verified = TRUE;
+		    }
+
+		    if (verified) {
+			dsession_mgr_table[index].open = FALSE;
+
+			strlcpy(dsession_mgr_table[index].session_id,
+				"Deleted", SESSION_SIZE);
+			strlcpy(dsession_mgr_table[index].status,
+				"REMOVED", TYPE_SIZE);
+
+			memcpy(&shm_table[index],
+				&dsession_mgr_table[index],
+				sizeof (dsession_mgr_t));
+		    }
+
+		} else {
+		    if (count == (RETRY_COUNT - 5) &&
+			    (server_pid != -1)) {
+
+			errno = 0;
+			if ((kill(server_pid, SIGTERM) == -1) &&
+				(errno != ESRCH))
+			    perror("kill server failed");
+
+			else if (debug)
+			    printf("server %ld killed\n",
+				    (long) server_pid);
+		    }
+		}
+	    }
+	}
+
+    } else if (strcmp(type, "add") == 0) {
+	while (!verified && (count++ < RETRY_COUNT)) {
+	    usleep(2000000);
+
+	    if (allsessions) {
+		/* add all sessions, only when called from init() */
+		if ((num_sessions = get_sessions("all")) == -1)
+		    return FALSE;
+
+		verified = TRUE;
+
+		for (i = 0; i < disp_num; i++) {
+		    if ((j = find_session_in_list(
+			    dsession_mgr_table[i].session_id)) != -1) {
+			if ((!ck_sessions[j].open) ||
+				(ck_sessions[j].display == -1))
+			    verified = FALSE;
+
+		    } else
+			verified = FALSE;
+		}
+
+	    } else {
+		/* add single session */
+		i = get_sessions(session_id);
+
+		if ((i == 1) && ck_sessions[0].open &&
+			(ck_sessions[0].display != -1))
+		    verified = TRUE;
+	    }
+	}
+
+	if (allsessions) {
+	    /* add all sessions */
+	    for (i = 0; i < disp_num; i++) {
+		if ((j = find_session_in_list(
+			dsession_mgr_table[i].session_id)) != -1) {
+		    /* consolekit session was created */
+		    dsession_mgr_table[i].open = ck_sessions[j].open;
+
+		    if (dsession_mgr_table[i].open) {
+			dsession_mgr_table[i].display = ck_sessions[j].display;
+			strlcpy(dsession_mgr_table[i].status,
+				"UP", TYPE_SIZE);
+
+			if (!set_server_pid(i)) {
+			    dsession_mgr_table[i].server_pid = -1;
+			    fprintf(stderr, "set server pid failed for :%d\n",
+				    dsession_mgr_table[i].display);
+			}
+
+		    } else {
+			strlcpy(dsession_mgr_table[i].status,
+				"FAILURE", TYPE_SIZE);
+			fprintf(stderr, "added %s not verified\n",
+				dsession_mgr_table[i].session_id);
+		    }
+
+		} else
+		    fprintf(stderr, "dsession %s not added\n",
+			    dsession_mgr_table[i].session_id);
+	    }
+
+	} else {
+	    /* Add single session */
+	    if ((i == 1) && (strcmp(ck_sessions[0].session_id, session_id)
+		    == 0)) {
+		/* consolekit session was created */
+		dsession_mgr_table[index].open = ck_sessions[0].open;
+
+		if (dsession_mgr_table[index].open) {
+		    dsession_mgr_table[index].display = ck_sessions[0].display;
+		    strlcpy(dsession_mgr_table[index].status,
+			    "UP", TYPE_SIZE);
+
+		    if (!set_server_pid(index)) {
+			dsession_mgr_table[index].server_pid = -1;
+
+			fprintf(stderr, "set server pid failed for :%d\n",
+		  		dsession_mgr_table[index].display);
+		    }
+
+		} else
+		    strlcpy(dsession_mgr_table[index].status,
+			    "FAILURE", TYPE_SIZE);
+
+		memcpy(&shm_table[index], &dsession_mgr_table[index],
+			sizeof (dsession_mgr_t));
+	    }
+	}
+    }
+
+    return verified;
+
+}
+
+static int
+delete_session(void)
+{
+    int  i;
+    char cmd[128];
+
+    for (i = 0; i < disp_num; i++) {
+	if (strcmp(dsession_mgr_table[i].dev_path, device) == 0) {
+	    break;
+	}
+    }
+
+    if (i == disp_num) {
+	fprintf(stderr, "invalid device path: %s\n", device);
+	return -1;
+    }
+
+    if ((!dsession_mgr_table[i].session_id[0]) ||
+	    (get_sessions(dsession_mgr_table[i].session_id) == 0)) {
+	/*
+	 * no valid session id in mgr table, this is abnormal.
+	 * try to work around.
+	 */
+	if (dsession_mgr_table[i].display != -1) {
+	    int j;
+
+	    if ((num_sessions = get_sessions("all")) == -1)
+		return -1;
+
+	    for (j = 0; j < num_sessions; j++) {
+		if (ck_sessions[j].display == dsession_mgr_table[i].display) {
+		    strlcpy(dsession_mgr_table[i].session_id,
+			    ck_sessions[j].session_id, SESSION_SIZE);
+
+		    break;
+		}
+	    }
+	}
+
+	if (strcmp(dsession_mgr_table[i].session_id, "Deleted") == 0) {
+	    /* session already deleted */
+	    printf("dsession for device %s already deleted\n",
+		    basename(device));
+
+	    return i;
+	}
+    }
+
+    if (!dsession_mgr_table[i].open &&
+	    (strcmp(dsession_mgr_table[i].status, "TRANSFERRED") == 0) &&
+	    dsession_mgr_table[i].usr_session[0]) {
+	/* has a user session for it, delete it first */
+	printf("warning: you are deleting a user session\n");
+
+	snprintf(cmd, sizeof (cmd),
+		"/usr/sbin/ck-seat-tool --delete --session-id=%s",
+		dsession_mgr_table[i].usr_session);
+
+	if (cmd_exec(cmd, NULL, 0)) {
+	    dsession_mgr_table[i].usr_session[0] = 0;
+
+	    printf("user session %s deleted\n",
+		    dsession_mgr_table[i].usr_session);
+	}
+    }
+
+    snprintf(cmd, sizeof (cmd),
+	    "/usr/sbin/ck-seat-tool --delete --session-id=%s",
+	    dsession_mgr_table[i].session_id);
+
+    if (cmd_exec(cmd, NULL, 0)) {
+	printf("%s for device %s deleted\n", dsession_mgr_table[i].session_id,
+		basename(device));
+
+	return i;
+
+    } else {
+	fprintf(stderr, "%s for device %s not deleted\n",
+		dsession_mgr_table[i].session_id, basename(device));
+
+	return -1;
+    }
+}
+
+static int
+add_session(Bool init, int entry)
+{
+    int    index;
+    char   cmd[256];
+    char   output[64];
+    int    display;
+
+    if (init) {
+	/* called from init() */
+	index = entry;
+
+	/* avoid using display :0 */
+	display = index + 1;
+
+    } else {
+	Bool found = FALSE;
+
+	for (index = 0; index < disp_num; index++) {
+	    if (strcmp(dsession_mgr_table[index].dev_path, device) == 0)
+		break;
+	}
+
+	if (index < disp_num) {
+	    /* add session on existing device */
+	    if (dsession_mgr_table[index].session_id[0] &&
+		    (strcmp(dsession_mgr_table[index].session_id, "Deleted")
+		    != 0)) {
+		printf("session for device already running - not added\n");
+
+		return -1;
+	    }
+
+	   /*
+	    * check to see if a ck session already running on
+	    * the same display. this could happen when previous
+	    * verify_and_set() got interrupted .
+	    */
+	    if (dsession_mgr_table[index].display != -1) {
+		int i;
+
+		if ((num_sessions = get_sessions("all")) == -1)
+			return -1;
+
+		for (i = 0; i < num_sessions; i++) {
+		    if (ck_sessions[i].display ==
+			    dsession_mgr_table[index].display) {
+              		strlcpy(dsession_mgr_table[index].session_id,
+				ck_sessions[i].session_id, SESSION_SIZE);
+
+			printf("%s for device %s restored in table\n",
+				dsession_mgr_table[index].session_id,
+				basename(dsession_mgr_table[index].dev_path));
+
+            		break;
+		    }
+                }
+
+		if (i < num_sessions)
+		    return index;
+            }
+
+	} else if (disp_num == MAX_DISP_DEV) {
+	    /* index == disp_num, and adding a new session */
+	    fprintf(stderr, "add session: too many devices\n");
+
+	    return -1;
+	}
+
+	/*
+         * unless called from init(), always need a re-probe, as the numbering
+	 * of root complex may have changed. So table's busid needs update if
+         * the device already exits in the table.
+         */
+	if (pci_system_init() != 0) {
+	    fprintf(stderr, "can't do pci system init\n");
+
+	    return -1;
+	}
+
+	iter = pci_slot_match_iterator_create(NULL);
+
+	while ((dev = pci_device_next(iter)) != NULL) {
+	    char dev_path[PATH_MAX];
+
+	    if (IS_VGA(dev->device_class)) {
+		pci_device_probe(dev);
+
+		if (DEV_PATH(dev))
+		    snprintf(dev_path, PATH_MAX,
+			    "/devices%s", DEV_PATH(dev));
+		else
+		    continue;
+
+		if (strcmp(device, dev_path) == 0) {
+		    snprintf(dsession_mgr_table[index].busid,
+			    sizeof (dsession_mgr_table[index].busid),
+			    "PCI:%d:%d:%d", dev->domain << 8 | dev->bus,
+			    dev->dev, dev->func);
+
+		    if (index < disp_num) {
+			if ((display = dsession_mgr_table[index].display)
+				== -1)
+			    display = index + 1;
+
+		    } else {
+			/* add a session for new device */
+			strlcpy(dsession_mgr_table[index].dev_path, dev_path,
+				PATH_MAX);
+
+			dsession_mgr_table[index].display = -1;
+			dsession_mgr_table[index].server_pid = -1;
+
+			disp_num++;
+			display = index + 1;
+		    }
+
+		    found = TRUE;
+
+		    break;
+		}
+
+	    }
+	}
+
+	pci_iterator_destroy(iter);
+	pci_system_cleanup();
+
+	if (!found) {
+	    fprintf(stderr, "cannot find device %s in probe\n", device);
+
+	    return -1;
+	}
+    }
+
+    /* prepare command */
+    snprintf(cmd, sizeof (cmd),
+	    "/usr/sbin/ck-seat-tool -a --session-type=LoginWindow"
+	    " --display-type=HotPlug --seat-id=StaticSeat1"
+	    " display=:%d busid=%s",
+	    display, dsession_mgr_table[index].busid);
+
+    memset(output, 0, sizeof (output));
+
+    /* run command */
+    if (cmd_exec(cmd, output, sizeof (output)) && output[0]) {
+	printf("%s for device %s added\n", output,
+		basename(dsession_mgr_table[index].dev_path));
+
+	strlcpy(dsession_mgr_table[index].session_id, output,
+		SESSION_SIZE);
+
+	return index;
+
+    } else {
+	fprintf(stderr, "dsession for device %s not added\n",
+		basename(dsession_mgr_table[index].dev_path));
+
+	return -1;
+    }
+}
+
+static Bool
+restart_session(void)
+{
+    int i;
+
+    if ((i = delete_session()) == -1) {
+	fprintf(stderr, "failed to delete dsession for %s\n",
+		basename(device));
+
+	return FALSE;
+
+    } else {
+	if (!verify_and_set("delete", i)) {
+	    fprintf(stderr, "deleted dsession can't be verified,"
+		    "restart failed\n");
+
+	    return FALSE;
+
+	} else {
+	    printf("deleted dsession verified\n");
+
+	    if ((i = add_session(FALSE, 0)) == -1) {
+		fprintf(stderr, "failed to add dsession for %s\n",
+			basename(device));
+
+		return FALSE;
+
+	    } else {
+		if (!verify_and_set("add", i)) {
+		    fprintf(stderr, "added dsession can't be verified\n");
+
+		    return FALSE;
+
+		} else {
+		    printf("added dsession %s verified\n",
+			    dsession_mgr_table[i].session_id);
+		}
+	    }
+	}
+    }
+
+    return TRUE;
+}
+
+static Bool
+sync_sessions(void)
+{
+    int   i, j, k;
+    Bool  ret = TRUE;
+    Bool  ck_session_changed = FALSE;
+
+    if ((num_sessions = get_sessions("all")) == -1)
+	return FALSE;
+
+    for (j = 0; j < num_sessions; j++) {
+	if ((strncmp(ck_sessions[j].session_type, "LoginWindow",
+		sizeof ("LoginWindow") - 1) == 0) &&
+		(strncmp(ck_sessions[j].display_type, "HotPlug",
+		sizeof ("HotPlug") - 1) == 0) &&
+		ck_sessions[j].open == FALSE) {
+	    /* handle closed sessions */
+	    int   display = -1;
+
+	    for (i = 0; i < disp_num; i++) {
+		if (strcmp(dsession_mgr_table[i].session_id,
+			ck_sessions[j].session_id) == 0) {
+		    display = dsession_mgr_table[i].display;
+
+		    break;
+		}
+	    }
+
+	    if (display != -1) {
+		/* found a session in mgr table with valid display */
+		for (k = 0; k < num_sessions; k++) {
+		    if ((strncmp(ck_sessions[k].session_type, "LoginWindow",
+			    sizeof ("LoginWindow") - 1) != 0) &&
+			    (display == ck_sessions[k].display)) {
+			/*
+			 * found user session (type is not "LoginWindow")
+			 * with same display. update mgr table
+			 */
+			if (strncmp(dsession_mgr_table[i].status, "TRANSFERRED",
+				sizeof ("TRANSFERRED") - 1) != 0) {
+			    strlcpy(dsession_mgr_table[i].status,
+				    "TRANSFERRED", TYPE_SIZE);
+			    dsession_mgr_table[i].open = FALSE;
+
+			    strlcpy(dsession_mgr_table[i].usr_session,
+				    ck_sessions[k].session_id,
+				    SESSION_SIZE);
+
+			    memcpy(&shm_table[i], &dsession_mgr_table[i],
+				    sizeof (dsession_mgr_t));
+
+			    if (debug)
+				printf("session %s updated in sync\n",
+					dsession_mgr_table[i].session_id);
+			}
+
+			break;
+		    }
+		}
+
+	    } else {
+		/* not a transferred session, delete it as it's closed */
+		char cmd[128];
+
+		snprintf(cmd, sizeof (cmd),
+			"/usr/sbin/ck-seat-tool --delete --session-id=%s",
+			ck_sessions[j].session_id);
+
+		if (cmd_exec(cmd, NULL, 0)) {
+		    if (debug)
+			printf("session %s deleted in sync\n",
+				ck_sessions[j].session_id);
+
+		    ck_session_changed = TRUE;
+
+		} else
+		    ret = FALSE;
+
+		if (i < disp_num) {
+		    /* session in mgr table, need to update entry */
+		    strlcpy(dsession_mgr_table[i].session_id,
+			    "Deleted", SESSION_SIZE);
+		    strlcpy(dsession_mgr_table[i].status,
+			    "REMOVED", TYPE_SIZE);
+
+		    memcpy(&shm_table[i], &dsession_mgr_table[i],
+			    sizeof (dsession_mgr_t));
+		}
+	    }
+	}
+    }
+
+    if ((ck_session_changed) && ((num_sessions = get_sessions("all")) == -1))
+	ret = FALSE;
+
+    for (i = 0; i < disp_num; i++) {
+	if (strcmp(dsession_mgr_table[i].status, "TRANSFERRED") == 0) {
+	    for (j = 0; j < num_sessions; j++) {
+		if ((strcmp(dsession_mgr_table[i].session_id,
+			ck_sessions[j].session_id) == 0) &&
+			ck_sessions[j].open &&
+			find_session_in_list(dsession_mgr_table[i].usr_session)
+			== -1) {
+		    /*
+		     * corresponding session in ck table becomes open and
+		     * the user session does not exist any more
+		     */
+		    strlcpy(dsession_mgr_table[i].status, "UP",
+			    TYPE_SIZE);
+
+		    dsession_mgr_table[i].open = TRUE;
+		    dsession_mgr_table[i].usr_session[0] = 0;
+
+	    	    memcpy(&shm_table[i], &dsession_mgr_table[i],
+		    	    sizeof (dsession_mgr_t));
+
+		    if (debug)
+			printf("session %s updated in sync\n",
+				dsession_mgr_table[i].session_id);
+
+		    break;
+		}
+	    }
+	}
+    }
+
+    if (ret && debug)
+	printf("sync sessions done\n");
+
+    return ret;
+}
+
+static Bool
+fini(void)
+{
+    int i;
+
+    if ((shmid = shmget(shm_key, sizeof (shared_mem_t),
+	    IPC_ALLOC)) == -1) {
+	perror("shared memory get error");
+
+	return FALSE;
+    }
+
+    if ((shm_addr = (char *) shmat(shmid,
+	    (void *) NULL, 0)) == (void *) -1) {
+	perror("shared memory attach error");
+
+	return FALSE;
+    }
+
+    mutex_lock(&lock);
+
+    get_dsession_mgr_table();
+
+    for (i = 0; i < disp_num; i++) {
+	if (dsession_mgr_table[i].dev_path[0]) {
+	    strlcpy(device, dsession_mgr_table[i].dev_path, PATH_MAX);
+
+	    if (delete_session() == -1)
+	    	fprintf(stderr, "failed to delete dsession for %s\n",
+			basename(device));
+	}
+    }
+
+    /* verify sessions just deleted */
+    if (debug)
+	printf("verifying the deleted dsessions ...\n");
+
+    if (verify_and_set("delete", ALL))
+	printf("deleted dsessions all verified\n");
+
+    else
+	fprintf(stderr, "deleted dsessions not verified\n");
+
+    memcpy(shm_table, dsession_mgr_table, sizeof (dsession_mgr_table));
+
+    mutex_unlock(&lock);
+
+    if (shmdt(shm_addr) == -1) {
+	perror("shared memory detach error");
+
+	return FALSE;
+    }
+
+    return TRUE;
+}
+
+static Bool
+clean(void)
+{
+    if (!fini())
+	fprintf(stderr, "failed to fini\n");
+
+    if ((shmid = shmget(shm_key, sizeof (shared_mem_t),
+	    IPC_ALLOC)) == -1) {
+	perror("shared memory get error");
+
+	return FALSE;
+    }
+
+    if ((shm_addr = (char *) shmat(shmid,
+	    (void *) NULL, 0)) == (void *) -1) {
+	perror("shared memory attach error");
+
+	return FALSE;
+    }
+
+    mutex_destroy(&lock);
+
+    if (shmdt(shm_addr) == -1) {
+	perror("shared memory detach error");
+
+	return FALSE;
+    }
+
+    /* destroy the shared memory area */
+    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
+	perror("shared memory remove error");
+
+	return FALSE;
+    }
+
+    printf("shared memory removed\n");
+
+    return TRUE;
+}
+
+static Bool
+init(void)
+{
+    int  i;
+    Bool shm_created = FALSE;
+
+    if ((shmid = shmget(shm_key, sizeof (shared_mem_t),
+	    IPC_ALLOC)) != -1) {
+	/* shared memory already exists */
+	if ((shm_addr = (char *) shmat(shmid,
+		(void *) NULL, 0)) == (void *) -1) {
+            perror("shared memory attach error");
+
+	    return FALSE;
+        }
+
+	mutex_lock(&lock);
+
+	get_dsession_mgr_table();
+
+	for (i = 0; i < disp_num; i++) {
+	    if (dsession_mgr_table[i].session_id[0] &&
+		    (strcmp(dsession_mgr_table[i].session_id,
+		    "Deleted") != 0)) {
+		fprintf(stderr, "need to delete all sessions "
+			"before running \"dsession -i/--init\"\n");
+
+	        mutex_unlock(&lock);
+
+		if (shmdt(shm_addr) == -1)
+		    perror("shared memory detach error");
+
+		return FALSE;
+	    }
+	}
+
+	shm_created = TRUE;
+    }
+
+    /* initialize mgr table */
+    if (pci_system_init() != 0) {
+	fprintf(stderr, "can't do pci system init\n");
+
+	if (shm_created) {
+	    mutex_unlock(&lock);
+
+	    if (shmdt(shm_addr) == -1)
+		perror("shared memory detach error");
+	}
+
+	return FALSE;
+    }
+
+    memset(dsession_mgr_table, 0, sizeof (dsession_mgr_table));
+
+    disp_num = 0;
+
+    iter = pci_slot_match_iterator_create(NULL);
+
+    while ((dev = pci_device_next(iter)) != NULL) {
+	if (IS_VGA(dev->device_class)) {
+	    if (disp_num == MAX_DISP_DEV) {
+        	fprintf(stderr, "init: too many display devices\n");
+
+		if (shm_created) {
+		    mutex_unlock(&lock);
+
+		    if (shmdt(shm_addr) == -1)
+			perror("shared memory detach error");
+		}
+
+		pci_iterator_destroy(iter);
+		pci_system_cleanup();
+
+		return FALSE;
+	    }
+
+	    pci_device_probe(dev);
+
+	    snprintf(dsession_mgr_table[disp_num].busid,
+		    sizeof (dsession_mgr_table[disp_num].busid),
+		    "PCI:%d:%d:%d", dev->domain << 8 | dev->bus,
+		    dev->dev, dev->func);
+
+	    if (DEV_PATH(dev)) {
+		snprintf(dsession_mgr_table[disp_num].dev_path,
+			PATH_MAX,
+			"/devices%s", DEV_PATH(dev));
+
+		dsession_mgr_table[disp_num].display = -1;
+		dsession_mgr_table[disp_num].server_pid = -1;
+
+		disp_num++;
+	    }
+	}
+    }
+
+    pci_iterator_destroy(iter);
+    pci_system_cleanup();
+
+    if (!shm_created) {
+	/* shared memory has never been created */
+	if ((shmid = shmget(shm_key, sizeof (shared_mem_t),
+		IPC_CREAT|IPC_EXCL|0600)) == -1) {
+	    perror("shared memory get error during create");
+
+	    return FALSE;
+	}
+
+	printf("shared memory create successful\n");
+
+	if ((shm_addr = (char *) shmat(shmid,
+		(void *) NULL, 0)) == (void *) -1) {
+	    perror("shared memory attach error");
+
+	    return FALSE;
+	}
+
+	mutex_init(&lock, USYNC_PROCESS, NULL);
+
+	mutex_lock(&lock);
+    }
+
+    /* dynamically add sessions, one for each device */
+    for (i = 0; i < disp_num; i++) {
+	if (dsession_mgr_table[i].dev_path[0] &&
+		add_session(TRUE, i) == -1)
+	    fprintf(stderr, "failed to add dsession for %s\n",
+		    basename(device));
+    }
+
+    /* verify sessions just added */
+    if (debug)
+	printf("verifying the added dsessions ...\n");
+
+    if (verify_and_set("add", ALL))
+	printf("%d added dsessions all verified\n", disp_num);
+
+    else
+	fprintf(stderr, "added dsessions not verified\n");
+
+    memcpy(shm_table, dsession_mgr_table, sizeof (dsession_mgr_table));
+
+    mutex_unlock(&lock);
+
+    if (shmdt(shm_addr) == -1) {
+	perror("shared memory detach error");
+
+	return FALSE;
+    }
+
+    return TRUE;
+}
+
+/*ARGSUSED*/
+static void
+sig_handler(int sig)
+{
+    int status;
+
+    if (debug)
+	printf("signal %d caught\n", sig);
+
+    if (!(status = mutex_trylock(&lock)))
+	mutex_unlock(&lock);
+
+    else  if (status == EBUSY)
+	mutex_unlock(&lock);
+
+    if ((shm_addr) && (shmdt(shm_addr) == -1))
+	perror("shared memory detach error");
+
+    (void) sigset(sig, SIG_DFL);
+
+    (void) kill(getpid(), sig);
+
+    exit(1);
+}
+
+static void
+usage(void)
+{
+    fprintf(stderr,
+	    "\nUsage:\n");
+
+    fprintf(stderr,
+	    "%s -h|--help\n%s", program_name,
+	    "    Print help messages\n\n");
+
+    fprintf(stderr,
+	    "%s [debug-option] sub-command\n%s", program_name,
+            "    Run sub-command, where\n\n"
+	    "    debug-option:\n"
+            "    -v or --verb\t\tPrint debug messages\n\n"
+	    "    sub-command:\t\t(<dev> is path of display device)\n"
+            "    -a or --add <dev>\t\tAdd a dsession to run on <dev>\n"
+            "    -d or --delete <dev>\tDelete a dsession running on <dev>\n"
+            "    -r or --restart <dev>\tRestart a dsession running on <dev>\n"
+            "    -l or --list all\t\tList all dsessions\n"
+            "    -l or --list dev\t\tProbe and list devs\n"
+            "    -l or --list <dev>\t\tList dsession running on <dev>\n"
+            "    -i or --init\t\tInitialize: create shared memory\n"
+	    "		\t\tand mutex, add all dsessions\n"
+            "    -f or --fini\t\tFinish: delete all dsessions\n"
+            "    -c or --clean\t\tDelete all dsessions,\n"
+	    "		\t\tdestroy mutex and shared memory\n");
+}
+
+static Bool
+get_shm_key() {
+    struct stat statbuf;
+
+    if (stat(FTOK_FILE, &statbuf) != 0) {
+	fprintf(stderr, "need to install dsession at %s before run\n",
+		FTOK_FILE);
+
+	return FALSE;
+    }
+
+    if ((shm_key = ftok(FTOK_FILE, FTOK_ID)) == -1) {
+	perror("IPC error: ftok");
+
+	return FALSE;
+    }
+
+    return TRUE;
+}
+
+int
+main(int argc, char **argv)
+{
+
+    program_name = argv[0];
+    Bool  add = FALSE;
+    Bool  delete = FALSE;
+    Bool  list_all = FALSE;
+    Bool  list_dev = FALSE;
+    Bool  list_probe_dev = FALSE;
+    Bool  restart = FALSE;
+    int   ret = 0;
+    int   signals[] = {SIGHUP, SIGTERM, SIGINT, SIGQUIT, SIGSEGV, SIGBUS,
+			SIGPIPE};
+    int  i;
+
+    if ((argc == 2) && ((strcmp("-h", argv[1]) == 0) ||
+            (strcmp("--help", argv[1]) == 0))) {
+        usage();
+
+	exit(0);
+    }
+
+    if ((argc > 1) && ((strcmp("-v", argv[1]) == 0) ||
+            (strcmp("--verb", argv[1]) == 0))) {
+	debug = TRUE;
+
+	argc--;
+	argv++;
+    }
+
+    if ((argc < 2) || (argc > 3)) {
+	usage();
+
+	exit(1);
+    }
+
+    for (i = 0; i < sizeof (signals)/sizeof (signals[0]); i++) {
+	if (sigset(signals[i], SIG_IGN) == SIG_DFL)
+		(void) sigset(signals[i], sig_handler);
+    }
+
+    if ((strcmp("-a", argv[1]) == 0) ||
+	    (strcmp("--add", argv[1]) == 0))
+	add = TRUE;
+
+    else if ((strcmp("-d", argv[1]) == 0) ||
+	    (strcmp("--delete", argv[1]) == 0))
+	delete = TRUE;
+
+    else if ((strcmp("-r", argv[1]) == 0) ||
+	    (strcmp("--restart", argv[1]) == 0))
+	restart = TRUE;
+
+    else if (((strcmp("-l", argv[1]) == 0) ||
+	    (strcmp("--list", argv[1]) == 0)) &&
+	    (argc == 3)) {
+	if (strcmp("all", argv[2]) == 0)
+	    list_all = TRUE;
+
+	else if (strcmp("dev", argv[2]) == 0)
+	    list_probe_dev = TRUE;
+
+	else
+	    list_dev = TRUE;
+    }
+
+    if ((argc == 3) && (add || delete || restart || list_all || list_dev)) {
+	if (add || delete || restart || list_dev) {
+	    char  *path;
+
+	    if (path = realpath(argv[2], NULL)) {
+		strlcpy(device, path, PATH_MAX);
+		free(path);
+
+	    } else {
+		fprintf(stderr, "invalid device path: %s\n", argv[2]);
+
+		exit(1);
+	    }
+	}
+
+	if (!get_shm_key()) {
+	    fprintf(stderr, "get_shm_key failed\n");
+
+	    exit(1);
+	}
+
+	if ((shmid = shmget(shm_key, sizeof (shared_mem_t),
+		IPC_ALLOC)) == -1) {
+	    perror("shared memory get error");
+
+	    exit(1);
+	}
+
+	if ((shm_addr = (char *) shmat(shmid,
+		(void *) NULL, 0)) == (void *) -1) {
+	    perror("shared memory attach error");
+
+	    exit(1);
+	}
+
+	mutex_lock(&lock);
+
+	get_dsession_mgr_table();
+
+	if (!sync_sessions())
+	    fprintf(stderr, "warning: sync sessions partially failed\n");
+
+	if (add) {
+	    if ((i = add_session(FALSE, 0)) == -1) {
+		fprintf(stderr, "failed to add dsession for %s\n",
+			basename(device));
+		ret = 1;
+
+	    } else {
+		if (verify_and_set("add", i))
+		    printf("added dsession %s verified\n",
+			    dsession_mgr_table[i].session_id);
+
+		else {
+		    fprintf(stderr, "added dsession can't be verified\n");
+		    ret = 1;
+		}
+	    }
+
+	} else if (delete) {
+	    if ((i = delete_session()) == -1) {
+		fprintf(stderr, "failed to delete dsession for %s\n",
+			basename(device));
+		ret = 1;
+
+	    } else {
+		if (verify_and_set("delete", i))
+		    printf("deleted dsession verified\n");
+
+		else {
+		    fprintf(stderr, "deleted dsession can't be verified\n");
+		    ret = 1;
+		}
+	    }
+
+	} else if (restart) {
+	    if (restart_session())
+		printf("restart dsession on dev %s succeeded\n",
+			basename(device));
+
+	    else {
+		fprintf(stderr, "failed to restart dsession for %s\n",
+			basename(device));
+		ret = 1;
+	    }
+
+	} else if (list_all) {
+	    if (!print_mgr_table(TRUE))
+		fprintf(stderr, "failed to print table\n");
+
+	} else if (list_dev) {
+	    if (!print_mgr_table(FALSE)) {
+		fprintf(stderr, "failed to print table for %s\n", device);
+		ret = 1;
+	    }
+	}
+
+	mutex_unlock(&lock);
+
+	if (shmdt(shm_addr) == -1) {
+	    perror("shared memory detach error");
+
+            exit(1);
+	}
+
+    } else if (argc == 2) {
+	if (!get_shm_key()) {
+	    fprintf(stderr, "get_shm_key failed\n");
+
+	    exit(1);
+	}
+
+	if ((strcmp("-i", argv[1]) == 0) ||
+		(strcmp("--init", argv[1]) == 0)) {
+	    if (!init()) {
+		fprintf(stderr, "failed to init\n");
+
+		exit(1);
+	    }
+
+	} else if ((strcmp("-f", argv[1]) == 0) ||
+		(strcmp("--fini", argv[1]) == 0)) {
+	    if (!fini()) {
+		fprintf(stderr, "failed to fini\n");
+
+		exit(1);
+	    }
+
+	} else if ((strcmp("-c", argv[1]) == 0) ||
+		(strcmp("--clean", argv[1]) == 0)) {
+	    if (!clean()) {
+		fprintf(stderr, "failed to clean\n");
+
+		exit(1);
+	    }
+
+	} else {
+	    usage();
+
+	    exit(1);
+	}
+
+    } else if (list_probe_dev) {
+	if (!probe_and_print_dev())
+	    ret = 1;
+
+    } else {
+	usage();
+
+	exit(1);
+    }
+
+    exit(ret);
+    /*NOTREACHED*/
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/open-src/app/dsession/sun-src/dsession.man	Mon Oct 13 15:22:07 2014 -0700
@@ -0,0 +1,98 @@
+'\" t 
+.\"
+.\" Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+.\"
+.\" Permission is hereby granted, free of charge, to any person obtaining a
+.\" copy of this software and associated documentation files (the "Software"),
+.\" to deal in the Software without restriction, including without limitation
+.\" the rights to use, copy, modify, merge, publish, distribute, sublicense,
+.\" and/or sell copies of the Software, and to permit persons to whom the
+.\" Software is furnished to do so, subject to the following conditions:
+.\"
+.\" The above copyright notice and this permission notice (including the next
+.\" paragraph) shall be included in all copies or substantial portions of the
+.\" Software.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+.\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+.\" THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+.\" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+.\" FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+.\" DEALINGS IN THE SOFTWARE.
+.\"
+.\"
+.TH DSESSION 1 "dsession 1.0.0" "X Version 11"
+.SH NAME
+dsession \- Dynamic Session Manager
+.SH SYNOPSIS
+.B "/usr/lib/ConsoleKit/dsession -h|--help"
+.sp
+.B "/usr/sbin/dsession [option] sub-command"
+
+.SH DESCRIPTION
+.I dsession
+uses ConsoleKit tool ck-seat-tool to dynamically add and delete individual
+sessions (the dynamically added and deleted sessions are also referred to as
+dsessions), uses ConsoleKit tool ck-list-sessions to list all or individual
+dsessions.
+
+With --init option, it probes whole PCI/PCIe system, and for each display
+\fIdevice\fP it finds, adds a dsession. When adding a dsession, it uses display file
+/etc/ConsoleKit/displays.d/HotPlug.display to start an X dsession on a display
+\fIdevice\fP identified by its Bus ID, and creates an entry in management table
+that has a mapping between display \fIdevice\fP path and dsession ID.  
+
+The management table is referenced and updated in dsession add/delete/restart 
+operations.
+
+.SH OPTION
+.IP "\-v, \-\-verb"
+Print debug messages.
+
+.SH SUB-COMMAND
+.IP "\-i, \-\-init"
+Initialize: create shared memory and mutex, add all dsessions.
+.IP "\-f, \-\-fini"
+Finish: delete all dsessions.
+.IP "\-c, \-\-clean"
+Delete all dsessions, destroy mutex and shared memory.
+.IP "\-a, \-\-add \fIdevice\fP"
+Add a dsession to run on \fIdevice\fP.
+.IP "\-d, \-\-delete \fIdevice\fP"
+Delete a dsession running on \fIdevice\fP.
+.IP "\-r, \-\-restart \fIdevice\fP"
+Restart a dsession running on \fIdevice\fP.
+.IP "\-l, \-\-list \fIdevice\fP"
+List a dsession running on \fIdevice\fP.
+.IP "\-l, \-\-list all"
+List all dsessions.
+.IP "\-l, \-\-list dev"
+List all display devices.
+
+.SH FILE
+.sp
+/usr/lib/ConsoleKit/dsession
+.br
+/etc/ConsoleKit/displays.d/HotPlug.display
+
+.SH "SEE ALSO"
+.sp
+ck-list-sessions (1)
+.br
+ck-seat-tool (1m)
+
+.\" Begin Sun update
+.SH "ATTRIBUTES"
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+.TS
+allbox;
+cw(2.750000i)| cw(2.750000i)
+lw(2.750000i)| lw(2.750000i).
+ATTRIBUTE TYPE	ATTRIBUTE VALUE
+Availability	pkg:/x11/session/dsession
+Interface Stability	Volatile
+.TE 
+.sp
+.\" End Sun update
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/manifests/x11-session-dsession.p5m	Mon Oct 13 15:22:07 2014 -0700
@@ -0,0 +1,31 @@
+# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+set name=pkg.fmri value=pkg:/x11/session/dsession@__version:dsession__
+set name=pkg.summary value="dsession - Dynamic Session Manager"
+set name=pkg.description \
+    value="dsession - dynamically start and stop X sessions"
+set name=variant.arch value=sparc
+dir  path=usr/lib
+dir  path=usr/lib/ConsoleKit
+file path=usr/lib/ConsoleKit/dsession mode=0544
+# dsession invokes consolekit tools
+depend type=require fmri=pkg:/library/xdg/consolekit