Anda di halaman 1dari 25

B--b do Systemd

O sistema de superviso e inicializao de servios Systemd foi anunciado como o novo,


revolucionrio e totalmente inovador substituto do venervel SysVinit. De fato, na descrio
terica ele parece ser muito poderoso, embora menos flexvel do que uma srie de scripts de
shell.
Para testar o Systemd, resolvi experiment-lo em minha mquina pessoal de produo,
equipada com um sempre moderno Gentoo.

Instalao
A quem se interessar pelo Systemd, ele est facilmente disponvel para Fedora e tambm para
Gentoo.
Depois de instalar e configurar tudo, basta iniciar o sistema normalmente, mas com uma
opo para o kernel:
init=/sbin/systemd

Problema 1: peso
Entre seus poderes especiais, cobertos num artigo anterior aqui no blog, est o de garantir
que determinado servio foi parado e, com ele, todos os processos filhos (e netos, bisnetos...)
que este havia gerado. O subsistema que permite esse recurso conhecido como Cgroups
(Control Groups, ou grupos de controle) e reside no kernel. Os Cgroups permitem atribuir
rtulos (ou tags) a cada processo que for iniciado no sistema, alm de registrar tais
informaes (processos e seus respectivos rtulos) num pseudo-sistema de arquivos, o que
facilita imensamente sua consulta por qualquer programa ou usurio.
Contudo, o recurso de Cgroups conhecido por requerer mais ciclos de CPU a cada criao
de um novo processo, assim como em todas as rotinas de gerenciamento de processos internas
ao kernel.
Nos meus testes, o sistema no ficou mais lento. O recurso de Cgroups j existe h bastante
tempo no kernel 2.6, mas somente agora est tendo um maior uso, tanto em funo do
Systemd quanto em virtude do "patch maravilha" que reduz drasticamente a percepo de
latncia pelo usurio. Se voc nunca usou os Cgroups, em breve chegar a hora de ativ-lo no
seu kernel, pois ele tende a se tornar um item indispensvel.
Problema 1 resolvido.

Problema 2: montagem de sistemas de arquivos


O Systemd dotado de inteligncia onde necessrio. Ele l o arquivo /etc/fstab durante a
inicializao do sistema, e cria as polticas de montagem automtica dos sistemas de arquivos
descritos no arquivo. Desde meu primeiro boot com o Systemd, a partio raiz foi montada
com sucesso e de forma transparente, assim como todas as demais, incluindo a /home.
Diferentemente do que eu imaginava a princpio, o Systemd no faz uso do servio autofs. Ele
utiliza o suporte do kernel ao autofs, mas implementa internamente as montagens
automticas, de forma totalmente independente do servio autofs.
No entanto, no meu sistema, eu j usava o servio autofs para realizar a montagem automtica
de uma partio btrfs, assim como a do meu /home. Portanto, hora de converter meus
automounts para os arquivos do Systemd.

Estrutura da configurao do Systemd


O Systemd armazena suas configuraes de servios em diversos arquivos. Os arquivos de
automount fornecidos pelo pacote do Systemd se localizam em /lib/systemd/system/. H
arquivos com sufixos .service (servios propriamente ditos, como Apache, Postfix etc.),
.target (semelhantes no iguais aos runlevels), .automount e .mount, entre outros.
O Systemd no precisa do arquivo /etc/fstab para saber quais sistemas de arquivos montar
em quais diretrios. Cada montagem definida em um arquivo .mount, que deve ter como
nome o diretrio de montagem. Exemplos:
var-run.mount
sys-kernel-debug.mount

O primeiro realiza a montagem do diretrio /var/run, enquanto que o segundo monta


/sys/kernel/debug.
O sistema de arquivos a ser montado nesses diretrios definido nos prprios arquivos.
Vejamos um trecho do arquivo var-run.mount:
[Mount]
What=tmpfs
Where=/var/run
Type=tmpfs
Options=mode=755,nosuid,nodev,noexec

Praticamente auto-explicativo, no? O arquivo define qual o sistema de arquivos


(What=tmpfs), o ponto de montagem (Where=/var/run), o tipo (Type=tmpfs) e as opes de
montagem (Options=mode=755,nosuid,nodev,noexec).
Confuso com as linhas What= e Type=? Ento vamos logo ao exemplo do /home.
cat /etc/systemd/system/home.mount
(...)
[Mount]

What=/dev/sda7
Where=/home
Type=ext4
Options=noatime
Minha partio /dev/sda7

ser montada em /home, com tipo ext4 e com a opo de


montagem noatime. Simples, no?
Problema 2 quase resolvido.
Se tivermos somente um arquivo .mount, o Systemd montar o sistema de arquivos assim que
possvel isto , durante a inicializao do sistema e no o desmontar mais. Para
reduzirmos o tempo de boot, o ideal permitir que os sistemas de arquivos no essenciais ao
prprio boot sejam montados sob demanda quando necessrio, certo? a que entra o arquivo
com sufixo .automount
cat /etc/systemd/system/home.automount
(...)
[Automount]
Where=/home

Pronto. Com esse arquivo, o Systemd j sabe que, sempre que algum processo acessar /home,
ele deve ser montado, caso j no esteja montado.
A princpio, pode parecer que os arquivos .mount e .automount poderiam ser unidos em um
nico, mas importante definir se determinado sistema de arquivos deve permanecer montado
ou no. E se voc acha que os arquivos .automount deveriam poder existir sozinhos isto ,
sem um .mount para acompanh-los e definir os dados da montagem lembre-se que voc
pode preferir que determinado sistema de arquivos seja montado sob demanda em uma
situao, mas que permanea montado em outra. Mais sobre isso em um post futuro.
Com os dois arquivos o .mount e o .automount criados, basta fazer com que um deles (no
nosso caso, o home.automount, pois queremos a montagem sob demanda) seja carregado
pelo nosso .target padro:
# systemctl enable home.automount

Agora sim: problema 2 resolvido.

Arquitetura da inicializao
Voc j conhece o sistema de inicializao bastante idoso que ainda est presente na maioria
das distribuies GNU/Linux, o SysVinit. Trata-se do sistema de inicializao criado para o
UNIX System V. Ele emprega o diretrio /etc/init.d/ para armazenar os scripts de
inicializao e tambm utiliza o conceito de runlevels. Sua grande desvantagem, no entanto,
a velocidade e a completa ausncia de paralelismo.
A baixa velocidade do SysVinit advm de seu uso de scripts de shell, fceis de escrever e
entender, mas tradicionalmente lentos na execuo. J houve tentativas de medidas para
solucionar isto por meio da substituio do shell usado para os scripts supostamente, o
Bash mais lento do que shells mais simples, e substitu-lo por um desses mais simples
3

poderia acelerar um pouco a execuo dos scripts. H at quem tenha tentado substituir o
shell por Python, assembly x86 ou C, mas esses projetos jamais deixaram seus nichos iniciais.
Com relao ausncia de paralelismo, as notas de lanamento do Debian 6.0 //Squeeze//
mostram que a distribuio conseguiu converter os scripts de inicializao para permitir sua
execuo em paralelo com base em dependncias entre os prprios scripts. Alm do Debian,
vrias outras iniciativas j surgiram algumas at j desapareceram para acrescentar
paralelismo ao sistema de inicializao, com maior ou menor grau de sucesso.

Arquitetura do Systemd
O Systemd, conforme j expliquei, visa a agir nos dois principais pontos problemticos do
SysVinit: shell e paralelismo.
Para eliminar o uso do shell, o Systemd realiza todas as chamadas redundantes isto ,
aquelas presentes na maioria dos scripts de forma embutida no binrio /sbin/systemd. E
para permitir o paralelismo, o Systemd abre sockets para comunicao entre os servios, de
forma que todos os servios marcados pelo administrador como desejados possam iniciar em
paralelo e, caso dependam de outros servios, estes tambm sejam iniciados sob demanda.

Diretrios do Systemd
Instalar o Systemd, no momento, uma tarefa restrita a algumas distribuies, como Fedora,
openSUSE, Debian, Gentoo, Arch e Ubuntu.
Os arquivos responsveis pelos servios no Systemd se localizam em
/lib/systemd/system/. No entanto, como cada administrador pode e deve, como no caso
das montagens de sistemas de arquivos criar os seus prprios servios, h um diretrio
especfico para esse tipo de personalizao: /etc/systemd/system/.
Ou seja: no mexa no /lib/systemd/system/. Mexa somente em
/etc/systemd/system/. No se espera que o diretrio /lib/ tenha arquivos de
configurao alterados pelo administrador.

Uma listagem do diretrio /lib/systemd/system/ logo aps a instalao revela algo em


torno de 140 arquivos e diretrios. Estes so servios que o pacote j traz configurados e
instalados para voc. Voc pode se basear neles para escrever os seus prprios servios
como o do primeiro artigo desta srie.

Arquivos de servios
Um fato muito positivo sobre o Systemd que a documentao j est muito bem feita. O
pacote do Systemd j traz as pginas de manual de cada tipo de servio. Experimente:
4

$ man -k systemd.
systemd.automount
systemd.conf
systemd.device
systemd.exec
systemd.mount
systemd.path
systemd.service
systemd.snapshot
systemd.socket
systemd.special
systemd.swap
systemd.target
systemd.timer
systemd.unit

(5)
(5)
(5)
(5)
(5)
(5)
(5)
(5)
(5)
(7)
(5)
(5)
(5)
(5)

systemd
systemd
systemd
systemd
systemd
systemd
systemd
systemd
systemd
special
systemd
systemd
systemd
systemd

automount configuration files


manager configuration file
device configuration files
execution environment configuration
mount configuration files
path configuration files
service configuration files
snapshot units
socket configuration files
systemd units
swap configuration files
target configuration files
timer configuration files
unit configuration files
de servios (systemd.service), e ela que

H uma pgina de manual para os arquivos


devemos consultar para entender ou desenvolver arquivos de servios.

No entanto, por ora, vamos apenas configurar nosso sistema para utilizar o Systemd e
alcanarmos a mesma funcionalidade que temos com o sistema de init tradicional.

Ativao dos servios


Suponho que os pacotes do Systemd j estejam instalados. Isto significa que voc j tem
disposio o comando systemctl, que permitir configurar os servios antes mesmo de voc
iniciar o sistema por ele.
Voc sabe quais servios ativos na sua mquina neste momento? Se sim, ative cada um deles
com o comando systemctl enable:
# systemctl enable acpid.service
# systemctl enable iptables.service
# systemctl enable cron.service
# systemctl enable home.automount
(e assim por diante)

Caso no exista algum servio de que voc precise improvvel voc precisar cri-lo.
Felizmente, fcil: basta usar este modelo extremamente minimalista:
[Unit]
Description=Descrio do servio, como "Cron daemon" ou "ACPI daemon"
[Service]
Type=forking
ExecStart=/etc/init.d/**servio** start
ExecStop=/etc/init.d/**servio** stop

A documentao do Gentoo oferece alguns exemplos de arquivos de servios que no esto


includos nos pacotes do Systemd.

Runlevels e dependncias
O Systemd dispensa o conceito de runlevels. Porm, como todos os sistemas ainda o utilizam,
existe um esquema de compatibilidade. Confira os diretrios
/lib/systemd/system/runlevel*.target:
$ cd /lib/systemd/system/
$ ls -l runlevel*.target
(...) runlevel0.target ->
(...) runlevel1.target ->
(...) runlevel2.target ->
(...) runlevel3.target ->
(...) runlevel4.target ->
(...) runlevel5.target ->
(...) runlevel6.target ->

poweroff.target
rescue.target
multi-user.target
multi-user.target
multi-user.target
graphical.target
reboot.target

A est a camada de compatibilidade: runlevels se comportam como servios .target, que na


realidade so apenas conjuntos de dependncias entre servios.
Quando o sistema manda o Systemd carregar o runlevel 5, ele carrega, na realidade, o
graphical.target.

E o que esse target carrega?


Servios .target sempre vm acompanhados de um diretrio .target.wants/, que
contm... novamente links simblicos:
$ cd /lib/systemd/system/
$ ls -l multi-user.target.wants/
(...) dbus.service -> ../dbus.service
(...) getty.target -> ../getty.target
(...) systemd-ask-password-wall.path -> ../systemd-ask-passwordwall.path
(...) systemd-user-sessions.service -> ../systemd-user-sessions.service
Interessante, no? Quando o Systemd carrega o target multi-user.target, ele inicia os

servios dbus.service, systemd-user-sessions.service, systemd-ask-passwordwall.path e tambm chama o target getty.target (j d para imaginar que este target seja
responsvel por iniciar os getty's, certo?).
$ cd /lib/systemd/system/
$ ls -l getty.target.wants/
ls: impossvel acessar getty.target.wants/:
Arquivo ou diretrio no encontrado
Opa! Mas eu no disse que um arquivo .target sempre vinha

acompanhado de um diretrio

.target.wants/?

Lembra que o administrador tambm configura o Systemd pelo diretrio /etc/? Vamos
procurar o getty.target.wants/ l:
$ ls -l /etc/systemd/system/getty.target.wants/
(...) getty@tty1.service -> /lib/systemd/system/getty@.service
(...) getty@tty2.service -> /lib/systemd/system/getty@.service

(...)
(...)
(...)
(...)

getty@tty3.service
getty@tty4.service
getty@tty5.service
getty@tty6.service

->
->
->
->

/lib/systemd/system/getty@.service
/lib/systemd/system/getty@.service
/lib/systemd/system/getty@.service
/lib/systemd/system/getty@.service

Interessantssimo! Como cabe somente ao administrador definir quais tty's recebero um


getty, esse diretrio j criado, por padro, no /etc/systemd/system/.
Por padro, o Systemd carrega um getty nos tty's 1 a 6. E veja tambm que todos os getty's
so links simblicos para o mesmo servio (/lib/systemd/system/getty@.service).
Servios com nome <algo>@.service tm esta propriedade: podem existir em vrias
instncias, sobre outros servios ou sobre outros recursos. Mais a este respeito num post
futuro.
E ento, voc consegue dizer em qual target foram adicionados aqueles servios que voc
mandou iniciar pessoalmente?
Por padro, eles so colocados em /etc/systemd/system/multi-user.target.wants/.

Ativao do Systemd
Pronto(a) para usar o Systemd? Lembre-se: este software ainda est em desenvolvimento.
Portanto, seu uso em produo no recomendado e pode levar a resultados
indesejveis. Esteja avisado(a).
Para fazer seu sistema usar o Systemd em vez do /sbin/init, basta informar isto ao seu
carregador de boot. No caso do GRUB, basta adicionar linha do kernel (aquela que comea
com kernel) o comando:
init=/sbin/systemd

J se voc usa o LILO, preciso acrescentar esse mesmo comando linha append.
Minha recomendao ter duas entradas para seu sistema no seu carregador de boot: uma
com o init padro e outra com init=/sbin/systemd.
Quando voc estiver se sentindo confiante para dar o prximo passo, reinicie seu sistema e
escolha a opo com o Systemd.
Ento voc iniciou seu sistema pelo Systemd, certo? Ento, hora de conferir quais servios
esto ativados.
Sem argumentos, o comando systemctl exibe uma lista dos servios iniciados no sistema:
$ systemctl
UNIT
boot.automount
dev-hugepages.automount
System Aut

LOAD
ACTIVE SUB
loaded active waiting
loaded active waiting

JOB

Automount /boot
Huge Pages File

dev-mqueue.automount
File S
home.automount
acpid.service
iptables.service
Sound Archi
dbus.service
Message Bus
fcron.service
gdm@tty9.service
Manager on t
getty@tty1.service
getty@tty2.service
getty@tty3.service
(...)

loaded active waiting

POSIX Message Queue

loaded active running


loaded active running
loaded active exited

Automount /home
ACPI Event Daemon
Advanced Linux

loaded active running

D-Bus System

loaded active running


loaded active running

fcron Cron Daemon


GNOME Display

loaded active running


loaded active running
loaded active running

Getty on tty1
Getty on tty2
Getty on tty3

Esta sada nos mostra os servios que o administrador (voc) pediu que fossem iniciados
note que alguns terminam em .automount, indicando tratar-se de uma montagem sob
demanda. Alm dos nomes dos servios, a coluna LOAD informa se o servio foi carregado.
ACTIVE diz se o servio est ativo ou inativo. SUB d mais detalhes sobre a coluna ACTIVE. No
caso dos servios .automount, note que seu SUB waiting, pois so montagens sob demanda
e esto aguardando para serem utilizadas. A maioria dos servios tem active na coluna SUB,
indicando que seus respectivos daemons esto em execuo, conforme esperado.
J o servio iptables.service foi carregado e saiu (exited na coluna SUB), o que
provavelmente indica que o servio no possui um daemon, mas apenas execute um comando.
De fato, se abrirmos o arquivo /etc/systemd/system/iptables.service, veremos o
seguinte:
$ less /etc/systemd/system/iptables.service
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
[Unit]
Description=iptables
DefaultDependencies=false
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/iptables-restore /var/lib/iptables/rules-save
[Install]
WantedBy=sysinit.target

Note que a linha responsvel pela execuo do servio (ExecStart=) contm apenas o
comando para que o utilitrio /sbin/iptables-restore carregue as regras do filtro de
pacotes armazenadas em um outro arquivo. Feito isto, o comando /sbin/iptables-restore
termina sua execuo.
Em comparao com o servio acpid.service, que mostrava active na coluna SUB,
veremos que a linha ExecStart= carrega, sim, um daemon que permanece ativo:
8

$ less /etc/systemd/system/acpid.service
[Unit]
Description=ACPI Event Daemon
After=syslog.target
# This could probably benefit from socket activation, but honestly I
think it
# is time for acpid to go away, and hence I am not planning to spend the
time
# to add socket activation here. We use Type=forking to ensure that the
# communication sockets are in place before boot proceeds with any
service
# needing this service. Would acpid support socket activation we could
use
# Type=simple here.
[Service]
ExecStart=/usr/sbin/acpid -f
[Install]
WantedBy=multi-user.target
A opo -f do comando /usr/sbin/acpid

faz justamente isto: mantm o daemon em


primeiro plano (foreground), e isto que faz o comando systemctl retornar active na
coluna SUB.

Outras opes do systemctl


A melhor fonte de informao sobre o systemctl sua tima pgina de manual (man 1
systemctl). Ela nos diz, por exemplo, que --full exibe os nomes dos servios sem abrevilos, e que -t automount exibe somente unidades do tipo .automount.
Alm disso, note que o comando systemctl mostra somente as unidades carregadas. Para
incluir na listagem as no carregadas, basta usar -a.
Ativar e desativar unidades j deve fazer parte da sua rotina:
# systemctl enable fcron.service
# systemctl disable anacron.service

Da mesma forma, iniciar, reiniciar e parar servios tambm bem fcil:


# systemctl start fcron.service
# systemctl restart sshd.service
# systemctl stop anacron.service

Existe tambm um comando para recarregar a configurao da unidade:


# systemctl reload sshd.service

Para consultar informaes detalhadas sobre uma determinada unidade, use systemctl
status:
# systemctl status sshd.service
sshd.service - SSH Secure Shell Service
Loaded: loaded (/lib/systemd/system/sshd.service)

Active: active (running) since Mon, 14 Feb 2011 15:43:35 -0200;


43min ago
Main PID: 1737 (sshd)
CGroup: name=systemd:/system/sshd.service
+ 1737 /usr/sbin/sshd -D

Poweroff, halt e reboot


Com o SysVinit, quando voc usa os comandos poweroff ou reboot, o sistema entra nos
runlevels 0 ou 6 e coordena o desligamento de todos os servios. O systemctl (ainda) no
compatvel com esses comandos.
Mas felizmente a diferena no to grande: os comandos so:

Desligar: systemctl poweroff

Reiniciar: systemctl reboot

Para voc continuar usando os comandos que sempre usou, basta adicionar pequenos scripts
ao diretrio /usr/local/sbin/. Por exemplo, crie o script /usr/local/sbin/poweroff
com o seguinte contedo:
#!/bin/bash
# Captura o nome do processo com PID=1
using_systemd="`ps -p 1 |grep systemd`"
if [[ "$using_systemd" = "systemd" ]]; then
/bin/systemctl poweroff
else
/sbin/poweroff
fi
Em seguida, s para garantir, verifique se o script /usr/local/sbin/poweroff

ser

efetivamente executado quando chamarmos simplesmente poweroff:


# which poweroff
/usr/local/sbin/poweroff

Este post comea com a mo na massa: vamos criar uma nova unidade de servio para o
fcron, j apresentado, elogiado e esmiuado anteriormente neste blog.
Primeiramente, vamos tomar alguma outra unidade de servio como exemplo? Que tal o
servio vixie-cron (o cron tradicional), que vem por padro nos pacotes atuais do Systemd, no
arquivo /lib/systemd/system/vixie-cron.service?
$ cat /lib/systemd/system/vixie-cron.service
[Unit]
Description=Vixie Cron Daemon
[Service]
Type=forking
ExecStart=/usr/sbin/cron

10

ExecStop=/bin/kill -TERM $MAINPID


[Install]
WantedBy=multi-user.target

Simples, no? Vamos examinar esse arquivo.


A descrio da unidade (lembrando: unidades so servios, mounts, automounts, sockets etc.)
diz Vixie Cron Daemon.
Como se trata de uma unidade de servio, necessrio incluir a seo [Service]. Nela,
definido o tipo (Type) do servio como forking (tpico de daemons que iniciam subprocessos
e terminam o processo pai), o comando para iniciar o servio ExecStart e o comando para
parar o servio (ExecStop).
Por ltimo, na seo [Install], que trata do "cadastro" dessa unidade no Systemd,
informado qual target (lembra dos targets? Foram explicados no segundo post desta srie)
deve chamar esse servio (multi-user.target, no caso).
Como o fcron um substituto do vixie-cron, podemos simplesmente trocar no arquivo as
partes diferentes entre os dois.

Troca-troca
Vamos comear copiando o arquivo para um novo local com um novo nome. O local,
evidentemente, /etc/systemd/system/, onde residem todas as configuraes e alteraes
feitas pelo administrador:
# cp /lib/systemd/system/vixie-cron.service

/etc/systemd/system/fcron.service
Vamos comear alterando a descrio para algo como Fcron Daemon. Alm disso,

qual o

binrio do fcron?
# which fcron
/usr/sbin/fcron
J temos as linhas Description

e ExecStart do fcron. E a linha ExecStop? Como o fcron

deve ser terminado?


Sempre uma boa ideia conferir como o sistema faz isso. O pacote do fcron para sua
distribuio certamente j traz seu script de inicializao que fica em /etc/init.d/. No meu
sistema de teste, o fcron terminado simplesmente enviando um sinal TERM ao processo.
Moleza!
ExecStop=/bin/kill -TERM $MAINPID

O prprio Systemd se encarrega de acompanhar o PID do servio. Quanta competncia... :)


Ento, temos nosso arquivo de unidade do servio do fcron assim:
11

$ cat /etc/systemd/system/fcron.service
[Unit]
Description=Fcron Daemon
[Service]
Type=forking
ExecStart=/usr/sbin/fcron
ExecStop=/bin/kill -TERM $MAINPID
[Install]
WantedBy=multi-user.target

Mas ser que ele funciona? Testemos!


# systemctl stop vixie-cron.service
# systemctl start fcron.service
# systemctl status fcron.service
fcron.service Loaded:
Active:
57s ago]
Process:
CGroup:

fcron Cron Daemon


loaded (/etc/systemd/system/fcron.service)
active (running) since [Wed, 16 Feb 2011 15:29:24 -0200;
1880 (/usr/sbin/fcron, code=exited, status=0/SUCCESS)
name=systemd:/systemd-1/fcron.service
+ 1881 /usr/sbin/fcron

Funciona! \o/

Melhorias
A pgina de manual chamada systemd.service (man 5 systemd.service) explica os
arquivos de unidades de servio do Systemd e diz que, no caso de servios do tipo forking,
uma boa ideia usar a opo PIDFile para apontar para o arquivo que contm o PID do
processo principal desse servio. Esse arquivo pode ser importante para o Systemd enviar os
sinais adequados (como o TERM no caso do nosso ExecStop) aos processos corretos. Sempre
que possvel, esse PID que o Systemd utiliza na varivel $MAINPID.
Ento, sejamos educados e faamos essa alterao, incluindo um PIDFile. Primeiro, vamos
ver onde exatamente o fcron coloca esse arquivo:
# grep pidfile /etc/fcron/fcron.conf
pidfile

/var/run/fcron.pid

Conforme esperado, o arquivo onde o prprio fcron informa o PID de seu processo principal
/var/run/fcron.pid.
Sabendo isto, podemos editar nosso arquivo fcron.service:
$ cat /etc/systemd/system/fcron.service
[Unit]
Description=fcron Cron Daemon
[Service]

12

Type=forking
ExecStart=/usr/sbin/fcron
ExecStop=/bin/kill -TERM $MAINPID
PIDFile=/var/run/fcron.pid
[Install]
WantedBy=multi-user.target

Reload
Sabemos tambm que o Fcron entende o sinal SIGUSR1 como uma ordem para que ele
recarregue seus arquivos de configurao, independente de haver alteraes (consulte man 8
fcron). Ou seja, se o administrador alterou uma configurao do fcron e ela no teve efeito
imediato, ela s entrar em vigor se o servio for reiniciado ou se o processo do fcron
receber um sinal SIGUSR1.
O Systemd oferece suporte a um comando para recarregar um servio (diferente de reiniciar
o servio) por meio do comando systemctl reload //servio//. No arquivo de unidade
de servio, a instruo de como fazer isso fica na diretiva ExecReload.
Ento, que tal incluirmos isso no nosso arquivo do servio, logo abaixo de ExecStop? Nosso
arquivo ficaria assim:
$ cat /etc/systemd/system/fcron.service
[Unit]
Description=fcron Cron Daemon
[Service]
Type=forking
ExecStart=/usr/sbin/fcron
ExecStop=/bin/kill -TERM $MAINPID
ExecReload=/bin/kill -USR1 $MAINPID
PIDFile=/var/run/fcron.pid
[Install]
WantedBy=multi-user.target

Nota importante: A verso do Systemd includa no repositrio do Fedora 14 a de nmero


10, um tanto desatualizada (a atual a 17). Ela no entende corretamente o comando
ExecReload e, em vez de passar o sinal USR1, passa o TERM, mesmo que o comando seja
systemctl reload fcron.service. Neste momento, a nica forma para ter um Systemd
mais recente no Fedora 14 seria compilar o cdigo-fonte.

Substituio do vixie-cron
O vixie-cron, como vimos est configurado para ser chamado pelo target multi-user. Se
quisermos substitu-lo pelo fcron, precisamos retirar o vixie-cron:
# systemctl disable vixie-cron

E finalmente j podemos ativar o incio automtico do nosso querido fcron:


13

# systemctl enable vixie-cron


ln -s '/etc/systemd/system/fcron.service' '/etc/systemd/
system/multi-user.target.wants/fcron.service'
Note que o prprio systemctl j cria automaticamente o link simblico em multiuser.target.wants/

apontando para o servio do fcron.

Neste ponto, voc j deve estar usando o Systemd em seu sistema e substituindo os seus
principais servios por arquivos .service do Systemd.
Vejamos, ento, como facilitar e estender essa tarefa.

Compatibilidade com SysVinit


O Systemd no melhor que o SysVinit em absolutamente tudo. Por usar scripts para subir
servios, o SysVinit consegue fazer diversos testes e verificaes para tomar decises e
carregar informaes externas na hora de iniciar o servio.
Seria muito bom se o Systemd tambm pudesse fazer isso, no?
E no que ele consegue? Basta usar o script do SysVinit nos comandos ExecStart e
ExecStop. Por exemplo, aquele nosso servio do Fcron poderia ter ficado assim:
$ cat /etc/systemd/system/fcron.service
[Unit]
Description=fcron Cron Daemon
[Service]
Type=forking
ExecStart=/etc/init.d/fcron start
ExecStop=/etc/init.d/fcron start
[Install]
WantedBy=multi-user.target

Muito menos trabalho, no?


O que voc est esperando? V correndo criar cpias .service de tudo que existe no seu
/etc/init.d/! :)

Carregamento de variveis
Outro recurso interessante do Systemd a capacidade de carregar variveis de um arquivo.
No Fedora, os scripts em /etc/init.d/ consultam os arquivos em /etc/sysconfig/. Esses
arquivos podem conter variveis com opes de execuo dos servios, como nmeros de
porta de rede para escutar, parmetros para ir ou no para segundo plano e assim por diante.
No Gentoo, sistema que estou usando para estes testes (por contar com uma verso
14

constantemente atualizada do Systemd), o diretrio /etc/conf.d/ que contm essas


informaes de execuo.
Vejamos o exemplo do servio portmap:
$ cat /etc/init.d/portmap
...
start() {
...
ebegin "Starting portmap"
start-stop-daemon --start --quiet --exec /sbin/portmap -- $
{PORTMAP_OPTS}
...
A poro da funo start() que efetivamente sobe o servio faz o seguinte: executa

e usa as opes definidas na varivel ${PORTMAP_OPTS} no arquivo de


configurao desse servio, ou seja, /etc/conf.d/portmap.
/sbin/portmap

Por sua vez, o arquivo /etc/conf.d/portmap contm o seguinte:


$ cat /etc/conf.d/portmap
...
# For a full list, just run `portmap -h`.
PORTMAP_OPTS="-l"
Ele define a varivel ${PORTMAP_OPTS} com o contedo -l.

Portanto, o
/etc/init.d/portmap, ao subir o servio, acaba executando:
/sbin/portmap -- -l

Esse -- indica ao comando que tudo que vem em seguida so opes, e no


nomes de arquivos ou outra coisa qualquer. Os desenvolvedores do script fazem
isso s para garantir que no haja falhas de interpretao do comando.

Boa notcia: o Systemd tambm capaz de usar variveis contidas em um arquivo.


Vamos criar um substituto bem simples para o nosso servio do portmap:
$ cat /etc/systemd/system/portmap.service
[Unit]
Description=Portmapper for RPC-related services
[Service]
Type=forking
ExecStart=/sbin/portmap
PIDFile=/var/run/portmap.pid
[Install]
WantedBy=multi-user.target

Este script sobe o portmap sem consultar o arquivo de opes em /etc/conf.d/. Ento, que
tal informarmos a opo de configurao dentro do prprio arquivo?
$ cat /etc/systemd/system/portmap.service

15

[Unit]
Description=Portmapper for RPC-related services
[Service]
Type=forking
Environment=PORTMAP_OPTS=-l
ExecStart=/sbin/portmap $PORTMAP_OPTS
PIDFile=/var/run/portmap.pid
[Install]
WantedBy=multi-user.target

Esta a forma "sujinha" de resolver o problema. Ela funciona, mas exige a definio das
variveis dentro do prprio arquivo de unidade do servio. No SysVinit, isto seria equivalente
a definir a varivel ${PORTMAP_OPTS} dentro do script de inicializao, em vez de usar um
arquivo s para essa configurao.
Vejamos, ento, a soluo mais "limpinha":
$ cat /etc/systemd/system/portmap.service
[Unit]
Description=Portmapper for RPC-related services
[Service]
Type=forking
#Environment=PORTMAP_OPTS=-l
EnvironmentFile=/etc/conf.d/portmap
ExecStart=/sbin/portmap $PORTMAP_OPTS
PIDFile=/var/run/portmap.pid
[Install]
WantedBy=multi-user.target

Agora sim! Passamos ao Systemd a informao de que as variveis de execuo do servio


portmap.service se encontram no arquivo /etc/conf.d/portmap. Ou seja, o
portmap.service vai consultar o arquivo /etc/conf.d/portmap para descobrir o valor da
varivel ${PORTMAP_OPTS}.
No entanto, se voc iniciar o servio portmap.service agora, ver que ele no carrega a
varivel ${PORTMAP_OPTS}. Por que ser???
A explicao se encontra no blog de Alexander Patrakov: o Systemd no entende variveis
definidas com aspas. E veja novamente um pouco acima como o /etc/conf.d/portmap
define a varivel ${PORTMAP_OPTS}: com aspas.
Ento, para tornar o arquivo /etc/conf.d/portmap compreensvel pelo Systemd, basta
retirar as aspas:
$ cat /etc/conf.d/portmap
...
PORTMAP_OPTS=-l

Feito isso, tudo funcionar conforme esperado.


16

Note tambm que o Systemd no entende variveis com chaves em volta:


${PORTMAP_OPTS}

Portanto, nos arquivos .service, use sempre a notao:


$PORTMAP_OPTS

Diretrio de configuraes para servios


Mas espere um pouco. Eu quero ter o Systemd e o OpenRC (sistema de init do Gentoo)
instalados na minha mquina. O Systemd ainda no est 100% pronto, ento eu posso acabar
tendo problemas que s o OpenRC pode resolver.
No entanto, se eu alterar todas as definies de variveis do /etc/conf.d/, os scripts do
OpenRC (e do SysVinit, caso seu sistema o utilize) deixaro de funcionar!
Soluo 1: um novo diretrio de configurao. Na minha mquina de testes, eu criei um
diretrio /etc/systemd/myconfigs/ e copiei para dentro dele todos os arquivos de
configurao do /etc/conf.d/, retirando as aspas:
# for arq in /etc/conf.d/*; do
sed -e 's/="\(.*\)"/=\1' /etc/conf.d/${arq} > \
/etc/systemd/myconfigs/${arq}.config
done

Soluo 2: dois arquivos de configurao no mesmo diretrio (por exemplo,


/etc/conf.d/portmap e /etc/conf.d/portmap.config). Com isto, voc evita a criao de
um novo diretrio de configurao. Porm, duplica os arquivos de configurao no mesmo
diretrio, o que pode causar confuso:
# for arq in /etc/conf.d/*; do
sed -e 's/="\(.*\)"/=\1' /etc/conf.d/${arq} > \
/etc/conf.d/${arq}.config
done

Depois de optar pela sua forma preferida, basta informar o arquivo correto no .service:
$ cat /etc/systemd/system/portmap.service
[Unit]
Description=Portmapper for RPC-related services
[Service]
Type=forking
EnvironmentFile=/etc/systemd/myconfigs/portmap.config
ExecStart=/sbin/portmap $PORTMAP_OPTS
PIDFile=/var/run/portmap.pid
[Install]
WantedBy=multi-user.target

Notas importantes:
17

possvel definir mais de uma varivel no arquivo de configurao e fazer


referncia a todas elas no arquivo .service.

Os arquivos de configurao para o Systemd no so interpretados por um


shell. Portanto, no permitido realizar operaes dentro deles. Somente a
definio de variveis permitida.

Caso haja mltiplas linhas EnvironmentFile no arquivo .service, somente a


ltima ser levada em considerao.

Caso haja mltiplas definies da mesma varivel no arquivo de


configurao, somente a ltima ser levada em considerao.

Exemplo final: carregador de mdulos


O Systemd capaz de carregar mdulos do kernel sob demanda. Porm, eu gosto de carregar
alguns mdulos que nenhum servio pede por exemplo, os mdulos dos sensores de
temperatura da CPU, uasdos pelo gkrellm para exibir informaes importantes na minha rea
de trabalho.
$ cat /etc/systemd/myconfigs/modules.config
MODULES=r8169 usbcore ehci-hcd uhci-hcd vboxdrv vboxnetadp
vboxnetflt fuse power-meter ds1682 pcf8574 tsl2550 ad7414
coretemp hwmon pcf8591 snd-hda-codec-intelhdmi
zram:num_devices=2
Como criar um script para carregar mdulos? Basta usar ExecStart=/sbin/modprobe
$MODULES,

certo? Ento vamos l:

# cat /etc/systemd/system/load-modules.service
[Unit]
Description=Load arbitrary modules
[Service]
Type=oneshot
EnvironmentFile=/etc/systemd/myconfigs/modules.config
ExecStart=/sbin/modprobe $MODULES
[Install]
WantedBy=multi-user.target

Ser que vai funcionar?


Experimente na sua mquina e me diga. :)
Infelizmente no funcionou, certo? Se voc forneceu mais de um mdulo na varivel
$MODULES no arquivo de configurao, o comando executado pelo Systemd foi:
/sbin/modprobe mdulo1 mdulo2 mdulo3

Porm, o modprobe s carrega um mdulo por vez. Ele entende os demais argumentos como
opes do mdulo (primeiro argumento). Confira isso com o comando:
18

# modprobe iptable_nat opt_LOG


insmod (...)/kernel/net/ipv4/netfilter/nf_defrag_ipv4.ko
insmod (...)/kernel/net/ipv4/netfilter/nf_conntrack_ipv4.ko
insmod (...)/kernel/net/ipv4/netfilter/nf_nat.ko
insmod (...)/kernel/net/ipv4/netfilter/iptable_nat.ko opt_LOG
FATAL: Error inserting iptable_nat (.../kernel/net/ipv4/
netfilter/iptable_nat.ko): Unknown symbol in module, or
unknown parameter (see dmesg)
O modprobe carrega as dependncias do mdulo, mas retorna erro ao tentar carregar

o mdulo

chamado (iptable_nat, no exemplo).


Ento, precisamos apelar para um script que receba uma lista de mdulos (com eventuais
parmetros, separados por :) e consiga carregar um de cada vez com o modprobe. A soluo
que implementei na mquina de testes:
$ cat /usr/local/sbin/load-modules.sh
#!/bin/bash
MODPROBE=/sbin/modprobe
# The module string is formatted like this:
# module1 module2 module3:option1=value1 module4:option1=
value1:option2=value2
[[ "$#" -le "0" ]] && exit 0
for module in $*
do
${MODPROBE} ${module/:/ } &>/dev/null
echo "${MODPROBE} ${module/:/ }" >> /tmp/tralala
done
# Always return 0
exit 0

Com esse script devidamente gravado e com modo octal 700 (permisso de execuo, leitura
e gravao somente para o usurio root pense sempre na segurana!), podemos alterar
nosso arquivo .service da seguinte forma:
# cat /etc/systemd/system/load-modules.service
[Unit]
Description=Load arbitrary modules
[Service]
Type=oneshot
EnvironmentFile=/etc/systemd/myconfigs/modules.config
ExecStart=/usr/loca/sbin/load-modules.sh $MODULES
[Install]
WantedBy=multi-user.target

Auto-crtica
Se j vamos usar um script para carregar os mdulos, por que no deixamos que o prprio
script carregue os mdulos a partir do arquivo de configurao?
19

Com isso, o arquivo de configurao poderia ser mais organizado, compondo a lista de
mdulos de forma mais organizada, como:
# Rede
MODULES="$MODULES r8169:opo1=valor:opo2=valor"
# USB
MODULES="$MODULES usbcore ehci-hcd uhci-hcd"
...

A opo pelo "engessamento" do Systemd foi justamente para reduzir o uso de scripts de shell
na inicializao uma das motivaes e metas do Systemd.
Contudo, talvez tenhamos finalmente encontrado um ponto em que os ganhos com a
flexibilidade do shell so mais relevantes do que sua perda de velocidade. O Systemd bom,
mas (ainda) no perfeito. Sorte que ele est apenas comeando. ;)
Se tudo correu certo at agora, voc j deve ter um sistema todo baseado no systemd. Talvez
ele utilize a "camada de compatibilidade" com o SysVinit, chamando os scripts localizados
em /etc/init.d/ a partir dos arquivos de unidade do systemd, ou talvez voc tenha criado
os seus prprios arquivos de unidade.
Uma correo, antes que seja tarde demais: o nome do projeto systemd, segundo sua pgina
no freedesktop.org (item "Spelling"). Falha minha.

Contribuio de cdigo para o systemd


Se voc criou um arquivo de unidade que no distribudo pelo systemd upstream (ou seja,
que no veio em /lib/systemd/system/), voc pode enviar seu novo arquivo de unidade
para o bugzilla do projeto ou para a lista de discusso.

Servios sob demanda


Conforme prometido, demonstrarei neste ltimo artigo da srie como usar o systemd para
iniciar seu servio sob demanda isto , somente e imediatamente quando necessrio.

Ativao por socket


Voc conhece o "super-servidor" xinetd? Pois bem, o systemd inclui os recursos do xinetd
para iniciar servios sob demanda. Existem duas justificativas para utilizar esse tipo de
ativao sob demanda.
A primeira justificativa para acelerar a inicializao do sistema. Sistemas como o syslog
precisam ser iniciados assim que o sistema liga, claro. O syslog utilizado por todos os
demais daemons do sistema, de forma que ele certamente ser necessrio na inicializao.
Porm, servios como SSH e CUPS geralmente no tm essa necessidade to estrita. O CUPS
20

pode ser iniciado, por exemplo, somente quando um cliente na rede enviar um documento
para impresso no servidor. E o SSH pode ser iniciado somente quando um cliente desejar se
conectar. Se selecionarmos o CUPS e o SSH para serem ativados sob demanda, poderemos
pul-los na inicializao do sistema e, com isso, economizar alguns preciosos segundos.
A segunda justificativa o consumo de recursos. E esta muito mais simples: por que iniciar
servios que no sero usados muitas vezes e que no precisam responder imediatamente
quando solicitados? Se tais servios puderem ser iniciados somente quando necessrio e, ao
fim de seu uso, forem novamente desligados, poderemos economizar recursos preciosos.

Ativao por sockets na prtica


Da mesma forma como unidades .automount (montagens sob demanda) requerem uma
unidade .mount correspondente, as unidades .socket requerem unidades .service
correspondentes.
No entanto, para ativao sob demanda, o nome da unidade .service correspondente ao
socket deve terminar em @:
$ ls /lib/systemd/system/ssh*
/lib/systemd/system/sshd.service
/lib/systemd/system/sshd.socket
/lib/systemd/system/sshd@.service
Note que temos uma unidade sshd.service

e outra sshd@.service. A unidade


sshd.service pode ser usada quando for desejvel que o servio SSH esteja constantemente
ativado (ou seja, quando quisermos abrir mo da ativao sob demanda do servio SSH). J a
unidade sshd@.service utilizada para ativao via socket, em conjunto com a
sshd.socket.
Vejamos os contedos da unidade sshd@.service:
$ cat /lib/systemd/system/sshd@.service
[Unit]
Description=SSH Per-Connection Server
After=syslog.target
[Service]
ExecStart=/usr/sbin/sshd -i
StandardInput=socket

este servio que ser iniciado em cada requisio recebida no socket informado ao systemd.
Note que o comando de execuo usado nesta unidade sshd -i. Na manpage do sshd (man
8 sshd), a opo -i indica que o sshd est sendo iniciado pelo inetd (antecessor do xinetd)
ou seja, est sendo iniciado sob demanda.
E agora, a unidade do socket:
21

$ cat /lib/systemd/system/sshd.socket
[Unit]
Conflicts=sshd.service
[Socket]
ListenStream=22
Accept=yes
[Install]
WantedBy=sockets.target
A diretiva Conflicts= serve para

esta unidade parar outra unidade quando for iniciada, ou


ser parada no caso contrrio. Ou seja, o comando systemctl start sshd.service
automaticamente faz o servio sshd.socket parar, e vice-versa.
Toda unidade do tipo socket precisa de uma seo [Socket]. Nela, informada a porta onde
o servio escutar (ListenStream para TCP e ListenDatagram para UDP) e a opo entre
aceitar e rejeitar a comunicao (Accept=no significa que o servio SSH ser desativado).
Se voc desejar escutar SSH em mltiplas portas, basta usar mltiplas linhas ListenStream=,
cada uma com uma das portas.
No caso de voc precisar alterar a porta padro do SSH, lembre-se de copiar o
arquivo /lib/systemd/system/sshd.socket para /etc/systemd/system/ e editar
somente esta cpia do arquivo os arquivos em /lib/systemd/ jamais devem
ser editados.

Note tambm um ponto muito importante: a seo [Install]. fundamental que toda
unidade .socket contenha WantedBy=sockets.target. Este target o responsvel por
iniciar todos os sockets na inicializao do sistema. Assim que o seu sistema iniciar, ele abrir
o(s) socket(s) especificado(s) em cada servio do sockets.target e o prprio systemd
escutar em todos eles. Assim que for recebida uma comunicao em um desses sockets (por
exemplo, um pacote na porta TCP 22, em nosso exemplo), o systemd iniciar o servio
sshd@.service, ceder a ele o socket aberto e permitir ao sshd@.service encarrergar-se do
pacote recebido.
Ou seja, neste caso a primeira comunicao pode demorar um pouco mais (nada significativo,
j que o sshd costuma subir bem rpido), mas o restante da sesso SSH seguir sem qualquer
atraso.
Para ativar o servio sob demanda:
# systemctl disable sshd.service
# systemctl start sshd.socket
# systemctl enable sshd.socket

Para confirmar que o systemd quem est escutando nas portas do SSH, experimente usar o
netstat:
# netstat -ltnp
(...)

22

tcp
0
(...)

0.0.0.0:22

0.0.0.0:*

OUA

1/systemd

Confirmado: o systemd quem escuta na porta 22 TCP.

Ativao por D-Bus


Antes de iniciar o assunto, uma breve explicao sobre o D-Bus, j que ele no to
conhecido pelo pblico em geral. O D-Bus (de desktop bus, ou barramento do desktop) foi
concebido juntamente com o HAL e o Udev para compor a base do desktop livre (todos so
hospedados em freedesktop.org). O D-Bus prov um mecanismo de comunicao entre
processos, de forma bem semelhante ao SysV IPC e outros mtodos de IPC (inter-process
communication).
Para exemplificar: o D-Bus quem permite que o seu desktop exiba anncios sobre pen
drives conectados e desconectados, mensagens instantneas recebidas e atualizaes de
pacotes disponveis. O programa de mensagens instantneas, por exemplo, se conecta ao DBus e "cria um canal" (que pode se chamar org.freedesktop.IM, digamos). Quando voc
recebe uma mensagem instantnea, o programa de mensagens instantneas envia uma
notificao pelo canal. Como o aplicativo de notificao na bandeja do sistema tambm est
conectado a esse mesmo canal, as informaes emitidas pelo programa de mensagens
instantneas so tratadas por ele e exibidas em um balo ou em forma de um cone que pisca,
por exemplo.
De volta aos servios. Uma unidade do systemd pode ser ativada por D-Bus. Para isto, basta
que ela se registre no D-Bus e abra um "canal". Com isso, tanto o systemd quanto os demais
aplicativos e servios do sistema podem se comunicar com o servio em questo por meio do
D-Bus. A grande vantagem disso poder iniciar o servio sob demanda.
O exemplo do CUPS tambm vale neste caso. Quando um usurio local manda um programa
imprimir determinado documento, o programa entra em contato com o daemon do CUPS via
D-Bus para fazer o pedido e passar as informaes necessrias. Isto requer, evidentemente,
que o CUPS tenha aberto um canal no D-Bus para escutar tais pedidos.
Porm, novamente no precisamos iniciar o CUPS j no boot, certo? Podemos deixar para
inici-lo somente quando algum pedir para imprimir algo. esta a ativao por D-Bus: o
systemd abre a conexo do servio ao D-Bus e fica escutando, mesmo sem o servio subir.
Assim que recebido um pedido de conexo, o systemd sobe o servio requisitado (o CUPS,
no nosso exemplo) e entrega o pedido a ele. Da mesma forma como ocorre na ativao por
socket, o servio talvez demore um pouco mais para responder o primeiro pedido, mas
econimiza-se tempo de boot e recursos do sistema.

Ativao por D-Bus na prtica


Vejamos o exemplo do Network Manager:
23

$ cat /lib/systemd/system/NetworkManager.service
[Unit]
Description=Network Manager
After=syslog.target
[Service]
Type=dbus
BusName=org.freedesktop.NetworkManager
ExecStart=/usr/sbin/NetworkManager --no-daemon
[Install]
WantedBy=network.target multi-user.target
Alias=dbus-org.freedesktop.NetworkManager.service

Note que no necessrio ter mltiplos arquivos de unidade; basta o arquivo .service.
Na seo [Service], preciso declarar que o tipo do servio dbus (Type=dbus) e, em
seguida, informar o nome do barramento (BusName=...).
Infelizmente, no possvel implementar imediatamente a ativao por D-Bus para todos os
servios. preciso que os desenvolvedores do daemon incluam nele esse recurso
(comunicao via D-Bus).
Neste momento, so poucos os servios que oferecem esse suporte (confira com um grep
Type=dbus /lib/systemd/system/*). Porm, qualquer daemon pode implementar esse tipo
de interface. O objetivo dos desenvolvedores do systemd que todos os servios possam ser
ativados desta maneira a ativao por D-Bus pode ser considerada a forma "nativa" do
systemd iniciar servios. No entanto, saiba que esse objetivo, caso seja alcanado, ainda
demorar muito para chegar.

Concluso
O systemd j uma realidade. No apenas ele ser o sistema de init padro no Fedora 15 (a
ser lanado em maio deste ano) ainda com uso intensivo da compatibilidade com SysVinit,
claro como j possvel hoje us-lo completamente em substituio ao init padro em
sistemas Gentoo e Arch Linux (pelo menos). No meu laptop com Gentoo, o systemd entrou
para no sair mais.
Se voc desenvolve algum daemon de servio que pode ser iniciado via SysVinit, seja gentil e
pr-ativo(a) e certifique-se de cumprir todas as etapas indicadas na seo New-Style
Daemons na manpage daemon(7) distribuda pelo systemd. Assim, seu servio j estar
prontssimo para todas as distribuies.
Fim de papo. Hora de variar o assunto. :)

24

25