Sincronizando seus dados com unionfs

Aviso: este artigo apenas descreve uma ideia ou dica de como resolver um problema. Não é minha responsabilidade se você testar a ideia aqui e seu computador subitamente congelar e pegar fogo. Prudência do leitor é aconselhável. Grato pela compreensão. 😉

Usando mais de uma distro de GNU/Linux em um mesmo computador, é comum nos vermos com o problema de lembrar em qual delas está um arquivo de que precisamos. Além de fazer backup do que vale a pena guardar (sempre recomendado), a triagem desses arquivos espalhados por diversos $HOMEs pode consumir muito do nosso tempo e paciência. O ideal, a curto prazo, seria manter sincronizado todo o conteúdo a que temos acesso, ou seja, tudo que está nas pastas Vídeos, Downloads, Imagens e Documentos automaticamente sincronizado entre todas as $HOMEs de todas as instalações de distros na mesma máquina. Desta forma a tarefa de backup tende a ser bem mais simples.

Para resolver esse problema, vamos usar um recurso muito popular quando trabalhamos com contêineres, mas que geralmente funciona debaixo dos panos: o unionfs. Apesar do nome, o union filesystem não é um sistema de arquivos propriamente dito, mas um serviço que se comporta como um, porque ao invés de ler e interpretar o conteúdo de uma partição (os formatos NTFS ou ext4 como exemplos), ele permite fundir dois ou mais diretórios em um único diretório. A beleza disso tudo é que esses diretórios podem estar em diversos sistemas de arquivo diferentes, o unionfs gerencia isso de forma transparente.

Para usar o unionfs como é usado neste artigo, você vai precisar instalar os pacotes do fuse (file system in userspace) e a implementação de unionfs em fuse, que deve ter um pacote com o nome unionfs-fuse ou algo parecido. Talvez exista também na sua distro um pacote chamado fuse-libs do qual fuse depende. Verifique como instalar esses pacotes na sua distribuição favorita. Concluída esta parte, o fuse permitirá que você declare suas configurações no /etc/fstab e as carregue durante o boot.

Voltando ao assunto, considere a forma como o diretório $HOME é organizado. Sabemos que arquivos de configuração criados e usados por aplicativos do usuário geralmente ficam escondidos na sua$HOME. Eles são criados com um ponto inicial (.bashrc, por exemplo) ou ficam agrupados em subdiretórios cujo nome começa com um ponto inicial (.config, por exemplo). Considerando também um bom hábito não popular o diretório $HOME com arquivos avulsos, poluindo ele e o deixando mais lento. Sempre guarde os arquivos em algum subdiretório (mais tarde você verá que esse pequeno detalhe de organização será importante para o tipo de solução que vou propor aqui).

Outra coisa importante sobre o unionfs é que ele define camadas por ordenação. O que isso quer dizer na prática é que, pra definir onde um arquivo novo vai parar quando ele é criado, a ordem de declaração dos diretórios é usada. Digamos que você tenha a seguinte configuração no seu /etc/fstab:

/A=rw:/B=rw    /C    fuse.unionfs

Ou seja, você vai unir os diretórios A e B, ambos com permissão de escrita, em um diretório C, o diretório que vem antes na definição (A) será o diretório que receberá um arquivo criado. Isto quer dizer que se você criar um arquivo em C (como o diretório C é apenas um ponto de montagem, não armazena nenhum conteúdo e tudo que está lá é virtual), tal arquivo acabará sendo criado em A. Pode-se testar isso criando um arquivo vazio em C com o comando de terminal touch e verificando onde ele está realmente:

[hal9000 /]$ cd C
[hal9000 C]$ touch arquivo
[hal9000 C]$ ls arquivo
arquivo
[hal9000 C]$ cd /A
[hal9000 A]$ ls
arquivo
[hal9000 A]$ cd /B
[hal9000 B]$ ls arquivo
ls: cannot access 'arquivo': No such file or directory

Como podemos ver, o arquivo na verdade acabou sendo criado no diretório A. Isso me levou a ideia de como usar o unionfs para fazer a sincronização dos conteúdos distribuídos.

Saindo de nosso exemplo hipotético para algo mais concreto, temos dois tipos de diretório que devemos considerar nessa organização: o diretório contendo os arquivos que queremos compartilhar entre todos as instalações de GNU/Linux e o diretório não compartilhado, que pertence apenas àquela instalação específica. Essa distinção se faz necessária porque existem arquivos que não queremos que estejam compartilhados entre mais de um sistema operacional: arquivos de configuração (sim, aqueles arquivos que começam com um ponto).

Arquivos de configuração são pertinentes apenas para os programas presentes em uma determinada instalação. Se você compartilhá-los e um outro sistema na máquina tiver uma versão diferente do mesmo aplicativo, você pode acabar esbarrando com crashes ou outros erros difíceis de detectar ao tentar executá-los. Ou, em pior caso, pode até perder suas configurações por causa de uma versão mais antiga de um programa que sobrescreveu um arquivo de configuração e ignorou dados que ele não reconheceu, mas que seriam úteis para uma versão mais nova do programa que está em outro sistema operacional na mesma máquina. Então, tenha isso em mente quando for organizar as suas configurações.

Prosseguindo com este exemplo, você pode criar uma partição extra de 1TB e usá-la para os arquivos compartilhados e montá-la em /media/extra; enquanto que o diretório com os arquivos de configuração pode ser bem menor, e ficar em /home/cfg no sistema atual. Você pode agora juntá-los para criar o diretório $HOME do usuário fulano da seguinte forma:

/home/cfg=rw:/media/extra=rw    /home/fulano    fuse.unionfs

Como /home/cfg é o diretório da primeira camada, isso garante que ele receberá todos os arquivos de configuração criados pelos aplicativos que você executar depois. E o diretório /media/extra é onde estão todos os arquivos que você deseja compartilhar em subdiretórios como Downloads, Imagens, Documentos etc. Se você sempre gravar seus arquivos em algum desses subdiretórios, você já estará automaticamente tornando esses arquivos compartilhados entre todos os outros $HOMEs que você possuir (e aí está o motivo pra você não deixar arquivos jogados na raiz da sua $HOME). Se você quiser criar um diretório novo a partir da base (ou seja, a partir de $HOME) e garantir que ele será compartilhado, você pode criá-lo diretamente em /media/extra e ver ele automaticamente replicado em /home/fulano.

Segundo o manual do unionfs-fuse, temos ainda várias opções úteis para montar o unionfs. A opção cow (copy-on-write) define quando um arquivo é efetivamente criado. Vale a pena manter essa opção ativa por questão de performance. A opção max_files define o número de arquivos abertos simultaneamente. O default é 1024. A opção allow_other permite que outros usuários acessem os arquivos naquele file system, o que é geralmente útil, especialmente se seus usuários em diversos sistemas variam em UID e GID.

Então, apesar das vantagens de organização e economia de espaço, existem alguns cuidados a se considerar:

  • Se você trabalha com IDEs grandes e pesadas como Eclipse e Android Studio que abrem muitos arquivos simultaneamente, considere usar um parâmetro max_files bem grande, como 16000 (max_files=16000) ou mais quando for criar a uniões de diretórios. Caso contrário você pode acabar tendo comportamentos imprevisíveis com essas ferramentas. O Android Studio, por exemplo, reclamava de não conseguir compilar um projeto montado em uma unidade de rede (?). Experimente brincar com esses valores de max_files até obter um comportamento aceitável e pelamordedeus, use controle de versão. 😉
  • Mesmo que arquivos de configuração sejam pequenos, lembre-se que o cache do browser e os plugins fica dentro de um subdiretório escondido (por exemplo, .mozilla) na sua $HOME, então lembre-se sempre de reservar alguns gigas para este fim.

Comentários? Dicas? Críticas? Sugestões?