Português do Brasil English
Devin no Facebook  Devin no Twitter  RSS do Site 
Linux    

Scripts Init no Linux – Parte 1


Comentários  13
Visualizações  
552.201

Os scripts de inicialização do Linux são utilizados desde os primórdios dos tempos (oh!) para não apenas colocar serviços e daemons para rodar na inicialização, mas para controlar os serviços em si no dia-a-dia. Tarefas como: descobrir se o postfix está rodando; iniciar aquele serviço que não subiu direito; reiniciar ou recarregar um daemon que você mudou a configuração; entre outros. E neste quesito, durante anos os scripts init no Linux foram lineares e simples… Entretanto, muita coisa mudou e foram surgindo outras funcionalidades.

Quando falamos em Init, podemos dizer que é o primeiro processo executado pelo Linux. Logo após o kernel ser carregado em memória, ele tem a opção de executar um programa. Este programa é o que chamamos de init. O init geralmente é o responsável por dizer quais os programas e/ou serviços devem ser iniciados logo após o carregamento do kernel e a detecção de hardware da máquina. Curiosamente, se você utilizar o comando ps, verá que o processo de PID número 1 é o sistema de init da sua distribuição.

Os scripts init clássicos, que surgiram nas primeiras distribuições Linux e continuam até hoje em muitas, são essas: SystemV e BSD-like. Estes sistemas eram lineares e bloqueadores, ou seja, um serviço vai sendo iniciado após o outro. Se um deles travar (demorando demais), a inicialização de todo o sistema vai ter que ficar esperando. Isso dá uma simplicidade grande na hora de adicionar serviços e criar scripts.

Com o tempo as distribuições Linux foram evoluindo e os desenvolvedores resolveram fazer melhorias nestes sistemas de inicialização. Algumas das melhorias tem como o objetivo:

  • Poder executar serviços paralelamente;
  • Lidar melhor com as dependências entre um serviço e outro (exemplo: precisa de rede para iniciar um servidor web);
  • Adicionar ou remover dispositivos (pendrives, discos, entre outros) e recarregar certos serviços quando isso ocorrer;
  • Não depender apenas de um arquivo com o PID para saber se o serviço está rodando bem…

E dentre algumas novas implementações de sistemas init, as que ganharam mais reconhecimento e uso foram: Upstart e systemd.

Na prática, se você colocar um shell script que faz tudo que você quer na inicialização e mandar o kernel carregar este script (parâmetro init=/seu/script), ele vai fazê-lo. Mas convenhamos: isso não é nada prático! :) Melhor mesmo é usar o que já fizeram de bom, que é o que vamos aprender aqui.

BSD-like

O sistema BSD-like começou como falei antes: um shell script que é executado logo após o kernel e roda tudo que você quer. Mexer nele era bem simples: bastava editar o arquivo /etc/rc e sucesso. O conteúdo do script é executado linearmente como um shell script comum. Houve algumas melhorias com o tempo, em que você além de poder mexer no arquivo /etc/rc, pode também criar shell scripts executáveis dentro do diretório /etc/rc.d, que podem ser executados em uma ordem específica, começando a implementar as funcionalidades de dependências.

Por ser um sistema init que não é tão usado pelas distribuições Linux, sai fora do escopo e por isso não entraremos em detalhes.

SystemV

O sistema SystemV foi um dos mais utilizados (e por mais tempo) em diversas distribuições Linux e por isso é o mais conhecido entre os usuários. Ele funciona da seguinte forma:

  1. O kernel carrega o programa init, que é o binário principal do SystemV init;
  2. O init lê o arquivo de configuração /etc/inittab e identifica a linha que começa com si::sysinit: (system initialization). Esta linha contém o shell script que o init vai carregar logo após o kernel;
  3. O shell script /etc/rc.sysinit é então executado. Ele contém todas as tarefas básicas do sistema pós-kernel: monta os psudeo sistemas de arquivos (proc, sys, entre outros), carrega módulos do kernel, define configurações de kernel (sysctl), monta e verifica sistemas de arquivos, entre outros;
  4. Quando o script completa sua execução, o init espera por um nível de execução (runlevel). Como ele não tem nenhum ainda, ele lê a linha do /etc/inittab que tem a definição initdefault, e muda para este runlevel. Por exemplo, em sistemas baseados em Red Hat:
    # inicializa com o runlevel 3 (modo multi-usuário completo)
    id:3:initdefault:
    
  5. Ainda no /etc/inittab, existem linhas que indicam o que vai ser executado em cada runlevel. Neste caso, o SystemV usa as seguintes linhas:
    l0:0:wait:/etc/rc.d/rc 0
    l1:1:wait:/etc/rc.d/rc 1
    l2:2:wait:/etc/rc.d/rc 2
    l3:3:wait:/etc/rc.d/rc 3
    l4:4:wait:/etc/rc.d/rc 4
    l5:5:wait:/etc/rc.d/rc 5
    l6:6:wait:/etc/rc.d/rc 6
    

    Cada linha dessa executa o script /etc/rc.d/rc com o parâmetro do runlevel que o init mudou. Por exemplo, se o runlevel for 3, o init executa o /etc/rc.d/rc 3.

  6. O script /etc/rc.d/rc executa todos os arquivos executáveis do diretório /etc/rcX.d, onde X é o runlevel. Se o runlevel for 3, ele vai usar o diretório /etc/rc3.d;
  7. Dentro desses diretório, há diversos links simbólicos começando com K (de kill, ou seja, para o processo) ou S (de start, ou seja, inicia o processo). Os arquivos são executados em ordem alfabética, então ele executa o que começa com K e depois o que começa com S;
  8. Por fim, esses arquivos são todos links simbólicos para os reais scripts no diretório /etc/init.d. Estes scripts aceitam como parâmetros start (quando o link começa com S, o init chama o script com o parâmetro start) e stop (quando o link começa com K, o init chama o script com o parâmetro stop).

Ufa!

Formato do script init

O shell script do /etc/init.d deve aceitar, no mínimo, os parâmetros start e stop. Nada melhor que um exemplo para mostrar:

  • Exemplo: /etc/init.d/meu-servico
#!/bin/bash
#
### BEGIN INIT INFO
# Provides:             meu-servico
# Required-Start:       $network
# Required-Stop:        $network
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description:    O Meu Serviço
# Description:          Uma descricao mais completa sobre o meu serviço
### END INIT INFO
# chkconfig: 2345 95 20

start() {
  echo 'Eu executei start!' > /var/log/meu-servico.log
}
 
stop() {
  echo 'Eu executei stop!' > /var/log/meu-servico.log
}
 
restart() {
  stop
  start
}                                                                                                                                                                          
                                                                                                                                                                           
case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  restart)
    restart
    ;;
  *)
    echo $"Usage: $0 {start|stop|restart}"
    exit 1
esac
 
exit $?

Depois é só tornar o script executável:

chmod 755 /etc/init.d/meu-servico
NOTA
NOTA

  • O conteúdo entre o bloco BEGIN INIT INFO / END INIT INFO contém informações no padrão LSB e é recomendado usar. Estas informações incluem: que runlevels o script deve iniciar e parar, do que ele depende, descrições, entre outros. Para mais informações, consulte esta página no site do Debian.
  • A linha no começo, com o chkconfig:, é uma definição para as distribuições baseadas em Red Hat (que usam o comando chkconfig para gerenciar esses scripts). Os números depois dele são: runlevels que devem ser escritos, a prioridade de start e a prioridade de stop.

Tenha em mente também que são shell scripts, então apesar do funcionamento ser geralmente o mesmo, o código pode variar bastante de script para script. Há uma diversidade de scripts em cada serviço de cada distribuição. Por isso, antes de fazer um script para seu serviço, dê uma olhada nos que já existem para sua distribuição e não se esqueça de aprender shell script :-)

Usando

Na prática, você já pode executar o script init com os comandos:

service meu-servico start
service meu-servico stop
service meu-servico restart

ou (prefira o service aos comandos diretos abaixo):

/etc/init.d/meu-servico start
/etc/init.d/meu-servico stop
/etc/init.d/meu-servico restart

Execute os comandos e veja o arquivo de log /var/log/meu-servico.log para cada um deles.

Em outros scripts, geralmente há também o parâmetro status, que dá a atual situação do serviço: ele está rodando ou não? O status funciona assim:

  1. Quando o serviço inicia, ele cria um arquivo contendo o PID do próprio serviço. Esses arquivos geralmente ficam em /var/run e terminam com extensão .pid;
  2. O shell script de init ao receber o parâmetro status procura esse arquivo. Se ele existir, o processo está rodando no PID contido no arquivo. Se o arquivo não existir, é porque o serviço não está rodando.
  3. Quando o serviço para, ele remove o arquivo contendo o seu PID.

Gerenciando os serviços na inicialização (runlevel)

Com o script colocado no lugar certo e com permissão de execução, existem comandos que gerenciam estes scripts e os colocam (fazem os links simbólicos) nos diretórios /etc/rcX.d corretamente.

  • Distribuições baseadas em Red Hat
# inclui um serviço
chkconfig --add meu-servico

# habilita o serviço na inicialização
chkconfig meu-servico on

# desabilita o serviço na inicialização
chkconfig meu-servico off

# retira todos os links simbolicos
chkconfig --del meu-servico

# lista todos os serviços, e quando estão habilitados e desabilitados em quais runlevels
chkconfig --list

# lista apenas um serviço
chkconfig --list meu-servico
  • Distribuições baseadas em Debian e Ubuntu
# inclui um serviço com prioridade 20 (o link fica como S20meu-servico)
update-rc.d meu-servico defaults

# inclui um serviço com prioridade 80 (o link fica como S90meu-servico)
update-rc.d meu-servico defaults 80

# retira todos os links simbolicos (-f é para forçar mesmo que o script exista no /etc/init.d)
update-rc.d -f meu-servico remove 

Bônus! Como funciona o /etc/inittab

O arquivo /etc/inittab contém a configuração principal do SystemV init. Na prática, para tudo que o comando init faz, este arquivo é consultado primeiro. Nele, temos uma configuração para cada linha. Anteriormente vimos que o init, ao mudar para o runlevel 3, executou uma série de arquivos dentro do /etc/rc3.d. Veja a linha dentro do /etc/inittab que fez isso:

l3:3:wait:/etc/rc.d/rc 3

Podemos dividir essa linha em campos separados por dois pontos (:), tendo assim os campos:

id:runlevels:ação:comando

Cada campo representa:

  • id: um ID unico para identificar a linha, com até 4 caracteres.
  • runlevels: quais os runlevels que essa linha vai funcionar (2345 significa que funciona no 2, no 3, no 4 e no 5)
  • ação: o que fazer com essa linha (que ação tomar), explicado mais pra frente
  • comando: qual comando/processo deve ser executado

    Voltando ao exemplo anterior:

    l3:3:wait:/etc/rc.d/rc 3
    

    Significa: a linha de configuração l3 vai funcionar quando o runlevel for 3, vai executar o comando /etc/rc.d/rc 3 e esperar (wait) até o runlevel acabar ou mudar. Particularmente, o campo de ação pode ter várias opções. Algumas delas:

  • respawn: executa o comando, e quando ele finalizar, executa-o novamente. Exemplos: terminais console (gettys);
  • wait: executa o comando uma vez, mesmo quando ele finalizar, espera até o runlevel acabar ou mudar para saber o que fazer;
  • sysinit: o primeiro comando que é executado logo após a inicialização (já explicado anteriormente);
  • initdefault: qual o primeiro runlevel que o init ficar logo após a inicialização;
  • ctrlaltdel: qual comando executar quando alguem precionar CTRL+ALT+DEL no terminal.

Existem outras ações, descritas também na página de manual inittab[5].

Você pode fazer alterações no init e mandar recarregá-lo através do comando:

# faz o init ler o /etc/inittab novamente (reload)
init q

E se você quer mudar de um runlevel para outro manualmente, basta fornecer o número do runlevel assim:

# muda para o runlevel 1
init 1

# muda para o runlevel 5
init 5

# muda para o runlevel 6 (reinicia a maquina)
init 6

Vamos entender as linhas melhor com alguns exemplos:

x:5:respawn:/etc/X11/prefdm -nodaemon

Quando o sistema for pro runlevel 5, executar o comando /etc/X11/prefdm -nodaemon (que é o ambiente gráfico em sistemas baseados em Red Hat). Se o usuário sair do sistema gráfico, ele executa novamente (respawn).

2:2345:respawn:/sbin/mingetty tty2

Se o runlevel for 2, 3, 4 ou 5, executar o comando /sbin/mingetty tty2. Este comando é o console em modo texto do Linux (CTRL+ALT+F2). Se o usuário fizer logout no console, o processo é finalizado, mas o init executa novamente devido ao respawn.

id:6:initdefault:

Essa é engraçada e geralmente a gente faz pra sacanear os amigos :P A linha diz para o init mudar inicialmente para o runlevel 6, que nas distribuições significa um reboot. Em outras palavras, a máquina fica reiniciando infinitamente.

Enfim, os scripts do /etc/inittab geralmente suprem a maioria dos casos. Mas particularmente, a ação de “respawn” do inittab é muito interessante e pode ser usada para você forçar um processo estar sempre em execução, não importa o que aconteça.

Outros

Além dos dois clássicos, existem outros tipos de sistemas init, como falado anteriormente. Podemos citar (e escrever sobre, em uma segunda parte deste tutorial):

Referências

552.201

Comentários  13
Visualizações  
552.201


TagsLeia também

Apaixonado por Linux e administração de sistemas. Viciado em Internet, servidores, e em passar conhecimento. Idealizador do Devin, tem como meta aprender e ensinar muito Linux, o que ele vem fazendo desde 1997 :-)


Leia também



Comentários

13 respostas para “Scripts Init no Linux – Parte 1”

  1. Nathana disse:

    Otimo material! Eu adorei, obrigada!

  2. Elton Lima disse:

    Ótimo conteúdo !

  3. Reginaldo disse:

    Eitch, este material me foi muito útil. Parabéns, pela qualidade da apresentação, didática e escrita.
    Verifiquei os conteúdos do seu site e acabou de ganhar um novo leitor.

  4. roberto disse:

    òtimo texto, didática impecável, demonstrando profundo conhecimento do assunto.
    Muito útil para todos aficionados do linux. Continue assim, desprendido em ajudar os outros, e que tudo de
    bom retorne para você. Muito Obrigado.

  5. […] Scripts Init no Linux – Parte 1 […]

  6. MUNIZ_TI disse:

    Seu site é muito interessante, aprendir muito sobre shell script.
    pergunta: quando vou logar no meu debian deu um erro com uma cara branca dizendo que teve problema com sistema de arquivos.
    como faço para resolver?
    agradeço desde já.

  7. emosca disse:

    Explanação bem feita. Boa didática.
    Mas uma pergunta de curioso (= desentendido que apenas quer saber como executar e ter resultado num procedimento, sem pormenores), como executar um script que após login do usuário apresente uma simples caixa de texto na Área de Trabalho "Olá Mundo!"?
    O script funciona (com Pop-up em Zenity, mas só é executado pelo terminal e não automaticamente, 'logou' -> Pop-up na tela: "Olá Mundo!"
    Obrigado!

  8. José disse:

    Show! Aprendi muito, parabéns pelo blob

  9. Marmileu disse:

    Olá Hugo…é possivel por um serviço no boot usando usuario ñ root? Se sim pode dar um exemplo?…

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *