How-To среда: вход в систему и сеансы
25.08.2007

Недавно нам был задан вопрос:

В мане по bash написано, что .bash_profile запускается, когда пользователь логинится в систему через шелл. Но я вхожу в систему, используя gdm. Поэтому я не уверен, что выполняется .bash_profile. Выполняется ли он и, если нет, то где мне задавать переменные окружения?

Чтобы ответить на этот вопрос, нужно понимать разницу между входом в систему и сеансом. Логин происходит, когда вы вводите логин и пароль в систему в текстовом режиме, и для вас запускается шелл. Шелл каждого пользователя прописан в файле /etc/password; вот, например, моя запись в этом файле:

chris:x:500:500:Chris Tyler:/home/chris:/bin/bash

Поля в этом файле разделены на колонки символом «:», и седьмое поле содержит путь к шеллу, который и будет запущен после логина в систему. Это не обязательно должен быть стандартный шелл-интерпретатор, это может быть любая корректная программа, например, меню или программа для работы с электронной почтой, что удобно как для неопытного пользователя, так и для ограничения возможностей пользователя в системе. Если нужно запретить пользователю логиниться в систему, можно прописать в качестве шелла /sbin/nologin, которая просто выводит сообщение «Этот аккаунт теперь не доступен» и выходит (можно задать любое сообщение, оно хранится в файле /etc/nologin.txt).

Стандартный шелл в Fedora — это /bin/bash (Bourne-again shell), название которого произошло от Bourne shell, одного из первых и наиболее популярного шелла под Unix. Как и другие шеллы, bash при каждом своем запуске выполняет скрипт ~/.bashrc и два скрипта при каждом логине: /etc/profile и один из ~/.bash_profile, ~/.bash_login, или ~/.profile — Fedora по-умолчанию создает пользователей с файлом ~/.bash_profile. Необходимо понимать разницу: если вы залогинились один раз и потом запустили три шелла, то файлы /etc/profile и ~/.bash_profile выполнятся один раз, а файл ~/.bashrc – три раза.

Сеанс же — это графическая версия логина. Сеанс запускается с помощью display-менеджера gdm (или, как альтернатива, kdm или xdm), которого надо запустить, как обычную программу. Сеанс работает под контролем менеджера сеансов, который запускает стандартные клиенты (GUI-программы), перезапускает некоторые клиенты, которые некорректно завершились, и может также запускать клиенты, которые оставались открытыми, когда был завершен последний сеанс. Менеджер сеансов среды GNOME называется gnome-session, а в KDE — это ksmserver, который запускается скриптом startkde. При запуске сеанса седьмое поле в файл /etc/passwd ингорируется и profile-скрипты не запускаются.

Но в Fedora это не совсем так: менеджер сеансов стартует по скрипту /etc/X11/xdm/Xsession, но этот скрипт не сразу запускает менеджер сеансов. Если вы запускаете среду  GNOME, скрипт выполняет следующую команду:

exec -l $SHELL -c "$SSH_AGENT $DBUS_LAUNCH gnome-session"

Для KDE же выполняется команда:

exec -l $SHELL -c "$SSH_AGENT $DBUS_LAUNCH startkde"

Переменные окружения, используемые в этих скриптах, определены в файле /etc/X11/xinit/xinitrc-common. Обычно, SHELL = /bin/bash, SSH_AGENT = /usr/bin/ssh-agent, и DBUS_LAUNCH = "/usr/bin/dbus-launch --exit-with-session".

Все вместе это означает, что bash запускается как логин-шелл, и, следовательно, выполняются и файлы /etc/profile и ~/.bash_profile. Затем запускается ssh_agent, который запускает dbus-launch, который, в свою очередь, запускает менеджера сеансов. Эта последовательность гарантирует, что переменные окружения будут установлены из profile-файлов.

Проверить это очень просто, добавив несколько строк в конец файла ~/.bash_profile:

# сообщение в стандартный вывод
echo ".bash_profile executed"

# показать сообщение в графической среде
zenity --info --text ".bash_profile executed"

# задать переменную окружения
export FDP=".bash_profile executed"

Теперь, если мы залогинимся в текстовом режиме, мы увидим сообщение:

Last login: Wed Aug 15 12:04:27 2007 from dailypackage.fedorabook.com
.bash_profile executed

(zenity:3689): Gtk-WARNING **: cannot open display:

[chris@localhost ~]$

Мы видим сообщение, показанное с помощью команды echo, но другое сообщение с помощью команды zenity не вывелось, так как не запущен X-сервер. Теперь, если мы залогинимся с помощью графического входа, мы увидим сообщение, выводимое через zenity, но не увидим сообщение, выводимое через echo (так как нет консоли, куда выводить сообщение). Независимо от того, каким способом вы логинитесь, переменная окружения FDP будет существовать в любом случае:

$ echo $FDP
.bash_profile executed

Так что вы можете уверенно использовать .bash_profile для создания переменных окружения.

Можно также программно определить, как залогинился пользователь (через графический интерфейс или через текстовый). Если через текстовый, то команда tty должна вернуть верный результат; если через графический, должна быть установлена переменная DISPLAY. Вот пример кода, в котором пользователю при входе в систему задается вопрос:

if [ "$DISPLAY" ]
then

if zenity --question --text "Do you want to foo?"
then

ANSWER="Y"

else

ANSWER="N" # Default if zenity can't connect to display

fi

elif tty --quiet
then

echo -n "Do you want to foo? "
read ANSWER

else

echo "No tty and no GUI!"
ANSWER="N" # Default if we can't ask the user

fi

В дополнении к profile-файлам, выполняющемся при логине, и ~/.bashrc файлу, выполняющемуся при запуске шелла, есть также файл ~/.bash_logout, который выполняется, когда пользователь выходит из системы. В Fedora этот скрипт просто очищает консоль, чтобы на ней не осталось никакой конфиденциальной информации.