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

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

Жанры

Разработка приложений в среде 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: }

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

Газлайтер. Том 10

Володин Григорий
10. История Телепата
Фантастика:
боевая фантастика
5.00
рейтинг книги
Газлайтер. Том 10

На границе империй. Том 7. Часть 2

INDIGO
8. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
6.13
рейтинг книги
На границе империй. Том 7. Часть 2

Звездная Кровь. Изгой

Елисеев Алексей Станиславович
1. Звездная Кровь. Изгой
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Звездная Кровь. Изгой

Хозяин Теней 4

Петров Максим Николаевич
4. Безбожник
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Хозяин Теней 4

Картофельное счастье попаданки

Иконникова Ольга
Фантастика:
фэнтези
5.00
рейтинг книги
Картофельное счастье попаданки

Экзорцист: Проклятый металл. Жнец. Мор. Осквернитель

Корнев Павел Николаевич
Фантастика:
фэнтези
героическая фантастика
5.50
рейтинг книги
Экзорцист: Проклятый металл. Жнец. Мор. Осквернитель

Доктора вызывали? или Трудовые будни попаданки

Марей Соня
Фантастика:
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Доктора вызывали? или Трудовые будни попаданки

Метатель

Тарасов Ник
1. Метатель
Фантастика:
боевая фантастика
попаданцы
рпг
фэнтези
фантастика: прочее
постапокалипсис
5.00
рейтинг книги
Метатель

Моя на одну ночь

Тоцка Тала
Любовные романы:
современные любовные романы
короткие любовные романы
5.50
рейтинг книги
Моя на одну ночь

Чехов. Книга 2

Гоблин (MeXXanik)
2. Адвокат Чехов
Фантастика:
фэнтези
альтернативная история
аниме
5.00
рейтинг книги
Чехов. Книга 2

Хозяин Теней 2

Петров Максим Николаевич
2. Безбожник
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Хозяин Теней 2

Сумеречный стрелок 7

Карелин Сергей Витальевич
7. Сумеречный стрелок
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Сумеречный стрелок 7

Жизнь под чужим солнцем

Михалкова Елена Ивановна
Детективы:
прочие детективы
9.10
рейтинг книги
Жизнь под чужим солнцем

Красноармеец

Поселягин Владимир Геннадьевич
1. Красноармеец
Фантастика:
боевая фантастика
попаданцы
4.60
рейтинг книги
Красноармеец