9.1. Inicialização do Sistema
Quando você inicia o computador, algumas mensagens rolarão pelo console automaticamente inicializando e as configurações são automaticamente executadas. Algumas vezes você pode querer alterar como este estágio funciona, para que você possa entendê-lo muito bem. Este é o propósito desta seção.
Em sistemas com BIOS, primeirooa BIOS assume o controle do computador, inicializa os controladores e o hardware, detecta os discos e faz a ponte entre tudo. Em seguida, ele procura o Master Boot Record (MBR) do primeiro disco na ordem de inicialização e carrega o código armazenado lá (primeiro estágio). Este código então inicia o segundo estágio e finalmente executa o carregador de inicialização (bootloader).
Em contraste com o BIOS, o UEFI é mais sofisticado, conhece sistemas de arquivos e pode ler as tabelas de partição. A interface procura no armazenamento do sistema uma partição marcada com um identificador globalmente exclusivo (globally unique identifier -
GUID) específico que a marca como a
EFI System Partition (
ESP - Partição de Sistema EFI), onde estão localizados os carregadores de inicialização, gerenciadores de inicialização, shell UEFI, etc., e inicia o gerenciador de inicialização desejado. Se o modo de Inicialização Segura (Secure Boot) estiver ativado, o processo de inicialização verificará a autenticidade dos binários EFI por assinatura (portanto,
grub-efi-arch-signed é necessário neste caso). A especificação UEFI também define o suporte para inicialização no modo BIOS herdado. Isso é chamado de
Compatibility Support Module (
CSM - Módulo de suporte de compatibilidade). Se o CSM estiver ativado, ele tentará inicializar a partir do MBR de uma unidade. No entanto, muitos sistemas novos não suportam mais o modo CSM.
Em ambos os casos, então, o carregador de inicialização assume, localiza ou um carregador de inicialização encadeado ou o núcleo no disco, carrega e o executa. O núcleo é então inicializado, começa a pesquisa pela partição e monta a partição contendo o sistema raiz, e finalmente o primeiro programa — init
. Frequentemente essa "partição raiz" e esse init
são, de fato, localizados em um sistema de arquivos virtual que só existe na RAM (daí o seu nome, "initramfs", anteriormente chamado de "initrd" para "initialization RAM disk"). Esse sistema de arquivos é carregado na memória pelo carregador de inicialização, muitas vezes a partir de um arquivo em um disco rígido ou da rede. Ele contém o mínimo exigido pelo núcleo para carregar o sistema de arquivos raiz "verdadeiro": este mínimo podem ser módulos de controlador para o disco rígido ou outros dispositivos sem os quais o sistema pode não inicializar, ou, mais frequentemente, scripts de inicialização e módulos para a montagem de arrays RAID, abertura de partições criptografadas, ativação de volumes LVM, etc. Uma vez que a partição raiz é montada, o initramfs libera o controle para o init real, e a máquina voltará para o processo de inicialização padrão.
9.1.1. O sistema init systemd
O “init real” é atualmente fornecido pelo systemd e esta seção documenta esse sistema init.
O systemd executa vários processos, se encarregando de configurar o sistema: teclados, controladores (drivers), sistemas de arquivos, rede, serviços. Ele faz isso enquanto mantém uma visão global do sistema como um todo e os requerimentos dos componentes. Cada componente é descrito por um "arquivo unit” (às vezes mais); a sintaxe geral é derivada dos amplamente usados "arquivos *.ini“, com os pares chave = valor
agrupados entre cabeçalhos [seção ("section")]
. Arquivos unit são armazenados em /lib/systemd/system/
e /etc/systemd/system/
; eles vêm em vários sabores, mas iremos focar nos serviços (“services”) e alvos (“targets”) aqui.
Um "arquivo .service
" do systemd descreve um processo gerenciado pelo systemd. Ele contém, grosseiramente, a mesma informação dos antigos scripts init, mas expresso de maneira declaratória (e muito mais concisa). O systemd maneja a massa de tarefas repetitivas (iniciar e parar o processo, checar seu status, registro de log, descarte de privilégios e muito mais), e o arquivo service apenas precisa preencher as especificações do processo. Por exemplo, aqui está um arquivo service para o SSH:
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
Alias=sshd.service
A seção [Unidade]
contém informações genéricas sobre o serviço, como sua descrição e recursos de página de manual, bem como relações (dependência e ordem) com outros serviços. A parte [Service]
contém as declarações relacionadas à execução do serviço (iniciando, parando, encerrando, reiniciando), diretórios e arquivo(s) de configuração usados. A última seção, [Install]
, traz novamente informações genéricas em quais destinos instalar o serviço e, neste caso, o alias que pode ser usado em vez do nome do serviço. Como você pode ver, há muito pouco código ali, apenas declarações. O Systemd se encarrega de exibir relatórios de progresso, acompanhar os processos e até reiniciá-los quando necessário. A sintaxe desses arquivos é totalmente descrita em várias páginas de manual (por exemplo, systemd.service(5), systemd.unit(5), systemd.exec(5), etc.).
O “arquivo .target
” do systemd descreve o estado do sistema no qual se sabe que um conjunto de serviços são operacionais. Ele pode ser pensado como um equivalente ao runlevel no estilo antigo. Um dos alvos pré-definidos ("targets") é local-fs.target
; quando ele é alcançado, o resto do sistema pode assumir que todos os sistemas de arquivos locais estão montados e acessíveis. Outros alvos incluem network-online.target
e sound.target
(para uma lista de alvoes especiais, veja systemd.special(7)). As dependências de um alvo podem ser listadas tanto dentro de um arquivo target (na linha Requires=
), quanto usando uma ligação simbólica para um arquivo service do diretório /lib/systemd/system/nome-do-target.target.wants/
. Por exemplo, /etc/systemd/system/printer.target.wants/
contém uma ligação para /lib/systemd/system/cups.service
; o systemd irá então garantir que o CUPS está rodando a fim de alcançar o printer.target
.
Como arquivos unit são declarativos ao invés de scripts ou programas, eles não podem ser executados diretamente, e só são interpretados pelo systemd; vários utilitários, entretanto, permitem que o(a) administrador(a) interaja com o systemd e controle o estado do sistema e de cada componente.
O primeiro de tais utilitários é o systemctl
. Quando rodado sem argumentos, lista todos os arquivos unit conhecidos pelo systemd (exceto aqueles que tenham sido desabilitados), assim como seus status. systemctl status
retorna uma visão melhor dos serviços, assim como os processos relacionados. Se o nome do serviço for informado (como em systemctl status ntp.service
), retorna ainda mais detalhes, assim como as últimas linhas de registro ("log") relacionadas ao serviço (mais sobre isso mais tarde).
Iniciar um serviço manualmente é uma simples questão de rodar systemctl start nomedoserviço.service
. Como se pode imaginar, parar o serviço é feito com systemctl stop nomedoserviço.service
; outros subcomandos incluem reload
e restart
.
Para controlar se um serviço está ativo (ou seja, se será iniciado automaticamente na inicialização), use systemctl enable nomedoserviço.service
(ou disable
). is-enabled
permite checar o status do serviço.
Um recurso interessante do systemd é que ele inclui um componente de registro de logs chamado journald
. Ele vem como um complemento para sistemas de registro de logs tradicionais como syslogd
, mas adiciona recursos interessantes como uma ligação formal entre um serviço e as mensagens que ele gera, e a habilidade de capturar mensagens de erro geradas pela sua sequência de inicialização. As mensagens podem ser exibidas mais tarde, com uma ajudinha do comando journalctl
. Sem qualquer argumento, ele simplesmente derrama todas as mensagens de log que ocorreram desde a inicialização do sistema; raramente será usado de tal maneira. Na maior parte do tempo será usado com um identificador de serviço:
#
journalctl -u ssh.service
-- Logs begin at Tue 2015-03-31 10:08:49 CEST, end at Tue 2015-03-31 17:06:02 CEST. --
Mar 31 10:08:55 mirtuel sshd[430]: Server listening on 0.0.0.0 port 22.
Mar 31 10:08:55 mirtuel sshd[430]: Server listening on :: port 22.
Mar 31 10:09:00 mirtuel sshd[430]: Received SIGHUP; restarting.
Mar 31 10:09:00 mirtuel sshd[430]: Server listening on 0.0.0.0 port 22.
Mar 31 10:09:00 mirtuel sshd[430]: Server listening on :: port 22.
Mar 31 10:09:32 mirtuel sshd[1151]: Accepted password for roland from 192.168.1.129 port 53394 ssh2
Mar 31 10:09:32 mirtuel sshd[1151]: pam_unix(sshd:session): session opened for user roland by (uid=0)
Outra opção de linha de comando útil é a -f
, que instrui o journalctl
a manter a exibição de novas mensagens assim que elas são emitidas (similar ao tail -f arquivo
).
Se um serviço não parece estar trabalhando como o esperado, o primeiro passo para resolver o problema é checar se o serviço está realmente rodando com systemctl status
; se ele não estiver, e as mensagens obtidas pelo primeiro comando não forem suficientes para diagnosticar o problema, confira os registros (logs) coletados pelo journald sobre esse serviço. Por exemplo, suponha que o servidor SSH não esteja funcionando:
#
systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: failed (Result: start-limit) since Tue 2015-03-31 17:30:36 CEST; 1s ago
Process: 1023 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
Process: 1188 ExecStart=/usr/sbin/sshd -D $SSHD_OPTS (code=exited, status=255)
Main PID: 1188 (code=exited, status=255)
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service start request repeated too quickly, refusing to start.
Mar 31 17:30:36 mirtuel systemd[1]: Failed to start OpenBSD Secure Shell server.
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
#
journalctl -u ssh.service
-- Logs begin at Tue 2015-03-31 17:29:27 CEST, end at Tue 2015-03-31 17:30:36 CEST. --
Mar 31 17:29:27 mirtuel sshd[424]: Server listening on 0.0.0.0 port 22.
Mar 31 17:29:27 mirtuel sshd[424]: Server listening on :: port 22.
Mar 31 17:29:29 mirtuel sshd[424]: Received SIGHUP; restarting.
Mar 31 17:29:29 mirtuel sshd[424]: Server listening on 0.0.0.0 port 22.
Mar 31 17:29:29 mirtuel sshd[424]: Server listening on :: port 22.
Mar 31 17:30:10 mirtuel sshd[1147]: Accepted password for roland from 192.168.1.129 port 38742 ssh2
Mar 31 17:30:10 mirtuel sshd[1147]: pam_unix(sshd:session): session opened for user roland by (uid=0)
Mar 31 17:30:35 mirtuel sshd[1180]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:35 mirtuel sshd[1182]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:35 mirtuel sshd[1184]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:35 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:35 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel sshd[1186]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel sshd[1188]: /etc/ssh/sshd_config line 28: unsupported option "yess".
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service: main process exited, code=exited, status=255/n/a
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
Mar 31 17:30:36 mirtuel systemd[1]: ssh.service start request repeated too quickly, refusing to start.
Mar 31 17:30:36 mirtuel systemd[1]: Failed to start OpenBSD Secure Shell server.
Mar 31 17:30:36 mirtuel systemd[1]: Unit ssh.service entered failed state.
#
vi /etc/ssh/sshd_config
#
systemctl start ssh.service
#
systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: active (running) since Tue 2015-03-31 17:31:09 CEST; 2s ago
Process: 1023 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
Main PID: 1222 (sshd)
CGroup: /system.slice/ssh.service
└─1222 /usr/sbin/sshd -D
#
Após checar o status do serviço (failed), fomos checar os registros; eles indicam um erro no arquivo de configuração. Após editar o arquivo de configuração e consertar o erro, reiniciamos o serviço e então verificamos se ele está realmente rodando.
9.1.2. O sistema init System V
O sistema init System V (que chamaremos init para abreviar) executa vários processos, seguindo instruções a partir do arquivo /etc/inittab
. O primeiro programa executado (o que corresponde ao passo sysinit) é /etc/init.d/rcS
, um script que executa todos os programas que estão dentro do diretório /etc/rcS.d /
.
Entre estes,você encontrará sucessivamente programas responsáveis por:
configurar o teclado do console;
carregar drivers (controladores): a maioria dos módulos do núcleo serão carregados pelo próprio núcleo assim que o hardware for detectado; drivers extras então são carregados automaticamente quando os módulos correspondente estiverem listados em /etc/modules
;
verificar a integridade do sistema de arquivos;
montar partições locais;
configurar a rede;
montar sistemas de arquivos em rede (NFS).
Após este estágio, o init
assume o controle e inicializa os programas habilitados no nível de execução padrão (que geralmente é o nível de execução 2). Ele executa o /etc/init.d/rc 2
, um script que inicia todos os serviços listados em /etc/rc2.d/
e cujos nomes começam com a letra "S". O número de duas casas que se segue tinha sido historicamente utilizado para definir a ordem em que os serviços devem ser iniciados. Atualmente, o sistema de inicialização padrão usa insserv
, o qual agenda automaticamente tudo com base nas dependências dos scripts. Desta forma, cada script de inicialização declara as condições que devem ser cumpridas para iniciar ou parar um serviço (por exemplo, se deve começar antes ou depois de outro serviço); o init
em seguida, lança-os na ordem que satisfaça estas condições. A numeração estática dos scripts, portanto, não é mais levada em consideração (mas eles sempre devem ter um nome começando por "S" seguido por dois dígitos e o nome atual do script usado por suas dependências). Geralmente, serviços base (tais como registros com o rsyslog
, ou atribuição de portas com portmap
) são inicializados primeiro, seguidos por serviços padrão e a interface gráfica (gdm3
).
Este sistema de inicialização baseado em dependência torna possível automatizar a renumeração, que poderia ser um pouco entediante se tivesse que ser feita manualmente, e limita os riscos de erro humano, já que o agendamento é realizado de acordo com os parâmetros indicados. Outro benefício é que os serviços podem ser iniciados em paralelo quando são independentes um do outro, o que pode acelerar o processo de inicialização.
init
distingue vários runlevels (níveis de execução), de modo que possa alternar de um para outro com o comando telinitnew-level
. Imediatamente,init
executa /etc/init.d/rc
novamente com novo runlevel. Esse script irá, em seguida, iniciar os serviços ausentes e interromper aqueles que não são mais desejados. Para fazer isso, faz referência ao conteúdo do /etc/rcX.d
(onde X representa o novo runlevel). Scripts começando com "S" (como em "Start") são serviços a serem iniciados; aqueles que iniciam com "K" (como em "Kill") são os serviços a serem interrompidos. O script não inicia qualquer serviço que já estaeja ativo em um runlevel anterior.
Por padrão, o init System V no Debian usa quatro runlevels diferentes:
Nível 0 é usado apenas temporariamente enquanto o computador está desligando. Como tal, ele só contém muitos scripts "K".
Nível 1, também conhecido como modo de usuário único, corresponde ao sistema em modo degradado; inclui apenas os serviços básicos e destina-se a operações de manutenção onde interações com usuários(as) comuns não são desejadas.
Nível 2 é o funcionamento normal, que inclui serviços de rede, uma interface gráfica, logins de usuário(a), etc.
Nível 6 é semelhante ao nível 0, exceto que é utilizado durante a fase de desligamento que precede uma reinicialização.
Existem outros níveis, especialmente de 3 a 5. Por padrão, são configurados para operar da mesma maneira como nível 2, mas o(a) administrador(a) pode modificá-los (adicionando ou excluindo os scripts nos diretórios correspondentes /etc/rcX.d
) para adaptá-los às necessidades específicas.
Todos os scripts contidos nos vários diretórios /etc/rcX.d
são na verdade apenas links simbólicos — criados durante a instalação de pacotes pelo programa update-rc.d
— que apontam para os scripts de fato armazenados em /etc/init.d/
. O(A) administrador(a) pode ajustar os serviços disponíveis em cada nível de execução reexecutando o update-rc.d
com parâmetros de ajuste. A página de manual do update-rc.d(1) descreve a sintaxe em detalhes. Note que remover todos os links simbólicos (com o parâmetro remove
) não é um bom método para desabilitar um serviço. Ao invés disso, você deve apenas configurá-lo para não iniciar no nível de execução desejado (enquanto preserva as chamadas correspondentes para pará-lo no caso de o serviço iniciar num nível de execução anterior). Uma vez que o update-rc.d
tem uma interface algo complexa, você pode preferir usar rcconf
(do pacote rcconf) que fornece uma interface mais amigável.
Finalmente, init
inicia programas de controle para vários consoles virtuais (getty
). Ele exibe um prompt, esperando por um nome de usuário(a), em seguida executa login usuário(a)
para iniciar uma sessão.