Подобную проверку всегда следует проводить в программах, запускающих произвольные команды на основе пользовательского ввода, используя функции popen() (или system()). Как вариант символы, которые не нужно проверять, можно было бы заключить в кавычки — таким образом командная оболочка не стала бы их интерпретировать.
Поскольку указатель на файловый поток, возвращаемый вызовом popen(), не ссылается на терминал, библиотека stdio применяет к данному потоку блочную буферизацию (см. раздел 13.2). Это значит, что по умолчанию при выполнении функции popen() в режиме w вывод передается дочернему процессу на другом конце канала только после заполнения буфера или закрытия самого канала с помощью вызова pclose(). Во многих случаях это не вызывает никаких проблем. Однако если нужно, чтобы потомок получал данные из канала немедленно, то есть два варианта: можно периодически вызывать fflush() или отключить буферизацию, используя вызов setbuf(fp, NULL). То же самое можно сделать, если мы создаем канал, задействуя системный вызов pipe(), а затем применяем fdopen() для получения потока стандартного вывода, связанного с записывающим концом канала.
Но все может оказаться сложнее, если процесс, вызывающий popen(), читает из канала (то есть при указании режима r). В таком случае, если потомок использует библиотеку stdio (и при этом не делает вызовов fflush() или setbuf()), то его вывод дойдет до вызывающего процесса либо после заполнения буфера, либо в результате вызова fclose(). (То же самое относится к ситуации, когда мы читаем из канала, созданного с помощью вызова pipe(), а процесс на другом конце записывает данные, применяя библиотеку stdio.) Если такое поведение вас не устраивает, исправить его почти невозможно — разве что можно отредактировать исходный код программы, выполняющейся в дочернем процессе, и добавить туда вызов setbuf() или fflush().
Если у вас нет доступа к исходному коду, канал можно заменить псевдотерминалом — IPC-каналом, один конец которого подключается к процессу и ведет себя как терминал. В итоге библиотека stdio будет буферизировать вывод построчно. Псевдотерминалы будут описаны в главе 60.
С точки зрения семантики очередь FIFO похожа на канал. Ее принципиальное отличие заключается в том, что у нее есть имя в рамках файловой системы и ее можно открывать так же, как обычный файл. Это позволяет использовать очереди FIFO для взаимодействия процессов, не имеющих отношения друг к другу (например, между клиентом и сервером).
Для работы с открытой очередью FIFO служат те же системные вызовы, что и в случае с каналами и другими файлами (то есть read(), write() и close()). По аналогии с каналами очередь FIFO имеет записывающий и считывающий конец, а данные, которые из них читаются, поступают в том же порядке, в каком они были записаны. На этом и основывается название FIFO —
Как и в случае с каналами, данные внутри очереди FIFO теряются при закрытии последнего дескриптора, который на нее ссылается.
Очередь FIFO можно создать, задействуя консольную команду mkfifo:
$ mkfifo [-m mode] pathname
где pathname — имя создаваемой очереди, а параметр — m используется, чтобы задать режим доступа (так же как это делается в команде chmod).
Функции fstat() и stat(), если их применить к очереди FIFO (или каналу), возвращают в поле st_mode структуры stat (см. раздел 15.1) тип файла S_IFIFO. При выводе с помощью команды ls — l очередь FIFO содержит в первом столбце тип p, а команда ls — F добавляет к ее имени символ канала (|).
Функция mkfifo() позволяет создать очередь FIFO с заданным именем.
#include
int mkfifo(const char *
Возвращает 0 при успешном завершении или -1 при ошибке
Аргумент mode задает права доступа к новой очереди FIFO. Они состоят из констант, к которым применяется побитовое ИЛИ (см. табл. 15.4). Как и к обычным правам доступа, к ним применяется атрибут umask (см. подраздел 15.4.6).
Изначально очереди FIFO создавались с помощью системного вызова mknod(pathname, S_IFIFO, 0), который позволяет создавать различные виды файлов, включая файлы устройств (в стандарте SUSv3 применение mknod() ограничивается созданием очередей FIFO). В стандарте POSIX.1-1990 появился более простой, хотя и менее универсальный программный интерфейс, mkfifo(). В большинстве UNIX-систем он реализован в виде обертки вокруг mknod().
Новую очередь FIFO может открыть любой процесс, имеющий соответствующие права доступа (см. подраздел 15.4.3).