运行 os.system 好像 python 没有用 sudo 执行
Run os.system as if python was not executed with sudo
当我 运行 以下命令时,一切都按预期工作。没有错误,我收到系统通知说 "Hello":
$ python3
>>> import os
>>> os.system("notify-send Hello")
0
但是,当我这样做时:
$ sudo python3
>>> import os
>>> os.system("notify-send Hello")
脚本卡住了,没有任何反应。
然后我尝试这样做:
$ sudo python3
>>> import os
>>> os.seteuid(1000)
>>> os.system("notify-send Hello")
(1000
是我的普通非根用户帐户)
但是,脚本仍然卡住了,没有任何反应。
我也试过这个:
$ sudo python3
>>> import os
>>> os.system("su my-user-name -c 'notify-send Hello'")
还有这个:
$ sudo python3
>>> import os
>>> os.seteuid(1000)
>>> os.system("su my-user-name -c 'notify-send Hello'")
他们都有同样的问题...
我不是在寻找创建通知的替代方法。我对 subprocess
或 notify2
之类的东西不感兴趣,它们会在我的系统上引起一类全新的问题。哦,请不要告诉我不要使用 sudo。我有我的理由。
我通过反复试验发现的实现细节是 notify-send
需要 XDG_RUNTIME_DIR
环境变量才能运行——至少对于这些版本:
$ dpkg -l | grep libnotify
ii libnotify-bin 0.7.7-3 amd64 sends desktop notifications to a notification daemon (Utilities)
ii libnotify4:amd64 0.7.7-3 amd64 sends desktop notifications to a notification daemon
我首先使用 env -i notify-send hello
确定它需要某种环境变量,但没有产生任何通知。
然后我用 this script
的修改版本将环境一分为二
如何获取该环境变量取决于您,但您需要 运行 notify-send
作为正确的用户并设置该变量。
这是一个示例 python 脚本,由于安全问题,我拒绝使用 os.system
:
import os
import pwd
import subprocess
import sys
def main():
if len(sys.argv) != 2:
raise SystemExit(f'usage `{sys.argv[0]} USER`')
if os.getuid() != 0:
raise SystemExit('expected to run as root')
# find the `gnome-session` executable, we'll use that to grab
# XDG_RUNTIME_DIR
cmd = ('pgrep', '-u', sys.argv[1], 'gnome-session')
pid = int(subprocess.check_output(cmd))
# read that process's environment
with open(f'/proc/{pid}/environ') as f:
for line in f.read().split('[=11=]'):
if line.startswith('XDG_RUNTIME_DIR='):
_, _, xdg_runtime_dir = line.partition('=')
break
else:
raise SystemExit('Could not find XDG_RUNTIME_DIR')
# run the notify send as the right user
uid = pwd.getpwnam(sys.argv[1]).pw_uid
os.seteuid(uid)
os.environ['XDG_RUNTIME_DIR'] = xdg_runtime_dir
os.execvp('notify-send', ('notify-send', 'ohai'))
if __name__ == '__main__':
exit(main())
免责声明:这个脚本正在做一些非常棘手的事情,我不一定会在生产代码中建议。特别是:
- shelling out pgrep 找到一个进程
- 读取另一个进程的环境变量
sudo
示例用法:
$ python3 t.py
usage `t.py USER`
$ python3 t.py asottile
expected to run as root
$ sudo python3 t.py asottile
# (I get a notification for `ohai`)
当我 运行 以下命令时,一切都按预期工作。没有错误,我收到系统通知说 "Hello":
$ python3
>>> import os
>>> os.system("notify-send Hello")
0
但是,当我这样做时:
$ sudo python3
>>> import os
>>> os.system("notify-send Hello")
脚本卡住了,没有任何反应。
然后我尝试这样做:
$ sudo python3
>>> import os
>>> os.seteuid(1000)
>>> os.system("notify-send Hello")
(1000
是我的普通非根用户帐户)
但是,脚本仍然卡住了,没有任何反应。
我也试过这个:
$ sudo python3
>>> import os
>>> os.system("su my-user-name -c 'notify-send Hello'")
还有这个:
$ sudo python3
>>> import os
>>> os.seteuid(1000)
>>> os.system("su my-user-name -c 'notify-send Hello'")
他们都有同样的问题...
我不是在寻找创建通知的替代方法。我对 subprocess
或 notify2
之类的东西不感兴趣,它们会在我的系统上引起一类全新的问题。哦,请不要告诉我不要使用 sudo。我有我的理由。
我通过反复试验发现的实现细节是 notify-send
需要 XDG_RUNTIME_DIR
环境变量才能运行——至少对于这些版本:
$ dpkg -l | grep libnotify
ii libnotify-bin 0.7.7-3 amd64 sends desktop notifications to a notification daemon (Utilities)
ii libnotify4:amd64 0.7.7-3 amd64 sends desktop notifications to a notification daemon
我首先使用 env -i notify-send hello
确定它需要某种环境变量,但没有产生任何通知。
然后我用 this script
的修改版本将环境一分为二如何获取该环境变量取决于您,但您需要 运行 notify-send
作为正确的用户并设置该变量。
这是一个示例 python 脚本,由于安全问题,我拒绝使用 os.system
:
import os
import pwd
import subprocess
import sys
def main():
if len(sys.argv) != 2:
raise SystemExit(f'usage `{sys.argv[0]} USER`')
if os.getuid() != 0:
raise SystemExit('expected to run as root')
# find the `gnome-session` executable, we'll use that to grab
# XDG_RUNTIME_DIR
cmd = ('pgrep', '-u', sys.argv[1], 'gnome-session')
pid = int(subprocess.check_output(cmd))
# read that process's environment
with open(f'/proc/{pid}/environ') as f:
for line in f.read().split('[=11=]'):
if line.startswith('XDG_RUNTIME_DIR='):
_, _, xdg_runtime_dir = line.partition('=')
break
else:
raise SystemExit('Could not find XDG_RUNTIME_DIR')
# run the notify send as the right user
uid = pwd.getpwnam(sys.argv[1]).pw_uid
os.seteuid(uid)
os.environ['XDG_RUNTIME_DIR'] = xdg_runtime_dir
os.execvp('notify-send', ('notify-send', 'ohai'))
if __name__ == '__main__':
exit(main())
免责声明:这个脚本正在做一些非常棘手的事情,我不一定会在生产代码中建议。特别是:
- shelling out pgrep 找到一个进程
- 读取另一个进程的环境变量
sudo
示例用法:
$ python3 t.py
usage `t.py USER`
$ python3 t.py asottile
expected to run as root
$ sudo python3 t.py asottile
# (I get a notification for `ohai`)