====== 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 [[sinal|signal handler]] para o [[sinal|sinal SIGHUP]], pois como o processo está desconectado de qualquer terminal ele naturalmente nunca receberá este sinal do sistema operacional. ===== Funções ===== * [[setsid]] * [[syslog]] ===== Exemplo completo ===== /* daemon.c */ #include #include #include #include #include #include #include #include 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; }