Nano não salva: como corrigir "Permission denied"
Veja por que o nano falha ao salvar com "Permission denied": proprietário, diretório pai, sistema somente leitura, espaço em disco e UID no contêiner.
Por que o nano não consegue salvar o seu arquivo
O nano não consegue salvar o seu arquivo por um de quatro motivos: você não é o proprietário do arquivo, o diretório pai não permite a operação que o nano está tentando executar, o sistema de arquivos está somente para leitura ou sem espaço, ou você está dentro de um contêiner executado com um ID de usuário diferente. Os dois primeiros são problemas de permissões, e os dois últimos não são. Verifique-os nessa ordem, porque o primeiro motivo abrange a maioria dos casos, pode ser confirmado com um comando e a correção é sudoedit, não sudo nano.
Nada é perdido enquanto o editor continua aberto. O texto permanece na memória. Você pode deixar o arquivo aberto, gravar o buffer em um caminho que pertença a você e colocá-lo no local correto depois. Essa alternativa é apresentada perto do final deste guia.
Execute estas verificações antes de alterar permissões
Aponte cada comando para o caminho real que está a editar. Eles respondem a perguntas diferentes, por isso execute-os todos antes de alterar qualquer coisa. Alterar permissões antes de saber qual verificação está a falhar normalmente cria um segundo problema além do primeiro.
id
ls -l /etc/nginx/nginx.conf
ls -ld /etc/nginx
namei -l /etc/nginx/nginx.conf
findmnt -no SOURCE,FSTYPE,OPTIONS -T /etc/nginx/nginx.conf
df -h /etc/nginx
df -i /etc/nginxid mostra o ID do utilizador e os IDs dos grupos que tem neste momento. ls -l mostra o proprietário, o grupo e os bits de permissão do próprio ficheiro. ls -ld mostra o mesmo para o diretório que contém o ficheiro. Esta é uma pergunta diferente, com uma resposta diferente. namei -l percorre todas as partes do caminho e lista o proprietário e as permissões de cada uma. Assim, responde às duas perguntas numa única saída. findmnt identifica o sistema de ficheiros usado nesse caminho e as opções com que foi montado. df -h indica o espaço livre e df -i indica os inodes livres. Os inodes podem esgotar-se separadamente do espaço. Se estas strings de permissões ainda não forem familiares, comece por como interpretar a string de permissões apresentada por ls -l.
Causa 1: o ficheiro pertence a root e a sua conta não
As permissões de leitura e escrita são distintas, e a maioria dos ficheiros em /etc pode ser lida por qualquer utilizador. Por isso, o nano abre o ficheiro, mostra o conteúdo e permite escrever livremente: nenhuma dessas ações altera o disco. A recusa ocorre ao guardar, quando o kernel compara o seu ID de utilizador e os seus IDs de grupo com o proprietário, o grupo e os bits de outros utilizadores definidos no ficheiro. O nano apenas transmite o que o kernel lhe indicou, por isso nenhuma opção do nano altera o resultado.
id e ls -l esclarecem a situação. O ficheiro pertence a root, a sua conta não é root e os bits de outros utilizadores não concedem permissão de escrita. Premir Ctrl-O novamente não resolve o problema.
Por que sudoedit é a forma correta de editar um ficheiro pertencente a root
SUDO_EDITOR=nano sudoedit /etc/nginx/nginx.confsudo cria uma cópia temporária do ficheiro com o proprietário definido como o seu utilizador, executa o nano nessa cópia com a sua própria conta e, depois de o editor terminar, copia o resultado para o local original com privilégios de root. O editor nunca é executado como root. sudo -e é o mesmo comando com outro nome. O editor é escolhido a partir de SUDO_EDITOR, depois de VISUAL e, por fim, de EDITOR. Por isso, definir export EDITOR=nano no perfil da sua shell torna esse editor a escolha predefinida em todo o sistema. Se nenhuma dessas variáveis indicar um editor existente e executável, sudoedit usa a definição editor do sudoers, que por predefinição é vi.
sudo nano também permite guardar o ficheiro, e esse é o problema. Concede a um editor interativo completo privilégios de root sobre todo o sistema de ficheiros durante a sessão. Assim, um caminho introduzido incorretamente no pedido para guardar pode substituir um ficheiro de sistema diferente com o seu texto, como root. Trabalhar como um utilizador normal que usa sudo apenas nos passos que precisam dele é o hábito que deve criar. sudoedit é a forma como esse hábito se aplica ao editar um ficheiro de configuração.
Duas regras do sudoedit surpreendem alguns utilizadores. O comando recusa-se a editar uma ligação simbólica e recusa-se a editar um ficheiro dentro de um diretório onde o utilizador tenha permissões de escrita, a menos que seja root. A segunda regra existe porque qualquer pessoa com permissões de escrita no diretório pode substituir o ficheiro enquanto o editor está aberto. Ambos os comportamentos são as predefinições do sudoers (sudoedit_follow desativado, sudoedit_checkdir ativado). Se o ficheiro ainda não existir, será criado.
Causa 2: o que o diretório pai realmente controla
As instruções escritas para outros editores dizem que guardar um ficheiro requer permissão de escrita no diretório, porque muitos editores guardam o ficheiro escrevendo um novo ficheiro e mudando o nome deste para substituir o antigo. O nano não funciona dessa forma. Abre o ficheiro indicado e escreve nesse próprio ficheiro. Por isso, quando o ficheiro já existe, o bit de escrita do diretório nunca é consultado.
O diretório continua a controlar outros aspetos. É por isso que ls -ld faz parte da lista de verificação:
- Criar um ficheiro que ainda não existe requer permissões de escrita e execução no diretório, porque é necessário adicionar-lhe um novo nome. A sua umask determina as permissões iniciais desse novo ficheiro.
- Aceder ao ficheiro requer permissão de execução, também chamada permissão de pesquisa, em todos os diretórios ao longo do caminho. Se faltar essa permissão num diretório, tudo o que estiver abaixo dele fica inacessível, e
namei -lmostra qual é esse diretório. - Guardar com cópias de segurança ou com o bloqueio de ficheiros ativado escreve um segundo ficheiro junto do original. Por isso, estas funcionalidades requerem um diretório com permissão de escrita. As cópias de segurança são controladas pela opção
-Bou porset backupnum nanorc. O bloqueio é controlado por-Gouset locking. Ambas as funcionalidades estão desativadas, exceto se as tiver ativado ou se a sua distribuição as tiver ativado.
As permissões dos diretórios também têm o mesmo peso noutras partes do sistema. O servidor SSH recusa uma chave quando o seu diretório pessoal ou o seu diretório .ssh pode ser escrito por outros utilizadores. Esta é uma causa comum de o SSH rejeitar a sua chave durante o início de sessão.
Como o nano escreve no ficheiro que já existe, o ficheiro mantém o seu inode, que é a identidade do ficheiro no disco associada ao nome. Tudo o que tiver o ficheiro aberto continua a acompanhá-lo, e uma montagem bind de um único ficheiro num contentor continua a funcionar. Os editores que guardam substituindo o ficheiro interrompem essa montagem, porque a montagem segue o inode, não o nome.
Causa 3: o sistema de ficheiros está montado como só de leitura ou não tem mais espaço
findmnt indica ro nas opções, o que significa que a escrita nunca iria ter sucesso. O sistema de ficheiros pode ter sido montado dessa forma, através de /etc/fstab ou de uma montagem bind só de leitura. Também pode ter sido remontado como só de leitura pelo kernel depois de um erro de disco. O segundo caso é o mais grave. sudo dmesg -T | tail -50 mostra as mensagens mais recentes do kernel, mas os erros de entrada/saída e do sistema de ficheiros que levaram à remontagem podem não estar entre as últimas 50 linhas. Execute sudo dmesg -T sem tail para ver todas as mensagens que o buffer circular do kernel ainda mantém e procure os erros registados antes da remontagem. A correção consiste em verificar o sistema de ficheiros enquanto este está desmontado. Um sistema de ficheiros que não seja o root pode ser desmontado e verificado no local. Para o root, um arranque normal pode fazer isso: o systemd verifica todos os sistemas de ficheiros cujo número de passagem do fsck em /etc/fstab seja superior a zero, verifica o root no initrd quando o initrd o suporta, e fsck.mode=force na linha de comandos do kernel força uma verificação completa. Quando o VPS não arranca o suficiente para isso, a consola de recuperação do fornecedor é a alternativa.
Um sistema de ficheiros cheio falha a mesma escrita por outro motivo. df -h abrange o caso normal. df -i abrange o caso que costuma passar despercebido: no ext4, o padrão habitual, os inodes vêm de um conjunto fixo criado quando o sistema de ficheiros foi criado, e uma árvore de ficheiros pequenos pode consumi-los todos enquanto df -h ainda mostra gigabytes livres. O XFS aloca inodes à medida que os ficheiros são criados, por isso este caso ocorre sobretudo no ext4. Quando não há espaço e nada evidente o está a ocupar, df e du indicam valores diferentes para um disco cheio aborda o ficheiro eliminado mas ainda aberto que causa o problema.
Um detalhe explica um sintoma confuso neste caso. O ext4 reserva uma parte dos seus blocos para o root quando o sistema de ficheiros é criado, por isso o root continua a escrever depois de os utilizadores normais serem impedidos. sudo parece então resolver o problema, o disco fica completamente cheio e o problema regressa numa forma mais grave.
Como o nano trunca o ficheiro antes de escrever o novo conteúdo, uma escrita que fique sem espaço a meio pode deixar o ficheiro mais curto do que era. Copie um ficheiro de configuração importante antes de o editar num sistema de ficheiros quase cheio. sudo cp -a /etc/nginx/nginx.conf /root/nginx.conf.bak preserva o proprietário, o grupo e as permissões na cópia.
Causa 4: está num contentor a editar um bind mount
A propriedade dos ficheiros é numérica. O kernel armazena um ID de utilizador, e o nome que vê vem do componente /etc/passwd que faz a consulta. Por isso, o mesmo ficheiro pode apresentar um nome no host e outro nome, ou apenas um número, dentro do contentor. Compare os números, não os nomes: execute id -u dentro do contentor e ls -ln no ficheiro.
Um ficheiro montado através de bind mount mantém a propriedade que tem no host. Quando o ficheiro no host pertence ao seu utilizador e o processo do contentor é executado com outro utilizador, a escrita é recusada dentro do contentor. Além disso, sudo dentro do contentor não altera o proprietário no host. Corrija o problema a partir do host, definindo como proprietário o ID com que o contentor é executado, ou execute o contentor com o ID que já é proprietário dos ficheiros. As imagens do linuxserver.io e de projetos semelhantes expõem as variáveis PUID e PGID que definem o utilizador com que o processo é executado.
Convém conhecer mais dois casos relacionados com contentores. Uma montagem criada como somente leitura com :ro, ou um contentor iniciado com --read-only, recusa escritas independentemente da propriedade. O comando cat /proc/mounts dentro do contentor mostra essa opção. Com o rootless Podman, um namespace de utilizadores mapeia os IDs de utilizador do contentor para um intervalo de IDs no host. Assim, um ficheiro que parece pertencer a root dentro do contentor pertence à sua conta sem privilégios fora dele.
Também existe o caso em que a edição é concluída, mas desaparece depois. Um ficheiro alterado dentro de um contentor, num caminho que não é uma montagem, fica na camada de escrita desse contentor. Essa camada é descartada quando o contentor é recriado. Altere o ficheiro no lado do host correspondente à montagem, ou durante a criação da imagem, se a alteração tiver de persistir.
A saída de emergência: guarde o ficheiro num caminho que lhe pertença
Não tente obter privilégios a partir do editor. Prima Ctrl-O, limpe o caminho na linha de comandos, introduza um caminho dentro do seu diretório pessoal, como /home/you/nginx.conf.new, e prima Enter. Depois prima Ctrl-X para sair. O seu trabalho está agora no disco, pertence-lhe, e o resto é uma cópia de ficheiro normal.
sudo cp /home/you/nginx.conf.new /etc/nginx/nginx.conf
sudo nginx -tUse cp aqui, em vez de mv. cp escreve através do ficheiro que já está no local, por isso esse ficheiro mantém o proprietário, o grupo e as permissões. mv no mesmo sistema de ficheiros substitui-o pelo seu ficheiro. Isto deixa um ficheiro de configuração em /etc pertencente à sua conta de utilizador, criando o próximo problema de permissões que terá de resolver.
Verifique o resultado com a ferramenta responsável pelo ficheiro antes de recarregar qualquer serviço. sudo nginx -t analisa a configuração do nginx, e sudo sshd -t analisa a configuração do servidor SSH. Dois ficheiros têm editores específicos que executam todo este procedimento por si: sudo visudo para /etc/sudoers e crontab -e para os seus próprios cron jobs. Cada um edita uma cópia temporária, verifica a sintaxe e instala o ficheiro apenas se a análise for bem-sucedida.
FAQ
Devo usar sudo nano ou sudoedit para editar um ficheiro do sistema?
Use sudoedit. Este comando copia o ficheiro para uma cópia temporária pertencente ao seu utilizador, executa o editor com a sua conta e grava o resultado como root quando o editor termina. Assim, o próprio editor nunca tem privilégios de root. Defina SUDO_EDITOR, VISUAL ou EDITOR como nano para escolher nano. sudo nano também funciona, mas dá a um editor interativo acesso de root a todos os caminhos do sistema durante a sessão. Um nome de ficheiro introduzido incorretamente na confirmação de gravação pode então danificar um ficheiro do sistema.
Preciso de permissão de escrita no diretório para gravar um ficheiro com nano?
Não, se o ficheiro já existir. nano grava no próprio ficheiro. Por isso, o kernel verifica o bit de escrita do ficheiro e o bit de execução de todos os diretórios no caminho. O bit de escrita do diretório é necessário quando o ficheiro ainda não existe, porque é preciso criar um novo nome. Também é necessário quando as cópias de segurança ou o bloqueio de ficheiros estão ativos, porque ambos criam um segundo ficheiro junto do original.
O proprietário está correto e o disco não está cheio. O que mais pode impedir a escrita?
Há quatro possibilidades. O sistema de ficheiros pode estar montado como somente leitura, como mostra findmnt -no OPTIONS -T /etc/nginx/nginx.conf. O ficheiro pode ter o atributo immutable, que lsattr mostra e sudo chattr -i remove. Nem root pode escrever no ficheiro enquanto esse atributo estiver definido. Em ext4, o conjunto de inodes pode estar esgotado mesmo com espaço livre disponível, como mostra df -i. SELinux ou AppArmor podem impedir a escrita mesmo quando os bits de permissão a permitem. O log de auditoria normalmente regista a recusa, mas as regras dontaudit do SELinux podem impedir uma escrita sem registar nada. sudo semodule -DB desativa essas regras enquanto reproduz o problema, e sudo semodule -B volta a ativá-las.
Onde guardo as alterações quando o ficheiro não pode ser gravado?
Prima Ctrl-O e indique um caminho que pertença ao seu utilizador, dentro da sua home ou noutro local onde possa escrever. O buffer continua na memória, por isso nada do que introduziu se perde. Depois, copie o ficheiro gravado para o local correto com sudo cp. Este comando mantém o proprietário e as permissões do ficheiro original. Em seguida, verifique o ficheiro com o comando de teste do próprio serviço antes de recarregar o serviço.
Porque desaparecem as minhas alterações dentro de um contentor Docker?
Quando o caminho não é um mount, a alteração fica na camada de escrita do contentor. Essa camada é eliminada quando o contentor é substituído. Edite o ficheiro no lado do host de um bind mount ou de um volume, ou inclua-o na imagem. Quando o caminho é um bind mount e a gravação é recusada, compare id -u dentro do contentor com o proprietário numérico obtido por ls -ln. O ficheiro mantém o proprietário do host, e o processo no contentor tem de usar o mesmo proprietário.