O poder subestimado dos serviços do usuário

Originalmente publicado no vivaolinux.

Introdução

As pessoas não sabem o quanto serviços quem rodam a nível de usuário por parte do init system podem ser úteis no dia a dia. Por não saberem disso, elas delegam essa função aos WMs1 ou scripts de inicialização o que elimina as vantagens de se usar um init system para isso.

Problema

Quando você monta um sistema minimalista com um simples gestor de janelas, você mesmo é responsável por iniciar serviços que rodam em segundo plano a fim de usufruir de funcionalidades como:

Você está ali montando a configuração do seu Window Manager favorito e de repente se vê colocando vários comandos de inicialização.

-- ~/.config/hypr/hyprland.lua
hl.on("hyprland.start", function ()
  hl.exec_cmd("hyprpaper")
  hl.exec_cmd("pipewire")
  hl.exec_cmd("wireplumber")
  hl.exec_cmd("pipewire-pulse")
  hl.exec_cmd("ssh-agent -D -a " .. os.getenv("XDG_RUNTIME_DIR").."/ssh-agent.sock")
  hl.exec_cmd("ollama serve")
end)

O problema é que esses serviços não possuem nenhum tipo de monitoramento, os seus logs não ficam disponíveis pra você acessar e você não tem como saber se o serviço inicializou da forma correta ou não.

Solução

Eu penso que esse tipo de coisa deveria ser gerenciado pelo init system do sistema operacional com serviços que rodam a nível de usuário. O systemd suporta isso e o OpenRC também! Portanto, vou usar esses dois gestores para exemplificar como solucionei esse problema.

Systemd

No systemd você pode criar serviços de usuário através de arquivos de unit localizados em:

~/.config/systemd/user/

Exemplo de serviço para o Wireplumber:

[Unit]
Description=Wireplumber daemon
After=pipewire.service
Requires=pipewire.service

[Service]
Type=forking
ExecStart=/usr/bin/wireplumber
Restart=on-failure
PIDFile=/home/user/.local/var/run/wireplumber.pid

[Install]
WantedBy=default.target

Para habilitar: systemctl --user enable wireplumber.service.

Note como o wireplumber depende de outros serviços para executar (pipewire). Tudo isso é gerenciado pelo systemd automaticamente.

OpenRC

No OpenRC, os scripts de usuário ficam em:

~/.config/rc/init.d/ (para configurações por usuário)

Exemplo de serviço para o Wireplumber:

#!/sbin/openrc-run
name="wireplumber"
description="Wireplumber daemon"
command="/usr/bin/wireplumber"
command_background="true"
supervisor="supervise-daemon"
pidfile="/home/user/.local/var/run/wireplumber.pid"

depend() {
  need pipewire
}

Para habilitar: rc-update -U add wireplumber

O OpenRC também consegue iniciar serviços que dependem um do outro na ordem correta igual o systemd faz! Porém, há um detalhe: no OpenRC você precisa criar um runlevel específico para serviços de usuário, adicionar os serviços que você quer e mudar para esse runlevel na hora do login.

Rode:

mkdir -p ~/.config/rc/runlevels/wayland

e então:

rc-update -U add wireplumber wayland

A única coisa que o teu gestor de janelas precisa fazer durante o login é mudar o runlevel que o OpenRC se encarrega do resto.

-- /home/user/.config/hypr/hyprland.lua
hl.on("hyprland.start", function ()
  hl.exec_cmd("/sbin/openrc -U wayland")
end)

Recursos

Conclusão

A única coisa que o gestor de janelas tem que se preocupar é com a configuração de teclas de atalho, o resto tem que ficar a cargo do sistema de init, pois não é papel do Hyprland ou qualquer outro WM gerenciar serviços em segundo plano e variáveis de ambiente. Os WMs são muito limitados nesse sentido, eles não guardam logs dos processos, quando o serviço para o WM não reinicializa, enfim, são muitas limitações que nem compensa delegar essa função a eles. Aproveita que você usa um init system moderno (systemd, OpenRC, runit e afins) e usufrua de um desktop minimalista sem deixar a sua configuração complicada.

Resultado final:

/home/user/.config/rc
├── conf.d
│   └── ollama-user.conf
├── init.d
│   ├── hyprpaper
│   ├── ollama-user
│   ├── pipewire
│   ├── pipewire-pulse
│   ├── ssh-agent
│   ├── waybar
│   └── wireplumber
├── rc.conf
└── runlevels
└── wayland
├── hyprpaper -> /home/user/.config/rc/init.d/hyprpaper
├── ollama-user -> /home/user/.config/rc/init.d/ollama-user
├── pipewire -> /home/user/.config/rc/init.d/pipewire
├── pipewire-pulse -> /home/user/.config/rc/init.d/pipewire-pulse
├── ssh-agent -> /home/user/.config/rc/init.d/ssh-agent
├── waybar -> /home/user/.config/rc/init.d/waybar
└── wireplumber -> /home/user/.config/rc/init.d/wireplumber

5 directories, 16 files

Quem quiser mais detalhes sobre algum serviço específico é só comentar. Forte abraço!


  1. WM é uma sigla para Window Manager que significa “Gestor de janela” em português. ↩︎