Привет! :)
Я хочу написать простого-простого демона и мне надо сделать с процессом следующее:
мне надо отсоединить от терминала - раз
перенаправить в корень - два
перенаправить поток В/В куда-н.
Хочу использовать daemon
B man написано:
Функция daemon() необходима для того, чтобы отсоединить программу от управляющего терминала и запустить ее как системный демон.Если аргумент nochdir не нулевой, то daemon() изменяет текущий рабо-чий каталог на корневой ("/").
Если аргумент noclose не нулевой, то daemon() перенаправляет стан-дартный поток ввода/вывода ошибок в /dev/null.
А какой должен быть аргумент?
Не поняла.
Не могли бы Вы мне написать, please!я так пинимаю daemon(0,0); - неправильно
>я так пинимаю daemon(0,0); - неправильно
noclose если 0, то тогда все что будет выведено в stdout или stderr будет писаться на тот терминал, с которого его запускали, если 1, то все будет уходить в dev/null. То есть если указать 0, то например при запуске демона на старте системы, допустим через rc механизм - все что он будет писать в stdout/stderr будет сыпаться на нулевую консоль.
>noclose если 0, то тогда все что будет выведено в stdout или
>stderr будет писаться на тот терминал, с которого его запускали, если
>1, то все будет уходить в dev/null.То есть надо 1, чтоб демон не выводил на глаза изумленного пользователя?
А как с root быть?
>То есть надо 1, чтоб демон не выводил на глаза изумленного пользователя?
>А как с root быть?
Так, я перепутал, нельзя мне с утра ничего писать :| . Если noclose=1 то будет писать на терминал, если noclose=0 все будет уходить в /dev/null.
А nochdir с какой целью сделано мне неясно, но если оставить 0 и работать демон будет допустим от root, то про сбросе core оно запишется в текущую директорию, то есть /, что может быть весьма нежелательно(можно конечно и указать куда писать coredump но по умолчанию будет так). Вообщем надо искать описание более подробное, для чего оно задумано.
>А nochdir с какой целью сделано мне неясно, но если оставить 0
>и работать демон будет допустим от root, то про сбросе core
>оно запишется в текущую директорию, то есть /, что может быть
>весьма нежелательно(можно конечно и указать куда писать coredump но по умолчанию
>будет так). Вообщем надо искать описание более подробное, для чего оно
>задумано.да всё очень просто. Если wd демона будет, например, примонтированная /mnt/flash, то замучаешься отмонтировать флешку так, чтобы демона не убивать. И куда сувать wd демона, кроме как на /? Можно конечно ещё в /bin, /etc или /sbin... а всё остальное может находиться физически не на корневой фс.
>да всё очень просто. Если wd демона будет, например, примонтированная /mnt/flash, то
>замучаешься отмонтировать флешку так, чтобы демона не убивать. И куда сувать
>wd демона, кроме как на /? Можно конечно ещё в /bin,
>/etc или /sbin... а всё остальное может находиться физически не на
>корневой фс.
А ведь верно:)
Лучше, вообще, не использовать daemon, а самому сделать fork и закрыть потоки. Ибо daemon не во всех осях присутствует. Его в солярке, например, нет.
>я так пинимаю daemon(0,0); - неправильно
Я бы не стал парится и сделал бы свой демонайз, вроде:bool Daemonize(string fname, string fstdout, string fstderr)
{
if (FileExist(fname.c_str()))
{
GlobalLogger.log_print(LLEV_ERROR, "PIDFile %s already exist. Stop another copy of daemon, or remove file", fname.c_str());
return false;
}pid_t mypid = fork();
if (mypid<0)
{
GlobalLogger.log_print(LLEV_ERROR, "Daemonize error: fork() %s", strerror(errno));
return false;
}
if (mypid==0)
{
if (fname!="")
{
FILE * fd = fopen(fname.c_str(), "w");
if (fd==NULL)
{
GlobalLogger.log_print(LLEV_ERROR, "Daemonize error: fopen(%s) %s", fname.c_str(), strerror(errno));
return false;
}
fprintf(fd, "%lu", getpid());
fclose(fd);
}
setsid();
int fd_stdout = open(fstdout.c_str(), O_RDONLY);
int fd_stdin = open(fstdin.c_str(), O_WRONLY);
close(stdin);
dup(fd_stdin);
close(stdout);
dup(fd_stdout);
}
else
{
exit(0);
}
return true;
}
Here is some skeleton code for creating a daemon (modified from Unix Network Programming: The Sockets Networking API Vol 1, third edition,by W. R. Stevens, B Fenner, and A. M Rudoff, Addison Wesley, 2004)int daemon_init(const char *pname, int facility)
{
int i;
pid_t pid;pid = fork();
if (pid < 0) error("forking");
if (pid > 0) exit(0); // parent process terminates
if (setsid() < 0) error("setsid"); // sets a new session id
//so that shell cannot send a kill signalsignal(SIGHUP, SIG_IGN); // ignore the hangup signal
pid = fork();
if (pid > 0) exit(0);//this guarantees that the child is not a session leader
//and so it cannot obtain a controlling terminalchdir("/"); // change to the root directory
for(i=0;i < MAXFD;i++) close(i);
open("/dev/null",O_RDONLY);
open("/dev/null",O_RDWR);
open("/dev/null",O_RDWR);// This guarantees that anything written to stdout or stderr will
// not cause a seg fault.openlog(pname, gLOG_PID, facility);
Ребятки а смысл перенаправлять стандартные потоки куда-то. Во смотрите возьму тот же код который представил primus(как я понимаю выдраный из книги) только чуток переделаный, ну и соответственно с коментами.
int daemon_init() //собственно входящие данные вставлять по надобности
{
int i;
pid_t pid;
switch(pid = fork())
{
case -1:
fprintf(stderr,"Не могу создать поток/n");
case 0:
//дочерний процесс
if (setsid() < 0) //собственно демонизация
error("setsid");
chdir("/"); // change to the root directory
close(1); //перекрываем stdin (по надобности)
close(2); //перекрываем stdout (по надобности)
//3 - stderr пока перекрывать не будем чтоб выкидывать отчет об ошибках
for(int i=0; i<20; i++)
signal(i, SIG_IGN); // игнорируем все сигналы
// окромя kill -9 <pid процесса>
exit(0);
default:
//тут собственно процесс предок (parent)
// любой код который будет выполняться в процессе предке
break;
}
вот собственно и все потом пишем любой класс или подпрогу которую бум запихивать в демона, ну и если надо через stderr выводить на терминал необходимую инфу от демона ну а потом если надо то можно организовать IPC сообщения но это уже тема другого топика. И еще желательно перехватывать от демона(когда он окончит свою работу) зомби например функцией wait(&<int>)
>Ребятки а смысл перенаправлять стандартные потоки куда-то.Когда ты делаешь setsid(), ты деассоциируешь свой процесс от терминального контекста, а когда ты начинаешь писать в stdin/stdout/stderr при отсутствии терминала, то тебя, как минимум, должны прибить не то SIGSTOP'ом, не то SIGTTOU, точно не помню.
>>Ребятки а смысл перенаправлять стандартные потоки куда-то.
>
>Когда ты делаешь setsid(), ты деассоциируешь свой процесс от терминального контекста, а
>когда ты начинаешь писать в stdin/stdout/stderr при отсутствии терминала, то тебя,
>как минимум, должны прибить не то SIGSTOP'ом, не то SIGTTOU, точно
>не помню.
ну откровенно говоря в принципе ты прав, но смотри вот кусочек кода(см ниже)
for(int i=0; i<20; i++)
signal(i, SIG_IGN); // игнорируем все сигналы
// окромя kill -9 <pid процесса>
Вот этим циклом демон начинает игнорировать практически все сигналы. в том числе и SIGSTOP и остальные. Что касается stderr то я при разработек своих питомцев использую поток ошибок для того чтоб посмотреть в каком свете сейчас находится питомец а с помощью вышеуказанного цикла демон просто не обращает внимания на все сигналы и прихлопнуть его может только сигнал SIGKILL которым культурно пользуется команда kill -9 <pid процесса>
А что касается потоков stdin/stdout то их можно либо запереть командой close(<дискриптор>) по русски когда мы создаем процесс не важно демон он или нет то мы также можем работать с его дискрипторами на стандартные потоки:
0 - stdin
1 - stdout
2 - stderrМое почтение
К сожалению вряд ли можно лишить серьезное приложение потоков stdin/stdout/stderr (пусть даже в перенаправленном виде) и игнорировать в нем все сигналы :(
>К сожалению вряд ли можно лишить серьезное приложение потоков stdin/stdout/stderr (пусть даже
>в перенаправленном виде) и игнорировать в нем все сигналы :(
Опятьже если ты прикажешь демону игнорировать сигналы он будет их игнорировать!
При помощи цикла который я описывал выше. По русски SID_IGN - макрос которрый
задает сигнал который(сигнал) будет игнорироваться. Данный макрос как и все остальные
живет в хедере signal.h
А с помощью системной функции signal(<sig_num>,<ф-я обработчик или макрос>) мы
обрабатываем нужные нам сигналы. Как я писал выше signal(i,SIG_IGN)
где i - номер сигнала. И если ради прикола написать тестового демона
который толком ничего не будет делать и запихнуть в него безконечный цикл
(для того чтоб наш демон сразу не завершался) и вставить в него игнорирование
сигналов то ты увидишь что когда демон запустится то простой командой
kill <pid процесса> демона ты не убьешь а он будет крутиться в памяти пока
или не пошлешь ему сигнал SIGKILL который генерирует команда kill -9 <pid процесса>
илиже не перегрузишь машину. Потому что остальные сигналы будут просто проигнорированы