Linux scripting - como aguardo o carregamento de mídia de CD / DVD antes da leitura / montagem?

2

Estou montando um script rápido e sujo para ler 100s de CD / DVDs em um NAS. Ele cuida da ejeção e carregamento da bandeja, mas eu não descobri uma maneira simples de esperar / bloquear para que a mídia fique disponível para o sistema operacional depois de inserir a bandeja.

  • eject -t sai assim que a bandeja é fechada
  • mount falhará com Nenhuma mídia encontrada se ela for executada imediatamente após eject , mas também quando for executada 15 segundos depois.

Os discos são bastante antigos e alguns demoram bastante tempo para ficarem disponíveis, por isso gostaria de evitar a não-solução "dormir por 2 minutos". Alguma ideia? Usando o Ubuntu 18.04.

    
por myxal 24.10.2018 / 19:51

2 respostas

2

Isso acontecerá?

while ! dd if=/dev/sr2 bs=2048 count=1 of=/dev/null 2>/dev/null; do sleep 1; done

Substitua /dev/sr2 pelo seu dispositivo de cd / dvd real.

Você pode torná-lo mais robusto, verificando erros diferentes de No medium found ; não testado, já que não tenho nenhum DVD quebrado à mão:

dev=/dev/sr2
while :; do
        err=$(dd if=$dev of=/dev/null bs=2048 status=none count=1 2>&1)
        case $err in
        "dd: failed to open '$dev': No medium found")
                sleep 1 ;;
        '')
                # successfully opened
                break ;;
        *)
                # unexpected error
                # play some SOUND in the speakers
                # and wait for user input to continue
                read wtf ;;
        esac
done

Atualização:

Nas unidades que o suportam, o Linux fechará automaticamente a bandeja ao tentar abrir o dispositivo. Embora isso possa ter sido desativado por ioctl(CDROM_CLEAR_OPTIONS, CDO_AUTO_CLOSE) , não consegui encontrar nenhum utilitário de linha de comando para implementá-lo. Como isso obriga a usar C , use melhor C para a coisa toda.

Então, aqui está um pequeno aplicativo que pode verificar e pesquisar o status da unidade de cd / dvd.

Se chamado com um único argumento:

cdstatus /dev/sr1

imprimirá o status de /dev/sr1 : um dos no_disc , tray_open , drive_not_ready ou disc_ok .

Se chamado com dois argumentos:

cdstatus /dev/sr1 1.3

ele pesquisará /dev/sr1 a cada 1,3 segundo até que seu status seja disk_ok .

Ele pode ser facilmente criado com cc -Os -Wall cdstatus.c -s -o cdstatus , desde que os pacotes gcc e libc6-dev estejam instalados.

cdstatus.c

#include <sys/ioctl.h>
#include <linux/cdrom.h>
#include <fcntl.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
int main(int argc, char **argv){
        int fd, s; int pt = -1;
        if(argc < 2)
                errx(1, "usage: %s /dev/srX [poll_secs] [verbose]", argv[0]);
        if((fd = open(argv[1], O_RDONLY|O_NONBLOCK)) == -1)
                err(1, "open %s", argv[1]);
        if(argc > 2 && ((pt = strtod(argv[2], 0) * 1000) < 1 || pt > 3600000))
                errx(1, "bad timeout '%s'", argv[2]);
redo:
        switch(s = ioctl(fd, CDROM_DRIVE_STATUS, 0)){
        case -1: err(1, "ioctl(CDROM_DRIVE_STATUS)");
        case CDS_NO_INFO: errx(1, "ioctl(CDROM_DRIVE_STATUS) not implemented");
        }
        if(pt < 0 || argc > 3)
                switch(s){
                case CDS_NO_DISC: printf("no_disc\n"); break;
                case CDS_TRAY_OPEN: printf("tray_open\n"); break;
                case CDS_DRIVE_NOT_READY: printf("drive_not_ready\n"); break;
                case CDS_DISC_OK: printf("disc_ok\n"); break;
                default: printf("status=%d\n", s); break;
                }
        if(pt > 0 && s != CDS_DISC_OK){
                if(poll(0, 0, pt) < 0) err(1, "poll");
                goto redo;
        }
        return s != CDS_DISC_OK;
}
    
por 25.10.2018 / 00:28
1

No final, um postar neste tópico vagamente relacionado no linuxquestions sugeriu usar wodim -atip (entre outras coisas) que acaba funcionando muito bem para bloquear até que o meio esteja disponível.

#!/bin/bash

set -e

DRIVE=${DRIVE:-"sr0"}
DESTROOT=${DESTROOT:-"/mnt/newshare"}
DRV_FULLNAME="$(</sys/class/block/$DRIVE/device/vendor) $(</sys/class/block/$DRIVE/device/model)"

[ -d /tmp/$DRIVE ] || mkdir /tmp/$DRIVE
while true; do
  eject /dev/$DRIVE
  echo "$DRV_FULLNAME is ready."
  read -p "Enter next disc code: " DISC
  if [ -z "$DISC" ]; then
    echo "No disc code = we're done, exiting"
    break
  fi
  eject -t /dev/$DRIVE || {
    read -n1 -r -p "Unable to load tray. Push it in and hit Any key..."
    echo
  }
  wodim dev=/dev/$DRIVE -atip > /dev/null || {
    echo "Medium not detected."
    break
  }
  mount /dev/$DRIVE /tmp/$DRIVE -o ro ||  {
    echo "Couldn't mount medium."
    break
  }
  cp -ia /tmp/$DRIVE/. $DESTROOT/$DISC/ || {
    echo "COPY FAILED. Put it on the read-error pile and continue with next one."
  }
done
    
por 24.10.2018 / 23:43