UNIX: разработка сетевых приложений
Рис. 15.1. Программа mycat после создания потокового канала при использовании функции socketpair
Затем процесс взывает функцию
, и дочерний процесс вызывает функциюforkдля выполнения программыexec. Родительский процесс закрывает дескрипторopenfile, а дочерний процесс закрывает дескриптор[1]. (Нет разницы, на каком конце потокового канала происходит закрытие. Дочерний процесс мог бы закрыть[0], а родительский —[1].) При этом получается схема, показанная на рис. 15.2.[0]Рис. 15.2. Программа mycat после запуска программы openfile
Родительский процесс должен передать программе
три фрагмента информации: полное имя открываемого файла, режим открытия (только чтение чтение и запись или только запись) и номер дескриптора, соответствующий его концу потокового канала (который мы обозначилиopenfile). Мы выбрали такой способ передачи этих трех элементов, как ввод аргументов командной строки при вызове функции[1]. Альтернативным способом будет отправка этих элементов в качестве данных по потоковому каналу. Программа отправляет обратно открытый дескриптор по потоковому каналу и завершается. Статус выхода программы сообщает родительскому процессу, смог ли файл открыться, и если нет, то какого типа ошибка произошла.execПреимущество выполнения дополнительной программы для открытия файла заключается в том, что за счет приравнивания привилегий пользователя к привилегиям владельца файла мы получаем возможность открывать те файлы, которые не имеем права открывать в обычной ситуации. Эта программа позволяет расширить концепцию обычных прав доступа Unix (пользователь, группа и все остальные) и включить любые формы проверки прав доступа. Мы начнем с программы
, показанной в листинге 15.7.mycatЛистинг 15.7. Программа mycat: копирование файла в стандартный поток вывода
//unixdomain/mycat.c1 #include "unp.h"2 int my_open(const char*, int);3 int4 main(int argc, char **argv)5 {6 int fd, n;7 char buff[BUFFSIZE];8 if (argc != 2)9 err_quit("usage: mycat <pathname>");10 if ((fd = my_open(argv[1], O_RDONLY)) < 0)11 err_sys("cannot open %s", argv[1]);12 while ((n = Read(fd, buff, BUFFSIZE)) > 0)13 Write(STDOUT_FILENO, buff, n);14 exit(0);15 }Если мы заменим вызов функции
вызовом функцииmy_open, эта простая программа всего лишь скопирует файл в стандартный поток вывода.openФункция
, показанная в листинге 15.8, должна выглядеть для вызывающего процесса как обычная функция Unixmy_open. Она получает два аргумента — полное имя и режим открытия (например,openобозначает, что файл доступен только для чтения), открывает файл и возвращает дескриптор.O_RDONLYЛистинг 15.8. Функция my_open: открытие файла и возвращение дескриптора
//unixdomain/myopen.c1 #include "unp.h"2 int3 my_open(const char *pathname, int mode)4 {5 int fd, sockfd[2], status;6 pid_t childpid;7 char c, argsockfd[10], argmode[10];8 Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);9 if ((childpid = Fork()) == 0) { /* дочерний процесс */10 Close(sockfd[0]);11 snprintf(argsockfd, sizeof(argsockfd), "%d", sockfd[1]);12 snprintf(argmode, sizeof(argmode), "%d", mode);13 execl("./openfile", "openfile", argsockfd, pathname, argmode,14 (char*)NULL);15 err_sys("execl error");16 }17 /* родительский процесс - ожидание завершения дочернего процесса */18 Close(sockfd[1]); /* закрываем конец, который мы не используем */19 Waitpid(childpid, &status, 0);20 if (WIFEXITED(status) == 0)21 err_quit("child did not terminate");22 if ((status = WEXITSTATUS(status)) == 0)23 Read_fd(sockfd[0], &c, 1, &fd);24 else {25 errno = status; /* установка значения errno в статус дочернегопроцесса */26 fd = -1;27 }28 Close(sockfd[0]);29 return (fd);30 }Создание потокового каналаФункция8создает потоковый канал. Возвращаются два дескриптора:socketpairиsockfd[0]. Это состояние, которое мы показали на рис. 15.1.sockfd[1]Функции fork и execВызывается функция9-16, после чего дочерний процесс закрывает один конец потокового канала. Номер дескриптора другого конца потокового канала помещается в массивfork, а режим открытия помещается в массивargsockfd. Мы вызываем функциюargmode, поскольку аргументы функции exec должны быть символьными строками. Выполняется программаsnprintf. Функцияopenfileвозвращает управление только в том случае, если она встретит ошибку. При удачном выполнении начинает выполняться функцияexeclпрограммыmain.openfile

