Nota: Este artigo, bem como referências descritas e licenças encontram-se em:
http://linux.lcc.ufmg.br
Todos nós armazenamos arquivos em nossos computadores. Guardamos fotos, vídeos, aqueles mp3, fazemos backups, guardamos dados importantes etc. Então cabe aqui um comentário que parece óbvio, mas que motivou a escrita deste artigo. Guardamos nossos arquivos porquê queremos acessá-los no futuro e queremos que estes arquivos estejam lá quando desejarmos acessá-los.
Acredito que todos nós já tenhamos perdido algum arquivo, quer seja por um descuido, quer seja por um problema físico em nossos HDs, ou ainda por um sistema de arquivos que se corrompe. Muitas técnicas para recuperação de arquivos existem e é provável que, se nunca as utilizamos, venhamos a usá-las algum dia em nossas vidas. Mas muitas destas técnicas falham em recuperar arquivos por problemas simples que podem ser evitados com os procedimentos corretos.
Este é o objetivo deste artigo.
chmod e a proteção dos dados
Todos os arquivos em
Linux possuem modos de operação que definem seu tipo de acesso e utilização. É fácil verificar estes modos utilizando o comando
chmod. Exemplo:
Criemos um arquivo de teste:
:> teste
Agora verifiquemos seus modos de acesso e utilização:
ls -l teste
A saída do comando ls -l, no meu caso, é a seguinte:
total 0
-rw-r--r-- 1 davelino davelino 0 May 21 10:35 teste
Os modos do arquivo teste estão explicitados no primeiro campo desta saída, ou seja:
-rw-r--r--
Estes campo possuem dez atributos (conte os sinais "-" também). O primeiro campo indica o tipo do arquivo. Para o caso de um diretório temos um "d" como primeiro atributo. Para um link simbólico um "l". Para um "character device", um "c", para um "block device" um "b" e assim por diante. No caso de um arquivo, temos apenas um "-".
Os atributos 2, 3 e 4 definem os modos para o criador do arquivo. Os atributos 5, 6 e 7 definem os modos do grupo (terceiro campo) ao qual aquele arquivo pertence e os últimos três atributos definem os modos para os usuários que não se enquadram nas duas categorias citadas anteriormente.
Um comando para alterarmos os modos de um arquivo é o
chmod (acrônimo para change modes). Por exemplo, fazendo-se:
chmod +x teste
Estamos modificando o atributo de execução do arquivo teste, permitindo que qualquer usuário possa executá-lo. Caso queiramos que apenas os usuários do mesmo grupo ao qual o arquivo pertence possam executá-lo faríamos:
chmod g+x teste
Uma das sintaxes do chmod - a utilizada acima - pode ser descrita da seguinte maneira:
chmod [perfil][+|-|=][permissões] arquivo
Os perfis disponíveis são:
- u - proprietário do arquivo
- g - usuários pertencentes ao mesmo grupo do arquivo
- o - usuários que não estão no grupo do arquivo
- a - todos os usuários
[+|-|=] são os operadores que explicitam se vamos adicionar ou remover um modo. O operador "=" adiciona a permissão em questão e remove todas as que não foram explicitadas. As permissões podem ser:
- r: leitura
- w: escrita
- x: execução / busca por diretórios
- X: execução (executa apenas se o arquivo é um diretório ou já possui permissão de execução para algum usuário
- s: configura o usuário e o grupo para execução
- t: restrição de deleção (sticky bit)
chmod contra corrupção involuntária de dados
Imaginem o seguinte caso: tenho uma coleção de arquivos (mp3, filmes, livros, trabalhos) armazenados em um diretório. Peço para listar as permissões destes arquivos e voilà, todos estão com permissão de escrita. Isto é realmente necessário? Pense no transtorno que uma linha mal escrita pode causar.
Por exemplo, um redirecionamento errado, que pode acontecer a qualquer um e lá se vai algum arquivo que poderia ser importante. Por estas e outras, evite conceder a permissão de escrita a arquivos onde apenas a leitura é necessária.
Em arquivos de backup isto é particularmente importante porque evita uma corrupção involuntária dos dados. Muitas vezes usamos rotinas para armazenar as cópias dos dados, chamando-as backup-<data>.bkp, por exemplo. Um errinho na data por exemplo e olha o nosso amigo Murphy tendo a chance que precisa para atuar. Quero chamar a atenção aqui para o fato de que sobrescrever um arquivo é mais fácil do que parece e esta configuração simples, das permissões dos arquivos importantes, pode ser uma ajuda e tanto quando cometemos este tipo de erro.
Vale lembrar que um sistema tolerante a erros caracteriza robustez e ganha muito em usabilidade e segurança. Vamos errar. Fato. E quando fizermos isto, queremos que os danos sejam os menores possíveis. Neste sentido que a tolerância deve ser entendida aqui.
chmod contra remoção involuntária de arquivos
O mesmo cenário da corrupção involuntária pode ser aplicado para o caso da remoção involuntária de arquivos. Um "rm" em arquivos errados pode ser algo terrível. Se temos arquivos importantes, cuja remoção pode causar transtornos, porque não configurar o (sticky bit) e limitarmos a remoção destes arquivos? Vale pensar um pouco sobre isto.
O comando rm
O "rm" é um comando utilizado quando desejamos remover arquivos. Diretórios são arquivos especializados em leitura. O "rm" possui algumas opções úteis para alertar o usuário antes de uma remoção ser executada. A opção mais comentada é a -i, que pergunta se deseja-se remover mesmo aquele arquivo. Em contrapartida, existe a opção -f que não faz nenhum tipo de questionamento, assumindo que o usuário sabe exatamente o que ele está fazendo. Existe uma outra opção, -I (i maiúsculo), que questiona o usuário quando este deseja remover mais de três arquivos ou quando se faz uma remoção recursiva, via "rm -r".
* rm -f:
Responsável pela maior parte das remoções indesejadas, muitas vezes usado em conjunto com a opção -r, o parâmetro -f faz com que o rm execute sem nenhum tipo de questionamento. Ideal para quem está convicto da decisão tomada. E, por mais que este comando seja perigoso - em caso de uma desatenção perdemos nossos arquivos e recuperá-los pode ser complicado, senão impossível -, ele é amplamente utilizado pela sua comodidade, pois na maioria dos casos estamos certos da ação que queremos executar.
* rm -i:
Opção interessante, mas que particularmente não recomendo. Isto porque usuários são seres humanos e seres humanos tendem a se acostumar com situações repetitivas e pior, em geral deixamos de avaliar situações repetitivas e em geral tomamos as mesmas decisões neste tipo de caso. Já tive bons exemplos onde, após um uso repetitivo do rm -i, a resposta à pergunta tende a ser sempre sim, independentemente do arquivo em questão. Então a eficácia deste parâmetro é questionável e eu não vejo motivos para utilizá-lo. No meu modo de ver, o rm -i "se torna" o rm -f com o uso.
* rm -I:
rm -I (i maiúsculo) questiona o usuário quando este deseja remover mais de três arquivos ou quando se faz uma remoção recursiva, via rm -r. É diferente do rm -i e diminui o efeito psicológico descrito anteriormente por não questionar ao remover qualquer arquivo. Imagine que dentro de uma janela grande de tempo, toda vez que utilizamos o rm ele tenha perguntado se desejamos realmente remover aqueles arquivos e que tenhamos respondido sim na maioria dos casos. Qual é a probabilidade de, na próxima vez que o rm perguntar sobre a remoção respondermos sim? Certamente, um número bem próximo de 1. Neste sentido, caso se queira utilizar um "alias" para chamar a atenção do usuário para uma remoção, acredito ser esta a melhor opção.
O conceito de lixeira
Uma boa prática é utilizarmos o conceito de lixeira. Uma lixeira é um diretório que armazena temporariamente os arquivos "removidos". Os arquivos de fato não são removidos, são movidos para a lixeira para uma remoção posterior. Simples e bastante tolerante. O custo é o gasto de espaço que é compensado facilmente quando encontramos um arquivo que achávamos ter removido dentro da lixeira.
Arquivos importantes, grupos e usuários diferentes
Se os arquivos são importantes, evitemos muitos dos problemas descritos anteriormente criando um usuário especial e um grupo especial para gerenciá-los. O que ganhamos com isto é que teremos os arquivos importantes sob custódia do usuário responsável por gerenciá-los, no grupo dos arquivos importantes.
Os sinistros descritos até aqui poderiam ser minimizados com esta política. A importância destes arquivos é explicitada e o perfil psicológico para gerenciá-los certamente se torna diferente. Em geral, tomamos mais cuidado neste cenário e consequentemente aumentamos o nível de atenção quando executamos tarefas neste caso.
Arquivos importantes, partição separada
Pode parecer bobagem, mas se os arquivos importantes se encontram em uma partição separada, pode ser muito mais fácil recuperá-los do que se eles estiverem juntos, em uma partição única. Isto por vários motivos, dentre eles destaco dois:
1. Uma partição diferente é em geral menor do que a partição principal do sistema. Então, é mais fácil varrer esta partição do que uma partição gigante, economizando assim o tempo de recuperação de um sinistro.
2. Em uma partição diferente, caso precisemos escrever algum arquivo (por exemplo a saída de um programa de recuperação de arquivos), não corremos o risco de os arquivos importantes serem sobrescritos.
Deste modo o planejamento da estrutura do sistema de arquivos torna-se importante para uma tolerância maior do sistema em casos de ocorrências de sinistros.
Facilitando a recuperação de arquivo
Um sistema de arquivos corrompido, uma remoção indesejada, todos estamos sujeitos a estes dissabores. O que temos que ter em mente nestes casos é que nem tudo está perdido. Avaliemos o seguinte caso:
* Lidando com uma remoção indesejada:
Pronto. Removemos um arquivo indesejado. Ou pior, removemos um diretório importante. O que ainda pode ser feito? O primeiro passo é cessarmos a execução do maior número de programas possível. Isto porque, quando removemos um arquivo, ele não é removido do disco, mas pode ser que uma aplicação necessite escrever em disco e sobrescreve o que desejamos recuperar e naturalmente não desejamos isto.
Agora podemos tentar o procedimento descrito no artigo
recuperando arquivos removidos para tentar recuperar os dados perdidos. Neste artigo faço uma consideração sobre dois tipos de arquivos neste caso, os fáceis e difíceis de recuperar.
Os arquivos fáceis são os que possuem em sua estrutura um cabeçalho e um rodapé. Os difíceis possuem apenas um cabeçalho. Tomemos como exemplo o formato gzip de compressão. O cabeçalho é representado por dois metadados, chamados por ID1 e ID2, ID1 = 31 (0x1f, {TEXTO}37), ID2 = 139 (0x8b, \213). Eles identificam o arquivo como sendo do tipo gzip, mas não contém um rodapé nem uma referência sobre o tamanho do arquivo. Então não temos como saber de antemão onde este arquivo termina, o que o caracteriza como um arquivo difícil de recuperar. O mesmo caso acontece com o formato bzip. Seu cabeçalho é algo como "BZh91AY&SY", mas também não possui rodapé.
Os formatos de imagem possuem em geral, tanto cabeçalhos quanto rodapés. Assim, caso ocorra uma remoção indesejada, basta procurar pelo intervalo entre o cabeçalho e o rodapé (no caso mais simples) e recuperamos os arquivos perdidos. O formato tar é mais interessante. Em seu cabeçalho, além de um metadado que caracteriza o arquivo como sendo um tar, ainda hão outros metadados que definem várias outras características dos arquivos dentro do pacote, como por exemplo o tamanho, os nomes etc. Pense no caso de uma remoção indesejada. É possível encontrarmos os arquivos tar procurando pelos seus respectivos cabeçalhos e, uma vez encontrados os cabeçalhos, como sabemos o tamanho dos arquivos podemos determinar onde ele termina.
À luz destes novos fatos, fica a sugestão: se for preciso utilizar os formatos de compressão bzip e gzip, tomem cuidado. Tenha em mente que, em caso de uma fatalidade, pode não ser possível recuperar os dados. Minha sugestão é, ao criar os arquivos compactados, agrupe os arquivos em um arquivo tar. Ao invés de utilizarmos o famoso .tar.bz2, utilizarmos um empacotamento à mais para garantirmos consistência dos dados. Talvez este procedimento simples seja a diferença entre uma recuperação bem sucedida e uma perda de informações imprescindíveis.
Quando temos um sistema de arquivo corrompido, em geral não podemos utilizar o procedimento do artigo citado anteriormente. Mas existem várias ferramentas para lidar com este tipo de problema, notadamente o fsck. O fsck costuma funcionar bem. Gostaria de comentar o seguinte: quando o sistema de arquivos perde a estrutura de superblocos (superblocos são locais onde sistema de arquivos mantém informações importantes sobre ele próprio), nem tudo está perdido. Existem várias cópias destes superblocos, que podem ser encontradas utilizando o comando:
# tune2fs -l <dispositivo onde o sistema de arquivos foi instalado>
Considerações finais
Vimos neste artigo como é possível um procedimento de redução de danos e algumas diretrizes para se construir um comportamento mais seguro, evitando assim um comprometimento das informações importantes. É interessante comentar que temos que levar em consideração o fato de que cometemos erros. E é neste sentido que devemos nos preparar. Quando os erros acontecerem devemos estar bem preparados a ponto de que o estrago que eles possam vir a causar não seja potencializado por condutas que poderíamos ter evitado. Este é o conceito de tolerância, descrito neste artigo. A tolerância, ao meu ver, precisa ser uma prerrogativa em todos os sistemas que pensemos em administrar e implementar.