Linux программирование в примерах
ID группы
Как и для ID пользователя, должен быть уникальным для каждой группы.
Список пользователей
Разделенный запятыми список пользователей, являющихся членами группы.
В предыдущем примере мы видели, что пользователь
является членом нескольких групп. Это членство на практике отражается в том, что называют набором групп (group set). Помимо главных номеров ID пользователя и ID группы, которые есть у процессов, набор групп является набором номеров ID дополнительных групп, который имеет при себе каждый процесс. Система проверяет на соответствие с этими ID групп, ID группы файла при осуществлении проверки прав доступа. Эта тема более подробно обсуждается в разделе 11 «Разрешения и ID пользователя и группы».arnoldAPI базы данных групп сходна с 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_mem1 /* ch06-groupinfo.с --- Демонстрация getgrent() и struct group */23 #include <stdio.h>4 #include <sys/types.h>5 #include <grp.h>67 extern void print_group(const struct group *gr);89 /* main --- вывести строки групп для пользователя в argv[1] */1011 int12 main(int argc, char **argv)13 {14 struct group *gr;15 int i;1617 if (argc != 2) { /* Проверка аргументов */18 fprintf(stderr, "usage: %s user\n", argv[0]);19 exit(1);20 }2122 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); /* Вывести запись */2627 endgrent();2829 exit(0);30 }Функция
сначала проверяет ошибки (строки 17–20). Основным компонентом программы является вложенный цикл. Внешний цикл (строка 22) перечисляет все записи базы данных группы. Внутренний цикл (строка 23) перечисляет всех членов массиваmain(). Если один из членов соответствует имени из командной строки (строка 24), для печати записи вызываетсяgr_mem(строка 25):print_group()32 /* print_group --- печать записи группы */3334 void35 print_group(const struct group *gr)36 {37 int i;3839 printf("%s:%s:%ld:gr->gr_name, gr->gr_passwd, (long)gr->gr_gid);4041 for (i = 0; gr->gr_mem[i] != NULL; i++) {42 printf("%s", gr->gr_mem[i]);43 if (gr->gr_mem[i+1) != NULL)44 putchar(',');45 }4647 putchar('\n');48 }Функция
(строки 34–48) проста, ее логика подобна логикеprint_group()для печати списка членов. Члены списка группы разделены запятыми; поэтому тело цикла до вывода запятой должно проверить, что следующий элемент в массиве не являетсяmain(). Этот код работает правильно, даже если в группе нет членов. Однако мы знаем, что для этой программы есть члены, иначеNULLне была бы вызвана! Вот что происходит при запуске программы:print_group()$ <b>ch06-groupinfo arnold</b>mail:x:12:mail,postfix,arnolduucp:x:14:uucp,arnoldfloppy:x:19:arnolddevel:x:42:miriam,arnoldarnold:x:2076:arnold6.4. Терминалы:
isatty()Модель стандартного ввода, стандартного вывода и стандартной ошибки Linux/Unix препятствует специальной трактовке устройств ввода и вывода. Программам обычно не нужно знать или беспокоиться о том, направляется ли их вывод на терминал, в файл, канал, физическое устройство или что-то еще.