использования простой вспомогательной программы, доступной в большинстве систем Linux и в некоторых других системах, но не стандартизованной — утилиты utempter. Утилита utempter является setgid (или, при необходимости, setuid) с достаточными полномочиями для модификации баз данных utmp и wtmp. Доступ к ней можно получить через простую библиотеку. Утилита utempter проверяет, владеет ли процесс tty, который пытается войти в базу данных utmp до разрешения операции, utempter предназначена только для pty; другие tty обычно открываются демонами с достаточными полномочиями для модификации файлов системных баз данных.
#include <utempter.h>
void addToUtmp(const char *pty, const char *hostname, int ptyfd);
void removeLineFromUtmp(const char *pty, int ptyfd);
void removeFromUtmp(void);
Функция addToUtmp() принимает три аргумента. Первый, pty, является полным путем к добавляемому pty. Второй, hostname, может быть NULL или сетевым именем системы, из которой сетевое подключение использует этот порожденный pty (что запускает ut_host, рассматриваемый в следующем разделе главы). Третий, ptyfd, должен быть открытым файловым дескриптором, ссылающимся на устройство, названное в аргументе pty.
Функция removeLineFromUtmp() принимает два аргумента; они определяются в точности как аргументы с таким же именем, передаваемые функции addToUtmp().
Некоторые существующие приложения записываются с помощью структуры, усложняющей хранение имени и файлового дескриптора для очистки элемента utmp. Из-за этого библиотека utempter поддерживает кэш самого позднего имени устройства и файлового дескриптора, передаваемого addToUtmp(), и удобную функцию removeFromUtmp(), не принимающую никаких аргументов и действующую как removeLineFromUtmp() на кэшированную информацию. Это подходит только для приложений, добавляющих лишь один элемент utmp; более сложные приложения, использующие более одного pty, должны вместо этого применять removeLineFromUtmp().
16.1.5. Запись вручную
Область обработки utmp и wtmp является одной из тех противоречивых областей, где механизмы различаются между системами и меняются на протяжении лет; даже определение информации, доступной в utmp и wtmp, до сих пор различается между системами. Изначально utmp и wtmp были просто массивами структур, записанных на диск; через некоторое время были созданы программные интерфейсы приложений (API) для надежной обработки записей.
По крайней мере, два таких интерфейса были официально стандартизованы; исходный интерфейс utmp (описанный в XSI, XPG2 и SVID2) и расширенный интерфейс utmpx (описанный в XPG4.2 и в поздних версиях POSIX). В Linux доступны оба интерфейса (utmp и utmpx). Интерфейс utmp, широко варьирующийся между машинами, имеет набор определений, которые делают возможной запись переносимого кода. Этот код пользуется преимуществом расширений, предоставляемых glibc. Более строго стандартизованный интерфейс utmpx в данный момент не предоставляет эти определения, но все еще поддерживает расширения.
Интерфейс Linux utmp был изначально задуман как супермножество других существующих интерфейсов utmp, a utmpx был стандартизован как супермножество других существующих интерфейсов utmp; к счастью, оба набора во многом одинаковы. В Linux различие между структурами данных utmp и utmpx заключается лишь в букве x.
Если вы не хотите применять расширения, мы рекомендуем использовать интерфейс utmpx, поскольку он наиболее переносим, пока вы не используете расширения, и строго стандартизован.
Однако если вы хотите применять расширения, мы рекомендуем использовать интерфейс utmp, поскольку glibc предоставляет определения, позволяющие записать переносимый код, пользующийся преимуществами расширений.
Существует также смешанный подход — включите оба заголовочных файла и используйте определения, предоставляемые glibc для интерфейса utmp, чтобы решить, применять ли расширения в интерфейсе utmpx. Этого мы не рекомендуем, поскольку нет гарантии, что заголовочные файлы utmp.h и utmpx.h не будут конфликтовать с системами, не относящимися к Linux. Если ожидается максимальная переносимость и функциональность, в одной из этих областей придется записать некоторые коды дважды — первую версию с использованием utmpx для легкого переноса в новые системы, а вторую с применением #ifdef — для максимальной функциональности в каждой новой системе, в которую вы перемещаетесь.
Здесь документируются лишь наиболее распространенные расширения; документация glibc покрывает все поддерживаемые расширения. Функции utmp работают в терминах struct utmp; мы игнорируем некоторые расширения. Структура и функции utmpx работают точно так же, как структура и функции utmp, поэтому мы не документируем их отдельно. Обратите внимание, что такая же структура используется и для utmp, и для wtmp, поскольку обе базы данных очень похожи.
struct utmp {
short int ut_type; /* тип входа */
pid_t ut_pid; /* идентификатор процесса входа */
char ut_line[UT_LINESIZE]; /* 32 символа */
char ut_id[4]; /* идентификатор inittab */
char ut_user[UT_NAMESIZE]; /* 32 символа */
char ut_host[UT_HOSTSIZE]; /* 256 символов */
struct timeval ut_tv;
struct exit_status ut_exit; /* состояние бездействующего процесса */
long ut_session;
int32_t ut_addr_v6[4];
};
Многие одинаковые элементы являются частью struct utmpx под тем же именем. Элементы, от которых не требуется быть элементами struct utmpx, комментируются как 'не стандартизованные POSIX' (ни один из них не стандартизован как часть struct utmp, поскольку сама struct utmp не стандартизована).
Элементы массива символов необязательно являются строками, завершающимися NULL. Используйте sizeof() либо другие ограничения размеров благоразумно.
ut_type | Одно из следующих значений: EMPTY, INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, DEAD_PROCESS, BOOT_TIME, NEW_TIME, OLD_TIME, RUN_LVL или ACCOUNTING, каждое из которых описано ниже. |
ut_tv | Время, ассоциированное с событием. Это единственный элемент, кроме |
