Чтение онлайн

на главную - закладки

Жанры

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

10.5.1. Запуск и ожидание с помощью

system

Программам часто требуется запускать другие программы и ожидать их завершения, прежде чем продолжать свою работу. Функция

system
позволяет это делать достаточно просто.

int system (const char* cmd);

system
порождает дочерний процесс, который выполняет
exec
для
/bin/sh
, который, в свою очередь, запускает
cmd
. Исходный процесс ожидает завершения дочерней оболочки и возвращает тот же код, что
wait
[28] . Если вам не нужно оставлять в памяти оболочку (что случается редко),
cmd
должна включать
предшествующее слово
"exec"
, которое заставляет оболочку вызывать
exec
вместо запуска
cmd
как подпроцесса.

28

В процессе работы

system
блокирует
SIGCHILD
, что заставляет передавать этот сигнал программе непосредственно перед тем, как
system
вернет управление (но после того, как
system
вызовет
wait
для порожденного процесса), поэтому программы, которые используют обработчики сигналов, должны это учитывать и обрабатывать такие ложные сигналы осторожно. Функция
system
также игнорирует
SIGINT
и
SIGQUIT
, а это означает, что быстрые циклические повторные вызовы
system
может оказаться невозможно прервать ничем, кроме
SIGSTOP
и
SIGKILL
.

Поскольку

cmd
запускается из оболочки
/bin/sh
, то здесь применимы все обычные правила расширения команд. Ниже показан пример вызова
system
, который отображает исходные тексты С из текущего каталога.

#include <stdlib.h>

#include <sys/wait.h>

int main {

int result;

result = system("exec ls *.c");

if (!WIFEXITED(result))

 printf("(аварийный выход)\n");

 exit(0);

}

Команда

system
должна применяться с большой осторожностью в программах, которые запускаются со специальными полномочиями. Поскольку системная оболочка предоставляет множество мощных средств и сильно зависит от переменных окружения,
system
является уязвимым местом в плане безопасности, которым могут воспользоваться злоумышленники для проникновения в систему. Однако до тех пор, пока приложение не является демоном или программой
setuid/setgid
, вызов
system
совершенно безопасен.

10.5.2. Чтение и запись из процесса

Хотя

system
отображает результат работы команды на устройство стандартного вывода и позволяет дочерним программам читать стандартный ввод, это не всегда идеально. Часто процесс желает читать вывод другого процесса либо отправлять текст на стандартный ввод.
popen
облегчает процессам решение этой задачи [29] .

FILE * popen(const char *cmd, const char *mode);

29

Хотя функция

popen
это делает просто, с ней связаны некоторые побочные эффекты, которые не сразу становятся очевидны. Она создает дочерний процесс, который может быть прерван перед тем, как будет вызвана
pclose
, что заставит функцию
wait
вернуть состояние процесса. Когда этот процесс завершится, он также сгенерирует
SIGCHLD
, что может привести в замешательство упрощенно написанный обработчик сигналов.

cmd
выполняется через оболочку, как и в
system
. Параметр
mode
должен быть
"r"
, если родительский процесс желает читать командный вывод, и
"w"
— для записи в стандартный ввод дочернего процесса. Следует отметить, что с помощью
popen
делать одновременно чтение и запись нельзя.

Два

процесса, которые читают и пишут друг в друга, достаточно сложны [30] и выходят за рамки возможностей
popen
[31] .

30

Этот тип обработки часто приводит к взаимоблокировкам, при которых процесс А ожидает, пока процесс В выполнит какую-то работу, в то время как процесс В ожидает процесса А, в результате чего ничего не происходит.

31

Если вам понадобится делать это, запустите дочерний процесс с помощью

fork
и
exec
, а потом воспользуйтесь
poll
для чтения и записи в дочерний процесс. Для этого предназначена программа под названием
expect
.

popen
возвращает
FILE*
(как это определено в стандартной библиотеке ввода-вывода ANSI/ISO), который может быть прочитан и записан подобно любому другому потоку
stdio
[32] , либо
NULL
, если операция не удается. Когда завершается родительский процесс, он может воспользоваться
pclose
для закрытия потока и прерывания дочернего процесса, если он все еще выполняется. Подобно
system
,
pclose
возвращает состояние дочернего процесса из
wait4
.

32

Информацию о чтении и записи в поток

stdio
можно найти в [15].

int pclose(FILE *stream);

Ниже приведен пример простой программы-калькулятора, которая использует программу

bc
для выполнения всей реальной работы. Важно сбрасывать поток, полученный от
popen
, после записи в него, чтобы предотвратить буферизацию
stdio
от задержки вывода (подробности о буферизации стандартных функций библиотеки
stdio
можно найти в [15]).

 1: /*calc.c*/

 2:

 3: /* Это очень простой калькулятор, который использует внешнюю команду bc

 4: для выполнения всей работы. Открывает канал к bc, читает команду,

 5: передает ее bc и завершается. */

 6: #include <stdio.h>

 7: #include <sys/wait.h>

 8: #include <unistd.h>

 9:

10: int main(void) {

11: char buf[1024];

12: FILE *bc;

13: int result;

14:

15: /* открыть канал на bc и выйти в случае неудачи */

16: bc = popen("bc", "w");

17: if (!bc) {

18: perror("popen");

19: return 1;

20: }

21:

22: /* пригласить ввести выражение, и прочитать его */

23: printf("expr:"); fflush(stdout);

24: fgets(buf, sizeof(buf), stdin);

25:

26: /* послать выражение bc для вычисления */

27: fprintf(bc, "%s\n", buf);

28: fflush(bc);

29:

30: /* закрыть канал на bc и ожидать выхода из нее */

31: result = pclose(bc);

32:

33: if (!WIFEXITED(result))

34: printf("(аварийный выход)\n");

35:

36: return 0;

37: }

Поделиться:
Популярные книги

Гарем вне закона 18+

Тесленок Кирилл Геннадьевич
1. Гарем вне закона
Фантастика:
фэнтези
юмористическая фантастика
6.73
рейтинг книги
Гарем вне закона 18+

Законы Рода. Том 6

Flow Ascold
6. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 6

Санек

Седой Василий
1. Санек
Фантастика:
попаданцы
альтернативная история
4.00
рейтинг книги
Санек

Ярость Богов

Михайлов Дем Алексеевич
3. Мир Вальдиры
Фантастика:
фэнтези
рпг
9.48
рейтинг книги
Ярость Богов

Третье правило дворянина

Герда Александр
3. Истинный дворянин
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Третье правило дворянина

Ученик. Книга третья

Первухин Андрей Евгеньевич
3. Ученик
Фантастика:
фэнтези
7.64
рейтинг книги
Ученик. Книга третья

Кодекс Охотника. Книга XV

Винокуров Юрий
15. Кодекс Охотника
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XV

Большая Гонка

Кораблев Родион
16. Другая сторона
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Большая Гонка

Краш-тест для майора

Рам Янка
3. Серьёзные мальчики в форме
Любовные романы:
современные любовные романы
эро литература
6.25
рейтинг книги
Краш-тест для майора

Дикая фиалка Юга

Шах Ольга
Фантастика:
фэнтези
5.00
рейтинг книги
Дикая фиалка Юга

Идеальный мир для Социопата 4

Сапфир Олег
4. Социопат
Фантастика:
боевая фантастика
6.82
рейтинг книги
Идеальный мир для Социопата 4

Вперед в прошлое 6

Ратманов Денис
6. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 6

Специалист

Кораблев Родион
17. Другая сторона
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Специалист

Жена по ошибке

Ардова Алиса
Любовные романы:
любовно-фантастические романы
7.71
рейтинг книги
Жена по ошибке