Функция 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 перед тем, как появится возможность читать или записывать в него.