Ferramentas do usuário

Ferramentas do site


daemon

Daemons (serviços)

Conceito de daemon

Em várias situações precisa-se que um processo fique em execução continuamente (eternamente) em uma máquina. A estes processos dá-se o nome de daemons ou serviços.

Geralmente são programas que são iniciados assim que o sistema operacional é inicializado. Coloca-se a chamada dos daemons nos arquivos de configuração para que os mesmos sejam ativados automaticamente durante o processo de boot do sistema. Um daemon só deve ser cancelado quando o sistema operacional está encerrando o seu processamento. Daemons são processos que rodam em background e não devem ter um terminal associado à eles.

Regras de codificação

Para se codificar um daemon deve-se realizar uma série de tarefas e chamadas de funções para que o processo se comporte como um daemon:

  • A primeira coisa a fazer no processo é chamar a função fork para duplicar o processo atual e terminar o processo pai. Assim, o término do processo pai libera o shell, pois o mesmo acha que o comando terminou. O processo filho herda o Process Group ID do pai mas cria um novo Process ID, garantindo que este processo não será um processo líder de grupo.
  • Deve-se chamar a função setsid para criar uma nova sessão. Com a criação de uma nova sessão, o processo filho torna-se o líder da sessão, torna-se o líder do grupo de processos e não irá possuir um terminal de controle.
  • Em sistemas baseados no Unix System V, deve-se realizar o fork novamente, pois algum evento futuro poderá ligar um terminal ao processo daemon.
  • Deve-se trocar o diretório atual para o diretório raiz ou para um diretório específico. Este diretório preferencialmente não deve ser um diretório montado depois do processo de boot.
  • Deve-se mudar a máscara de criação do processo para 0 usando a função umask. Isto possibilita o processo daemon criar arquivos com a permissão desejada. Caso não se chame esta função, pode ser que o processo daemon herde alguma máscara que esteja desabilitando alguma permissão necessária para o funcionamento do daemon.
  • Todos os descritores de arquivos que não serão utilizados pelo processo daemon devem ser fechados. Isto previne que o daemon segure algum descritor herdado aberto. Geralmente o daemon fecha todos os descritores antes de abrir qualquer arquivo, garantindo assim que somente os arquivos necessários ficarão abertos durante o tempo de vida do daemon.
  • Deve-se associar a entrada padrão, saída padrão e saída de erro padrão para /dev/null. Assim, caso algum evento ocorra, o sistema operacional irá descartar.
  • Caso durante a vida do processo daemon ele precise ler algum arquivo de configuração ou mudar sua configuração interna, deve-se instalar um signal handler para o sinal SIGHUP, pois como o processo está desconectado de qualquer terminal ele naturalmente nunca receberá este sinal do sistema operacional.

Funções

Exemplo completo

/* daemon.c */
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
 
int daemon_init (void)
{
   pid_t iPid;
   long iMaxFd;
   int i, fd0, fd1, fd2;
   struct sigaction sa;
 
   /* 1. passo - duplicar o processo usando o fork */
   if((iPid = fork()) < 0)
   {
      perror("fork:");
      exit(1);
   }
 
   if(iPid != 0) /* finaliza o pai */
   {
      exit(0);
   }
 
   /* 2. passo - chamar a função setsid para criar uma nova sessão de processo, 
     ficando o processo filho como líder da sessão e sem um terminal de controle
     associado ao processo */
   setsid();
 
 
   /* 3. passo - é necessário realizar 2 forks para evitar
     que o shell ligue um terminal ao processo. Também é
     necessário ignorar o sinal de término do pai */
 
   sa.sa_handler = SIG_IGN;
   sigemptyset(&sa.sa_mask);
   sa.sa_flags = 0;
   if(sigaction(SIGHUP, &sa, NULL) < 0)
   {
      perror("sigaction:");
      exit(1);
   }
 
   if((iPid = fork()) < 0)
   {
      perror("fork:");
      exit(1);
   }
 
   if(iPid != 0) /* finaliza o pai */
   {
      exit(0);
   }
 
   /* 4. passo - troca-se o diretório atual para a raiz do sistema ou para um diretorio do 
      próprio daemon */
   chdir("/");
 
   /* 5. passo - inicializa a máscara padrão de criação de arquivos */
   umask(0);
 
   /* 6. passo - fechando todos os descritores de arquivos existentes no
      sistema. Utiliza-se a informação de número máximo de descritores configurado 
      no sistema e obtido com a função sysconf. */
   iMaxFd = sysconf (_SC_OPEN_MAX);
   for (i=0; i < iMaxFd; i++)
   {
      close (i);
   }
 
   /* 7. passo - abrindo arquivos de entrada padrao, saida padrao e saida de erro para /dev/null */
   fd0 = open("/dev/null", O_RDWR);
   fd1 = dup(0);
   fd2 = dup(0);
 
   /* abrindo a log */
   openlog("daemon_init", LOG_CONS, LOG_DAEMON);
 
   if( fd0 != 0 || fd1 != 1 || fd2 != 2 )
   {
      syslog(LOG_ERR, "não foi aberto um dos arquivos %d %d %d", fd0, fd1, fd2);
   }
 
 
   return 0;
}
 
int main(void)
{
   int i;
   daemon_init(); /* chama o daemon */
 
   for(i=0;i<20;i++)
   {
      syslog(LOG_NOTICE, "faltam %d segundos para terminar o daemon", 20-i);
      sleep(1);
   }
 
   return 0;
}
daemon.txt · Última modificação: 2023/09/12 16:14 por 127.0.0.1