Checagem Ortográfica no NeoVim

Uma correção ortográfica nunca vai mal e, no NeoVim, temos essa opção. Basta configurar, reiniciar e usar.

Configuração

-- Arquivo: ~/.config/nvim/init.lua
vim.opt.spell = true
vim.opt.spelllang = 'pt_br'         -- Apenas Português
--vim.opt.spelllang = 'en_us,pt_br' -- Inglês e Português

Adicione as linhas acima no arquivo de configuração init.lua e reinicie o NeoVim, que ele vai abaixar os dicionários (você pode ter que pressionar ENTER algumas vezes até que finalize).

Comandos

  • ]s Próxima palavra incorreta
  • [s Palavra incorreta anterior
  • z= Sugestões ortográficas
  • 1z= Usa a primeira sugestão (qualquer número)
  • zg Adiciona palavra como correta
  • zw Adiciona palavra como incorreta

Referências

Stop Yocto Build with Default downloads, sstate-cache, and tmp Directories

One thing that annoyed me for some time was starting a Yocto build and, only after a few minutes or hours, remember to fix the downloads, sstate-cache and tmp directories in build/conf/local.conf.

In general we want to share the downloads and the sstate-cache with other builds to speed things up as much as possible, especially when several people are working on the same the build machine. In that case we would just commit that configuration to the repository, so everyone uses it and forgets about it.

However we can also have the case where people build on many shared machines with different configurations as well on their local machines. Then everyone agrees to leave the default because that makes nobody happy.

In this case that configuration is never committed to the repository and is always floating around, get lost on a stash for a rebase or merge, and so on. When you less expect the build has started and the default directories are being used.

By default Yocto uses three directories inside build: downloads, sstate-cache, and tmp. I want to always use somewhere else.

So, to fail the build when I forget to change them, I simply create the three directories and make them read-only.

cd build
mkdir downloads sstate-cache tmp
chmod 555 downloads sstate-cache tmp

And, if this idea pleases everybody in the team, it is possible to create some placeholder read-only file inside each directory before making the directories read-only (with chmod 555 ...), then commit these untouchable directories to the repository.

touch downloads/ro sstate-cache/ro tmp/ro
chmod 444 downloads/ro sstate-cache/ro tmp/ro

I hope this helps and good luck!

Instalando NeoVim pelo Código Fonte

Hoje tentei usar NeoVim com os plugins do kickstart porém, na hora de executar o comando nvim ocorreu um erro!

A versão disponível para instalação com o apt não era recente o suficiente para usar os plugins.

Uma das opções é compilar o programa à partir do código fonte:

Os passos abaixo foram testados com Ubuntu 22.04 e Debian 12.

Passo a Passo

  1. Instalar as dependências:
sudo apt install git make cmake ninja-build gettext unzip curl

A instalação destes programas é necessária para obtermos as ferramentas necessárias para obter o código e compilá-lo com sucesso.

Outros programas relacionados aos que listamos também são instalados junto.

  1. Obter o código fonte do NeoVim clonando o repositório no GitHub:
git clone https://github.com/neovim/neovim

O repositório é clonado dentro de uma nova pasta chamada neovim. O download é de cerca de 250 MB.

  1. Entrar na pasta do repositório:
cd neovim
  1. Selecionar a versão que desejamos compilar. Aqui seleciono a versão mais recente, que é a v0.9.5:
git checkout v0.9.5

Se quiser escolher uma versão específica (ou uma mais nova) basta visualizar a lista de tags do repositório com o comando git tag -l.

  1. Agora vamos compilar:
make CMAKE_BUILD_TYPE=Release

Este comando de compilação é indicado no arquivo README.md do repositório. Apenas make já funcionaria, porém o restante do comando habilita as otimizações durante a compilação, que fazem o programa ter uma performance muito melhor.

A compilação demorou cerca de 2 minutos no meu computador.

  1. Agora que está compilado, vamos instalar o NeoVim no computador, de forma que todos os usuários possam usá-lo:
sudo make install

Pronto está instalado e podemos testá-lo!

nvim
  1. Agora vamos instalar os plugins do kickstart:
git clone https://github.com/nvim-lua/kickstart.nvim ~/.config/nvim

Clonamos o repositório kickstart.nvim direto na pasta de configuração do NeoVim (direto em ~/.config/nvim).

Basta abrir o NeoVim novamente e podemos ver ele processando a nova configuração e instalando os plugins.

nvim

Error Building Qt6 Toolchain with Yocto

Error Building Qt6 Toolchain with Yocto

I was trying to build Qt6 toolchain with Yocto (meta-qt6 from https://code.qt.io/yocto/meta-qt6 branch 6.7) but I got an error with the following lines:

$ bitbake meta-toolchain-qt6
FileNotFoundError: [Errno 2] No such file or directory: 'cups-config'
ERROR: Task (meta-qt6/recipes-qt/qt6/qtpdf_git.bb:do_compile) failed with exit code '1'

It seems that cups is necessary to build qtpdf. So I created a new meta layer with the following bbappend file, which fixed the issue.

# File: qtpdf_git.bbappend
DEPENDS += " cups "

I created a meta layer to fix this issue. Check it out on GitHub:

https://github.com/djboni/meta-qt6-fix

I hope this helps and good luck!

WiFi no Raspberry Pi

Agora que o Raspberry Pi está com as configurações básicas prontas, (veja o post anterior), o próximo passo é simplificar a conexão dele com a internet.

Quero deixá-lo em um lugar onde não atrapalhe. Quanto menos fios e cabos precisar melhor, portanto WiFi é uma opção melhor do que Ethernet.

Esse Raspberry Pi é bem antigo e não tem WiFi integrado na placa e precisa de um adaptador USB-WiFi.

Mas vamos lá para a configuração. Para quem não sabe, o sistema operacional do Raspberry OS (ou Raspbian) é baseado no Debian Linux e podemos usar muito da documentação deste.

O link abaixo explica como configurar o WiFi no Debian:

https://wiki.debian.org/WiFi/HowToUse#Using_ifupdown

Primeiro precisamos determinar qual é o nome do adaptador WiFi (seja ele integrado na placa ou via USB). Para isso logamos usando SSH e usamos o comando ip a, que lista as interfaces de rede.

$ ip a
> 1: lo: ...
> 2: eth0: ...
> 3: wlan0: ...

A saída do comando tem um tanto a mais de informação do que estou mostrando. Porém podemos identificar "wlan0" como a interface WiFi.

Agora vamos criar um arquivo de configuração para a rede sem fio:

  1. Usamos sudo su para mudar para o usuário root;
  2. Mudamos a máscara de criação de arquivos para 077, que faz com que apenas o dono do arquivo tenha acesso. Isso é importante para evitar os usuários possam ler o arquivo abaixo, que vai conter a senha do WiFi
  3. Criamos o arquivo de configuração usando o comando touch; e
  4. Editamos o arquivo (com o editor nano) adicionando a configuração mostrada em seguida.
$ sudo su
$ uname 077
$ touch /etc/network/interfaces.d/wlan0.conf
$ nano /etc/network/interfaces.d/wlan0.conf

O arquivo de configuração pode ter qualquer nome. Para facilitar coloco o nome da interface que ele configura.

O conteúdo do arquivo de configuração é mostrado abaixo, configurando a interface para ser detectada automaticamente, usar DHCP para obter um endereço de IP e também configura o SSID da rede (nome da rede sem fio) e a sua senha.

# Arquivo: /etc/network/interfaces.d/wlan0.conf mode=0600
allow-hotplug wlan0
iface wlan0 inet dhcp
    wpa-ssid NOME_DA_REDE
    wpa-psk SENHA_DA_REDE

Note que no arquivo de configuração precisamos especificar corretamente o nome da interface de rede duas vezes, "wlan0" no meu caso.

Raspberry Pi modelo B com WiFi

Agora é só reiniciar o Raspberry Pi, desconectar todos os cabos desnecessários e curtir ele através da rede sem fio. Agora, a única coisa que ele precisa é uma tomada.

Revivendo um Raspberry Pi B (modelo antigo)

Tenho um Raspberry Pi antigo, modelo B, e quero fazer ele voltar à vida para rodar testes de projetos multiplataforma.

Gravando o Cartão SD

Entrando no site do Raspberry Pi, encontramos a página de downloads. Optei por escolher a imagem manualmente na página abaixo.

https://www.raspberrypi.com/software/operating-systems/

Como pretendo criar um servidor, não preciso da imagem desktop, podendo utilizar a imagem "lite" (leve), que tem apenas a linha de comando.

Fiz o download da imagem "Raspberry Pi OS Lite (32-bit)", obtendo o arquivo "2022-09-22-raspios-bullseye-armhf-lite.img.xz".

Se você tiver algum modelo mais novo do Raspberry Pi, é possível usar uma imagem "Raspberry Pi OS Lite (64-bit)". Há uma lista dos modelos que suportam o sistema 64-bits.

Para extrair a imagem usamos o comando xz. Isso remove o arquivo compactado .img.xz cria um arquivo descompactado .img.

$ xz -d 2022-09-22-raspios-bullseye-armhf-lite.img.xz

Então, para gravá-la usamos o comando dd, enviando os dados para o cartão SD no caminho /dev/mmcblk0.

$ dd if=2022-09-22-raspios-bullseye-armhf-lite.img of=/dev/mmcblk0

Se tiver dúvidas sobre qual é o seu cartão de memória, o comando ls -lrt /dev/ vai te mostrar uma lista com os dispositivos detectados no sistema, listados do mais velho para o mais novo.

Se quiser também é possível escrever no cartão SD enquanto extrai, sem criar o arquivo descomprimido.

$ xz -dc 2022-09-22-raspios-bullseye-armhf-lite.img.xz | dd of=/dev/mmcblk0

Antes do Primeiro Boot

Habilitando SSH

Para realizar algumas modificações montei a partição de root e de boot do Raspberry Pi.

$ mount /dev/mmcblk0p2 /mnt
$ mount /dev/mmcblk0p1 /mnt/boot

Na pasta /mnt/boot (/boot do Raspberry Pi) criei um arquivo vazio chamado ssh, que faz o servidor SSH ser habilitado no primeiro boot.

touch /mnt/boot/ssh

Obsoleto: Isso evita ter que acessar o mini computador com tela e teclado só para habilitar o SSH. Assim posso ir direto para o acesso remoto.

Infelizmente, agora é preciso configurar usuário e senha no primeiro boot. Então parece ser obrigatório conectar uma tela e teclado. Deve haver algum jeito de evitar isso.

Agora basta desmontar a partição e iniciar o Raspberry Pi com o cartão SD.

$ umount /dev/mmcblk0p1
$ umount /dev/mmcblk0p2

Raspberry Pi modelo B

Primeiro Boot

As primeiras coisas a fazer são:

  • Escolher o usuário
  • Escolher a senha
  • Identifique o IP no roteador (no meu caso é 192.168.0.101)
  • Instalar chave SSH (opcional)
    $ ssh-copy-id [email protected]
    
  • Fazer o login pelo SSH
    $ ssh [email protected]
    
  • Atualizar
    pi$ sudo apt update
    pi$ sudo apt upgrade
    
  • Reduzir a memória da GPU
    pi$ sudo raspi-config
    
    • 4 Performance Options
      • P2 GPU Memory
        • 8 > OK
    • Finish
  • Reiniciar
    pi$ sudo reboot
    

Ansible: Criptografando Senhas de Usuários

As vezes queremos gerar uma senha fixa para usuários, a qual vamos reutilizar em várias máquinas.

Um exemplo típico é criar usuário administrador, capaz de realizar login com senha. Dessa forma, caso ocorra algum problema com o servidor SSH ou perca a sua chave privada junto com o seu HD, ainda é possível fazer login direto na máquina, por VNC ou por outros meios de acesso remoto.

Porém essa é a senha de administrador de muitos computadores e não queremos colocá-la diretamente em scripts de configuração, como os do Ansible, onde podem ser lidas diretamente.

Podemos, no entanto, criar uma versão encriptada da senha (a mesma usada no arquivo /etc/shadow) e aí sim colocá-la no script.

O código abaixo cria uma senha segura 24 caracteres utilizando pwgen. A opção -s indica que a senha deve ser completamente aleatória.

$ pwgen -s 24 1
> VONga6jUFoXCMQNhDlHgTHQY

Por fim usamos openssl passwd para encriptar a senha gerada Usamos a opção -6 para criptografar a senha com SHA512.

$ openssl passwd -6 'VONga6jUFoXCMQNhDlHgTHQY'
> $6$80Ll7KOwC/XDQVgZ$NwTjYG8cXcMTr9NI1EbtaX7OEAIBq3ULUSJPmpjtk/vUiyB9duYO3aNqmWmBnS.mjgaN37/mo34R8COzNrFBh0

Dessa forma, a preciosa senha está segura, longe de olhos curiosos, e podemos colocá-la no script de criação de usuários.

# Arquivo:  tasks/default-tasks.yml
---
- name: Criar usuário admin com senha
  ansible.builtin.user:
    name: admin
    comment: Usuário Administrador
    password: "$6$80Ll7KOwC/XDQVgZ$NwTjYG8cXcMTr9NI1EbtaX7OEAIBq3ULUSJPmpjtk/vUiyB9duYO3aNqmWmBnS.mjgaN37/mo34R8COzNrFBh0"

Ansible: Testando Playbooks

Ansible é uma excelente ferramenta para automatização de tarefas.

Cria-se uma lista de computadores e instalando neles um servidor SSH e Python 3, é possível automatizar a instalação de programas, alteração de configurações e, o meu favorito, atualização dos computadores.

No maior estilo do TDD (Test Driven Development), muitas vezes, queremos ter certeza que algo está funcionando antes de prosseguir com a execução do playbook.

Exemplos destes casos são:

  • A nova configuração funciona?
  • O usuário realmente pode (não pode) usar usar sudo?
  • Login do usuário root está mesmo desativado?
  • O firewall liberou/bloqueou a porta HTTP?

Podemos criar testes como esses com certa facilidade e inclusive podemos escolher entre a máquina remota ou local para executar os comandos, o que é essencial para alguns testes.

Abaixo mostro dois exemplos, testando as permissões de um usuário do servidor remoto e testando se o computador local pode fazer login como root.

# Arquivo: tasks/testes.yml
---
- name: TESTE Verificar se o usuário 'admin' pode usar SUDO sem senha
  # Teste no servidor remoto:
  # - su admin -c "xxx": executa o comando xxx como admin;
  # - whoami: imprime o nome do usuário; e
  # - Esperamos que imprima 'admin' (sem o sudo) e em seguida
  #   imprima 'root' (com sudo).
  ansible.builtin.command: |
    su admin -c "whoami; sudo whoami"
  register: result
  changed_when: false
  failed_when: >
    result.stdout_lines[0] != 'admin'
    or result.stdout_lines[1] != 'root'
  timeout: 5

- name: TESTE Negar login do usuário 'root' port SSH
  # Teste no computador local:
  # - SSH, ativando senha e desativando chave pública;
  # - whoami: um comando qualquer para ser executado; e
  # - Esperamos que a tentativa de login seja negada.
  ansible.builtin.command: >
    ssh -oPasswordAuthentication=yes -oPubkeyAuthentication=no
    -p{{ ansible_port }} root@{{ ansible_host }} whoami
  register: result
  changed_when: false
  failed_when: "'Permission denied (publickey)' not in result.stderr"
  timeout: 5
  # Esta parte final definie que o teste é executado no computador local
  # (que executa o Ansible).
  # Desativamos ansible_become para que use o usuário atual, em vez de
  # usar sudo para se tornar root.
  delegate_to: localhost
  vars:
    ansible_become: false

Ansible: Variáveis Dependentes do Sistema Operacional

Ansible é uma excelente ferramenta para automatização de tarefas.

Cria-se uma lista de computadores e instalando neles um servidor SSH e Python 3, é possível automatizar a instalação de programas, alteração de configurações e, o meu favorito, atualização dos computadores.

No entanto, há coisas que são diferentes de um sistema para outro, por exemplo caminhos de arquivos de configuração e nomes de pacotes.

Para evitar criar várias e várias tarefas que fazem a mesma coisa ajustadas para cada sistema (when: ansible_distribution == ...), enchendo o playbook com código repetido, Ansible permite a importação de arquivos de variáveis com o módulo include_vars, onde podemos escolher dinamicamente o arquivo de variáveis correspondente ao sistema.

Então podemos criar um arquivo para cada um dos sistemas em uso e seguir em frente. Porém isso acaba por se tornar um pesadelo de manutenção: cada nova variável precisa ser adicionada em TODOS os arquivos de variáveis e, ao criar um arquivo de variáveis novo, é preciso atualizar todas as variáveis possíveis.

Uma alternativa interessante seria uma criar estrutura hierárquica, onde definimos valores padrão para todos, em seguida substituímos com os valores para a família, então com os valores para a distribuição e quem sabe até com valores para certas versões.

Padrão          default
                 /   \
Família      Debian  FreeBSD
              / \
Distro  Debian   Ubuntu

Além disso, é importante que a inexistência de algum desses arquivos de especialização não seja um empecilho.

Com um pouco de pesquisa e um pouco de tentativa-e-erro, e com "um pouco" quero dizer interminável, cheguei no código abaixo:

# Arquivo: tasks/default-tasks.yml
---
- name: Carrega variáveis padrão, da família e da distro
  ansible.builtin.include_vars: "{{ item }}"
  with_fileglob:
    - vars/default.yml
    - vars/family_{{ ansible_os_family }}.yml
    - vars/distro_{{ ansible_distribution }}.yml

Usamos include_vars, como de costume, porém junto com with_fileglob. Este geralmente é usado para encontrar vários arquivos usando coringas (wildcards) como vars/*.yml. Mas aqui não usamos coringas, damos direto o nome do arquivo. Se o arquivo não é encontrado ele é ignorado.

Abaixo estão exemplos dos arquivos de variáveis padrão e especializado.

# Arquivo: vars/default.yml
---
doas_config_file: /etc/doas.conf
# Arquivo: vars/family_FreeBSD.yml
---
doas_config_file: /usr/local/etc/doas.conf

Copiando a suas chaves SSH do GitHub ou GitLab

As vezes queremos copiar uma chave pública SSH para um computador.

Esse é um jeito fácil de adicionar a sua própria chave ou de adicionar a chave de alguém para te ajudar com algum problema.

Tendo uma conexão com a internet, é possível fazer o download das chaves públicas SSH de qualquer usuário do GitHub ou GitLab.

Com os comandos abaixo é possível fazer o download da chave adicioná-las nas chaves permitidas para acesso SSH. Basta trocar USUARIO pelo nome do usuário desejado.

  1. Configure a máscara de permissões para 077: leitura e escrita apenas para o usuário dono.
    • umask 077
  2. Crie a pasta ~/.ssh, se ela não existir.
    • mkdir -p ~/.ssh
  3. Faça o download das chaves:
    • GitHub: curl https://github.com/USUARIO.keys >>~/.ssh/authorized_keys
    • GitLab: curl https://gitlab.com/USUARIO.keys >>~/.ssh/authorized_keys

Também podemos usar wget em vez de curl, substituindo curl por wget -O-.