Запустите os.system, как будто Python не был выполнен с помощью 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
моя обычная учетная запись без полномочий root)
Но все же сценарий застревает и ничего не происходит.
Я также попробовал это:
$ 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. У меня есть причины.
1 ответ
Детали реализации, которые я обнаружил методом проб и ошибок: 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
, который не произвел уведомления.
Затем я разделил среду на части с помощью модифицированной версии этого скрипта.
Как вы получите эту переменную среды, зависит от вас, но вам нужно запустить 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('\0'):
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())
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: этот скрипт делает некоторые очень хакерские вещи, которые я не обязательно предлагал бы в производственном коде. В частности:
- Обстреливая 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`)