Integration of dbus and KDE: starting and stopping the session part of dbus with KDM.

Want to support HowtoForge? Become a subscriber!
 
Submitted by stefbon (Contact Author) (Forums) on Fri, 2006-09-15 13:55. :: Other | Other

Integration of dbus and KDE: starting and stopping the session part of dbus with KDM. 

Contents

0. Introduction
1. Adjusting the configuration of KDM
2. Starting the sessiondaemon of dbus and make environmentvariables available.
2.1 About the startupfiles of Bash.
2.2 Starting the sessionbus part of dbus
2.3 Stopping the sessionbus part of dbus
2.4 One user is more than one time logged in

0. Introduction


Since some time now a lot of applications make use of D-BUS. This is the case with KDE 3.5, the current stable release of KDE. With the upcomming KDE 4, D-BUS is getting more important, replacing DCOP.

In this howto I want to describe a way to start and stop the user and session dependent part of dbus. The major goals I have in mind with this approach are:

- make the environmentvariables important for d-bus aware applications available;
- make sure the dbus sessionpart is not started more than once for a single user;
- make sure the dbus sessionpart is stopped when a session of a user ends;

I assume the user logs in with KDM, the loginmanager for KDE 3.5. The construction could very well used with other loginmanagers (XDM, GDM) as well.
KDM has the ability to run scripts at the beginning of a session (at startup), and at the end (reset). One of them can start (and stop) the dbus session part.

1. KDM: the files


KDM uses some files to start and stop:

. Xstartup
run as root, after a user succesfully logs in.

. Xsession
runs with permissions of the authorized user, to start the desired session (KDE).

. Xreset
run as root, after the user session has ended.

Where Xstartup is the place to start things up, Xreset is the place to undo these commands.

For more information about these files look at the handbook of KDM.

By adding the following code to the Xstartup file:


-- snip --
for script in /etc/session.d/kdm/startup/*.sh; do
	if [ -x $script ]; then
	
		eval $script $USER kdm
	fi;
done;

and the code to the Xreset file:

-- snip --
for script in /etc/session.d/kdm/reset/*.sh; do
	if [ -x $script ]; then
	
		eval $script $USER kdm
	fi;
done;

Create the directories where the scripts go:

install -m755 -d /etc/session.d/kdm/startup
install -m755 -d /etc/session.d/kdm/reset
install -m755 -d /etc/session.d/scripts/start
install -m755 -d /etc/session.d/scripts/stop


The files in these directories must be accessible for every ordinary user: therefore the permissions are 755.
All scripts in these directories should have the same permissions: 755.

Every user should be able to execute the script, but only root is able to modify them.

1. Starting the sessiondaemon of dbus and make the environmentvariables available

The dbus package is split up in two parts: one systemwide part and one for (each) session/user. The systemwide part (a daemon) is started at boottime, with special privileges of a dedicated user. The sessionwide part (also a daemon) has to started when a session for a user begins, and stopped when the session ends.

The construction with kdm I'm using here is ideal for this. One script in the startup directory to start the sessiondaemon for a user, running with the privileges of that user, and one in the reset directory an other script has to stop that daemon.

But is not so simple as that. Some variables (DBUS_SESSION_BUS_ADDRESS and DBUS_SESSION_BUS_PID) have to be available in the environment to every application which works with dbus. IMHO the setting of these variables should go in the bash-startupscripts. Then whatever script or application you're running, these variables are set to the right value.

1.1 About the startupfiles of Bash

The sessiondaemon of dbus creates a file which contains the environmentvariables. As stated above this file should be read (sourced) by bash when it starts for this user.

When bash is started by "login" as an interactive login shell, it reads /etc/profile and ~/.bash_profile. Bash is also started by "kdm", and the files /etc/profile and ~/.bash_profile are sourced.

My idea is to store the output of the command

dbus-launch --auto-syntax


in the file

$HOME/.dbus-session

This file is "sourced" when bash start. This happens not automatically, but you will have to add the following script to /etc/profile.d :

cat >> /etc/profile.d/dbus-session.sh << "EOF"
if [ -f $HOME/.dbus-session ]; then
        . $HOME/.dbus-session
fi;
EOF

This way, the environment variables are made available when Bash starts.

1.2 Starting the sessionbus part of dbus

I assume that dbus is installed, and that it is started at boottime.

Create a script in the /etc/session.d/scripts/start directory dbus-session-start.sh:

cd /etc/session.d/scripts/start

cat >> dbus-session-start.sh << "EOF"
#!/bin/bash
retcode=0;
userid=$1
userproperties=$(getent passwd | grep -m 1 -E "^$userid")
homedir=$(echo $userproperties | cut -d ":" -f 6);
gidnr=$(echo $userproperties | cut -d ":" -f 4);
uidnr=$(echo $userproperties | cut -d ":" -f 3);
if [ -d $homedir ]; then
    #
    # do a check whether dbus-daemon is already running
    # dbus-daemon needs to be started by the user (uidnr) logging in
    #
    
    if [ -f $homedir/.dbus-session ]; then
        # do a check the dbus-daemon for this user is running with the pid
        # in the .dbus-session file
 
        # pid according to the ps command
        ps_dbus_session_pid=$(ps aux | grep -m 1 -E "^$userid.*dbus-daemon.*session.*" \
        | grep -v "grep" | sed 's@[[:space:]][[:space:]]*@ @g' | cut -d " " -f 2)
        
        # read the pid from the .dbus-session file
        . $homedir/.dbus-session
        # check they are the same       
        if [ -z "$ps_dbus_session_pid" ]; then
        
            # dbus for this user not running
            rm $homedir/.dbus-session
            
        elif [ $DBUS_SESSION_BUS_PID -ne $ps_dbus_session_pid ]; then
        
            # there is something wrong: stop dbus-daemon for this user 
            # and remove .dbus-session file
            if [ $(id -u) -eq 0 ]; then
                sudo -H -u $userid sh -c "kill $ps_dbus_session_pid"
            elif [ $(id -u) -eq $uidnr ]; then
                kill -SIGTERM $ps_dbus_session_pid;
            fi
            rm $homedir/.dbus-session
            
        fi
    
    fi  
    if [ ! -f $homedir/.dbus-session ]; then
        # only start a dbus session if .dbus-session file it not found
        # in users homedirectory 
  
        if [ $(id -u) -eq 0 ]; then
            sudo -u $userid -H /bin/sh -c "dbus-launch --auto-syntax > $homedir/.dbus-session"
            retcode=$?
            chown $uidnr:$gidnr $homedir/.dbus-session
        elif [ $(id -u) -eq $uidnr ]; then 
            dbus-launch --auto-syntax > $homedir/.dbus-session
            retcode=$?
        fi
    fi
fi;
if [ $retcode -ne 0 ]; then
    echo "An error with dbus ($retcode)."
fi;
exit $retcode
EOF



chmod --verbose --mode 755 /etc/session.d/scripts/start/dbus-session-start.sh
ln -v -sf ../../scripts/start/dbus-session-start.sh /etc/session.d/kdm/startup/10dbus.sh



This script, executed by KDM at startup will start the dbus session daemon for this user, and will create the .dbus-session file in the homedirectory of this user, containing all the dbusvariables.
It will only do this when dbus is not already running for this user.

Now when bash starts at login, it reads (sources) this file.

As you can see, I've split the start of dbus up into two parts:
- dbus-session-start.sh, runs when a (kdm)session starts
- .dbus-session, sourced when a (bash)session starts, could be sourced multiple times

Futher, I use the --auto-syntax parameter, where I assume Bash is used. So I could use here --sh-syntax, but it works.

And Sudo is needed to run dbus-launcher as the user who's logging in, cause KDM runs this script as root. (actually the script checks for the id of the account running this script. It is root (id = 0) then sudo is used to change to the user starting a session. When the id and the id of the user logging in are the same, nothing has to be done.

2.3 Stopping the sessionbus part of dbus

Creating the dbus-session-stop.sh script in the reset directory:

cd /etc/session.d/scripts/stop


cat >> dbus-session-stop.sh << "EOF"
#!/bin/bash
retcode=0;
userid=$1
userproperties=$(getent passwd | grep -m 1 -E "^$userid")
homedir=$(echo $userproperties | cut -d ":" -f 6);
gidnr=$(echo $userproperties | cut -d ":" -f 4);
uidnr=$(echo $userproperties | cut -d ":" -f 3);
        
if [ -f $homedir/.dbus-session ]; then
        
        . $homedir/.dbus-session
        
        if [ -n "$DBUS_SESSION_BUS_PID" ]; then
                if [ $(id -u) -eq 0 ]; then
                    sudo -u $userid -H /bin/sh -c "kill $DBUS_SESSION_BUS_PID"
                    retcode=$?
                    rm $homedir/.dbus-session
                elif [ $(id -u) -eq $uidnr ]; then
                    kill $DBUS_SESSION_BUS_PID
                    retcode=$?
                    rm $homedir/.dbus-session
                fi
        
        fi
fi;
if [ $retcode -ne 0 ]; then
    echo "An error with dbus ($retcode)."
fi;
exit $retcode
EOF



chmod --verbose --mode 755 dbus-session-stop.sh
ln -v -sf ../../scripts/stop/dbus-session-stop.sh /etc/session.d/kdm/reset/90dbus.sh


This script stops the session part of the dbus-daemon.

2.4 One user is more than one time logged in

For most of the situations this construction is good enough. Most users have one session at a time. Now what happens when a user has more than one sessions at the same time? Is it nessacary to start the sessionpart of dbus for every session, or is one instance sufficient?

This construction does not allow more than one dbus-daemon per user. I think that should be good enough.

CHANGELOG:

[2006-01-18]
* Initial howto
[2006-07-18]
* Changed the bash scripts
[2006-09-09]
* add check to see dbus-daemon is already running for this user and the information found in .dbus-session is right


Please do not use the comment function to ask for help! If you need help, please use our forum.
Comments will be published after administrator approval.