Preparar um Pendrive com FAT32 a prova de Burrice

A muito tempo que não escrevo um script em bash e percebo que estou muito enferrujado. No entanto, depois de algumas tentativas e erros, com muitas consultas ao man e a rede, o script saiu.

A ideia deste script é eliminar um potencial acidente, a qual já me deixou sem sistema operacional e sem meus preciosos documentos, arquivos, planilhas, projetos, …, ao menos umas três vezes ao longo destes últimos 15 anos de computação. A estória somente não foi pior nas últimas ocorrências pois me tornei sistemático o suficiente para manter backups, ao menos bimestrais, nos últimos anos.

O problema vem na execução de comandos básicos como o dd e o fdisk em meros pendrives de uso geral. Procedimentos comuns que devemos fazer sempre que instalamos um sistema novo em alguma máquina, através do pendrive, ou simplesmente se deseja formatar o dispositivo. Não foi uma vez em que troquei o /dev/sdb por um /dev/sda, e neste momento o sistema foi para o saco.

Na última trágica ocasião em que isto aconteceu, me lembro que estava do meio para o final do semestre na universidade, e perdi notas de provas, de trabalhos e outras atividades, enquanto que o meu backup mais recente datava de quase um ano atrás.

Na ocasião fui obrigado a aprender a utilizar o TestDisk para recuperar as informações perdidas do disco rígido recém particionado/formatado e felizmente recuperei a maior parte das informações primordiais. Na ocasião, até pensei em fazer um tutorial a respeito do processo, no entanto o desespero para a recuperação dos dados foi tamanho que achei mais conveniente concentrar minha minha atenção em recuperar os dados, deixando o texto para uma outra ocasião. O TestDisk está anotado em minha lista de futuros artigos.

A intenção deste texto não é ser um texto de orientação a criação de bash scripts, mas apenas documentar uma experiencia em tentar tornar o uso do sistema menos destrutivo, em tarefas básicas.

A Ideia do Script

A ideia do script é que este seja inteligente o suficiente para impedir que erros tolos, como formatar um disco em uso não ocorram. Para isto tracei as seguintes premissas para o script:

  • Não particionar/formatar dispositivos com partições montadas;
  • Não particionar/formatar discos definidos como disco de sistema.

A primeira premissa é feita na linha 18, onde os dispositivos montados são listados na variável MOUNTEDDEVS, através de uma consulta ao comando df.

Quanto à segunda premissa, havia a possibilidade de consultar o arquivo /etc/fstab. Mas devido a possibilidade do uso dos códigos UUID para indicar as partições dos disco, o que virou padrão na maioria das distribuições, optei por adicionar os disco do sistema em uma variável, SYSDEVICES, como dispositivos reservados para o sistema. Esta variável esta definida na linha 20 com os dispositivos sda e sdb, que são os dois discos que compõem o meu sistema.

Como medida de segurança adicional, o aplicativo apenas formata os discos do sistema se estes estiverem desmontados e a opção --force for passada para o script.

Como particionamento/formatação de um dispositivo é algo muito destrutivo, o script ainda irá pedir uma confirmação antes de executar os comandos, linha 88.

O dispositivo a ser particionado/formatado pode ser passado como parâmetro com a opção -d <device>. Se este não for passado, o último dispositivo conectado a uma das portas USB será selecionado com uma consulta nas últimas linhas do comando dmesg, linha 48.

Adicionei ainda: uma opção de warning, -w, para simular os comandos sem de executá-los; uma opção para adicionar um label para o dispositivo, -n; além do help do script, -h.

O script completo segue abaixo:

#!/bin/bash 
#
# Create a new FAT32 partition on the stick and write a FAT32 
# filesystem on it.
#

function help()
{
    echo "Use: # `basename $0` [options]:"
    echo "    Where:"
    echo "        -d "
    echo "        -n "
    echo "        --force (to force format of SYSDEVICES)"
    echo "        -w (warning mode. Don't format)"
    echo "        -h for help"
}

MOUNTEDDEVS=`df -h | grep '^\/dev\/sd[a-z]' | cut -c-8 | sort | uniq | cut -c6-`
FORCE=false
SYSDEVICES="sda sdb"
WARN=false

while [ ! -z $1 ]; do
    case $1 in
        '-d')
            DEV=$2
            shift
            ;;
        '-n')
            DEVNAME=$2
            shift
            ;;
        '--force')
            FORCE=true
            ;;
        '-w')
            WARN=true
            ;;
        '-h'|*)
            help
            exit 0
            ;;
    esac
    shift
done

if [ -z "$DEV" ]; then
    DEV=`dmesg | tail | grep '\[.*\] *sd[bcdefg]' | rev | cut -d" " -f1 | rev | tr -d ':0123456789' | head -n1`
fi

if [ -z "$DEVNAME" ]; then
    DEVNAME="USBDisk"
fi

echo -n "Check by mounted devices: "
for dev in $MOUNTEDDEVS; do
    if [ "$dev" == "$DEV" ]; then
        # Abort format of mounted devices
        echo "mounted..."
        echo "Device /dev/$DEV is in use. To format it you need umount all partitions this device before."
        df -h | grep "^\/dev\/$DEV"
        exit 0
    fi
done
echo "Device isn't mounted..."

echo -n "Check by System devices: "
SYSDEV=false
for dev in $SYSDEVICES; do
    if [ "$dev" == "$DEV" ]; then
        SYSDEV=true
        if $FORCE; then
            echo "Is a system device, but forced enable..."
            break
        fi
        echo -e "Is a system device...\n"
        echo "Use --force option to format a system device, or edit SYSDEVICES variable in this script."
        exit 0
    fi
done
if ! $SYSDEV; then
    echo "Is not a system device..."
fi

echo -ne "\nFormat device /dev/${DEV} with name ${DEVNAME} (y/N)? "
read ANS

if [ "$ANS" != "Y" -a "$ANS" != "y" ]; then
    exit 0
fi

echo -e "\nClear first 10MB..."
if $WARN; then
    echo "dd if=/dev/zero of=/dev/$DEV bs=1M count=10"
else
    dd if=/dev/zero of=/dev/$DEV bs=1M count=10
fi

echo -e "\nRemove partitions in device /dev/${DEV} ..."

if $WARN; then
    echo "fdisk /dev/$DEV <

Uso do Script

Chamei o script de usbfat32, uma vez que no momento é um script especializado para formatar dispositivos USB em FAT32. Mas é possível que adiante estenda a ideia. As linhas a seguir mostram alguns exemplos de uso:

Limpa a tabela de partição do dispositivo /dev/sdc, formata em FAT32 e configura o nome do dispositivo para 'Alves':

usbfat32 -d sdc -n Alves

Limpa a tabela de partição do dispositivo recém inserido a porta USB, formata em FAT32 e configura o nome do dispositivo para 'Alves':

usbfat32 -n Alves

O mesmo que o comando anterior, mas sem executar nada:

usbfat32 -n Alves -w

A próxima linha de comando mostra o que acontece ao tentar formatar um dispositivo montado:

usbfat32 -d sda
Check by mounted devices: mounted...
Device /dev/sda is in use. To format it you need umount all partitions this device before.
/dev/sda1        25G  8.4G   17G  34% /
/dev/sda4       102G   14G   89G  14% /home

Neste último comando o dispositivo está desmontado, mas está assinalado como sendo dispositivo do sistema:

usbfat32 -d sdb
Check by mounted devices: Device isn't mounted...
Check by System devices: Is a system device...

Use --force option to format a system device, or edit SYSDEVICES variable in this script.

Neste último caso, se usar a opção --force o dispositivo /dev/sdb será particionado e em seguida formatado em FAT32.

Conclusões

O script está com o código ainda tosco, necessitando de um pouco de lapidação, como disse estou muito sem prática. No entanto faz bem o seu papel. Acho que assim ao menos fica reduzida a probabilidade de formatar o HD no lugar do pendrive. Os interessados em melhorar a ideia estão convidados a compartilhar.

Este post tem 5 comentários

  1. AnN

    Olá! Primeiramente, gostaria de parabenizá-lo pelo ótimo trabalho que vem realizando neste site!

    São poucos os sites que compartilham dicas e informações a respeito do Slackware.

    Gostaria de fazer parceria, também tenho um blog destinado ao Slackware. Se tiver interesse, entre em contato comigo via email.

  2. rudsonalves

    Ola AnN, valeu. Lhe mandei um email. No entanto deveria ter deixado o endereço de seu blog.

  3. AnN

    Olá @rudsonalves,

    me desculpe a demora, devido ao trabalho e a faculdade também não estou tendo tempo de atualizar meu blog, e acabei esquecendo de responder teu email. Como perdi o endereço do seu email na minha caixa de entrada (o gmail deleta automaticamente após um tempo), então voltei aqui para respondê-lo. Coloquei o endereço do blog no campo Web Site, conversaremos por email se ainda quiser manter parceria. Até mais, abraços!

  4. netto

    Bacana seus artigos…. pena que o Facebook não permite compartilha-los em lugar nenhum porque o seu domínio está identificado como nocivo.
    Abraços

Deixe um comentário

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.