Но в начале хочу сказать, что все эти сложности могут проявляться и в других случаях - при попытках запустить графические приложения от root, поэтому для облегчения тестирования я буду использовать крышку ноутбука. Я буду ей махать, и при этом будет выполнятся скрипт /etc/acpi/default.sh. Точнее я буду просто давить маленькую кнопочку на ноутбуке, которая нажимается крышкой при закрытии. Эта кнопочка генерирует ACPI событие с группой "button" и событием "lid", по которому например можно гасить экран, или повергнуть систему в suspend. Причём скрипт запускается примерно в том-же окружении, что и cron-овские задачи, поэтому тестировать я буду здесь, а потом уже начисто проверять в cron. Намного проще нажать кнопку, чем ждать 1-2 минуты, не так ли?
Хотя, в системах , отличных от Gentoo, этот скриптик может оказаться в другом месте. Так что проверяйте всё сами - эксперимент, эксперимент и ещё раз эксперимент!
Итак, попробуем вывести на экран диалог с текстом. Для этого есть 2 программы:
1. xmessage - универсальная, не зависит от оконного менеджера, но не очень красивая.
Попробуйте запустить xmessage -center "Hello Sergey"
2. kdialog - в составе KDE
Пробуем так: kdialog --msgbox "Hello Sergey"
Я предпочитаю kdialog, как более симпатичный.
Пробуем использовать - вписываем вызов по событию lid:
lid)
kdialog --msgbox "Hello Sergey" > /err 2>&1
;;
не забываем перенаправить все сообщения в /err, чтоб было над чем подумать.
Давим кнопочку - ничего не происходит (и не удивительно, зачем бы я тогда тут распинался?). Читаем /err, и видим что-то подобное этому:
/etc/acpi/default.sh: line 31: kdialog: команда не найдена
Язык может быть и другим - зависит от настроек локали. Но, допустим вам не нравится русский, или вместо сообщения вы получили какие-то кракозябы? Это легко исправить:
lid)
export LC_ALL=C
export LANG=C
kdialog --msgbox "Hello Sergey" > /err 2>&1
;;
Теперь уже лучше:
/etc/acpi/default.sh: line 33: kdialog: command not found
Но почему происходит эта ошибка? Да потому что kdialog действительно not found - пути к ней не прописаны. Это можно исправить 2 способами - использовать полный путь, или модифицировать PATH
1.
lid)
export PATH=$PATH:/usr/kde/3.5/bin/
kdialog --msgbox "Hello Sergey" > /err 2>&1
;;
2. Прописать полный путь
lid)
/usr/kde/3.5/bin/kdialog --msgbox "Hello Sergey" > /err 2>&1
;;
Во этом случае нас могут подстерегать некоторые затруднения - если программа вызывает какую-то другую программу, то эта другая программа в свою очередь может не найтись! Везде прописывайте полные пути!
Получаем вот что:
kdialog: cannot connect to X server
Бедняжка не может найти X сервер... Нужно ему помочь! Опять таки 2 способа указать сервер:
1. Указать из командной строки
kdialog --msgbox "Hello Sergey" -display :0
2. Задать переменную DISPLAY:
export DISPLAY=":0"
Второй способ мне кажется более удобным, так как не все программы поддерживают опцию -display
Пробуем:
lid)
export DISPLAY=":0"
/usr/kde/3.5/bin/kdialog --msgbox "Hello Sergey" > /err 2>&1
;;
И снова получаем получаем ошибку:
Xlib: connection to ":0.0" refused by server
Xlib: No protocol specified
kdialog: cannot connect to X server :0
Сервер найден, но он нас не пускает - секьюрити, панимаиш...
И снова есть несколько путей(ну это же Линукс!):
1. Использовать программу xhost, которая просто разрешает коннектиться к серверу всем. Не очень безопасно, не так ли? Тем не менее его можно применять, например, если вы сидите дома и никого не боитесь (aka "я в домике").
'xhost +' разрешает всем коннектиться к серверу. Но, запускать эту программу надо не из скрипта! При запуске из скрипта у программы нет прав, чтоб изменять права, поэтому эту команду нужно впихнуть либо в автозагрузку X сервера, либо выполнить самому. Где находится эта автозагрузка, я без понятия, поэтому дальше этот способ рассматривать не будем.
2. Для авторизации клиентов используется файл указанный в переменной окружения XAUTHORITY. Если переменная не задана - используется файл $HOME/.Xauthority
Поэтому попробуем руту подсунуть файл авторизации пользователя:
lid)
export XAUTHORITY="/home/sazarkevich/.Xauthority"
export DISPLAY=":0"
/usr/kde/3.5/bin/kdialog --msgbox "Hello Sergey" > /err 2>&1
;;
И... Это работает!
3. Вариант похож на предыдущий, но просто в /root делаем ссылку на .Xauthority пользователя:
ln -s /home/sazarkevich/.Xauthority /root/.Xauthority
Клиент пытается авторизоваться на сервере, берёт файл авторизации $HOME/.Xauthority, а это оказывается файл уже авторизованного пользователя. Вуаля.
4. Последний вариант - запуск из под пользователя
lid)
export DISPLAY=":0"
su sazarkevich -c '/usr/kde/3.5/bin/kdialog --msgbox "Hello Sergey" > /tmp/err 2>&1'
;;
Заметьте, ошибки скидываем в /tmp/err, т.к. пользователь sazarkevich не имеет доступа к корневой директории!
При этом автоматически используется .Xauthority пользователя.
Конечно, это не вполне хорошее решение. Тут жёстко задан пользователь. Более того, вы всегда должны работать за сервером :0 - если вы запустите ещё один сервер, на него ничего выводится не будет.
Однако, если вы за компьютером работаете всегда под одним пользователем (не root, боже упаси), и не запускаете лишних X серверов, а это часто так и есть, то вариант вполне подходящий.
Теперь с учётом всех проблем пробуем запустить оповещение из cron-а:
1. Полный путь
2. задать DISPLAY
3. разрешить авторизацию
Если вы запускаете задачи крона пользователя (crontab -e -u sazarkevich), то 3-ий пункт не нужен - он автоматически выполняется по 4-ому методу.
Если почему-либо вы используете крон через root-а(crontab -e -u root), то 3-ий пункт необходим.
Вот примерно так:
SHELL=/bin/bash
DISPLAY=":0"
MAIL=sazarkevich
# Morning shotdown
0 9 * * * /usr/kde/3.5/bin/konsole -e /home/sazarkevich/bin/morning-poweroff.sh
Это у меня по утрам, в 9 часов, запускается консоль, в которой 60 секунд идёт обратный отсчёт. Если никто не позаботится нажать Ctrl+C во время обратного отсчёта - компьютер выключится. Если кто-то за ним в это время работает, то он может отменить выключение.
Вот так. Всё просто!
8 комментариев:
>Поэтому попробуем руту подсунуть файл авторизации пользователя
а если другого пользователя нет?
или другой пользователь тоже не может авторизовываться..
В общем толку от трех последних способов нет, а первый способ тоже не раскыт!
Если другого пользователя нет, то это не наш пользователь. Наши люди в X-ы на root-е не ездят. Они имеют для этого "другого пользователя".
А по поводу "толку от трех последних способов нет". Нет, так и не пользуйтесь. Мне толк есть, я пользуюсь. Может ещё кому толк будет.
Полный путь можно не прописывать, если он есть в PATH. Т.е. если программа запускается просто из терминала, то и cron её тоже запустит.
Вот, например, у меня сработало так:
crontab -u ildar -e
и там прописываю
DISPLAY=:0.0
#*/1 * * * * gedit
Затем перезапуск cron-а (у меня vixie-cron)
/etc/init.d/vixie-cron restart
и через минуту запускается gedit.
Только, хотя мы и запускаем программу gedit от имени пользователя ildar, но команда crontab -u ildar -e у меня выполняется только из-под root-а.
Ой, прошу прощения!
Не
DISPLAY=:0.0
#*/1 * * * * gedit
а
DISPLAY=:0.0
*/1 * * * * gedit
# - это комментарий :)
Гм. А вот у меня PATH урезанный.
Может это зависит от дистрибутива? У меня Gentoo
Отправить комментарий