Как создать pid файл
Часто случается ситуация, что нужно запустить приложение в Linux, которое не должно быть завершено при выходе пользователя, а режима демона у приложения нет.
На этот случай можно воспользоваться парой приемов.
Первый способ
Запустить в сессии программы screen, которая не завершается при выходе пользователя.
screen -d -m команда
Пример:
screen -d -m -S backgroud_ping ping 127.0.0.1
Эта команда запустит пинг адреса 127.0.0.1 и присвоит сессии имя backgroud_ping.
Для возврата к приложению и получению управления нужно:
посмотреть список активный сессий screen:
в выводе консоли мы увидим имя и PID процесса:
There is a screen on:
1218.backgroud_ping (13.05.2016 15:43:34) (Detached)
1 Socket in /var/run/screen/S-root.
запущенная сессия будет иметь имя backgroud_ping, и в данном случае, PID будет 1218.
теперь остается подключиться к процессу screen, это делается командой:
screen -r номер_PID
в нашем случае это будет:
Мы получили обратно управление над приложением.
Второй способ
Использовать утилиту nohup, которая запустит приложение с игнорированием сигналов потери связи (SIGHUP), что позволит продолжить выполнение приложения после выхода пользователя из системы.
вывод будет перенаправлен вместо консоли в файл nohup.out, который будет находиться в папке из которой производился запуск. Посмотреть вывод консоли можно командой:
tail -f nohup.out
nohup ping 127.0.0.1 &
В данном случае вернуться к приложению и получить управление нельзя. его можно только завершить командой kill.
Третий способ
Использовать утилиту start-stop-daemon, которая создана для запуска в фоне приложений, которые сами не умеют переходить в фон.
start-stop-daemon -S -b -x путь_и_имя_исполняемого_файла -m -p путь_и_имя_pid_файла
start-stop-daemon -S -b -x /bin/ping -m -v -p /run/ping.pid -- -I eth0 127.0.0.1
В данном примере мы запускаем утилиту ping с параметрами (-I eth0 127.0.0.1) и создаем PID-файл (/run/ping.pid).
Для остановки программы использутся другие параметры:
start-stop-daemon -K -x путь_и_имя_исполняемого_файла
start-stop-daemon -K -p путь_и_имя_pid_файла
start-stop-daemon -K -p /run/ping.pid
Находим номер процесса, записанный в файл /run/ping.pid и останавливаем его.
Более правильно всегда использовать PID-файлы, потому что имя запускаемой программы не всегда равно имени запущенного процесса.
Заказать создание и поддержку безопасной IT-инфраструктуры любой сложности
В этой статье будет рассмотрено использование start-stop-daemon . Данная утилита идет в составе dpkg и, следовательно, присутствует в любой системе на базе Debian/Ubuntu.
Ее функция следующая: она позволяет запустить любой процесс в виде демона, то есть в фоне. Это нужно для того, чтобы запускать в фоне те процессы, которые сами не умеют уходить в фон. Запуск процесса в виде демона позволит не держать постоянной открытой tty-консоль или вкладку в терминале, а также даст больше возможностей для контроля данного процесса.
Основы
Как упомянуто выше, основное предназначение - запуск программ в фоновом режиме. В качестве примера будет взят museekd , демон-клиент для p2p-сети soulseek. start-stop-daemon имеет два обязательных параметра: -S (или –start ) и -K ( –stop ), один из которых должен присутствовать в любой команде. Далее следуют параметры, указывающие, что и как запустить.
Запуск демона
Для того, чтобы запустить демон необходимо помимо ключа -S указать так же исполняемый файл – /usr/bin/museekd . Исполняемый файл задается ключом -x
Программа запустится и будет работать в фоне. Для взятого примера этого достаточно.
Остановка демона
Для остановки процесса нужно указать ключ -K , т.е. действие «стоп», а так же сам процесс, который нужно остановить. Процесс для остановки так же указывается по исполняемому файлу, с помощью ключа -x
start-stop-daemon найдет процесс museekd и остановит его (по умолчанию - отправив SIGTERM).
Работа с pid-файлами
Если вы хотите запустить несколько копий одной программы, следует использовать pid-файлы 1) для управления такими процессами. Для запуска museekd с созданием pid-файла следует использовать ключ -p . Пример:
Здесь также появился ключ -m , указывающий утилите start-stop-daemon, что pid-файл нужно создать при запуске программы. Некоторые программы умеют создавать pid-файлы самостоятельно – в этом случае данный ключ не нужен.
Теперь в заданном файле записан PID запущенного процесса. Зная его, вы можете отличить его от других копий той же программы, найти процесс, к примеру, в top и сделать с ним что-либо (например, изменить приоритет или остановить).
Для остановки процессов также можно использовать pid-файлы, чтобы остановить конкретный процесс. При этом указание исполняемого файла не требуется, нужно лишь задать действие «стоп» и pid-файл
start-stop-daemon прочитает PID из заданного файла, проверит, есть ли такой процесс и остановит его.
Прочие возможности
Передача параметров запускаемой программе
Если запускаемой программе нужно передать какие-либо параметры, они отделяются двумя дефисами. Все, что идет далее, не воспринимается как параметры для start-stop-daemon, а передается запускаемой программе в неизмененном виде. Пример запуска museekd с альтернативным файлом конфигурации:
Данная конструкция запустит museekd -c .museekd/config.new . Двойной дефис и следующие за ним параметры не обязательно располагать после исполняемого файла. Главное – в конце комманды.
Утилита start-stop-daemon имеет гораздо больше возможностей, чем описано в данной статье. Например, она позволяет запустить процесс от имени другого пользователя или даже в chroot-окружении, задать приоритет процесса, изменить сигнал остановки (например, использовать SIGKILL вместо SIGTERM) и т. п. Больше информации можно получить из man start-stop-daemon и start-stop-daemon –help .
return -1;
>
else if (!pid) // если это потомок
// данный код уже выполняется в процессе потомка
// разрешаем выставлять все биты прав на создаваемые файлы,
// иначе у нас могут быть проблемы с правами доступа
umask(0);
// создаём новый сеанс, чтобы не зависеть от родителя
setsid();
// переходим в корень диска, если мы этого не сделаем, то могут быть проблемы.
// к примеру с размантированием дисков
chdir( "/" );
// закрываем дискрипторы ввода/вывода/ошибок, так как нам они больше не понадобятся
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// Данная функция будет осуществлять слежение за процессом
status = MonitorProc();
return status;
>
else // если это родитель
// завершим процес, т.к. основную свою задачу (запуск демона) мы выполнили
return 0;
>
>
* This source code was highlighted with Source Code Highlighter .
- LoadConfig – данная функция загружает конфиг из указанного файла, её код будет зависеть от формата конфига, который вы используете, и в рамках данной статьи не будет рассматриваться.
- Закрытие дескрипторов необходимо по той причине, что мы не будем использовать printf и scanf прочие функции работы с консольным вводом/выводом. Данное действие не обязательно и используется для экономии ресурсов.
- Переход в корень диска, необходим для того, чтобы впоследствии не было проблем связанных с размонтированием дисков. Если текущая папка демона будет находиться на диске, который необходимо будет отмонтировать, то система не даст этого, до тех пор, пока демон не будет остановлен.
- MonitorProc – данная функция будет выполнять основные действия, связанные с мониторингом состояния программы.
- Уведомление о завершении процесса демона.
- Получение кода завершения демона.
int MonitorProc()
int pid;
int status;
int need_start = 1;
sigset_t sigset;
siginfo_t siginfo;
// настраиваем сигналы которые будем обрабатывать
sigemptyset(&sigset);
// сигнал остановки процесса пользователем
sigaddset(&sigset, SIGQUIT);
// сигнал для остановки процесса пользователем с терминала
sigaddset(&sigset, SIGINT);
// сигнал запроса завершения процесса
sigaddset(&sigset, SIGTERM);
// сигнал посылаемый при изменении статуса дочернего процесса
sigaddset(&sigset, SIGCHLD);
// пользовательский сигнал который мы будем использовать для обновления конфига
sigaddset(&sigset, SIGUSR1);
sigprocmask(SIG_BLOCK, &sigset, NULL);
// данная функция создаст файл с нашим PID'ом
SetPidFile(PID_FILE);
// бесконечный цикл работы
for (;;)
// если необходимо создать потомка
if (need_start)
// создаём потомка
pid = fork();
>
// запустим функцию отвечающую за работу демона
status = WorkProc();
// завершим процесс
exit(status);
>
else // если мы родитель
// данный код выполняется в родителе
// ожидаем поступление сигнала
sigwaitinfo(&sigset, &siginfo);
// если пришел сигнал от потомка
if (siginfo.si_signo == SIGCHLD)
// получаем статус завершение
wait(&status);
// преобразуем статус в нормальный вид
status = WEXITSTATUS(status);
// прервем цикл
break ;
>
else if (status == CHILD_NEED_WORK) // если требуется перезапустить потомка
// запишем в лог данное событие
WriteLog( "[MONITOR] Child restart\n" );
>
>
else if (siginfo.si_signo == SIGUSR1) // если пришел сигнал что необходимо перезагрузить конфиг
kill(pid, SIGUSR1); // перешлем его потомку
need_start = 0; // установим флаг что нам не надо запускать потомка заново
>
else // если пришел какой-либо другой ожидаемый сигнал
// запишем в лог информацию о пришедшем сигнале
WriteLog( "[MONITOR] Signal %s\n" , strsignal(siginfo.si_signo));
// убьем потомка
kill(pid, SIGTERM);
status = 0;
break ;
>
>
>
// запишем в лог, что мы остановились
WriteLog( "[MONITOR] Stop\n" );
// удалим файл с PID'ом
unlink(PID_FILE);
* This source code was highlighted with Source Code Highlighter .
- PID_FILE – константа, которая будет хранить имя файла для сохранения PID’a. В нашем случае это /var/run/my_daemon.pid
- WriteLog – функция осуществляющая запись в лог. В ней вы можете придумать то, что душе угодно и писать лог куда угодно или вообще передавать его куда-нибудь
- WorkProc – функция, которая реализует непосредственно функционал демона
f = fopen(Filename, "w+" );
if (f)
fprintf(f, "%u" , getpid());
fclose(f);
>
>
* This source code was highlighted with Source Code Highlighter .
На данный момент наш демон уже умеет запускаться, следить за своим потомком, который выполняет основные функции и при необходимости перезапускать его или посылать ему сигнал об изменение конфигурации. Далее рассмотрим шаблон кода потомка:
int WorkProc()
struct sigaction sigact;
sigset_t sigset;
int signo;
int status;
// сигналы об ошибках в программе будут обрататывать более тщательно
// указываем что хотим получать расширенную информацию об ошибках
sigact.sa_flags = SA_SIGINFO;
// задаем функцию обработчик сигналов
sigact.sa_sigaction = signal_error;
// установим наш обработчик на сигналы
sigaction(SIGFPE, &sigact, 0); // ошибка FPU
sigaction(SIGILL, &sigact, 0); // ошибочная инструкция
sigaction(SIGSEGV, &sigact, 0); // ошибка доступа к памяти
sigaction(SIGBUS, &sigact, 0); // ошибка шины, при обращении к физической памяти
// блокируем сигналы которые будем ожидать
// сигнал остановки процесса пользователем
sigaddset(&sigset, SIGQUIT);
// сигнал для остановки процесса пользователем с терминала
sigaddset(&sigset, SIGINT);
// сигнал запроса завершения процесса
sigaddset(&sigset, SIGTERM);
// пользовательский сигнал который мы будем использовать для обновления конфига
sigaddset(&sigset, SIGUSR1);
sigprocmask(SIG_BLOCK, &sigset, NULL);
// Установим максимальное кол-во дискрипторов которое можно открыть
SetFdLimit(FD_LIMIT);
// запишем в лог, что наш демон стартовал
WriteLog( "[DAEMON] Started\n" );
// остановим все рабочеи потоки и корректно закроем всё что надо
DestroyWorkThread();
>
else
WriteLog( "[DAEMON] Create work thread failed\n" );
>
WriteLog( "[DAEMON] Stopped\n" );
// вернем код не требующим перезапуска
return CHILD_NEED_TERMINATE;
>
* This source code was highlighted with Source Code Highlighter .
- InitWorkThread — функция которая создаёт все рабочие потоки демона и инициализирует всю работу.
- DestroyWorkThread — функция которая останавливает рабочие потоки демона и корректно освобождает ресурсы.
- ReloadConfig — функция осуществляющая обновление конфига (заново считать файл и внести необходимые изменения в свою работу). Имя файла можно также взять из параметров командной строки.
Принципе работы следующий: устанавливаем свой обработчик на сигналы ошибок, затем запускаем все рабочие потоки и ждем сигналов завершения или обновления конфига.
Обработка ошибок при работе, с подробным отчетом в лог.
Конечно же демоны должны работать идеально и не вызывать всякого рода ошибок, но ошибаться может каждый, да и порой встречаются ошибки, которые довольно тяжело обнаружить на стадии тестирования. Особенно это актуально для ошибок которые проявляются при большой загруженности. По этому важным моментом в разработке демона является правильная обработка ошибок, а также выжимание из ошибки как можно большей информации. В данном случае рассмотрим обработку ошибок с сохранением стека вызовов (backtrace). Это даст нам информацию о том, где именно произошла ошибка (в какой функции), а также мы сможем узнать то, кто вызвал эту функцию.
Код функции обработчика ошибок:
static void signal_error( int sig, siginfo_t *si, void *ptr)
void * ErrorAddr;
void * Trace[16];
int x;
int TraceSize;
char ** Messages;
// запишем в лог что за сигнал пришел
WriteLog( "[DAEMON] Signal: %s, Addr: 0x%0.16X\n" , strsignal(sig), si->si_addr);
// произведем backtrace чтобы получить весь стек вызовов
TraceSize = backtrace(Trace, 16);
Trace[1] = ErrorAddr;
// получим расшифровку трасировки
Messages = backtrace_symbols(Trace, TraceSize);
if (Messages)
WriteLog( "== Backtrace ==\n" );
// запишем в лог
for (x = 1; x < TraceSize; x++)
WriteLog( "%s\n" , Messages[x]);
>
WriteLog( "== End Backtrace ==\n" );
free(Messages);
>
WriteLog( "[DAEMON] Stopped\n" );
// остановим все рабочие потоки и корректно закроем всё что надо
DestroyWorkThread();
// завершим процесс с кодом требующим перезапуска
exit(CHILD_NEED_WORK);
>
* This source code was highlighted with Source Code Highlighter .
При использовании backtrace можно получить данные примерно такого вида:
[DAEMON] Signal: Segmentation fault, Addr: 0x0000000000000000
== Backtrace ==
/usr/sbin/my_daemon(GetParamStr+0x34) [0x8049e44]
/usr/sbin/my_daemon(GetParamInt+0x3a) [0x8049efa]
/usr/sbin/my_daemon(main+0x140) [0x804b170]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6) [0x126bd6]
/usr/sbin/my_daemon() [0x8049ba1]
== End Backtrace ==
Из этих данных видно, что функция main вызвала функцию GetParamInt. Функция GetParamInt вызвала GetParamStr. В функции GetParamStr по смещению 0x34 произошло обращение к памяти по нулевому адресу.
Также помимо стека вызовов можно сохранить и значение регистров (массив uc_mcontext.gregs).
Необходимо заметить, что наибольшую информативность от backtrace можно получить только при компилировании без вырезания отладочной информации, а также с использованием опции -rdynamic.
Как можно было заметить, в коде используются константы CHILD_NEED_WORK и CHILD_NEED_TERMINATE. Значение этих констант вы можете назначать сами, главное чтобы они были не одинаковые.
Некоторые вопросы связанные с ресурсами системы.
Важным моментом является установка максимального кол-ва дескрипторов. Любой открытый файл, сокет, пайп и прочие тратят дескрипторы, при исчерпании которых невозможно будет открыть файл или создать сокет или принять входящее подключение. Это может сказаться на производительности демона. По умолчанию максимальное кол-во открытых дескрипторов равно 1024. Такого кол-ва очень мало для высоконагруженных сетевых демонов. Поэтому мы будем ставить это значение больше в соответствии со своими требованиями. Для этого используем следующую функцию:
int SetFdLimit( int MaxFd)
struct rlimit lim;
int status;
// зададим текущий лимит на кол-во открытых дискриптеров
lim.rlim_cur = MaxFd;
// зададим максимальный лимит на кол-во открытых дискриптеров
lim.rlim_max = MaxFd;
// установим указанное кол-во
status = setrlimit(RLIMIT_NOFILE, &lim);
* This source code was highlighted with Source Code Highlighter .
Вместо заключения.
Вот мы и рассмотрели как создать основу для демона. Конечно же код не претендует на идеальный, но со своими задачами справляется отлично.
В следующей статье будут рассмотрены моменты, связанные с установкой/удалением демона, управления им, написанием скриптов автозагрузки для init.d и непосредственно добавлением в автозагрузку.
Задача демона или init script'a?
Кто должен заботиться о создании и удалении?
Демона в общем случае.
Демон убин kill'om, мои действия?
Вот, кстати, много придумывал: как обезопасить процесс и обеспечить однозначно уникальный запуск. Навелосипедил нечто вроде pgrep + чтение pid-файла. Потом навелосипедил улучшение этого велосипеда (если есть PID-файл, сначала проверяется, что за процесс имеет такой PID: если тот же, то второй процесс отваливается, если чужой — продолжается стандартная проверка по /proc)
PID-файл стал невалидным. Какие тебе еще нужны действия?
Простейший случай: если нет процесса с PID'ом, записанном в PID-файле, либо этот процесс — не наш, то пересоздать PID файл и работать. Но есть шанс, что у тебя что-то уже работает, а PID-файл кто-нибудь стер, например.
Нажали RESET, твои действия при буте?
Кто должен заботиться о создании и удалении?
О создании — демон. Но путь к PID-файлу задаваться — инитскриптом.
О проверке валидности и удалении — инитскрипт.
Последнее исправление: geekless 02.11.12 19:33:02 (всего исправлений: 1)
OK, т.е. в иделе я так понял - оба.
Если требуется суровая надежность - сделай пару процессов.
Не, требуется просто проконтроллировать, чтобы демон был только один. Есть другие методы?
Проверить наличие PID'а при запуске и решить, что это и нужно ли еще.
Как вариант: создать, открыть, unlink. Тогда файл пропадёт, когда процесс его использующий пропадёт.
если за создание/УДАЛЕНИЕ pid-файла — отвечает сам демон — то я совершенно не вижу каких-либо препятствий в том чтобы демон мог быть спокойно убит через kill .
главное это чтобы был НЕ ``$ kill -KILL`` (а обычный ``$ kill -TERM``)
когда демон получает системный сигнал о том что его убивают — то демон закрывается и САМ в это время подчищает за собой pid-файл. всё логично :)
Не катит. Файл должен быть видимым.
или может быть надо было дать ссылку эту:
А если его по kill -9 грохнули? Или он сам с сегфолтом каким-нибудь отвалился, либо от oom-killer'а по башке получил?
тогда то что я аписал не поможет :)
вот именно поэтому сейчас и внедряется везде SystemD .
..а не потомучто Леннарт якобы дружит с гипножабой :-)
Бред. Каждый демонописатель в ответе за того, кого приручил свой велосипед.
Свои варианты я выше приводил. Они работают и никаких зондов в задницу вставлять не надо.
да если подумать — то какого фига вообще демон должен заботится о своём собственном PID ?
демон должен просто работать. и уметь себя корректно завершать (когда его просят завершать).
ситуации с segfault — сервершенно не является компетенцией демона, который делает эти segfault . за разрешение таких ситуаций должен отвечать вышестоящщий демон сервис.
это точно также логично, как и логично не обращать внимание на segfault-ные ситуации во время создания/удаления PID силами самого демона.
какого фига вообще демон должен заботится о своём собственном PID?
Ничего себе. Если подумать, какого фига я должен заботиться о своем благосостоянии? Пусть меня озолотят! А я ничего ради этого не буду делать.
ситуации с segfault — сервершенно не является компетенцией демона, который делает эти segfault
Ага, отвалившийся после километра пробега кардан — не вина автомеханика дяди Васи.
Ага, отвалившийся после километра пробега кардан — не вина автомеханика дяди Васи.
а почему это его вина? наиболее вероятно — что был инцедент с неким хулиганом, который проник на автостоянку ОЧЕНЬ СИЛЬНО стучал жёстким диском по кардану.
. (а потом на этом жёстком диске — хулиган установил Linux.. но уже уже другая история :)).
по крайней мере мы знаем что автомеханник приложил все силы чтобы кардан не отваливался :)
(даже если окажется что ситуация с хулиганом оказалась вымышленной кемто :))
вобщем, мне кажется что я НЕ смогу тебе обяснить всю эту ЛеннартПоттерингвскую философию..
..её надо понимать. чуствовать.
она приходит сама к тебе, если захочет
Для этого надо мастдайку осилить ;)
кстате на МастДайке — SystemD не работает.. и поэтому если нужно запускать демон именно там — то как раз МастДай это именно то место где нужно тра..продумывать ситуации с различными неожиданными завершениями демона (Segfault) и его соответствующим отношением к PID-файлу..
..а вот святой GNU/Linux в лицце Поттеринга — всё упрощает. и делает логичным =(^_^)=
в генточке об этом может позаботиться start-stop-daemon, насчет других дистров не знаю, может он там тоже есть
ТОЧНО! я понял! ДА! нужно осилить весь геморой в венде, чтобы понять почему нужен SystemD
(вендовый геморой — этоже многократно-усиленный геморой старых UNIX-принципов. )
венда — она как лупа!
а зачем в винде PID-файл нужен-то? Там вроде как винда сама за сервисами следит
святой GNU/Linux в лицце Поттеринга
Ну ты и вендузятник.
В винде sc есть.
ну да, есть. А что хотел сказать анонимус - не понятно
Вообще не понимаю зачем нужны эти пиды? Ведь можно же просто сделать один раз символьное устройство которое работало бы по следующему принципу: при чтении из него отдавало количество процессов запущенных от данного бинарника (или скрипта). И при запуске демон должен прочесть из этого устройства цифру, а дальше в зависимости если число равно 1 (т.е. один процесс от этого файла в системе) то начать работу, а если больше то самоубитсама.
ды вы что?! обкурились все?!
для этого дела в операционной системе есть блокировочные файлы!
делаешь при запуске демона — по отношению к блокировочному-файлу (не файлу устройства, а блокировачному файлу!) — ЭКСКЛЮЗИВНУЮ-НЕ_БЛОКИРУЮЩУЮ блокировку.
. и в этом случае второй демон просто не сможет запустится.
что за костыли вы какието предлагаете? демон сам себя убивает если видит своего клона — ДЫ ЭТО ОХРЕНЕТЬ МОЖНО какой костыль!
PID-файлы вообще нужны не для того чтобы не было дубликатов демнов. а для других целей.
PID-файлы вообще нужны не для того чтобы не было дубликатов демнов. а для других целей.
Для того, чтобы скрипты знали PID демона?
А для предотвращения повторного запуска lock-файл, так?
Вот из - за таких вот умников потом когда падает демон, невозможно перезапустить его пока не удалишь эти файлы ручками
Для того, чтобы скрипты знали PID демона?
хотя да. PID-файл особо то не нужен. например. если есть шина dBus.
А для предотвращения повторного запуска lock-файл, так?
заниматься lock-файлом правда не обязан именно самому демону.
за него могут сделать это другие :) ..
например внутри скрипта по запуску:
$ flock -xn /run/my_daemon/lock /usr/bin/my_daemon
ну или вообще использовать SystemD и не париться об блокировачных файлах тогда
Гейтс, залогинся уже! Мы тебя раскусили :)
Вот из - за таких вот умников потом когда падает демон, невозможно перезапустить его пока не удалишь эти файлы ручками
блокирвачные файлы НЕ НУЖНО СПЕЦИАЛЬНО УДАЛЯТЬ . они могут существовать ВЕЧНО и это никак не мешает запускать программу МНОГО РАЗ ПОВТОРНО.
/my_test_lock_file — попробуй много раз подрят позапускай эту строчку. )
Тут один тролль в треде сделал логичный коммент, а если демон упал, а файл остался. Проверять скриптом, есть ли всё ещё демон?
Забей на него, он тролль =)
Так что, мы пришли к тому, что файлы копятся? Как они потом удаляются?
Гейтс, залогинся уже! Мы тебя раскусили :)
если бы я был бы Гейстчом — ябы начал рассказывать что Венде для блокировачных файлов — существует специальная (сугубо виртуальная) файловая система..
в генточке об этом может позаботиться start-stop-daemon, насчет других дистров не знаю, может он там тоже есть
Как часть openrc, эту тулзень можно скомпилять подо что угодно. Да и другие варианты есть. В большинстве случаев своё приложение можно даже не учить демонизироваться и делать всякие сопутствующие церемонии, а выполнять это всё start-stop-daemon'ом или аналогом.
Так это не баг, там костыль предложен для неправильного использования. Форкаться для ухода в фон должен start-stop-daemon, а не запускаемый им демон, тогда и с пидфайлом никаких проблем не будет.
Форкаться для ухода в фон должен start-stop-daemon, а не запускаемый им демон..
Если уж доверяешь дело сторонней тулзе, то доверяй целиком. Не доверяешь — велосипедь всё сам. Да и проще так со всех сторон.
Не, требуется просто проконтроллировать, чтобы демон был только один. Есть другие методы?
Читайте также: