# 02 - SysVinit (System V Initialization)
video: https://youtu.be/... no frontmatter da nota.A arquitetura do SysVinit (System V Initialization) representou, por mais de duas décadas, o padrão de facto para a orquestração do espaço de usuário em sistemas operacionais baseados em Linux e Unix. Herdado do UNIX System V Release 4 (SVR4) da AT&T, o SysVinit foi concebido para resolver as limitações estruturais de seu predecessor, o BSD init (que dependia de um único e monolítico script /etc/rc para inicializar a máquina). A revolução introduzida pelo SysVinit foi a modularidade stateful, permitindo que o administrador definisse perfis de execução excludentes (os Runlevels) e delegasse a inicialização de subsistemas a scripts independentes gerenciados de forma centralizada.
Do ponto de vista da engenharia de software, o SysVinit opera sob um paradigma estritamente imperativo e sequencial. Diferente de sistemas modernos orientados a grafos de dependências (como o systemd), o SysVinit não compreende o que um serviço "precisa" para rodar; ele apenas executa instruções shell em uma ordem lexicográfica rígida, presumindo que a estabilidade do sistema emergirá do sequenciamento correto projetado pelo administrador.
1. O Motor de Estados: A Arquitetura do /sbin/init
O binário principal do SysVinit, localizado em /sbin/init, é estruturalmente um programa em C muito simples. Sua responsabilidade não é iniciar serviços de rede ou montar discos diretamente, mas atuar como uma máquina de estados finitos.
Ao ser invocado pelo kernel ao final do boot (assumindo o PID 1), o init executa as seguintes tarefas atômicas:
- Apropria-se do papel de "Ceifador" (Reaper) de processos zumbis, estabelecendo um loop baseado nas syscalls da família
wait(). - Lê compulsivamente seu arquivo de configuração mestre:
/etc/inittab. - Determina o estado desejado (default runlevel).
- Executa os processos ou scripts mapeados para aquele estado.
- Entra em estado de dormência (bloqueado em
select()ou ouvindo sinais POSIX e o socket/dev/initctl), aguardando que o administrador solicite uma mudança de estado (transição de runlevel) através do comandotelinit.
2. A Anatomia Crítica do /etc/inittab
O arquivo /etc/inittab é o coração arquitetural do SysVinit. Ele não é um script executável, mas uma tabela de diretivas de roteamento de processos. O parser do init analisa este arquivo linha por linha, ignorando comentários (#), buscando um formato posicional estrito delimitado por dois pontos (:).
A sintaxe canônica de uma linha no inittab é:
id:runlevels:action:process
Detalhamento dos Campos
id: Um identificador único de 1 a 4 caracteres alfanuméricos. Serve como chave primária para o processo na tabela interna de rastreamento doinit.runlevels: Uma string contendo os números (ou letras, comoSpara Single-User) correspondentes aos estados em que esta linha deve ser ativada. Se vazio, presume-se que a ação se aplica a todos os estados.action: A palavra-chave que dita a política de controle do processo. Esta é a lógica de controle mais sofisticada do SysVinit:sysinit: O processo é executado uma única vez durante o boot, antes de qualquer outra diretiva. Usualmente aponta para o script mestre/etc/rc.d/rc.sysinit, responsável por montar o/proc,/sys, ativar o swap e realizar ofsckna raiz. Oinitbloqueia sua própria execução até que este processo retorne.boot/bootwait: Executados imediatamente após osysinit. A variantewaitforça oinita pausar a leitura doinittabaté o término do comando.initdefault: Uma diretiva especial que não possui campoprocess. Ela instrui oinitsobre qual runlevel deve ser assumido ao final do processo de boot (ex:id:3:initdefault:).wait: Executado quando o sistema entra no runlevel especificado. Oinitinvoca o processo e aguarda (espera síncrona) que ele termine antes de processar a próxima linha doinittab. É esta ação que invoca o despachante/etc/rc.d/rc.respawn: A ação mais resiliente. Oinitcria um fork para rodar o processo, mas não aguarda seu término. Em vez disso, monitora o PID filho. Se o processo morrer, oinito reinicia imediatamente. Historicamente, é usado para manter os processosgetty/mingettyvivos nos Terminais Virtuais (tty1atty6), garantindo que o prompt de login sempre retorne após um logout.-
ctrlaltdel: Intercepta o sinal de interrupção de hardware (SIGINT) gerado pela combinação de teclasCtrl+Alt+Delno console físico, tipicamente invocando/sbin/shutdown -t3 -r now. -
process: O caminho absoluto do binário ou script shell a ser executado, juntamente com seus argumentos.
3. O Despachante e o Paradigma de Links Simbólicos (O script rc)
A transição de fato entre os serviços do sistema é delegada à diretiva wait do inittab, que tradicionalmente possui linhas similares a esta:
l3:3:wait:/etc/rc.d/rc 3
O script rc (Run Command) atua como o orquestrador do espaço de usuário. O SysVinit puro não sabe o que é um banco de dados ou um servidor web; ele apenas delega ao rc a instrução: "Transite o sistema para o Estado 3".
O Sistema de Diretórios rcX.d
Para implementar a modularidade SVR4, os scripts reais de inicialização de cada serviço (daemons) residem em um repositório centralizado, usualmente /etc/init.d/ ou /etc/rc.d/init.d/. Estes scripts são escritos em Bash ou sh, e devem obrigatoriamente aceitar, no mínimo, os argumentos start e stop.
Para cada runlevel (0 a 6), existe um diretório correspondente, como /etc/rc3.d/ (para o Runlevel 3). O conteúdo destes diretórios não são os scripts em si, mas links simbólicos (symlinks) apontando para o repositório central. A magia da ordem de execução reside na Nomenclatura Posicional desses symlinks, que segue o padrão:
[K ou S][00-99][Nome_do_Servico]
- A Fase Kill (
K): Quando o scriptrcé chamado para transitar para um novo estado, a primeira coisa que ele faz é listar todos os links no diretório alvo que começam com a letraK(de Kill), ordená-los alfabeticamente e executá-los passando o argumentostop. Isso garante que serviços não desejados no novo estado sejam terminados ordenadamente. Exemplo:K15httpd stop, seguido deK50netfs stop. - A Fase Start (
S): Após desligar o desnecessário, orclista os links que começam comS(de Start), também ordenando alfabeticamente, e os executa com o argumentostart. Exemplo:S10network start, seguido deS22sshd starteS99local start.
A ausência de grafos de dependência significa que a carga lógica da inicialização recai integralmente sobre os ombros do administrador e dos empacotadores da distribuição, que precisam garantir manualmente que o symlink do sshd possua um número (ex: 22) estritamente maior que o número do symlink de configuração da placa de rede (ex: 10), garantindo que a ordem lexicográfica respeite a dependência física de execução.
4. O Problema da Daemonização e a Perda de Estado
Para compreender por que o SysVinit foi obsoleto em infraestruturas modernas de alta disponibilidade, é crucial analisar sua maior vulnerabilidade arquitetural: a ignorância de estado decorrente da Daemonização Tradicional Posix.
Quando o script rc invoca um serviço, como /etc/init.d/nginx start, o interpretador shell inicia. O script realiza verificações, define variáveis de ambiente e, eventualmente, chama o binário /usr/sbin/nginx.
Para que o script shell possa terminar (e retornar o controle ao script rc para que ele continue inicializando o próximo serviço), o nginx não pode bloquear o terminal. Ele precisa rodar em background. O padrão de desenvolvimento C para daemons (System V Daemonization) exige que o processo execute a técnica de Double-Fork:
- O processo
nginxfaz umfork(). O pai sai (exit(0)). O shell entende que o comando "terminou". - O filho chama
setsid()para se desvincular do terminal controlador (TTY). - O filho faz um segundo
fork(). O filho sai. - O neto (o processo real do daemon operante) continua rodando infinitamente em background, reparentado automaticamente pelo PID 1.
A Consequência: O processo pai morreu e o script shell que o SysVinit invocou retornou código 0 (Sucesso). A partir desse momento, o SysVinit perde completamente a capacidade de rastrear a linhagem do processo. O PID 1 não sabe qual é o PID real do nginx. Ele é forçado a confiar que o daemon escreverá seu próprio PID em um arquivo de texto (ex: /var/run/nginx.pid).
Se o processo neto (o daemon) sofrer um crash (Segmentation Fault), o arquivo PID ficará obsoleto (stale). O SysVinit não notará que o serviço caiu, e não há mecanismo nativo de reinicialização automática (como o Restart=always do systemd), exigindo ferramentas auxiliares monstruosas como monit ou supervisord operando no espaço de usuário via polling constante.
5. O Gargalo do Bloqueio Síncrono (I/O Blocking)
A segunda limitação fatal do paradigma SVR4 é a sincronia serializada. O script mestre rc executa as tarefas sequencialmente em uma única thread.
Considere a inicialização do link S10network. Se a placa de rede tentar obter um endereço IP via DHCP e o servidor DHCP da empresa estiver inativo ou lento, o script /etc/init.d/network ficará bloqueado, aguardando um timeout que pode durar 60 segundos.
Durante este minuto inteiro, a CPU da máquina permanece virtualmente em 0% de uso. Todo o processo de boot está paralisado. O servidor SSH (S22sshd), que não tem nenhuma dependência real de um endereço IP externo para iniciar a escuta no socket Unix local, é forçado a aguardar a falha do script anterior. Esta barreira de sincronização linear impede a utilização do paralelismo de processadores multicore modernos, resultando em tempos de inicialização inaceitavelmente longos para ambientes em nuvem (onde o provisioning de instâncias precisa ocorrer em milissegundos).