Tenho os seguintes requisitos:
- Se um pendrive USB específico for inserido, ele deve ser detectado e montado automaticamente. As informações sobre onde ele deve ser montado estarão em
/etc/fstab
(claro). - Se o pendrive for danificado, uma limpeza completa deverá ocorrer automaticamente, resultando na ausência de vestígios de que ele foi montado (ou ainda está montado) e/ou de quaisquer unidades systemd não finalizadas.
- Se a(s) partição(ões) em questão forem
umount
editadas manualmente, tudo também deverá ser limpo, mesmo que o stick ainda esteja presente; removê-lo do plugue deverá limpar apenas o que não pôde ser limpo antes (provavelmente as.device
unidades).
Para conseguir isso de forma limpa, a inserção do pendrive deve causar o início de uma unidade systemd personalizada, que então configuraremos para fazer o resto.
O que é necessário para escrever isso?
Vamos supor que temos um pendrive com três partições:
/dev/sdc1
e /dev/sdc2
- que são criptografadas com LUKS, e /dev/sdc3
- que não é criptografada.
Por exemplo,
>sudo blkid /dev/sdc{1,2,3}
/dev/sdc1: UUID="de9a000f-fa60-4050-8d11-864e97829b8a" TYPE="crypto_LUKS" PARTUUID="219578f5-5905-41cd-895d-7b937ac0756a"
/dev/sdc2: UUID="012059c1-6b88-4937-889a-a21448740492" TYPE="crypto_LUKS" PARTUUID="59c7f6f3-a5cb-41af-82fa-b515031d85d5"
/dev/sdc3: LABEL="README" UUID="9d262deb-2343-4096-bccf-bb26ed4415ad" BLOCK_SIZE="1024" TYPE="ext2" PARTUUID="165db3da-4ebb-4f59-ab09-ee5e5b26ed43"
Aqui UUID
está o que é usado em /dev/disk/by-uuid
:
>ls -l /dev/disk/by-uuid | grep sdc
lrwxrwxrwx 1 root root 10 Dec 22 18:27 012059c1-6b88-4937-889a-a21448740492 -> ../../sdc2
lrwxrwxrwx 1 root root 10 Dec 22 18:27 9d262deb-2343-4096-bccf-bb26ed4415ad -> ../../sdc3
lrwxrwxrwx 1 root root 10 Dec 22 18:27 de9a000f-fa60-4050-8d11-864e97829b8a -> ../../sdc1
Como o nome do dispositivo /dev/sdc
é bastante aleatório, devemos usar apenas o UUID de agora em diante.
Para montar manualmente a partição não criptografada, precisamos executar (certifique-se de que nada esteja montado em /mnt e/ou /mnt/usb!):
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad
SERIAL=408D5CBECAC3E7C0E9170AEC
sudo /bin/mkdir -p /mnt/usb/$SERIAL/part3
sudo mount -t ext2 /dev/disk/by-uuid/$UUID /mnt/usb/$SERIAL/part3
Onde eu escolhi usar o valor ID_SERIAL_SHORT
do dispositivo USB, que pode ser obtido com, por exemplo:
>udevadm info -n /dev/sdc3 | grep -E '(ID_SERIAL_SHORT|ID_FS_UUID)='
E: ID_SERIAL_SHORT=408D5CBECAC3E7C0E9170AEC
E: ID_FS_UUID=9d262deb-2343-4096-bccf-bb26ed4415ad
Vamos armazenar o ponto de montagem /etc/fstab
adicionando-o a esse arquivo:
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad /mnt/usb/408D5CBECAC3E7C0E9170AEC/part3 ext2 rw,noauto 0 0
Note que depois disso, podemos fazer :
sudo mount /dev/sdc3
e ele fará a montagem perfeitamente, desde que o dispositivo de bloco tenha o UUID esperado.
As outras duas partições /dev/sdc{1,2}
são criptografadas e precisam primeiro
UUID1=573bfda0-69f5-4fb9-9d7e-333a70a51710
UUID2=6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID1 usb-$UUID1
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID2 usb-$UUID2
para ser executado, onde eu assumo que a variável de ambiente LUKS_PASS
contém a frase-senha necessária para descriptografar a partição LUKS. Os UUIDs aqui são aqueles que blkid retorna:
>sudo blkid /dev/sdc{1,2}
/dev/sdc1: UUID="573bfda0-69f5-4fb9-9d7e-333a70a51710" TYPE="crypto_LUKS" PARTUUID="caa57a9d-7389-4990-a243-34b19a179368"
/dev/sdc2: UUID="6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010" TYPE="crypto_LUKS" PARTUUID="10813450-6dcc-4700-9e88-d0577c0c9aeb"
Isso cria um /dev/mapper/usb-$UUID
dispositivo (para cada partição), cada um com seu próprio UUID:
>sudo blkid /dev/mapper/usb*
/dev/mapper/usb-573bfda0-69f5-4fb9-9d7e-333a70a51710: LABEL="gold1-2024-12-21" UUID="67f056be-dbbc-4f7a-979d-6ff077d16e93" BLOCK_SIZE="4096" TYPE="ext2"
/dev/mapper/usb-6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010: LABEL="gold2-2024-12-21" UUID="94bfcc55-6b52-431f-bc76-3aa198c107c7" BLOCK_SIZE="4096" TYPE="ext2"
E são esses UUIDs que queremos adicionar /etc/fstab
.
Para facilitar a vida, escrevi o seguinte script que imprime a /etc/fstab
configuração necessária quando executado após inserir um USB (para o meu caso específico):
# Get the device path.
DEVPATH=$(/bin/ls /dev/disk/by-id/usb-Kingston_DataTraveler* | grep -E -v -- '-part[0-9]+$')
# Get the serial of the USB stick.
ID_SERIAL_SHORT=$(udevadm info -n $DEVPATH | grep ID_SERIAL_SHORT | sed -e 's/.*ID_SERIAL_SHORT=//')
# Run over all existing partitions.
for p in $(/bin/ls $DEVPATH-part*); do
# Extract the "part?" string.
PART=$(echo $p | sed -r -e 's/.*-(part[0-9]+)$/\1/')
# Get the UUID of the block device of this partition iff it is a LUKS encrypted partition.
UUID=$(blkid --match-token TYPE=crypto_LUKS $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/' || true)
if [ -n "$UUID" ]; then
# Decrypt the partition.
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID usb-$UUID
# Get the UUID of the encrypted partition.
UUID2=$(blkid /dev/mapper/usb-$UUID | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
echo -e "UUID=$UUID2\t/mnt/usb/$ID_SERIAL_SHORT/$PART\text2\trw,noauto\t0 0"
sudo cryptsetup luksClose usb-$UUID
else
# Get UUID of non-encrypted partition.
UUID=$(blkid $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
echo -e "UUID=$UUID\t/mnt/usb/$ID_SERIAL_SHORT/$PART\text2\trw,noauto\t0 0"
fi
done
Após exportar, LUKS_PASS
certifique-se de executar o script acima usando sudo -E
para preservar o ambiente. Exemplo de saída:
>sudo -E ./foo.sh
UUID=db97c4b0-8f92-4edc-bacb-dc90e62de2e2 /mnt/usb/408D5CBECAC3E7C0E9170AEC/part1 ext2 rw,noauto 0 0
UUID=c45c6a7a-1c0f-49c4-bcfb-15766114daa1 /mnt/usb/408D5CBECAC3E7C0E9170AEC/part2 ext2 rw,noauto 0 0
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad /mnt/usb/408D5CBECAC3E7C0E9170AEC/part3 ext2 rw,noauto 0 0
Com /etc/fstab
a configuração feita e sabendo exatamente quais comandos são necessários, o que resta é automatizar isso com udev
e systemd units
.
A questão é: como?