Поскольку cmd
запускается из оболочки /bin/sh
, то здесь применимы все обычные правила расширения команд. Ниже показан пример вызова system()
, который отображает исходные тексты С из текущего каталога.
#include
#include
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] Хотя функция popen() это делает просто, с ней связаны некоторые побочные эффекты, которые не сразу становятся очевидны. Она создает дочерний процесс, который может быть прерван перед тем, как будет вызвана pclose() , что заставит функцию wait() вернуть состояние процесса. Когда этот процесс завершится, он также сгенерирует SIGCHLD , что может привести в замешательство упрощенно написанный обработчик сигналов.
.
FILE * popen(const char *cmd, const char *mode);
cmd
выполняется через оболочку, как и в system()
. Параметр mode
должен быть "r"
, если родительский процесс желает читать командный вывод, и "w"
— для записи в стандартный ввод дочернего процесса. Следует отметить, что с помощью popen()
делать одновременно чтение и запись нельзя.
Два процесса, которые читают и пишут друг в друга, достаточно сложны [30] Этот тип обработки часто приводит к взаимоблокировкам, при которых процесс А ожидает, пока процесс В выполнит какую-то работу, в то время как процесс В ожидает процесса А, в результате чего ничего не происходит.
и выходят за рамки возможностей popen()
[31] Если вам понадобится делать это, запустите дочерний процесс с помощью fork() и exec() , а потом воспользуйтесь poll() для чтения и записи в дочерний процесс. Для этого предназначена программа под названием expect .
.
popen()
возвращает FILE*
(как это определено в стандартной библиотеке ввода-вывода ANSI/ISO), который может быть прочитан и записан подобно любому другому потоку stdio
[32] Информацию о чтении и записи в поток stdio можно найти в [15].
, либо NULL
, если операция не удается. Когда завершается родительский процесс, он может воспользоваться pclose()
для закрытия потока и прерывания дочернего процесса, если он все еще выполняется. Подобно system()
, pclose()
возвращает состояние дочернего процесса из wait4()
.
int pclose(FILE *stream);
Ниже приведен пример простой программы-калькулятора, которая использует программу bc
для выполнения всей реальной работы. Важно сбрасывать поток, полученный от popen()
, после записи в него, чтобы предотвратить буферизацию stdio
от задержки вывода (подробности о буферизации стандартных функций библиотеки stdio
можно найти в [15]).
1: /*calc.c*/
2:
3: /* Это очень простой калькулятор, который использует внешнюю команду bc
4: для выполнения всей работы. Открывает канал к bc, читает команду,
5: передает ее bc и завершается. */
6: #include
7: #include
8: #include
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);
Читать дальше