flags |= FD_CLOEXEC; /* Устанавливаем FD_CLOEXEC */
if (fcntl(STDOUT_FILENO, F_SETFD, flags) == –1) /* Обновляем флаги */
errExit("fcntl — F_SETFD");
}
execlp("ls", "ls", "-l", argv[0], (char *) NULL);
errExit("execlp");
}
procexec/closeonexec.c
Во время выполнения вызова exec() текст существующего процесса удаляется. Этот текст мог содержать обработчики сигналов, установленные вызывающей программой. Поскольку обработчики исчезли, ядро изменяет диспозиции для всех перехватываемых сигналов на SIG_DFL. Диспозиции всех остальных сигналов (то есть SIG_IGN или SIG_DFL) остаются без изменений. Это требование стандарта SUSv3.
В стандарте SUSv3 игнорирование сигнала SIGCHLD оговаривается отдельно (в подразделе 26.3.3 уже отмечалось, что это позволяет избежать возникновения процессов-«зомби»). Однако в нем не уточняется, игнорируется ли данный сигнал на протяжении всего вызова exec(), или же его действие сбрасывается к SIG_DFL. В Linux применяется первый вариант, но в некоторых реализациях UNIX (таких как Solaris) происходит сбрасывание. Из этого следует, что для достижения максимальной переносимости программ, которые игнорируют сигнал SIGCHLD, нам следует выполнять signal(SIGCHLD, SIG_DFL) перед вызовом exec() и исходить из того, что исходной диспозицией этого сигнала является SIG_DFL.
Удаление данных, кучи и стека старой программы также означает, что любой альтернативный стек сигналов, полученный в результате вызова sigaltstack() (см. раздел 21.3), теряется. Поскольку этот стек не сохраняется во время выполнения exec(), бит SA_ONSTACK тоже сбрасывается для всех сигналов.
Во время выполнения exec() у процесса сохраняются сигнальная маска и сигналы, находящиеся в состоянии ожидания. Это позволяет блокировать и складывать в очередь сигналы для новой программы. Однако в стандарте SUSv3 отмечается, что многие существующие приложения ошибочно предполагают, что определенные сигналы при их запуске изначально имели диспозицию SIG_DFL или были разблокированными (в частности, стандарты языка С содержат куда менее конкретную спецификацию сигналов, в которой не упоминается их блокирование; следовательно, программы на этом языке, написанные на несовместимых с UNIX системах, не знают о том, что сигналы нужно разблокировать). По этой причине в стандарте SUSv3 рекомендуется не блокировать и не игнорировать сигналы во время выполнения сторонних программ с помощью exec(). Под сторонними подразумеваются программы, написанные не нами. Если приложение разработали мы сами или если мы знаем, как оно ведет себя с сигналами, от этого правила можно отойти.
Функция system() позволяет вызывающей программе выполнять произвольные консольные команды. В этом разделе мы опишем принцип ее работы, а в следующем — покажем, как ее можно реализовать с помощью вызовов fork(), exec(), wait() и exit().
В разделе 44.5 рассматриваются функции popen() и pclose(), которые тоже могут быть использованы для вызова консольных команд, но при этом позволяют вызывающей программе либо считывать вывод команды, либо отправлять ей ввод.
#include
int system(const char *
Описание возвращаемого значения ищите в основном тексте
Функция system() создает дочерний процесс для выполнения команды command. Ниже показан пример ее вызова:
system("ls | wc");
Принципиальными преимуществами функции system() являются простота и удобство.
• Нам не нужно иметь дело с деталями вызовов fork(), exec(), wait() и exit().
• Обработка ошибок и сигналов выполняется за нас самой функцией system().
• Поскольку system() использует для выполнения
Главным недостатком функции system() является ее низкая производительность. Запуск команды с ее помощью требует создания как минимум двух процессов — одного для командной оболочки, и еще одного — для выполняемой команды; каждый такой процесс требует вызова exec(). Если эффективность или скорость являются важным требованием, для запуска нужной программы лучше воспользоваться непосредственно вызовами fork() и exec().
Значение, возвращаемое функцией system(), зависит от следующих факторов.