daemon
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
:
- 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 processodaemon
criar arquivos com a permissão desejada. Caso não se chame esta função, pode ser que o processodaemon
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 odaemon
segure algum descritor herdado aberto. Geralmente odaemon
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
esaí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