Em distribuições baseadas em Linux modernas o SystemD é o mecanismo de inicialização padrão. Você já deve se ter deparado com uma tela parecida com a abaixo, cheia de “Oks” verdes:
Essa é a “tela” do SystemD. Cada Ok verde desse quer dizer que um serviço foi inicializado com sucesso. Essa imagem foi retirada durante o boot de um Raspberry Pi 3B, o Raspbian utiliza o SystemD como sistema de inicialização.
Sendo assim o SystemD é uma ferramenta que vale muito a pena ser estudada. Por exemplo, você cria sua aplicação baseada em Linux e Raspberry Pi, e ela deve começar a trabalhar já durante a inicialização sem que alguém deva logar no sistema e a inicializar manualmente. O que você vai utilizar? SystemD!
SystemD – System and Service Manager
O SystemD é uma serie de programas e bibliotecas, desenvolvido inicialmente pela Red Hat, que juntos fornecem funcionalidades básicas para uma distribuição Linux como: configurações do comportamento de serviços como sequência correta de inicialização e desligamento. Entre os utilitários que nós temos acesso em um terminal o mais utilizado é o systemctl, esse programa é utilizado para inicializar, parar e verificar o estado de serviços pelo SystemD. Vamos estudar a utilização dos comandos para o systemctl abaixo no exemplo.
SystemD – Exemplo
Nesse exemplo vamos imaginar que temos uma aplicação, serviço, script que precisa ser inicializado imediatamento apos ligar uma Raspberry Pi, e também realizar algumas rotinas durante o desligamento da nossa Raspberry Pi.
Scripts – Blink
Primeiramente precisamos do nosso “serviço” ou programa, script que será inicializado durante o boot. Para isso vamos escrever um simples blink em bash script utilizando o acesso à GPIO da nossa Raspberry Pi via SysFS:
#!/bin/bash echo 24 > /sys/class/gpio/export echo out > /sys/class/gpio/gpio24/direction while [ 1 ]do echo 1 > /sys/class/gpio/gpio24/value sleep 0.2s echo 0 > /sys/class/gpio/gpio24/value sleep 0.2s done
Vamos salvar esse script como blink.sh, ele será o script de inicialização do nosso serviço e ficará piscando um led na GPIO 24 do Raspberry Pi:
Com o arquivo salvo ainda temos que dar o privilégio de execução à ele:
chmod +x blinkConclusão.sh
Agora podemos executar o arquivo e testar se o led vai piscar:
./blink.sh
Esse script vai executar infinitamente enquanto o processo existir, para fechar o processo digite “ctrl+c”.
Agora vamos criar um script chamado blinkShutdown.sh com o seguinte contéudo:
#!/bin/bash for (( c=1; c<=5; c++ )) do echo 1 > /sys/class/gpio/gpio24/value sleep 0.09s echo 0 > /sys/class/gpio/gpio24/value sleep 0.09s done echo 24 > /sys/class/gpio/unexport
Você pode ver que esse script é bem parecido com o anterior, mas nesse não escrevemos no /sys/class/gpio/export e nem no /sys/class/gpio/gpio24/direction pois isso já foi feito no script anterior, que será o script de start do nosso serviço. O blinkShutdown.sh será nosso script de stop, ele vai piscar por 5 vezes bem rapidamente e fará o unexport do pino 24. Temos também que dar privilégios de execução para ele:
chmod +x blinkShutdown.sh
Unit File – Descrição do Serviço
Com os scripts do nosso serviço prontos podemos escrever o nosso Unit File que é o arquivo que define um serviço para o SystemD:
[Unit]Description=Vamos piscar leds. [Service]Type=simpleExecStart=/home/pi/blink.shExecStop=/home/pi/blinkShutdown.sh [Install]WantedBy=multi-user.target
Vamos salvar esse arquivo como blink.service.
Agora vamos entender a estrutura desse arquivo:
-
[Unit]
-
Geralmente a primeira seção de um Unit File é aonde estão as informações de ajuda e descrição, e dependências sobre nosso serviço.
-
Diretiva Description vai dentro de Unit como o nome já entrega é uma descrição breve do nosso serviço, é o valor dessa diretiva que será escrita na “tela” do SystemD após o Ok verde, isso se nosso serviço for inicializado com sucesso. Caso contrário o valor será escrito após um Failed vermelho.
-
-
-
[Service]
-
-
Dentro de Service vamos ter as configurações sobre ações do nosso serviço.
-
Diretiva Type descreve a forma de como serão executados os processos, scripts, programas do nosso serviço.
-
Diretiva ExecStart arquivo do programa, aplicação, script que será executado ao inicializar o serviço. No nosso exemplo vamos colocar o caminho do arquivo blink.sh
-
Diretiva ExecStop arquivo do programa, aplicação, script que será executado ao parar o serviço. No nosso exemplo vamos colocar o caminho do arquivo blinkShutdown.sh
-
-
-
[Install]
-
-
Dentro de Install vamos descrever o comportamento de inicialização do serviço.
-
Diretiva WantedBy irá dizer ao SystemD quando nosso serviço será inicializado. Geralmente o SystemD tem uma ordem bem definida de quais serviços serão inicializados primeiramente, e quais serviços tem relações de dependências e devem esperar. O valor dessa diretiva então é o serviço, ou grupo alvo, ao qual nosso serviço faz parte e deve ser inicializado em conjunto. No nosso caso o padrão é o multi-user.target que geralmente nesse ponto as dependências mais básicas para que nossa distro Linux funcione corretamente já foram inicializadas.
-
-
Para colocar nosso serviço disponível para o SystemD temos que copiar o nosso blink.service para o diretório padrão de services do SystemD:
sudo cp blink.service /lib/systemd/system/
Com nosso Unit File no diretório do SystemD já podemos utilizar o utilitário systemctl para testar nosso serviço:
sudo systemctl start blink
Se tudo ocorrer certo nosso led começara a piscar, lembrando que no caso do comando systemctl start o SystemD vai executar nosso blink.sh como definimos em ExecStart. Também é importante chamar a atenção que quando utilizamos o systemctl podemos passar o nove inteiro no nosso Unit File ou só o nome antes da extensão .service, no nosso caso blink.service eu posso usar somente o nome blink que o utilitário ira entende.
Podemos também parar o serviço:
sudo systemctl stop blink
Nesse caso ele vai executar o blinkShutdown.sh como definimos em ExecStop, irá piscar o led rapidamente 5x e pronto nosso serviço está parado.
SystemD – Habilitar Serviço Durante Boot
Ok, mas nesse ponto se reiniciarmos nosso Raspbian podemos ver que o led não vai começar a piscar sozinho. Precisamos de mais um comando, esse muito importante pois irá habilitar nosso serviço pra executar durante o boot e durante o encerramento do Raspbian:
sudo systemctl enable blink
Pronto, agora temos um serviço habilitado a ser executado pelo SystemD de forma automática durante o boot e encerramento. Parar testar e só reiniciar o Raspbian.
Se você estiver utilizando o Raspberry Pi via serial, como estou utilizando, você poderá ver na “tela” do SystemD, antes de login, o nosso serviço sendo inicializado e recebendo um Ok:
Para testar se o led vai piscar 5x rapidamente e desligar, durante o encerramento, é só desligar o Raspbian ou reiniciar novamente. Também podemos ver durante o encerramento nosso serviço sendo listado com um Ok:
SystemD – Solução de Problemas
Caso ocorra um problema durante a inicialização de algum serviço ou ele comece a se comportar de forma inesperada podemos utilizar o systemctl pra verificar seu estado e logs para solucionar o problema:
No caso acima o systemctl status nos retornou que o serviço está ativo e funcionando corretamente.
No caso abaixo eu modifiquei nosso Unit File colocando o nome errado do arquivo do script para gerar um erro, confira o retorno do systemctl status:
Conclusão
O SystemD é uma ferramenta muito poderosa que nos dá inúmeras possibilidades de configurações para inicialização de aplicações durante o boot de nossos sistemas embarcados baseados em distribuições Linux. Ele ainda vai além configurando comportamentos para encerramento da nossa aplicação, em caso de desligamento da placa e recuperação de falhas.
Vale muito a pena investir em tempo de estudo no SystemD.
Pra mim não rolou ainda.
Retorna o erro abaixo:
update-rc.d: error: cannot find a LSB script for [meu script]
Matheus, Boa tarde.
Tenho um problema que nao consigo de jeito nenhum fazer funcionar.
Sou meio leigo no assunto de Linux mas fuço bastante e dou meus pulos.
Tenho um Raspberry PI 3 com Raspbian ligado num monitor e quero apenas que quando ele ligar, carregue de forma automatica o Chromium.
Assisti seu video mas nao sei e no meu caso se aplica.
POderia me dar uma luz?
Antonio,
Dê uma olhadinha nesse tutorial, tem um script que você pode aproveitar 🙂
Abraços!
Diogo – Equipe MakerHero
Participei da Raspberry JAM Osasco, a palestra de Matheus Castello foi um diferencial bem vindo, tive ideia exata da arquitetura usada no projeto, mesmo com pouco tempo apresentou um ótimo conteúdo ! Difícil um jovem com um conhecimento exímio da área. Ganhou um divulgador do seu trabalho.
Abraços
Vanderlei Franco
fb.com/professorvanderleifranco
instagram.com/vanderfranco/
Olá Vanderlei!
O Matheus é um dos nossos SuperMakeres!
Se quiser conhecer mais sobre o nosso projeto:
https://www.makerhero.com/maker-hero/
Abraços!
André Rocha – Equipe MakerHero
Parabéns pelo artigo Matheus, muito bem explicado.
Vou aproveitar pra deixar uma dica também pra quem quer inicializar uma aplicação que utilize a interface (GUI), utilizei em um projeto, basta adicionar algumas coisas no arquivo.service, exemplo abaixo:
[Unit]
Description= Nome do seu serviço
[Service]
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/pi/.Xauthority
ExecStart=caminho do seu arquivo
Restart=always
RestartSec=10s
KillMode=process
TimeoutSec=infinity
[Install]
WantedBy=graphical.target
Para conectar a tela principal então configuramos (Environment=DISPLAY=:0), e informamos à nossa aplicação onde encontrar as credenciais necessárias para usar o sistema X windows com (Environment=XAUTHORITY=/home/pi/.Xauthority)
Nos meus teste percebi que não da pra saber muito bem quando o sistema X será iniciado, por isso aquelas duas linhas (Restart=always ; RestartSec=10s) que fazem o programa tentar reiniciar a cada 10 segundos caso ele falhe ou saia. O (KillMode=process) diz ao systemd para matar qualquer processo associado ao programa se o serviço falhar e o (TimeoutSec = infinity) significa que nós não queremos parar de tentar executar o programa.
Na parte do [Install] o (WantedBy=graphical.target) diz para o sistema aguardar iniciar a interface gráfica para executar o programa.
Valeu.
Olá Viktor, obrigado pelas dicas, mas e no caso de por exemplo, eu precisar rodar um script python que acessa a gpio e tem que ser executado pelo sudo , como eu faria pra carregá-lo pelo systemD ?
Obrigado
Excelente, foi muito útil Viktor, parabéns e obrigado!