Как создать pid файл

Обновлено: 02.07.2024

Часто случается ситуация, что нужно запустить приложение в 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 – данная функция будет выполнять основные действия, связанные с мониторингом состояния программы.
  1. Уведомление о завершении процесса демона.
  2. Получение кода завершения демона.

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:32:32 )
Последнее исправление: 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, а не запускаемый им демон..


Если уж доверяешь дело сторонней тулзе, то доверяй целиком. Не доверяешь — велосипедь всё сам. Да и проще так со всех сторон.


Не, требуется просто проконтроллировать, чтобы демон был только один. Есть другие методы?

Читайте также: