Разработка приложений в среде 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
делать одновременно чтение и запись нельзя. Два
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
рейтинг книги
Законы Рода. Том 6
6. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Санек
1. Санек
Фантастика:
попаданцы
альтернативная история
4.00
рейтинг книги
Ярость Богов
3. Мир Вальдиры
Фантастика:
фэнтези
рпг
9.48
рейтинг книги
Третье правило дворянина
3. Истинный дворянин
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Ученик. Книга третья
3. Ученик
Фантастика:
фэнтези
7.64
рейтинг книги
Кодекс Охотника. Книга XV
15. Кодекс Охотника
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Большая Гонка
16. Другая сторона
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Краш-тест для майора
3. Серьёзные мальчики в форме
Любовные романы:
современные любовные романы
эро литература
6.25
рейтинг книги
Дикая фиалка Юга
Фантастика:
фэнтези
5.00
рейтинг книги
Идеальный мир для Социопата 4
4. Социопат
Фантастика:
боевая фантастика
6.82
рейтинг книги
Вперед в прошлое 6
6. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Специалист
17. Другая сторона
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Жена по ошибке
Любовные романы:
любовно-фантастические романы
7.71