Запуск процесса в фоновом режиме в Linux с C
Я пытаюсь сделать что-то немного странно здесь. Мне нужно запустить процесс, logcat, из deamon, который будет работать в фоновом режиме и печатать на терминал без контроля stdin. Это для ведения журнала, поэтому в идеале logcat будет печатать сообщения журнала, позволяя пользователю вводить стандартные команды и инициализировать программы из оболочки. Вот код для демона, который у меня есть до сих пор. Программа logcat запускается и показывает сообщения журнала, но я не могу вводить какие-либо команды в вывод, как кажется, что программа взяла под контроль ввода.
int main ( int argc, char** argv, char** env )
{
int fd;
if ((fd = open("/dev/console", O_RDWR)) < 0) {
fd = open("/dev/null", O_RDWR);
}
printf("THIS IS A TESTn");
dup2(1, fd);
dup2(2, fd);
pid_t childpid = fork();
if(childpid == -1) {
perror("Failed to fork, logcat not starting");
return 1;
}
if(childpid == 0) {
//this is the child, exec logcat
setsid();
int execReturn = execl("/system/bin/logcat", "logcat", (char *) 0);
} else {
//this is the parent do nothing
close(fd);
return 0;
}
close(fd);
return 0;
}
спасибо
3 ответов
на 'logcat' команда, похоже, предназначена для разработки Android - это может объяснить нечетное расположение команды.
ключевая операция, которую вы должны исправить, заключается в том, чтобы закрыть текущий стандартный вход (терминал) и открыть /dev/null/
устройства ввода:
close(0);
if ((fd = open("/dev/null", O_RDONLY)) != 0)
...error - failed to open /dev/null!
это означает, что ваш демонизированный дочерний процесс ничего не будет читать с терминала.
что я думаю, что вы хотите сделать есть:
- запустите программу запуска из командной строки, которая будет иметь стандартный вход, стандартный выход и стандартную ошибку, подключенную к "терминалу".
- внутри вашей программы, вы хотите заменить стандартный ввод, так что
/dev/null
. - вы хотите оставить стандартный вывод в покое-вы хотите
logcat
для записи на текущий стандартный выход. - вы, вероятно, хотите оставить стандартную ошибку в покое тоже.
в какой-то момент разбирательства вы делаете свой демонизации правильно (заимствуя ссылку из ответа @bstpierre), убедившись, что терминал, к которому вы подключены, не является вашим управляющим терминалом, так что прерывания и зависания, отправленные на терминал, не влияют на ваш демон. Сантехника проще, чем то, что вы настроили - вы должны иметь дело со стандартным входом и оставить стандартный выход и стандартную ошибку без изменений (вместо изменения выходы и оставляя вход неизменным).
теперь вы можете захотеть, чтобы вывод пошел в /dev/console
; если это так, то целесообразно пересмотреть код, чтобы открыть /dev/console
. Однако возвращаться к /dev/null
Если вы не можете открыть /dev/console
; ваша программа должна сообщить об ошибке и сбое (потому что нет смысла писать logcat в /dev/null
!). Убедитесь, что вы открываете консоль с помощью O_NOCTTY
флаг, чтобы он не стал управляющим терминалом для демон.
последний комментарий, который я бы сделал:
- вы уверены, что хотите, чтобы случайный текст появлялся над вашим терминалом или консолью, когда он используется для других вещей?
мне не очень нравится, когда это происходит.
Читайте также: так 958249
Как демонизировать в Linux [мертвой ссылке]
как демонизировать в Linux [wayback машинный архив выше]
суть на github -- код взят из ссылки выше
резюме:
одна из вещей, с которыми я постоянно сталкиваюсь, - это демоны Linux, которые должным образом не демонизируют себя. Чтобы правильно демонизировать, необходимо выполнить следующие шаги.
- вызов fork () используется для создания отдельного процесса.
- вызов setsid () используется для отсоединения процесса от родительского (обычно оболочки).
- маска файла должна быть сброшена.
- текущий каталог должен быть изменен на что-то доброкачественное.
- стандартные файлы (stdin,stdout и stderr) необходимо открыть заново.
невыполнение любого из этих шагов приведет к процессу демона, который может плохо себя вести. Типичные симптомы следующие.
- запуск демона, а затем выход из системы приведет к зависанию терминала. Это особенно неприятно с ssh.
- каталог, из которого был запущен демон, остается заблокированным.
- ложные выходные данные отображаются в оболочке, из которой был запущен демон.
для этого в glibc есть специальная функция:
#include <unistd.h>
...
/* We are in the parent, yet */
daemon(0,0);
/* Now we are in the child */
...
подробнее здесь http://linux.die.net/man/3/daemon