URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 5840
[ Назад ]

Исходное сообщение
"как использовать daemon"

Отправлено Настя , 25-Окт-06 09:14 
Привет! :)
Я хочу написать простого-простого демона и мне надо сделать с процессом следующее:
мне надо отсоединить от терминала - раз
перенаправить в корень - два
перенаправить поток В/В куда-н.
Хочу использовать daemon
B man написано:
Функция daemon() необходима для того, чтобы отсоединить программу от управляющего терминала и запустить ее как системный демон.

Если аргумент nochdir не нулевой, то daemon() изменяет текущий рабо-чий каталог на корневой ("/").
Если аргумент noclose не нулевой, то daemon() перенаправляет стан-дартный поток ввода/вывода ошибок в /dev/null.
А какой должен быть аргумент?
Не поняла.
Не могли бы Вы мне написать, please!

я так пинимаю daemon(0,0); - неправильно


Содержание

Сообщения в этом обсуждении
"как использовать daemon"
Отправлено Forth , 25-Окт-06 09:24 
>я так пинимаю daemon(0,0); - неправильно
noclose если 0, то тогда все что будет выведено в stdout или stderr будет писаться на тот терминал, с которого его запускали, если 1, то все будет уходить в dev/null. То есть если указать 0, то например при запуске демона на старте системы, допустим через rc механизм - все что он будет писать в stdout/stderr будет сыпаться на нулевую консоль.


"как использовать daemon"
Отправлено Настя , 25-Окт-06 09:40 
>noclose если 0, то тогда все что будет выведено в stdout или
>stderr будет писаться на тот терминал, с которого его запускали, если
>1, то все будет уходить в dev/null.

То есть надо 1, чтоб демон не выводил на глаза изумленного пользователя?

А как с root быть?



"как использовать daemon"
Отправлено Forth , 25-Окт-06 10:07 
>То есть надо 1, чтоб демон не выводил на глаза изумленного пользователя?
>А как с root быть?
Так, я перепутал, нельзя мне с утра ничего писать :| . Если noclose=1 то будет писать на терминал, если noclose=0 все будет уходить в /dev/null.
А nochdir с какой целью сделано мне неясно, но если оставить 0 и работать демон будет допустим от root, то про сбросе core оно запишется в текущую директорию, то есть /, что может быть весьма нежелательно(можно конечно и указать куда писать coredump но по умолчанию будет так). Вообщем надо искать описание более подробное, для чего оно задумано.


"как использовать daemon"
Отправлено pup , 26-Окт-06 06:53 
>А nochdir с какой целью сделано мне неясно, но если оставить 0
>и работать демон будет допустим от root, то про сбросе core
>оно запишется в текущую директорию, то есть /, что может быть
>весьма нежелательно(можно конечно и указать куда писать coredump но по умолчанию
>будет так). Вообщем надо искать описание более подробное, для чего оно
>задумано.

да всё очень просто. Если wd демона будет, например, примонтированная /mnt/flash, то замучаешься отмонтировать флешку так, чтобы демона не убивать. И куда сувать wd демона, кроме как на /? Можно конечно ещё в /bin, /etc или /sbin... а всё остальное может находиться физически не на корневой фс.


"как использовать daemon"
Отправлено Forth , 26-Окт-06 09:00 
>да всё очень просто. Если wd демона будет, например, примонтированная /mnt/flash, то
>замучаешься отмонтировать флешку так, чтобы демона не убивать. И куда сувать
>wd демона, кроме как на /? Можно конечно ещё в /bin,
>/etc или /sbin... а всё остальное может находиться физически не на
>корневой фс.
А ведь верно:)


"как использовать daemon"
Отправлено Wulf , 25-Окт-06 14:53 
Лучше, вообще, не использовать daemon, а самому сделать fork и закрыть потоки. Ибо daemon не во всех осях присутствует. Его в солярке, например, нет.


"как использовать daemon"
Отправлено Alexander S. Salieff , 26-Окт-06 18:34 
>я так пинимаю 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;
}


"как использовать daemon"
Отправлено primus , 26-Окт-06 20:34 
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 signal

   signal(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 terminal

   chdir("/"); // 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);  
  


"как использовать daemon"
Отправлено red_mould , 28-Окт-06 23:10 
Ребятки а смысл перенаправлять стандартные потоки куда-то. Во смотрите возьму тот же код который представил 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>)
  


"как использовать daemon"
Отправлено Alexander S. Salieff , 29-Окт-06 02:41 
>Ребятки а смысл перенаправлять стандартные потоки куда-то.

Когда ты делаешь setsid(), ты деассоциируешь свой процесс от терминального контекста, а когда ты начинаешь писать в stdin/stdout/stderr при отсутствии терминала, то тебя, как минимум, должны прибить не то SIGSTOP'ом, не то SIGTTOU, точно не помню.


"как использовать daemon"
Отправлено red_mould , 29-Окт-06 13:17 
>>Ребятки а смысл перенаправлять стандартные потоки куда-то.
>
>Когда ты делаешь 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

Мое почтение


"как использовать daemon"
Отправлено Alexander S. Salieff , 29-Окт-06 14:24 
К сожалению вряд ли можно лишить серьезное приложение потоков stdin/stdout/stderr (пусть даже в перенаправленном виде) и игнорировать в нем все сигналы :(

"как использовать daemon"
Отправлено red_mould , 30-Окт-06 12:08 
>К сожалению вряд ли можно лишить серьезное приложение потоков stdin/stdout/stderr (пусть даже
>в перенаправленном виде) и игнорировать в нем все сигналы :(
Опятьже если ты прикажешь демону игнорировать сигналы он будет их игнорировать!
При помощи цикла который я описывал выше. По русски SID_IGN - макрос которрый
задает сигнал который(сигнал) будет игнорироваться. Данный макрос как и все остальные
живет в хедере signal.h
А с помощью системной функции signal(<sig_num>,<ф-я обработчик или макрос>) мы
обрабатываем нужные нам сигналы. Как я писал выше signal(i,SIG_IGN)
где i - номер сигнала. И если ради прикола написать тестового демона
который толком ничего не будет делать и запихнуть в него безконечный цикл
(для того чтоб наш демон сразу не завершался) и вставить в него игнорирование
сигналов то ты увидишь что когда демон запустится то простой командой
kill <pid процесса> демона ты не убьешь а он будет крутиться в памяти пока
или не пошлешь ему сигнал SIGKILL который генерирует команда kill -9 <pid процесса>
илиже не перегрузишь машину. Потому что остальные сигналы будут просто проигнорированы