Tabela de conteúdos

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:

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;
}