我有一个makeself
脚本,我希望以root身份运行;这是一个桌面安装程序。
在脚本结束时,最近安装到文件系统的软件尝试在用户空间中启动。
使用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
会产生没有,XTerm
和gnome-terminal
都会产生GNOME_DESKTOP_SESSION_ID
。
如何从安装程序脚本中获取此GNOME_DESKTOP_SESSION_ID
变量,而无需用户将-E
参数等内容传递给sudo
命令?
请注意,虽然GtkLookAndFeel
是Linux的主要外观,但我也不想对export JAVA_OPTS
进行硬编码,我更愿意继续回归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
。
答案 0 :(得分:1)
事实证明这是一个两步过程...
UPSTART_SESSION
/proc/$pid/environ
个环境变量
export UPSTART_SESSION
并致电initctl --user get-env GNOME_DESKTOP_SESSION_ID
为了使其对其他变量更具可伸缩性,我将其包装成bash辅助函数。此函数也应该有助于获取其他用户环境变量。 请注意,如果变量的值在名称中有空格,则无效。
在下面的示例中,只需要UPSTART_SESSION
和GNOME_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 $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
}
答案 1 :(得分:0)
您需要在/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