AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 788561
Accepted
Carlo Wood
Carlo Wood
Asked: 2024-12-23 07:33:07 +0800 CST2024-12-23 07:33:07 +0800 CST 2024-12-23 07:33:07 +0800 CST

Como montar automaticamente (criptografar) partições de um pendrive usando udev e systemd

  • 772

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 umounteditadas 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 .deviceunidades).

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/sdc1e /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 UUIDestá 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_SHORTdo 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/fstabadicionando-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_PASSconté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-$UUIDdispositivo (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/fstabconfiguraçã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_PASScertifique-se de executar o script acima usando sudo -Epara 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/fstaba configuração feita e sabendo exatamente quais comandos são necessários, o que resta é automatizar isso com udeve systemd units.

A questão é: como?

udev
  • 2 2 respostas
  • 59 Views

2 respostas

  • Voted
  1. Carlo Wood
    2024-12-25T05:53:28+08:002024-12-25T05:53:28+08:00

    EDIT: TLDR; você precisa ler minha outra resposta primeiro.

    Aqui está um relatório passo a passo da minha pesquisa.

    Registro de depuração

    Pode haver uma maneira melhor, mas a seguinte funciona: criei um script executável com /usr/local/sbin/log_serviceo seguinte conteúdo:

    #! /bin/sh
    echo "$1 : \"$2\""
    

    Quando isso for executado, /bin/systemd-cat -t usbtesta saída escrita pelo script na saída padrão será gravada no diário.

    Para monitorar a saída, executamos, em uma janela de terminal separada:

    journalctl -b -t systemd -t usbtest -f
    

    para monitorar a saída em tempo real.

    Dispositivo falso

    Primeiro criei um serviço falso que usarei como um ".device" falso (embora este seja um .service).

    Crie o seguinte arquivo como /etc/systemd/system/A.service:

    [Unit]
    Description=A fake device (service A)
    
    [Service]
    ExecStart=/bin/systemd-cat -t usbtest /usr/local/sbin/log_service A start
    ExecStop=/bin/systemd-cat -t usbtest /usr/local/sbin/log_service A stop
    
    [Install]
    WantedBy=multi-user.target
    

    e então execute sudo systemctl daemon-reloadpara que o sistema em execução fique ciente disso.

    Tente iniciar o novo serviço:

    sudo systemctl start A
    

    Isso resulta na saída de log imediata:

    Dec 23 14:20:16 daniel systemd[1]: Started A fake device (service A).
    Dec 23 14:20:16 daniel usbtest[1583423]: A : "start"
    Dec 23 14:20:16 daniel usbtest[1583428]: A : "stop"
    Dec 23 14:20:16 daniel systemd[1]: A.service: Deactivated successfully.
    

    A razão é que o script que está sendo executado ( /usr/local/sbin/log_service) retorna imediatamente. Como em vez disso queremos imitar um serviço que podemos iniciar e parar por meio do systemctl, adicionamos a linha RemainAfterExit=yes:

    [Unit]
    Description=A fake device (service A)
    Wants=B.service         # See below.
    
    [Service]
    Type=oneshot            # See below.
    RemainAfterExit=yes
    ExecStart=/bin/systemd-cat -t usbtest /usr/local/sbin/log_service A start
    ExecStop=/bin/systemd-cat -t usbtest /usr/local/sbin/log_service A stop
    
    [Install]
    WantedBy=multi-user.target
    

    Agora podemos sudo systemctl start Ae separadamente sudo systemctl stop A.

    Montagem falsa .service

    Vamos fazer isso novamente para um novo serviço B. A ideia é que queremos que ele Bseja iniciado automaticamente quando Afor iniciado, e parar Adeve causar Ba parada. Parar Bmanualmente, no entanto, não deve parar A.

    Como B será dependente de A e ambos fazem log, queremos que B seja iniciado após A terminar o log (o ExecStart de A terminou), portanto, altere A.servicenovamente e adicione Type=oneshot; queremos garantir que todos os ExecStarts sejam feitos antes que qualquer serviço dependente comece. Observe que outra diferença é que com o tipo oneshot, se houver várias ExecStartlinhas, elas serão feitas sequencialmente e a próxima só será iniciada após a anterior terminar, ao contrário de Type=simple, o padrão, que inicia todas ExecStartas linhas em paralelo (porque não se espera que elas terminem rapidamente, ou de jeito nenhum). No entanto, isso não nos preocupa: temos apenas uma única ExecStart(uma que retorna "imediatamente", caso contrário, você não pode usar oneshot).

    Não vou repetir tudo o que tentei aqui; apenas o resultado final que funciona:

    [Unit]
    Description=Fake mount service (service B)
    After=A.service
    Requisite=A.service
    
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStart=/bin/systemd-cat -t usbtest /usr/local/sbin/log_service B start
    ExecStop=/bin/systemd-cat -t usbtest /usr/local/sbin/log_service B stop
    
    [Install]
    WantedBy=A.service
    

    (não se esqueça de executar novamente sudo systemctl daemon-reload).

    O que precisamos After=A.servicefala por si: você não pode montar um dispositivo se ele não existir (ou seja, se a unidade .device estiver ativa); portanto, não queremos iniciar B até que A tenha sido iniciado.

    Para que B seja iniciado sempre que A for iniciado, não é suficiente ter o WantedBy=A.service, precisamos adicionar Wants=B.serviceà [Unit]seção de A.service!

    Com isso, B é iniciado se iniciarmos A. Não queremos que A seja iniciado se tentarmos iniciar B: isso não faz sentido. Portanto, usamos Requisite=A.serviceas opposite to Requires=A.service(or BindsTo=A.service). Como resultado, isso simplesmente se recusa a iniciar B se A não estiver ativo (conforme a documentação):

    >sudo systemctl start B
    A dependency job for B.service failed. See 'journalctl -xe' for details.
    

    em vez de começar A.

    Também podemos parar B quando ambos estiverem ativos; isso só para B ( não podemos nem parar o .device, pois isso não faria sentido: ele ainda está conectado). Executar systemctl start Adepois disso (mesmo que A já esteja ativo) inicia B novamente, o que é provavelmente o que queremos.

    Finalmente, parar A enquanto ambos estão ativos para primeiro B e depois A - exatamente como queremos. Isso é estranho, no entanto, porque, pela documentação, entendo que esse é um recurso BindsTo=que tem a seguinte descrição:

    Configura dependências de requisitos, muito semelhantes em estilo a Requires=. No entanto, esse tipo de dependência é mais forte: além do efeito de Requires=, ele declara que se a unidade vinculada a for parada, esta unidade também será parada. Isso significa que uma unidade vinculada a outra unidade que entra repentinamente em estado inativo também será parada. As unidades podem entrar repentinamente e inesperadamente em estado inativo por diferentes motivos: o processo principal de uma unidade de serviço pode terminar por sua própria escolha, o dispositivo de apoio de uma unidade de dispositivo pode ser desconectado ou o ponto de montagem de uma unidade de montagem pode ser desmontado sem o envolvimento do sistema e do gerenciador de serviços.

    que descreve exatamente o que precisamos ("uma unidade de dispositivo pode estar desconectada"). Enquanto a documentação de Requisite=é

    Semelhante a Requires=. No entanto, se as unidades listadas aqui não forem iniciadas ainda, elas não serão iniciadas e a inicialização desta unidade falhará imediatamente. Requisite= não implica uma dependência de ordenação, mesmo se ambas as unidades forem iniciadas na mesma transação. Portanto, esta configuração deve geralmente ser combinada com After=, para garantir que esta unidade não seja iniciada antes da outra unidade.

    Então, queremos isso (iniciar B falhará se A ainda não tiver sido iniciado em vez de tentar iniciar B), mas não menciona a parte que BindsTotambém precisamos (parar A interromperá B).

    No entanto, se eu adicionar BindsTo=A.servicea função de Requisite=é anulado e iniciar B simplesmente inicia A (primeiro). Um bug no systemd (testado com a versão 257-1 no Arch)?

    Usando um dispositivo real (udev)

    Podemos adicionar uma udevregra para detectar a inserção de um dos pendrives que eu quero detectar. Note que mesmo sem tal regra, inserir um pendrive já faz com que .deviceunidades sejam criadas:

    >systemctl list-units --type=device | grep usb8
      sys-devices-pci0000:00-0000:00:08.1-0000:0c:00.3-usb8-8\x2d4-8\x2d4.3-8\x2d4.3:1.0-host12-target12:0:0-12:0:0:0-block-sdc-sdc1.device loaded active plugged DataTraveler_3.0 1
      sys-devices-pci0000:00-0000:00:08.1-0000:0c:00.3-usb8-8\x2d4-8\x2d4.3-8\x2d4.3:1.0-host12-target12:0:0-12:0:0:0-block-sdc-sdc2.device loaded active plugged DataTraveler_3.0 2
      sys-devices-pci0000:00-0000:00:08.1-0000:0c:00.3-usb8-8\x2d4-8\x2d4.3-8\x2d4.3:1.0-host12-target12:0:0-12:0:0:0-block-sdc-sdc3.device loaded active plugged DataTraveler_3.0 README
      sys-devices-pci0000:00-0000:00:08.1-0000:0c:00.3-usb8-8\x2d4-8\x2d4.3-8\x2d4.3:1.0-host12-target12:0:0-12:0:0:0-block-sdc.device      loaded active plugged DataTraveler_3.0
    

    mas como os nomes dessas .deviceunidades podem mudar (mesmo que apenas com base no local em que eu as conecto), não podemos usar seus nomes da maneira que usamos A.serviceem todos os lugares. Além disso, precisamos adicionar um Wants=B.servicea esses dispositivos - o que estes não têm. E, finalmente, não queremos disparar B.servicepara qualquer dispositivo USB suas partições e sua mãe, mas apenas para as partições que listei acima.

    Tudo isso pode ser alcançado criando uma nova regra udev.

    Enquanto o pendrive estiver conectado (que tem uma terceira partição /dev/sdc3) podemos executar por exemplo:

    >sudo udevadm test /sys/class/block/sdc3 2>/dev/null | grep -E '(DEVPATH|DEVNAME|ACTION|SUBSYSTEM|TAGS|ID_BUS|ID_SERIAL|DEVLINKS|SYSTEMD_WANTS)'
      DEVPATH=/devices/pci0000:00/0000:00:08.1/0000:0c:00.3/usb8/8-4/8-4.4/8-4.4:1.0/host12/target12:0:0/12:0:0:0/block/sdc/sdc3
      DEVNAME=/dev/sdc3
      ACTION=add
      SUBSYSTEM=block
      TAGS=:systemd:
      ID_BUS=usb
      ID_SERIAL=Kingston_DataTraveler_3.0_408D5CBF5F0AE7C0E9150B70-0:0
      ID_SERIAL_SHORT=408D5CBF5F0AE7C0E9150B70
      DEVLINKS=/dev/disk/by-diskseq/115-part3 /dev/disk/by-path/pci-0000:0c:00.3-usb-0:4.4:1.0-scsi-0:0:0:0-part/by-partuuid/deb41f73-7955-4eba-8fac-2c7d01b93af4 /dev/disk/by-id/usb-Kingston_DataTraveler_3.0_408D5CBF5F0AE7C0E9150B70-0:0-part3 /dev/disk/by-path/pci-0000:0c:00.3-usb-0:4.4:1.0-scsi-0:0:0:0-part/by-label/README /dev/disk/by-path/pci-0000:0c:00.3-usb-0:4.4:1.0-scsi-0:0:0:0-part3 /dev/disk/by-partuuid/deb41f73-7955-4eba-8fac-2c7d01b93af4 /dev/disk/by-path/pci-0000:0c:00.3-usbv3-0:4.4:1.0-scsi-0:0:0:0-part3 /dev/disk/by-path/pci-0000:0c:00.3-usb-0:4.4:1.0-scsi-0:0:0:0-part/by-partnum/3 /dev/disk/by-uuid/046ba81b-7d9c-4a54-a69f-6fba06ac7754 /dev/disk/by-label/README /dev/disk/by-path/pci-0000:0c:00.3-usb-0:4.4:1.0-scsi-0:0:0:0-part/by-uuid/046ba81b-7d9c-4a54-a69f-6fba06ac7754
      CURRENT_TAGS=:systemd:
    

    Observe como isso nos diz que udev está ciente de tudo (UUID e ID_SERIAL_SHORT em particular), mas SYSTEMD_WANTS não está definido. Precisamos que seja definido como B.service.

    Em seguida, criamos uma nova regra udev criando o arquivo /etc/udev/rules.d/69-gold-usb.rulescom o conteúdo:

    SUBSYSTEMS=="block", ENV{ID_SERIAL_SHORT}=="408D5CBECBBDE7C0E9160666|408D5CBF5F0AE7C0E9150B70|408D5CBECAC3E7C0E9170AEC", ENV{SYSTEMD_WANTS}="B.service"
    

    E recarregue com sudo udevadm control --reload-rules. Ao executar sudo udevadm test /sys/class/block/sdc3novamente (como acima) obtemos o mesmo resultado, mas com uma linha extra:

    >sudo udevadm test /sys/class/block/sdc3 2>/dev/null | grep -E '(DEVPATH|DEVNAME|ACTION|SUBSYSTEM|TAGS|ID_BUS|ID_SERIAL|DEVLINKS|SYSTEMD_WANTS)'
    ...
      SYSTEMD_WANTS=B.service
    

    indicando que a regra funciona.

    Podemos testar a mesma coisa conectando e desconectando o pendrive enquanto estiver em execução

    sudo udevadm monitor --property | grep -E '^UDEV.*(add|remove)|^SYSTEMD_WANTS' | grep -B1 SYSTEMD_WANTS
    

    Isso dá, ao adicionar o pendrive:

    UDEV  [182604.679907] add      /devices/pci0000:00/0000:00:08.1/0000:0c:00.3/usb8/8-4/8-4.4/8-4.4:1.0/host12/target12:0:0/12:0:0:0/block/sdc (block)
    SYSTEMD_WANTS=B.service
    UDEV  [182604.703373] add      /devices/pci0000:00/0000:00:08.1/0000:0c:00.3/usb8/8-4/8-4.4/8-4.4:1.0/host12/target12:0:0/12:0:0:0/block/sdc/sdc2 (block)
    SYSTEMD_WANTS=B.service
    UDEV  [182604.705526] add      /devices/pci0000:00/0000:00:08.1/0000:0c:00.3/usb8/8-4/8-4.4/8-4.4:1.0/host12/target12:0:0/12:0:0:0/block/sdc/sdc1 (block)
    SYSTEMD_WANTS=B.service
    UDEV  [182604.708620] add      /devices/pci0000:00/0000:00:08.1/0000:0c:00.3/usb8/8-4/8-4.4/8-4.4:1.0/host12/target12:0:0/12:0:0:0/block/sdc/sdc3 (block)
    SYSTEMD_WANTS=B.service
    

    e o mesmo acontece removeao desligar.

    Observe como a regra é acionada para ambos, /dev/sdcassim como para cada uma das três partições. Como estamos interessados ​​apenas nas partições, vamos adicionar ENV{DEVTYPE}=="partition"à regra udev:

    SUBSYSTEMS=="block", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL_SHORT}=="408D5CBECBBDE7C0E9160666|408D5CBF5F0AE7C0E9150B70|408D5CBECAC3E7C0E9170AEC", ENV{SYSTEMD_WANTS}="B.service"
    

    Agora temos uma udevregra que detecta a inserção de um dos três pendrives USB e, como resultado, inicia B.service. No entanto, B.servicefalta o After=, Requisite=e WantedBy=, de modo que desconectar o pendrive USB ainda não tem o efeito desejado.

    Adicionando a dependência do .device ao B.service

    Se tivéssemos apenas uma partição para lidar (digamos, /dev/sdc3 deste pendrive em particular), então uma maneira direta de adicionar a dependência parece ser usar um dos DEVLINKS- mais notavelmente,

    /dev/disk/by-uuid/046ba81b-7d9c-4a54-a69f-6fba06ac7754
    

    que é, claro, totalmente fixo para uma partição dada. No entanto, esses nomes de caminho devem ser escapados: todas as barras devem ser substituídas por traços ( -), e se tentarmos:

    Requisite=dev-disk-by-uuid-046ba81b-7d9c-4a54-a69f-6fba06ac7754.device
    

    Então obtemos o seguinte erro interessante quando B.serviceé iniciado:

    Dec 23 20:01:45 daniel systemd[1]: /dev/disk/by/uuid/046ba81b/7d9c/4a54/a69f/6fba06ac7754 is inactive.
    Dec 23 20:01:45 daniel systemd[1]: Dependency failed for Fake mount service (service B).
    

    Observe como também o -que faz parte do UUID foi convertido para /. A maneira correta de gerar esta string é com

    >systemd-escape dev/disk/by-uuid/046ba81b-7d9c-4a54-a69f-6fba06ac7754.device
    dev-disk-by\x2duuid-046ba81b\x2d7d9c\x2d4a54\x2da69f\x2d6fba06ac7754.device
    

    Mas, usar essa string em B.servicevez da string A.servicerevela que nãoB é parado se desconectarmos o pendrive USB (como esperado apenas olhando a documentação). Portanto, precisamos também adicionar uma linha.BindsTo=

    B.serviceentão se torna:

    [Unit]
    Description=Fake mount service (service B)
    After=dev-disk-by\x2duuid-046ba81b\x2d7d9c\x2d4a54\x2da69f\x2d6fba06ac7754.device
    Requisite=dev-disk-by\x2duuid-046ba81b\x2d7d9c\x2d4a54\x2da69f\x2d6fba06ac7754.device
    BindsTo=dev-disk-by\x2duuid-046ba81b\x2d7d9c\x2d4a54\x2da69f\x2d6fba06ac7754.device
    
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStart=/bin/systemd-cat -t usbtest /usr/local/sbin/log_service B start
    ExecStop=/bin/systemd-cat -t usbtest /usr/local/sbin/log_service B stop
    
    [Install]
    WantedBy=dev-disk-by\x2duuid-046ba81b\x2d7d9c\x2d4a54\x2da69f\x2d6fba06ac7754.device
    

    Curiosamente, agora a tentativa de iniciar sudo systemctl start Bnão falha, mas trava se o USB não estiver conectado, até que você o conecte. Isso é bem legal, eu acho.

    Conectar o USB inicia automaticamente Bde qualquer maneira. Nesse ponto, podemos parar manualmente Bcomo antes, em que ponto Bé parado enquanto o stick está conectado e então podemos simplesmente (re)iniciar Bmanualmente sem que ele trave.

    Podemos passar apenas o UUID (dinâmico) para o serviço, como um hack, fazendo:

    ENV{SYSTEMD_WANTS}="B@$env{ID_FS_UUID}.service"
    

    and then use %i in the .service to access the UUID. I call this a "hack" because it only works because an UUID doesn't contain illegal character for an escaped string: you SHOULD pass a systemd escaped string here; in that case %i would be that escaped string and %I would be the original, unescaped string.

    However, this is not usable: we NEED the escaped string for After=, Requisite=, BindsTo= and WantedBy= because there is no way to manipulate %i: it must be used as-is.

    There is a way to create the escaped string during the udev rule, but due to a bug in udev it is impossible to actually use that if it contains any backslashes (it is beyond me how such a horrible bug can exist for years without anyone fixing it).

    The only remaining option therefore is to use SYMLINK with a path that doesn't contain any characters that need to be escaped with a backslash (aka, no '-' characters). In fact, we can pass any information using this trick!

    SUBSYSTEMS=="block", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL_SHORT}=="408D5CBECBBDE7C0E9160666|408D5CBF5F0AE7C0E9150B70|408D5CBECAC3E7C0E9170AEC", PROGRAM="/usr/local/sbin/udev-escape '$env{ID_FS_UUID}'", SYMLINK+="usb/%c", ENV{SYSTEMD_WANTS}="B@usb-%c.service"
    

    This way we can pass (any) information (in this case only ID_FS_UUID) while still using %i for the dependency stuff in the @.service template! We only have to make sure that the %c, the output of PROGRAM (and thus the SYMLINK) does not contain any characters that need to be escaped or are escaped with a backslash.

    The /usr/local/sbin/udev-escape that I use contains:

    #! /bin/sh
    
    # Utility to convert any string to something that will
    # survive being passed through %c of an udev rule to
    # a systemd service using SYSTEMD_WANTS.
    # Written by Carlo Wood (Dec 2024).
    
    echo "$1" | /usr/bin/base64 -w0 | /usr/bin/tr '+/=' '.:_'
    

    Simple, but you have to admit, brilliant.

    The counter part is /usr/local/sbin/udev-unescape:

    #! /bin/sh
    
    # Utility to decode string that were produced by udev-unescape.
    # Carlo Wood (Dec 2024).
    
    echo "$1" | /usr/bin/tr '.:_' '+/=' | /usr/bin/base64 -d
    

    Warning: the output of this program can contain ANYTHING, including newline characters. So you should be very careful how to use it in a service, that is being run by root and stuff. Probably best to apply some filtering.

    Using the above, %i is going to have a value like MDQ2YmE4MWItN2Q5Yy00YTU0LWE2OWYtNmZiYTA2YWM3NzU0Cg__. The device path then is /dev/%I, or /dev/usb/MDQ2YmE4MWItN2Q5Yy00YTU0LWE2OWYtNmZiYTA2YWM3NzU0Cg__, which will be a symlink to for example /dev/sdc3. And inside the service scripts we can retrieve our information by passing %i to udev-unescape:

    >udev-unescape MDQ2YmE4MWItN2Q5Yy00YTU0LWE2OWYtNmZiYTA2YWM3NzU0Cg__
    046ba81b-7d9c-4a54-a69f-6fba06ac7754
    

    Hence, [email protected] now becomes:

    [Unit]
    Description=Fake mount service (service B)
    After=dev-%i.device
    Requisite=dev-%i.device
    BindsTo=dev-%i.device
    
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStart=/bin/systemd-cat -t usbtest /usr/local/sbin/log_service "%i" start
    ExecStop=/bin/systemd-cat -t usbtest /usr/local/sbin/log_service "%I" stop
    
    [Install]
    WantedBy=dev-%i.device
    

    Passing arbitrary information from udev to a service.

    Udev has a lot of information available, it would be a waste not to pass that. With the USB stick inserted, you can now easily see which partitions are available:

    >ls -l /dev/usb
    lrwxrwxrwx  1 root root       7 Dec 24 15:58 MDQ2YmE4MWItN2Q5Yy00YTU0LWE2OWYtNmZiYTA2YWM3NzU0Cg__ -> ../sdc3
    lrwxrwxrwx  1 root root       7 Dec 24 15:58 NDc1NTNmNjQtZTRiMS00YWQxLTg5ZTItNzMxMzNiZGFhNjVkCg__ -> ../sdc2
    lrwxrwxrwx  1 root root       7 Dec 24 15:58 YTUyZWU4ZjAtYThmYS00MjAwLThjMTktZDc5ODMwM2FjMTE4Cg__ -> ../sdc1
    

    Lets say we want to investigate what information is available for sdc1. We can list the ATTR values with:

    >sudo udevadm info -a -p $(udevadm info -q path -n /dev/sdc1)
    ...
      looking at device '/devices/pci0000:00/0000:00:08.1/0000:0c:00.3/usb8/8-4/8-4.4/8-4.4:1.0/host12/targ>
        KERNEL=="sdc1"
        SUBSYSTEM=="block"
        DRIVER==""
        ATTR{alignment_offset}=="0"
        ATTR{discard_alignment}=="0"
        ATTR{inflight}=="       0        0"
    ...etc
    

    And we can inspect the udev environment variables using - say:

    >sudo udevadm test $(udevadm info -q path -n /dev/usb/YTUyZWU4ZjAtYThmYS00MjAwLThjMTktZDc5ODMwM2FjMTE4Cg__)
    ...
    Reading rules file: /etc/udev/rules.d/69-gold-usb.rules
    ...
    sdc1: /etc/udev/rules.d/69-gold-usb.rules:2 Running PROGRAM="/usr/local/sbin/udev-escape 'a52ee8f0-a8fa-4200-8c19-d798303ac118'"
    sdc1: Running in test mode, skipping execution of '/usr/local/sbin/udev-escape 'a52ee8f0-a8fa-4200-8c19-d798303ac118 crypto_LUKS''.
    ...
    Properties:
      DEVPATH=/devices/pci0000:00/0000:00:08.1/0000:0c:00.3/usb8/8-4/8-4.4/8-4.4:1.0/host12/target12:0:0/12:0:0:0/block/sdc/sdc1
      DEVNAME=/dev/sdc1
      DEVTYPE=partition
    ...
      ACTION=add
      SUBSYSTEM=block
      TAGS=:systemd:
      ID_BUS=usb
      ID_MODEL=DataTraveler_3.0
      ID_MODEL_ENC=DataTraveler\x203.0
      ID_MODEL_ID=1666
      ID_SERIAL=Kingston_DataTraveler_3.0_408D5CBF5F0AE7C0E9150B70-0:0
      ID_SERIAL_SHORT=408D5CBF5F0AE7C0E9150B70
    ...
      ID_TYPE=disk
      ID_FS_UUID=a52ee8f0-a8fa-4200-8c19-d798303ac118
      ID_FS_TYPE=crypto_LUKS
    ...
      [email protected]
    

    Note that SYSTEMD_WANTS has an empty %i because we never really did run udev-escape in this case.

    We're going to need the value of ID_FS_TYPE too, so lets change the udev rule to its FINAL VERSION:

    daniel:/etc/udev/rules.d>cat 69-gold-usb.rules
    # Detect insertion of any of the three "Kingston DataTravel SE9 G3 64GB" USB security sticks.
    SUBSYSTEMS=="block", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL_SHORT}=="408D5CBECBBDE7C0E9160666|408D5CBF5F0AE7C0E9150B70|408D5CBECAC3E7C0E9170AEC", ACTION=="add", PROGRAM="/usr/local/sbin/udev-escape '$env{ID_FS_UUID} $env{ID_FS_TYPE}'", SYMLINK+="usb/%c", ENV{SYSTEMD_WANTS}="mount-gold@usb-%c.service"
    
    # Added 22 December 2024.
    # After changing this file run: sudo udevadm control --reload-rules
    

    Here I added $env{ID_FS_TYPE} to the encoding of the symlink.

    Adding auto-mounting

    We're now done with udev. [email protected] is started properly and we can pass any information (from udev) to it that we need.

    To finish this project, lets rename [email protected] to something normal and change it to call some real scripts.

    What I did was create the file /etc/systemd/system/[email protected] with the following content:

    [Unit]
    Description=Mount Gold USB device /dev/%I.
    After=dev-%i.device
    Requisite=dev-%i.device
    BindsTo=dev-%i.device
    
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStart=/usr/local/sbin/usb-gold-start %i
    ExecStop=/usr/local/sbin/usb-gold-stop %i
    
    [Install]
    WantedBy=dev-%i.device
    

    This incorporates everything we learned about the unit file leaving us only with the task of writing the scripts.

    TODO

    This answer is getting so long that I decided to post it already. I'll make updates to the remaining parts once I got it fully working.

    My current files are: /usr/local/sbin/usb-gold-start:

    #! /bin/sh
    
    # Strip the leading "usb-" from the argument.
    ENCODED_DATA=${1:4}
    # Decode the data that was passed.
    DATA="$(/usr/local/sbin/udev-unescape $ENCODED_DATA)"
    # Extract the value of ID_FS_UUID (the first argument).
    ID_FS_UUID=${DATA%%\ *}
    # Extract the value of ID_FS_TYPE (the second argument).
    ID_FS_TYPE=${DATA#*\ }
    # Cache the block device path of the partition.
    DEVPATH="/dev/disk/by-uuid/$ID_FS_UUID"
    
    # Use /etc/fstab to mount the partition.
    if [ "$ID_FS_TYPE" = "ext2" ]; then
      mount $DEVPATH
    elif [ "$ID_FS_TYPE" = "crypto_LUKS" ]; then
      /usr/local/sbin/get-usb-gold-luks-pass | cryptsetup -q luksOpen $DEVPATH usb-$ID_FS_UUID
      mount $(blkid --output export /dev/mapper/usb-$ID_FS_UUID | grep '^UUID=')
    fi
    

    /usr/local/sbin/usb-gold-stop:

    #! /bin/sh
    
    # Strip the leading "usb-" from the argument.
    ENCODED_DATA=${1:4}
    # Decode the data that was passed.
    DATA="$(/usr/local/sbin/udev-unescape $ENCODED_DATA)"
    # Extract the value of ID_FS_UUID (the first argument).
    ID_FS_UUID=${DATA%%\ *}
    # Extract the value of ID_FS_TYPE (the second argument).
    ID_FS_TYPE=${DATA#*\ }
    
    ACTION=stop
    
    echo $1 > /tmp/"$ACTION"_$ID_FS_UUID
    echo $ENCODED_DATA >> /tmp/"$ACTION"_$ID_FS_UUID
    echo $DATA >> /tmp/"$ACTION"_$ID_FS_UUID
    echo $ID_FS_UUID >> /tmp/"$ACTION"_$ID_FS_UUID
    echo $ID_FS_TYPE >> /tmp/"$ACTION"_$ID_FS_UUID
    
    if [ "$ID_FS_TYPE" = "ext2" ]; then
      # Nothing to be done: it is already unmounted by the time the service is stopping.
      #umount /dev/disk/by-uuid/$ID_FS_UUID
      true
    fi
    

    EDIT (28 December 2024):

    It turned out that also the SYMLINK trick can't be used, because that ".device" is killed during the cryptsetup, causing the .service to be terminated before cryptsetup returns. The latter still gets the chance to finish what it is doing, but mounting afterwards is a no-go.

    Therefore, we need(ed) another method: One can use IMPORT{program} which preserves backslashes. For example: IMPORT{program}="/usr/local/sbin/udev-gold-usb-systemd_wants.sh $env{ID_SERIAL_SHORT}-part$env{PARTN}", in which case it is theoretically possible to write double backslashes to the output of udev-gold-usb-systemd_wants.sh which then become single backslashes. However, this is deprecated because it has been decided (I think) that this 8-year-old bug just has to be fixed (see the previous link to the systemd issue; which has considerably grown since I added it). For the time being, it is best to stay away from trying to pass backslashes completely.

    • 2
  2. Best Answer
    Carlo Wood
    2024-12-30T00:35:06+08:002024-12-30T00:35:06+08:00

    This answer is written after I solved the problem (as opposed to writing it while I was doing all the research).

    systemd already supports mounting encrypted filesystems out of the box. The following points are required:

    • A new udev rule to trigger a custom template service unit.
    • A custom service to trigger systemd's mount unit.
    • An entry in /etc/fstab for each partition, from which systemd-fstab-generator will generate the required mount unit.
    • An entry in /etc/crypttab for each partition that is encrypted, from which systemd-cryptsetup-generator will generate the required [email protected] template unit.

    While implementing this we have to take into account that udev rules and systemd escape functionality do not play well together. We need to avoid the use of backslashes or it either won't work or will break in the near future when these bugs are fixed.

    The custom service is only required because a mount unit can not be a template.

    The udev rule

    The udev rule can contain tests like ATTR{removable}=="1". To get a full list of possible ATTR tests, run:

    sudo udevadm info --attribute-walk --name=/dev/sdc1
    

    where /dev/sdc1 is the device path of a currently inserted USB stick partition.

    Likewise, one can get a list of possible ENV{<property name>}=="<regular expression>" values with:

    sudo udevadm info --query=property --export --name=/dev/sdc1
    

    which will list lines as ID_SERIAL_SHORT='408D5CBF5F0AE7C0E9150B70'. For example, my /etc/udev/rules.d/69-gold-usb.rules contains:

    # Detect insertion of any of the three "Kingston DataTravel SE9 G3 64GB" USB security sticks.
    SUBSYSTEMS=="block", \
    ENV{DEVTYPE}=="partition", \
    ENV{ID_SERIAL_SHORT}=="408D5CBECBBDE7C0E9160666|408D5CBF5F0AE7C0E9150B70|408D5CBECAC3E7C0E9170AEC", \
    ACTION=="add", \
    IMPORT{program}="/usr/local/sbin/udev-gold-usb-systemd_wants.sh $env{ID_SERIAL_SHORT}-part$env{PARTN}"
    
    # Added 28 December 2024.
    # After changing this file run: sudo udevadm control --reload-rules
    

    And yes, you can use backslashes to split up long lines. Just don't forget to use == (not =) and don't forget the comma's.

    Note that this rule uses IMPORT{program} which is currently (December 2024) the only way to pass double backslashes to a SYSTEMD_WANTS property, but as the behavior of systemd is going to change in that regard (no longer requiring double backslashes), we shouldn't be using backslashes. This means that we can use slashes ('/' for paths) which are converted to a hyphen ('-'), but we can't use a hypen ('-' as appear in UUIDs) which would be escaped as '\x2d'.

    The script /usr/local/sbin/udev-gold-usb-systemd_wants.sh contains:

    #! /bin/sh
    echo "SYSTEMD_WANTS=mount-gold@$1.service"
    

    and we are passing to it something like 408D5CBF5F0AE7C0E9150B70-part1 where the hypen is an escaped '/'! This string therefore must be used as, and thus exist, as part of a path that contains "408D5CBF5F0AE7C0E9150B70/part1" or it can't work.

    Don't forget to run

    sudo udevadm control --reload-rules
    

    to re-read all udev rules after you made changes.

    The template service [email protected]

    As said before, this custom service is only required to allow the udev rule to have a variable path (although, I copied the idea from here without really testing if we can't specify the .mount directly).

    For the rest is does nothing, but a StartExec is required. Therefore this unit file contains:

    [Unit]
    Description=Mount Gold USB device /mnt/usb/%I.
    Requires=mnt-usb-%i.mount
    After=mnt-usb-%i.mount
    
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStart=/bin/true
    

    And as .mount unit files use their mount point as name, this means that this specifies the mount point as /mnt/usb/408D5CBF5F0AE7C0E9150B70/part1! Fortunately we don't have to create that directory ourselves, see below.

    The /etc/fstab entry.

    /etc/fstab can contain entries that will cause systemd to generate .mount unit files, normally at boot time, but you can re-trigger this by running:

    sudo systemctl daemon-reload
    

    Here is an example of what is in my /etc/fstab:

    UUID=5b214986-7db3-439c-99ba-f4da0cebdf34       /mnt/usb/408D5CBF5F0AE7C0E9150B70/part1 ext2    rw,noauto,noatime,x-mount.mkdir,x-systemd.requires=systemd-cryptsetup@usba52ee8f0a8fa42008c19d798303ac118.service       0 0
    UUID=a3c7ffb6-3883-42a9-a880-e51f10e69f30       /mnt/usb/408D5CBF5F0AE7C0E9150B70/part2 ext2    rw,noauto,noatime,x-mount.mkdir,x-systemd.requires=systemd-cryptsetup@usb47553f64e4b14ad189e273133bdaa65d.service       0 0
    UUID=046ba81b-7d9c-4a54-a69f-6fba06ac7754       /mnt/usb/408D5CBF5F0AE7C0E9150B70/part3 ext2    rw,noauto,noatime,x-mount.mkdir 0 0
    

    Note how this contains the same mount point path /mnt/usb/408D5CBF5F0AE7C0E9150B70/part1, otherwise it wouldn't cause the generation of the mnt-usb-408D5CBF5F0AE7C0E9150B70-part1.mount unit.

    The first column, UUID=5b214986-7db3-439c-99ba-f4da0cebdf34, contains the UUID of the partition that must be mounted: the decrypted /dev/mapper/usba52ee8f0a8fa42008c19d798303ac118, not the encrypted /dev/sdc1 partition. x-mount.mkdir causes the mount point path to be automatically created if it doesn't exist. And x-systemd.requires=systemd-cryptsetup@usba52ee8f0a8fa42008c19d798303ac118.service makes sure that cryptsetup is being run first in order to create that decrypted /dev/mapper/usba52ee8f0a8fa42008c19d798303ac118 that we want to mount.

    Also note that partition 3 is not encrypted, so 046ba81b-7d9c-4a54-a69f-6fba06ac7754 is the UUID of /dev/sdc3 and that line doesn't have a x-systemd.requires=.

    The /etc/crypttab entry.

    For the encrypted partitions to work, we also need an entry in /etc/crypttab:

    usba52ee8f0a8fa42008c19d798303ac118     /dev/disk/by-uuid/a52ee8f0-a8fa-4200-8c19-d798303ac118  none    luks,noauto
    usb47553f64e4b14ad189e273133bdaa65d     /dev/disk/by-uuid/47553f64-e4b1-4ad1-89e2-73133bdaa65d  none    luks,noauto
    

    Here /dev/disk/by-uuid/a52ee8f0-a8fa-4200-8c19-d798303ac118 is the encrypted partition (it points to /dev/sdc1) and usba52ee8f0a8fa42008c19d798303ac118 is a random id, which as it turns out, can not contain backslashes [...]. In order to avoid collisions I used the UUID, but had to remove the hypens from it.

    Entering the pass phrase to unlock the LUKS partitions.

    With the above in place and having reloaded the configs (see above), inserting the USB stick will send a broadcast message to all tty's with something like:

    Broadcast message from root@<your host name> (Sun 2024-12-29 16:46:37 CET):
    
    Password entry required for '<some description>' (PID 281235).
    Please enter password with the systemd-tty-ask-password-agent tool.
    

    Just hit Enter to see your prompt again (assuming it was still empty and your weren't in the middle of typing), and run:

    sudo systemd-tty-ask-password-agent
    

    This will then allow you to enter whatever secret is required. If the USB contains more than one partition, but have the same pass phrase, then you only have to enter it once (the second one will try the last entered pass phrase first and since that works won't require you to enter it again). I didn't test what happens if they have a different pass phrase, I can imagine that in that case you have a problem; maybe need to run sudo systemd-tty-ask-password-agent again after a failure or something like that.

    Using a YubiKey

    Install the package libfido2. Then, with your YubiKey inserted, run:

    sudo systemd-cryptenroll --fido2-device=auto /dev/sdc1
    

    (and afterwards for all other encrypted partitions, of course). This will ask you to enter the passphrase of /dev/sdc1, then it will ask for the FIDO2 PIN. If you didn't change that yet, it will be the default 123456.

    You can change this PIN with the following command:

    sudo ykman fido access change-pin
    

    Doesn't matter if you do this before or after. It has no effect on the FIDO credentials.

    You can inspect the result with

    sudo cryptsetup luksDump /dev/sdc1
    

    This now should show one more key under Keyslots:, at the very least the one containing your pass phrase, but also a new one. Under Tokens: you will see an entry with systemd-fido2, and a reference to the Keyslot that it uses.

    To make the system use the YubiKey, change the entries in your /etc/crypttab to contain fido2-device=auto. For example,

    usba52ee8f0a8fa42008c19d798303ac118     /dev/disk/by-uuid/a52ee8f0-a8fa-4200-8c19-d798303ac118  none    luks,noauto,fido2-device=auto
    

    and rerun sudo systemctl daemon-reload.

    If now you insert the USB key it should do a broadcast message as before, but if then you run sudo systemd-tty-ask-password-agent it will ask for Please enter LUKS2 token PIN:. Enter the PIN that you set (or still 123456) and then tap your YubiKey once for every partition that needs to be decrypted.

    Now your partitions should be mounted. If they are not mounted then you are in deep shit because I didn't explain anything, I just hand-held you with the final answer :(. Expect many days of reading documents and learning all kinds of commands to find out intermediate results and debug output (e.g. journalctl -b -t systemd). Asking an A.I. for help with learning these commands actually helps here.

    Finally, here is a little script that I used to print the required entries for /etc/fstab and /etc/crypttab, because that is a lot of work and I had three of these USB sticks (in case of failure of one in the future):

    # Get the device path.
    DEVPATH=$(/bin/ls /dev/disk/by-id/usb-Kingston_DataTraveler* | grep -E -v -- '-part[0-9]+$')
    ID_SERIAL_SHORT=$(udevadm info -n $DEVPATH | grep ID_SERIAL_SHORT | sed -e 's/.*ID_SERIAL_SHORT=//')
    echo "/etc/fstab:"
    for p in $(/bin/ls $DEVPATH-part*); do
      PART=$(echo $p | sed -r -e 's/.*-(part[0-9]+)$/\1/')
      UUID=$(blkid --match-token TYPE=crypto_LUKS $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/' || true)
      if [ -n "$UUID" ]; then
        MAPPERID=$(echo "usb$UUID" | sed -e 's/-//g')
        echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID $MAPPERID 2>/dev/null
        UUID2=$(blkid /dev/mapper/$MAPPERID | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
        ID_FS_TYPE=$(udevadm info -n /dev/mapper/$MAPPERID | grep 'ID_FS_TYPE=' | sed -e 's/.*ID_FS_TYPE=//')
        echo -e "UUID=$UUID2\t/mnt/usb/$ID_SERIAL_SHORT/$PART\t$ID_FS_TYPE\trw,noauto,noatime,x-mount.mkdir,x-systemd.requires=systemd-cryptsetup@$MAPPERID.service\t0 0"
        sudo cryptsetup luksClose $MAPPERID 2>/dev/null
      else
        UUID=$(blkid $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
        ID_FS_TYPE=$(udevadm info -n $p | grep 'ID_FS_TYPE=' | sed -e 's/.*ID_FS_TYPE=//')
        echo -e "UUID=$UUID\t/mnt/usb/$ID_SERIAL_SHORT/$PART\t$ID_FS_TYPE\trw,noauto,noatime,x-mount.mkdir\t0 0"
      fi
    done
    echo "/etc/crypttab:"
    for p in $(/bin/ls $DEVPATH-part*); do
      PART=$(echo $p | sed -r -e 's/.*-(part[0-9]+)$/\1/')
      UUID=$(blkid --match-token TYPE=crypto_LUKS $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/' || true)
      if [ -n "$UUID" ]; then
        MAPPERID=$(echo "usb$UUID" | sed -e 's/-//g')
        echo -e "$MAPPERID\t/dev/disk/by-uuid/$UUID\tnone\tluks,noauto,fido2-device=auto"
      fi
    done
    
    • 2

relate perguntas

  • Como atribuir links simbólicos a dispositivos seriais do dispositivo usb para serial CP2105?

  • Por que o Udev está carregando dois módulos de kernel para um único dispositivo USB?

  • Altere os dados dos sensores iio por meio de ACCEL_MOUNT_MATRIX personalizado

  • Executando script por meio da regra udev no Chrome OS [fechado]

  • udev, udisks, dbus e comando dd

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve