Search code examples
javasudoenvironmentgnomegnome-terminal

Have script detect gnome session


I have a makeself script which I expect to be run as root; It's a desktop installer.

At the end of the script, the software which was recently installed to the filesystem tries to launch in user-space.

This works well using sudo -u $(logname) /path/to/application (or alternately sudo -u $SUDO_USER ... in Ubuntu 16.04) however a critical environmental variable from the user is missing:

GNOME_DESKTOP_SESSION_ID

I need GNOME_DESKTOP_SESSION_ID because the child process belongs to Java and Java uses this environmental variable for detecting the GtkLookAndFeel.

However attempts to use sudo -i have failed.

From some basic tests, the GNOME_DESKTOP_SESSION_ID doesn't appear to be a natural environmental variable when this users logs in. For example, if I CTRL+ALT+F1 to a terminal, env |grep GNOME yields nothing whereas XTerm and gnome-terminal both yield GNOME_DESKTOP_SESSION_ID.

How can I get a hold of this GNOME_DESKTOP_SESSION_ID variable from within the installer script without requiring users to pass something such as the -E parameter to the sudo command?

Note, although GtkLookAndFeel is the primary look and feel for Linux, I prefer not to hard-code the export JAVA_OPTS either, I prefer to continue to fallback onto Oracle's detection techniques for support, longevity and scalability reasons.

Update: In Ubuntu, GNOME_DESKTOP_SESSION_ID lives in /usr/share/upstart/sessions/xsession-init.conf

 initctl set-env --global GNOME_DESKTOP_SESSION_ID=this-is-deprecated

Which leads to using initctl get-env to retrieve it. Unfortunately this does not help within a new sudo shell, nor does any (optimistic) attempt at dbus-launch.


Solution

  • It turns out this is a two-step process...

    1. Read the user's UPSTART_SESSION environmental variables from /proc/$pid/environ
    2. Then export UPSTART_SESSION and call initctl --user get-env GNOME_DESKTOP_SESSION_ID

    To make this a bit more scalable to other variables, I've wrapped this into a bash helper function. This function should assist fetching other user-environment variables as well. Word of caution, it won't work if the variable's value has a space in the name.

    In the below example, only UPSTART_SESSION and GNOME_DESKTOP_SESSION_ID are required to answer the question.

    Once sudo_env is called, the next call to sudo -u ... must be changed to sudo -E -u .... The -E will import the newly exported variables for use by a child process.

    # Provide user environmental variables to the sudo environment
    function sudo_env() {
        userid="$(logname 2>/dev/null || echo $SUDO_USER)"
        pid=$(ps aux |grep "^$userid" |grep "dbus-daemon" | grep "unix:" |awk '{print $2}')
        # Replace null delimiters with newline for grep
        envt=$(cat "/proc/$pid/environ" |tr '\0' '\n')
    
        # List of environmental variables to use; adjust as needed
        # UPSTART_SESSION must come before GNOME_DESKTOP_SESSION_ID
        exports=( "UPSTART_SESSION" "DISPLAY" "DBUS_SESSION_BUS_ADDRESS" "XDG_CURRENT_DESKTOP" "GNOME_DESKTOP_SESSION_ID" )
    
        for i in "${exports[@]}"; do
            # Re-set the variable within this session by name
            # Careful, this technique won't yet work with spaces
            if echo "$envt" | grep "^$i=" > /dev/null 2>&1; then
                eval "$(echo "$envt" | grep "^$i=")" > /dev/null 2>&1
                export $i > /dev/null 2>&1
            elif initctl --user get-env $i > /dev/null 2>&1; then
                eval "$i=$(initctl --user get-env $i)" > /dev/null 2>&1
                export $i > /dev/null 2>&1
            fi
    
            echo "$i=${!i}"
        done
    }