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.
5 Comentários