обладаете хоть каким-нибудь опытом программирования в Linux, то наверняка неоднократно получали это сообщение.
Если для процесса установлен лимит на размер файла дампа, равный 0 (рассматривался ранее в этой главе), то никакой дамп ядра не выгружается.
10.5. Простые дочерние процессы
Хотя функции fork()
, exec()
и wait()
позволяют программам в полной мере использовать модель процессов Linux, многим приложениям не нужен такой контроль дочерних процессов. Существуют две библиотечных функции, которые упрощают создание дочерних процессов: system()
и popen()
.
10.5.1. Запуск и ожидание с помощью system()
Программам часто требуется запускать другие программы и ожидать их завершения, прежде чем продолжать свою работу. Функция system()
позволяет это делать достаточно просто.
int system (const char* cmd);
system()
порождает дочерний процесс, который выполняет exec()
для /bin/sh
, который, в свою очередь, запускает cmd
. Исходный процесс ожидает завершения дочерней оболочки и возвращает тот же код, что wait()
[28]. Если вам не нужно оставлять в памяти оболочку (что случается редко), cmd
должна включать предшествующее слово 'exec'
, которое заставляет оболочку вызывать exec()
вместо запуска cmd
как подпроцесса.
Поскольку cmd
запускается из оболочки /bin/sh
, то здесь применимы все обычные правила расширения команд. Ниже показан пример вызова system()
, который отображает исходные тексты С из текущего каталога.
#include <stdlib.h>
#include <sys/wait.h>
int main() {
int result;
result = system('exec ls *.c');
if (!WIFEXITED(result))
printf('(аварийный выход)
');
exit(0);
}
Команда system()
должна применяться с большой осторожностью в программах, которые запускаются со специальными полномочиями. Поскольку системная оболочка предоставляет множество мощных средств и сильно зависит от переменных окружения, system()
является уязвимым местом в плане безопасности, которым могут воспользоваться злоумышленники для проникновения в систему. Однако до тех пор, пока приложение не является демоном или программой setuid/setgid
, вызов system()
совершенно безопасен.
10.5.2. Чтение и запись из процесса
Хотя system()
отображает результат работы команды на устройство стандартного вывода и позволяет дочерним программам читать стандартный ввод, это не всегда идеально. Часто процесс желает читать вывод другого процесса либо отправлять текст на стандартный ввод. popen()
облегчает процессам решение этой задачи[29].
FILE * popen(const char *cmd, const char *mode);
cmd
выполняется через оболочку, как и в system()
. Параметр mode
должен быть 'r'
, если родительский процесс желает читать командный вывод, и 'w'
— для записи в стандартный ввод дочернего процесса. Следует отметить, что с помощью popen()
делать одновременно чтение и запись нельзя.
Два процесса, которые читают и пишут друг в друга, достаточно сложны[30] и выходят за рамки возможностей popen()
[31].
popen()
возвращает FILE*
(как это определено в стандартной библиотеке ввода-вывода ANSI/ISO), который может быть прочитан и записан подобно любому другому потоку stdio
[32], либо 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 <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: