Разработка приложений в среде Linux. Второе издание - Майкл Джонсон
Шрифт:
Интервал:
Закладка:
Функция setutent() перемещает внутренний указатель базы данных в начало.
Функция endutent() закрывает базу данных. Это закрывает файловый дескриптор и освобождает ассоциированные данные. Вызывайте endutent() как перед использованием utmpname() для доступа к другому файлу utmp, так и после завершения доступа к данным utmp.
Наиболее надежным способом модификации базы данных wtmp являются две функции, определенные BSD и доступные как часть glibc.
Функция updwtmp() принимает файловое имя базы данных wtmp (обычно _PATH_WTMP) и заполненную структуру struct utmp, пытаясь добавить элемент к файлу wtmp. Эта функция не сообщает об ошибках.
Функция logwtmp() является удобной функцией, заполняющей struct utmp и вызывающей updwtmp() для нее. Аргумент line копируется в ut_line, name — в ut_user, host — в ut_host, ut_tv заполняется текущим показанием времени, a ut_pid — текущим идентификатором процесса. Как и updwtmp(), эта функция не сообщает об ошибках.
В программе utmp демонстрируются некоторые методы чтения баз данных utmp и wtmp.
1: /* utmp.с */
2:
3: #include <stdio.h>
4: #include <unistd.h>
5: #include <string.h>
6: #include <time.h>
7: #include <sys/time.h>
8: #include <sys/types.h>
9: #include <sys/socket.h>
10: #include <netinet/in.h>
11: #include <arpa/inet.h>
12: #include <utmp.h>
13: #include <popt.h>
14:
15: void print_utmp_entry(struct utmp * u) {
16: struct tm *tp;
17: char * type;
18: char addrtext[INET6_ADDRSTRLEN];
19:
20: switch (u->ut_type) {
21: case EMPTY: type = "EMPTY"; break;
22: case RUN_LVL: type = "RUN_LVL"; break;
23: case BOOT_TIME: type = "BOOT_TIME"; break;
24: case NEW_TIME: type = "NEW_TIME"; break;
25: case OLD_TIME: type = "OLD_TIME"; break;
26: case INIT_PROCESS: type = "INIT_PROCESS"; break;
27: case LOGIN_PROCESS: type = "LOGIN_PROCESS"; break;
28: case USER_PROCESS: type = "USER_PROCESS"; break;
29: case DEAD_PROCESS: type = "DEAD_PROCESS"; break;
30: case ACCOUNTING: type = "ACCOUNTING "; break;
31: }
32: printf("%-13s:", type);
33: switch (u->ut_type) {
34: case LOGIN_PROCESS:
35: case USER_PROCESS:
36: case DEAD_PROCESS:
37: printf(" line: %s", u->ut_line);
38: /* fall through */
39: case INIT_PROCESS:
40: printf("n pid: %6d id: %4.4s", u->ut_pid, u->ut_id);
41: }
42: printf ("n");
43: tp = gmtime(&u->ut_tv.tv_sec);
44: printf("time: %24.24s.%lun", asctime(tp), u->ut_tv.tv_usec);
45: switch (u->ut_type) {
46: case USER_PROCESS:
47: case LOGIN_PROCESS:
48: case RUN_LVL:
49: case BOOT_TIME:
50: printf("пользователь: %sn", u->ut_user);
51: }
52: if (u->ut_type == USER_PROCESS) {
53: if (u->ut_session)
54: printf(" сеанс: %lun", u->ut_session);
55: if (u->ut_host)
56: printf (" хост: %sn", u->ut_host);
57: if (u->ut_addr_v6[0]) {
58: if (!(u->ut_addr_v6[1] |
59: u->ut_addr_v6[2] |
60: u->ut_addr_v6[3])) {
61: /* заполнение только первой группы означает адрес IPV4 */
62: inet_ntop(AF_INET, u->ut_addr_v6,
63: addrtext, sizeof(addrtext));
64: printf(" IPV4: %sn", addrtext);
65: } else {
66: inet_ntop(AF_INET_6, u->ut_addr_v6,
67: addrtext, sizeof(addrtext));
68: printf (" IPV6: %sn", addrtext);
69: }
70: }
71: }
72: if (u->ut_type == DEAD_PROCESS) {
73: printf(" завершение : %u: %un",
74: u->ut_exit.e_termination,
75: u->ut_exit.e_exit);
76: }
77: printf("n");
78: }
79:
80: struct utmp * get_next_line (char * id, char * line) {
81: struct utmp request;
82:
83: if (!id && !line)
84: return getutent();
85:
86: memset(&request, 0, sizeof(request));
87:
88: if (line) {
89: strncpy(&request.ut_line[0], line, UT_LINESIZE);
90: return getutline(&request);
91: }
92:
93: request.ut_type = INIT_PROCESS;
94: strncpy(&request.ut_id[0], id, 4);
95: return getutid(&request);
96: }
97:
98: void print_file(char * name, char * id, char * line) {
99: struct utmp * u;
100:
101: if (utmpname(name)) {
102: fprintf (stderr, "сбой при открытии базы данных utmp %sn", name);
103: return;
104: }
105: setutent();
106: printf("%s:n====================n", name);
107: while ((u = get_next_line(id, line))) {
108: print_utmp_entry(u);
109: /* POSIX требует очистки статических данных перед
110: * повторным вызовом getutline или getutid
111: */
112: memset(u, 0, sizeof(struct utmp));
113: }
114: endutent();
115: }
116:
117: int main(int argc, const char **argv) {
118: char * id = NULL, *line = NULL;
119: int show_utmp = 1, show_wtmp = 0;
120: int c;
121: poptContext optCon;
122: struct poptOption optionsTable[] = {
123: {"utmp", 'u', POPT_ARG_NONE|POPT_ARGFLAG_XOR,
124: &show_utmp, 0,
125: "переключить просмотр содержимого файла utmp", NULL},
126: { "wtmp", 'w', POPT_ARG_NONE | POPT_ARGFLAG_XOR,
127: &show_wtmp, 0,
128: "переключить просмотр содержимого файла wtmp", NULL},
129: {"id", 'i', POPT_ARG_STRING, &id, 0,
130: "показать записи процесса для заданного идентификатора inittab",
131: "<inittab id>" },
132: {"line", 'l', POPT_ARG_STRING, &line, 0,
133: "показать записи процесса для заданной строки устройства",
134: "<line>" },
135: POPT_AUTOHELP
136: POPT_TABLEEND
137: };
138:
139: optCon = poptGetContext("utmp", argc, argv, optionsTable, 0);
140: if ((c = poptGetNextOpt(optCon)) < -1) {
141: fprintf(stderr, "%s:%sn",
142: poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
143: poptStrerror(c));
144: return 1;
145: }
146: poptFreeContext(optCon);
147:
148: if (id && line)
149: fprintf(stderr, "Невозможно выбирать сразу по идентификатору и строке,"
150: "выбор по строкеn");
151:
152: if (show_utmp)
153: print_file(_PATH_UTMP, id, line);
154: if (show_utmp && show_wtmp)
155: printf("nnn");
156: if (show_wtmp)
157: print_file(_PATH_WTMP, id, line);
158:
159: return 0;
160: }
16.2. Обзор termios
Все манипуляции tty осуществляются с помощью одной структуры, struct termios, а также нескольких функций, определенных в заголовочном файле <termios.h>. Из этих функций широко применяются только шесть. Когда не нужно устанавливать скорость передачи данных по линии, используются только две наиболее важных функции — tcgetattr() и tcsetattr().
#include <termios.h>
struct termios {
tcflag_t c_iflag; /* флаги режима ввода */
tcflag_t c_oflag; /* флаги режима вывода */
tcflag_t c_cflag; /* флаги управляющего режима */
tcflag_t c_lflag; /* флаги локального режима */
cc_t c_line; /* дисциплина линии связи */
cc_t c_cc[NCCS]; /* управляющие символы */
};
int tcgetattr(int fd, struct termios * tp);
int tcsetattr(int fd, int oact, struct termios * tp);
Почти в каждом случае программы должны использовать tcgetattr() для получения текущих установок устройства, модифицировать эти установки, а затем применять tcsetattr() для активизации модифицированных установок. Многие программы также сохраняют копии оригинальных установок и восстанавливают их перед завершением. В общем случае, следует модифицировать только интересующие вас установки; изменение других установок может усложнить работу пользователей с необычными системными конфигурациями (или сбоями в вашем коде).
Вызов tcsetattr() может не принять на обработку выбранные вами установки; разрешено игнорировать произвольные установки. Если оборудование просто не поддерживает установку, tcsetattr() игнорирует ее, а не возвращает ошибку. Если вам небезразлично воздействие, оказываемое установкой, следует использовать tcgetattr() после tcsetattr() и проверить, оказало ли воздействие внесенное вами изменение.
Для получения установок устройства tty необходимо открыть устройство и передать файловый дескриптор tcgetattr(). Это вызывает проблемы с некоторыми устройствами tty; некоторые обычно можно открыть лишь один раз с целью предотвращения конфликта устройств. К счастью, передача флага O_NONBLOCK в open() вызывает его немедленное открытие и предотвращает блокирование любых операций. Однако все равно можно предпочесть блокирование read(); в таком случае используйте fcntl() для отключения режима O_NONBLOCK перед тем, как появится возможность читать или записывать в него.