Листинг 40.3. Обновление файлов utmp и wtmp
loginacct/utmpx_login.c
#define _GNU_SOURCE
#include
#include
#include
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
struct utmpx ut;
char *devName;
if (argc < 2 || strcmp(argv[1], "-help") == 0)
usageErr("%s username [sleep-time]\n", argv[0]);
/* Инициализируем запись входа в систему для файлов utmp и wtmp */
memset(&ut, 0, sizeof(struct utmpx));
ut.ut_type = USER_PROCESS; /* Это запись о входе в систему */
strncpy(ut.ut_user, argv[1], sizeof(ut.ut_user));
if (time((time_t *) &ut.ut_tv.tv_sec) == -1)
errExit("time"); /* Указываем текущее время */
ut.ut_pid = getpid();
/* Устанавливаем поля ut_line и ut_id на основе того, какой терминал связан
со стандартным вводом. Мы исходим из того, что имена терминалов имеют вид
"/dev/[pt]t[sy]*". Имя каталога "/dev/" занимает пять символов; префикс
"[pt]t[sy]" — три символа (в итоге получается восемь символов). */
devName = ttyname(STDIN_FILENO);
if (devName == NULL)
errExit("ttyname");
if (strlen(devName) <= 8) /* Это условие не должно выполняться */
fatal("Terminal name is too short: %s", devName);
strncpy(ut.ut_line, devName + 5, sizeof(ut.ut_line));
strncpy(ut.ut_id, devName + 8, sizeof(ut.ut_id));
printf("Creating login entries in utmp and wtmp\n");
printf(" using pid %ld, line %.*s, id %.*s\n",
(long) ut.ut_pid, (int) sizeof(ut.ut_line), ut.ut_line,
(int) sizeof(ut.ut_id), ut.ut_id);
setutxent(); /* Переходим в начало файла utmp */
if (pututxline(&ut) == NULL) /* Добавляем в файл utmp запись о входе в систему */
errExit("pututxline");
updwtmpx(_PATH_WTMP, &ut); /* Добавляем запись о входе в систему в файл wtmp */
/* Засыпаем, давая пользователю возможность просмотреть файлы utmp и wtmp */
sleep((argc > 2)? getInt(argv[2], GN_NONNEG, "sleep-time"): 15);
/* Теперь "выходим из системы"; используем значения из ранее
инициализированной структуры 'ut', меняя их следующим образом: */
ut.ut_type = DEAD_PROCESS; /* Нужно для записи данных о выходе из системы */
time((time_t *) &ut.ut_tv.tv_sec); /* Указываем время выхода */
memset(&ut.ut_user, 0, sizeof(ut.ut_user));
/* Имя пользователя в записи о выходе равно NULL */
printf("Creating logout entries in utmp and wtmp\n");
setutxent(); /* Переходим в начало файла utmp */
if (pututxline(&ut) == NULL) /* Заменяем ранее созданную в utmp запись */
errExit("pututxline");
updwtmpx(_PATH_WTMP, &ut); /* Добавляем запись о выходе в файл wtmp */
endutxent();
exit(EXIT_SUCCESS);
}
loginacct/utmpx_login.c
Этот файл хранит информацию о времени последнего входа в систему каждого пользователя (в отличие от файла wtmp, в котором находятся данные обо всех входах и выходах из системы). В числе прочего файл lastlog позволяет программе login информировать пользователей о том, когда они в последний раз входили в систему (в начале новой сессии). Данный файл должен обновляться приложениями, отвечающими за вход в систему (наряду с utmp и wtmp).
Как и в случае с файлами utmp и wtmp, местоположение и формат lastlog могут варьироваться (а в ряде UNIX-систем он и вовсе отсутствует). В Linux этот файл имеет путь /var/log/lastlog, на который указывает константа _PATH_LASTLOG, объявленная в заголовочном файле
Записи в файле lastlog имеют следующий формат (описанный в
#define UT_NAMESIZE 32
#define UT_HOSTSIZE 256
struct lastlog {
time_t ll_time; /* Время последнего входа в систему */
char ll_line[UT_NAMESIZE]; /* Терминал для удаленного входа */
char ll_host[UT_HOSTSIZE]; /* Имя компьютера, с которого
был выполнен удаленный вход */
};
Обратите внимание: приведенные записи не содержат имени или идентификатора пользователя. Вместо этого они индексируются по UID. То есть, чтобы найти в файле lastlog запись для пользователя с идентификатором 1000, нужно перейти к подходящему байту (1000 * sizeof(struct lastlog)). Это продемонстрировано в программе из листинга 40.4, которая позволяет просматривать записи для пользователей, указанных в командной строке. По своим функциям она похожа на команду lastlog(1). Ниже показан пример вывода, возвращаемого в результате ее выполнения:
$ ./view_lastlog annie paulh
annie tty2 Mon Jan 17 11:00:12 2011
paulh pts/11 Sat Aug 14 09:22:14 2010
Для обновления файла lastlog его точно так же нужно открыть, перейти в подходящую позицию и выполнить запись.
Поскольку lastlog проиндексирован по пользовательскому идентификатору, мы не можем отличить записи о входе в систему, относящиеся к разным именам пользователей с одним и тем же UID (в разделе 8.1 отмечалось, что вход с одного UID под разными именами хоть и является необычным, но вполне возможен).