让脚本检测 gnome 会话

Have script detect gnome session

我有一个 makeself 脚本,我希望它是 运行 作为 root;这是一个桌面安装程序。

在脚本末尾,最近安装到文件系统的软件尝试在用户 space 中启动。

使用 sudo -u $(logname) /path/to/application(或 sudo -u $SUDO_USER ... in Ubuntu 16.04)效果很好,但是缺少用户的关键环境变量:

GNOME_DESKTOP_SESSION_ID

我需要 GNOME_DESKTOP_SESSION_ID 因为子进程属于 Java 并且 Java 使用此环境变量来检测 GtkLookAndFeel.

但是尝试使用 sudo -i 失败了。

从一些基本测试来看,GNOME_DESKTOP_SESSION_ID 似乎不是该用户登录时的自然环境变量。例如,如果我 CTRL+ALT+F1 到终端,env |grep GNOME 什么都不产生,而 XTermgnome-terminal 都产生 GNOME_DESKTOP_SESSION_ID.

如何在不要求用户向 sudo 命令传递 -E 参数的情况下从安装程序脚本中获取此 GNOME_DESKTOP_SESSION_ID 变量?

请注意,尽管 GtkLookAndFeel is the primary look and feel for Linux, I prefer not to hard-code the 两者都有,但出于支持、寿命和可扩展性的原因,我更愿意继续使用 Oracle 的检测技术。

更新:在Ubuntu,GNOME_DESKTOP_SESSION_ID住在/usr/share/upstart/sessions/xsession-init.conf

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

这导致使用 initctl get-env 来检索它。不幸的是,这在新的 sudo shell 中没有帮助,也没有任何(乐观的)尝试 dbus-launch.

您需要在 /etc/sudoers.d 上创建一个包含以下内容的新文件:

Defaults env_keep+=GNOME_DESKTOP_SESSION_ID

但是,有一个问题,如果你已经在 sudo 里面,它不会被再次读取。

所以,完整的解决方案是在你的脚本中使用 sudo 来创建这个文件,然后在另一个 sudo 中执行你的命令:

#!/bin/bash
# ignore sudo
if [[ -z $SUDO_USER ]]; then
    #save current dir
    DIR="$(pwd)"
    #generate random string (file name compatible)
    NEW_UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
    #create env_keep file
    sudo -i -- <<EOF0
        echo "Defaults env_keep+=GNOME_DESKTOP_SESSION_ID" > /etc/sudoers.d/"$NEW_UUID"_keep_java_laf
    EOF0
    sudo -u YOUR_USER -i -- <<EOF
        #go to original directory
        cd "$DIR"
        #execute your java command
        java YOUR_COMMAND
    EOF
    #clean file
    sudo rm -f /etc/sudoers.d/"$NEW_UUID"_keep_java_laf
else
    echo "sudo not allowed!";exit 1;
fi

原来这是一个两步过程...

  1. /proc/$pid/environ
  2. 读取用户的UPSTART_SESSION环境变量
  3. 然后 export UPSTART_SESSION 并调用 initctl --user get-env GNOME_DESKTOP_SESSION_ID

为了使其对其他变量更具可扩展性,我将其包装到 bash 辅助函数中。此功能还应有助于获取其他用户环境变量。 注意,如果变量的值在名称中包含 space,它将不起作用。

在下面的例子中,只需要 UPSTART_SESSIONGNOME_DESKTOP_SESSION_ID 来回答这个问题。

调用 sudo_env 后,下一次调用 sudo -u ... 必须更改为 sudo -E -u ...-E 将导入新导出的变量以供子进程使用。

# 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 }')
    # Replace null delimiters with newline for grep
    envt=$(cat "/proc/$pid/environ" |tr '[=10=]' '\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
}