API базы данных групп сходна с API для базы данных пользователей. Следующие функции определены в
<grp.h>
:
#include <sys/types.h> /* XSI */
#include <grp.h>
struct group *getgrent(void);
void setgrent(void);
void endgrent(void);
struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid);
struct group соответствует записям в /etc/group:
struct group {
char *gr_name; /*
имя группы */
char *gr_passwd; /* пароль группы */
gid_t gr_gid; /* id группы */
char **gr_mem; /* члены группы */
};
Поле
gr_mem
требует некоторого объяснения. Хотя оно объявлено в виде указателя на указатель (
char**
), лучше представить его как массив строк (наподобие
argv
). Последний элемент в массиве устанавливается в
NULL
. Когда в списке нет членов, первый элемент массива равен
NULL
.
ch06-groupinfo.с
демонстрирует, как использовать
struct group
и поле
gr_mem
. Программа принимает в командной строке имя единственного пользователя и печатает все записи групп, в которых появляется этот пользователь:
1 /* ch06-groupinfo.с --- Демонстрация getgrent и struct group */
2
3 #include <stdio.h>
4 #include <sys/types.h>
5 #include <grp.h>
6
7 extern void print_group(const struct group *gr);
8
9 /* main --- вывести строки групп для пользователя в argv[1] */
10
11 int
12 main(int argc, char **argv)
13 {
14 struct group *gr;
15 int i;
16
17 if (argc != 2) { /* Проверка аргументов */
18 fprintf(stderr, "usage: %s user\n", argv[0]);
19 exit(1);
20 }
21
22 while ((gr = getgrent) != NULL) /* Получить запись каждой группы: */
23 for (i = 0; gr->gr_mem[i] != NULL; i++) /* Рассмотреть каждый член */
24 if (strcmp(gr->gr_mem[i], argv[i]) == 0) /* Если пользователь найден... */
25 print_group(gr); /* Вывести запись */
26
27 endgrent;
28
29 exit(0);
30 }
Функция
main
сначала проверяет ошибки (строки 17–20). Основным компонентом программы является вложенный цикл. Внешний цикл (строка 22) перечисляет все записи базы данных группы. Внутренний цикл (строка 23) перечисляет всех членов массива
gr_mem
. Если один из членов соответствует имени из командной строки (строка 24), для печати записи вызывается
для печати списка членов. Члены списка группы разделены запятыми; поэтому тело цикла до вывода запятой должно проверить, что следующий элемент в массиве не является
NULL
. Этот код работает правильно, даже если в группе нет членов. Однако мы знаем, что для этой программы есть члены, иначе
print_group
не была бы вызвана! Вот что происходит при запуске программы:
$ ch06-groupinfo arnold
mail:x:12:mail,postfix,arnold
uucp:x:14:uucp,arnold
floppy:x:19:arnold
devel:x:42:miriam,arnold
arnold:x:2076:arnold
6.4. Терминалы:
isatty
Модель стандартного ввода, стандартного вывода и стандартной ошибки Linux/Unix препятствует специальной трактовке устройств ввода и вывода. Программам обычно не нужно знать или беспокоиться о том, направляется ли их вывод на терминал, в файл, канал, физическое устройство или что-то еще.
Однако иногда бывают моменты, когда программе действительно нужно знать, с какого рода файлом связан файловый дескриптор. Семейство вызовов
stat
часто предоставляет достаточно сведений обычный файл, каталог, устройство и т.д. Хотя иногда даже этого недостаточно, и для интерактивных программ, в частности, вам может потребоваться знать, не представляет ли дескриптор файла
tty
.
tty (сокращение для Teletype, одного из ранних производителей компьютерных терминалов) является любым устройством, представляющим терминал, т.е. нечто, что человек мог бы использовать для взаимодействия с компьютером. Это может быть либо аппаратное устройство, такое, как клавиатура и монитор персонального компьютера, или старинный терминал видеодисплея, соединенный с компьютером через последовательный порт или модем, или программный псевдотерминал, такой, который используется в оконных системах и при сетевых регистрациях.
Различить можно с помощью
isatty
.
#include <unistd.h> /* POSIX */
int isacty(int desc);
Эта функция возвращает 1, если дескриптор файла
desc
представляет терминал, в противном случае 0. В соответствии с POSIX
isatty
может установить
errno
для указания ошибки; поэтому до вызова
isatty
следует установить errno в 0, а затем проверить ее значение, если был возвращен 0. (Справочная страница GNU/Linux isatty(3) не упоминает об использовании
errno
.) Стандарт POSIX также указывает, что просто возврат
isatty
1 не означает, что на другом конце дескриптора файла находится человек!