lsof: Ficheiros Abertos, Portas e Diagnóstico no Linux

Neste artigo:

  1. Instalar o lsof
  2. Ler a saída: as colunas COMMAND, PID, USER, FD, TYPE e NAME
  3. Quem abre este ficheiro: caminho e directórios (+D)
  4. Quem segura a porta 8080: -i, protocolos e estados TCP
  5. O que este processo tem aberto: -p, -c e -g
  6. Ficheiros apagados que continuam a gastar disco
  7. Sockets Unix, NFS e o que o lsof conta como ficheiro
  8. Quando o lsof trava: NFS inacessível, -b e -S
  9. Scripts: -t, exit code e o pipeline com wc
  10. Diagnóstico de segurança com o lsof
  11. Erros Comuns
  12. Checklist
  13. Artigos Relacionados
  14. Fontes Oficiais

Todos os dias o disco enche e o df aponta para um directório onde o ls não mostra nada. Ou a porta 8080 devolve “address already in use” e não há serviço nenhum à vista com ps. Ou um umount falha com “target is busy” sem ninguém admitir estar a usar o disco. As três perguntas têm a mesma resposta: um processo tem qualquer coisa aberta que os comandos comuns não mostram. No Linux, tudo o que um processo tem aberto — ficheiros regulares, directórios, bibliotecas, sockets TCP e UDP, pipes — vive na tabela de descritores do processo, e o comando que a lê é o lsof (LiSt Open Files).

O lsof vem nos repositórios de todas as distribuições principais: o Debian 12 traz a versão 4.95.0 e o Debian 13 a 4.99.4 (packages.debian.org, trixie), e o Ubuntu 24.04 LTS segue a mesma série (packages.ubuntu.com). O projecto é mantido pela equipa lsof-org no GitHub, que assumiu o código de Vic Abell, e a referência é a man page lsof(8). Este guia parte de um Debian 12/13 ou Ubuntu LTS, instala o pacote e percorre as perguntas de diagnóstico pela ordem em que aparecem: quem abre um ficheiro, quem segura uma porta, o que um processo tem aberto, os ficheiros apagados que gastam disco, e o exit code para scripts.

1. Instalar o lsof

sudo apt update
sudo apt install lsof
lsof -v

O lsof -v imprime a revisão compilada no binário — em Debian 13, a 4.99.4. Nalgumas instalações mínimas (contentores, imagens de cloud) o pacote não vem de origem. Sem ele, os sintomas acima ficam sem resposta porque ss e lsof respondem a perguntas diferentes: o ss lista os sockets que existem, o lsof liga cada socket e cada ficheiro ao processo que o detém.

2. Ler a saída: as colunas COMMAND, PID, USER, FD, TYPE e NAME

O primeiro passo é ler a tabela que o lsof imprime. Um exemplo do manual:

sudo lsof /var/log/wtmp
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
systemd  1     root    9u   REG    8,1   273408    631 /var/log/wtmp
  • COMMAND são os primeiros nove caracteres do nome do comando (o +c 0 imprime o nome completo, até ao limite que o kernel devolve).
  • FD é o descritor: um número (0=stdin, 1=stdout, 2=stderr), ou uma abreviatura — cwd (directório actual), rtd (raiz), txt (código do programa), mem (ficheiro mapeado em memória). A letra a seguir do número é o modo de abertura: r leitura, w escrita, u leitura e escrita.
  • TYPE distingue REG (ficheiro regular), DIR, CHR, FIFO, unix e os sockets de rede.
  • NAME fecha a linha: para sockets de rede mostra local:porta->remoto:porta, e o estado TCP aparece em parênteses, como (ESTABLISHED).

Sem opções, o lsof lista todos os ficheiros abertos por todos os processos — saída de milhares de linhas num servidor cheio. As opções seguintes existem para filtrar essa tabela.

3. Quem abre este ficheiro: caminho e directórios (+D)

A pergunta mais directa é responder com o caminho do ficheiro. O tutorial oficial usa exatamente este caso:

lsof /etc/passwd

O caminho funciona por equivalência de dispositivo e inode — um ficheiro renomeado entre a abertura e a consulta continua a ser encontrado. Para um sistema de ficheiros inteiro (a pergunta clássica do umount), o nome do ponto de montagem lista tudo o que está aberto nele:

lsof /mnt/dados

Para “quem está a usar algo dentro deste directório?”, há duas formas de busca em árvore:

lsof +D /var/log
  • O +D desce a árvore completa a partir do directório, faz stat(2) a cada ficheiro e cruza o resultado com a tabela de ficheiros abertos.
  • O +d (minúsculo) olha apenas para o nível de topo do directório.
  • O manual avisa expressamente: o +D pode ser lento e exigir bastante memória em directórios grandes, porque percorre a árvore inteira — em / é uma operação a evitar. Para o disco inteiro, o caminho do sistema de ficheiros (lsof /) faz o mesmo trabalho sem construir a lista de ficheiros.
  • O +D não segue symbolic links nem atravessa pontos de montagem dentro da árvore, a não ser que se junte -x.

4. Quem segura a porta 8080: -i, protocolos e estados TCP

A gramática do -i é [46][protocolo][@anfitrião][:porta], e cobre as perguntas de rede mais comuns:

lsof -i :8080
lsof -iTCP -sTCP:LISTEN
lsof -iUDP
lsof [email protected]
  • lsof -i :8080 responde a “quem tem esta porta” — para TCP e UDP ao mesmo tempo. E lsof -iTCP:8080 restringe ao protocolo TCP.
  • lsof -iTCP -sTCP:LISTEN lista só os sockets à escuta: é o inventário de portas abertas do servidor, com o processo responsável por cada uma. O -sTCP: aceita os nomes de estado TCP — LISTEN, ESTABLISHED, SYN_SENT, CLOSE_WAIT, TIME_WAIT, entre outros — e o ^ inverte (por exemplo, tudo menos ESTABLISHED).
  • O @anfitrião filtra a outra ponta da ligação — útil para responder “que ligações existem para este endereço”.
  • lsof -i4 e lsof -i6 separam IPv4 de IPv6.

Duas bandeiras deixam a saída mais rápida: -P impede a conversão de números de porta para nomes de serviço (a tabela /etc/services) e -n impede a resolução de endereços para nomes. Ambas tornam o comando mais rápido e evitam esperas quando o DNS não responde — num servidor com DNS degradado, lsof -nP -i é a forma que não bloqueia.

O -i é também a resposta a “há algum serviço aqui que eu não conheço?”: socket à escuta sem dono conhecido é candidato a investigação, e CLOSE_WAIT acumulados apontam para aplicações que não fecham ligações.

Um limite do -i que a FAQ lembra: ligações em TIME_WAIT ou FIN_WAIT nem sempre têm processo por trás — o socket já não pertence a ninguém — e o lsof não as vê. Também por isso o pedido “quem segura a porta 8080” pode chegar disfarçado: o “address already in use” nem sempre nasce de um processo vivo — sockets em TIME_WAIT também o causam, e aí o ss -tanp mostra o estado que o lsof esconde.

5. O que este processo tem aberto: -p, -c e -g

A partir do PID, o -p lista tudo o que o processo detém:

lsof -p 1234
lsof -p 1234,5678

Quando se conhece o nome do comando em vez do PID, o -c evita procurar o PID primeiro — o manual usa o sendmail como exemplo:

lsof -c nginx
lsof -c sshd
  • O -c casa pelo começo do nome do comando. Vários -c somam-se (OR). Aceita também expressão regular entre barras: lsof -c /^..o.$/i.
  • O -u filtra por utilizador e aceita a negação ^: lsof -u www-data são os ficheiros do utilizador. E lsof -u^root exclui todos os processos do root — a negação aplica-se antes dos restantes critérios.
  • O -g selecciona por grupo de processos e, sem argumento, acrescenta a coluna PGID à saída.
  • Importante: sem o -a, os critérios de selecção somam-se por OR. lsof -p 1234 -u postgres lista os ficheiros do PID 1234 mais os do utilizador postgres. Para a intersecção, é preciso -a: lsof -a -p 1234 -u postgres. Esta regra é a origem de muitos resultados “a mais” quando se combinam filtros.

6. Ficheiros apagados que continuam a gastar disco

O df acusa disco cheio, o du não encontra a culpa, e a explicação é um ficheiro apagado com rm enquanto um processo o mantinha aberto — tipicamente um log rodado pelo logrotate com um serviço antigo a escrever nele. O espaço só é libertado quando o último descritor fecha.

O lsof apanha o caso por dois caminhos. O +L1 lista os ficheiros abertos com link count zero — o estado exacto de um ficheiro desligado do sistema de ficheiros mas ainda aberto:

lsof +L1
lsof -a +L1 /var

Uma nota sobre o filtro por directório: o lsof -a +L1 /var só restringe aos apagados dessa árvore quando o /var é ponto de montagem próprio — caso contrário, o manual trata-o como um directório simples e a lista cobre o sistema de ficheiros todo.

No Linux, os caminhos de ficheiros apagados são reportados por omissão com o sufixo (deleted) no fim — pergunta da FAQ oficial do lsof:

sudo lsof | grep deleted
rsyslogd  812 syslog   7w   REG  254,1  2147483648  521214 /var/log/syslog (deleted)

A recuperação passa pelo /proc: enquanto o descritor estiver aberto, o conteúdo continua acessível em /proc/PID/fd/N — o número é o da coluna FD, aqui o 7:

sudo ls -l /proc/812/fd/7
sudo cp /proc/812/fd/7 /var/log/syslog.recuperado

A cópia sai igual ao conteúdo que o processo vê. Duas notas: a cópia não é o mesmo inode — o serviço continua a escrever no ficheiro antigo, e sem reinício o espaço nunca se liberta. Com o descritor aberto em escrita, é possível truncar via /proc sem reiniciar, mas isso é medida de incidente, não rotina.

O tutorial oficial chama a este caso “Finding an Unlinked Open File” e usa exactamente o lsof +L1 para o encontrar.

7. Sockets Unix, NFS e o que o lsof conta como ficheiro

Uma socket UNIX é também um ficheiro aberto, e o -U lista essa família:

lsof -U
lsof -i -U
  • lsof -i -U é o exemplo do manual para “todos os ficheiros de rede, Internet e domínio UNIX”.
  • O -N lista os ficheiros montados por NFS, do lado do cliente. Nota do manual: num servidor NFS, o lsof não mostra os ficheiros que os clientes têm abertos — só vê os processos da máquina onde corre.
  • A coluna TYPE distingue unix, IPv4, IPv6, REG, DIR — é ela que diz se uma linha de /var/run/... é ficheiro regular ou socket.
  • A opção -E acrescenta os pontos de ligação (endpoints) de pipes e sockets UNIX do Linux — quem está do outro lado de um socket.

8. Quando o lsof trava: NFS inacessível, -b e -S

O lsof usa as chamadas stat(2), lstat(2) e readlink(2) para montar a tabela — e estas podem bloquear no kernel quando um NFS perde o servidor. A FAQ oficial dedica-lhe uma secção: cada ponto de montagem sem resposta custa quinze segundos por omissão, e um servidor com vários pontos NFS mortos parece congelado.

sudo lsof -S 5
sudo lsof -b -w
  • -S 5 reduz o tempo de espera para cinco segundos por sistema de ficheiros.
  • -b evita as chamadas que podem bloquear — a custo de informação em falta e de avisos, silenciáveis com -w (forma combinada: lsof -bw).
  • Serve para discos de um servidor NFS que caiu: lsof -b /mnt/nfs ainda lista os ficheiros abertos, desde que a tabela de montagens forneça o número de dispositivo alternativo.
  • Se a lentidão vier da resolução de nomes ou de portas, a receita da FAQ é -n e -P — o mesmo par da secção 4.

9. Scripts: -t, exit code e o pipeline com wc

O -t imprime só os PIDs, sem cabeçalho — a forma de alimentar kill e xargs. O exemplo do manual:

lsof -t /lib/*/libssl.so.* | xargs -r kill -HUP

Em produção, o kill -HUP a processos que não tenham handler de SIGHUP mata a aplicação — o padrão do manual vale para serviços que recarregam com HUP, e para os outros o reinício de processo (com rollback) é o caminho seguro.

kill -HUP `lsof -t /var/log/app.log`

O exit code é o contrato para scripts: o lsof sai com 0 quando encontrou tudo o que lhe foi pedido e 1 quando alguma pesquisa falhou — com o -Q a ignorar os termos sem resultados. O manual mostra o padrão:

if lsof /u/abe/foo > /dev/null 2>&1; then
    echo "ficheiro ainda em uso"
fi

Para contar linhas de saída — quantos ficheiros tem um processo aberto, quantas ligações um serviço mantém — o pipeline com wc -l é o atalho:

lsof -p 1234 | wc -l
lsof -iTCP:443 | wc -l
lsof -u www-data | wc -l

Contas a ter em conta: o cabeçalho conta como linha (subtrair 1, ou tail -n +2), e sem sudo um utilizador só vê os próprios ficheiros — a contagem de processos alheios sai truncada sem erro.

Uma nota que a FAQ sublinha: o lsof -p PID | wc -l não é o número de descritores do processo — a saída inclui cwd, rtd, txt e mem, que não ocupam descritores. Para contar descritores reais (o limite do ulimit), o caminho certo é ls /proc/PID/fd | wc -l.

Para contagens periódicas, o modo repeat -r N repete a listagem cada N segundos sem o custo de arranque de chamadas repetidas na shell.

10. Diagnóstico de segurança com o lsof

Para além do incêndio do dia, o lsof responde a duas perguntas de segurança que os inventários estáticos não cobrem:

sudo lsof -iTCP -sTCP:LISTEN -P -n
sudo lsof -u^root -a -i
  • A primeira é o inventário de portas à escuta com processo associado — é a lista que se compara com a linha de base do servidor. Qualquer entrada nova, em interface inesperada ou sem dono conhecido, merece investigação.
  • A segunda (negação + -a) responde a “que ligações de rede existem fora dos processos do root” — o sítio onde um processo comprometido sob utilizador de serviço se esconde.
  • Um executável a correr de /tmp ou /dev/shm não aparece pelo -i — o NAME dessa saída mostra endereços e portas, não o caminho do binário. O detector certo é o descritor de texto: sudo lsof -d txt | grep -E '/tmp|/dev/shm' (alternativa: ls -l /proc/*/exe). Encontrado o PID, o lsof -a -i -p PID mostra os sockets que ele mantém.
  • Compilado com --enable-security, o lsof deixa cada utilizador listar só os próprios ficheiros — daí o sudo em quase tudo. O lsof -h mostra se a instalação tem essa restrição.

Erros Comuns

Sintoma Causa provável Correcção
lsof -p 1234 -u postgres devolve demasiado Critérios somados por OR -a: lsof -a -p 1234 -u postgres
Porta aparece em ss mas não no lsof -i Sem root, o lsof não vê os ficheiros dos outros utilizadores sudo lsof -i :PORTA
O lsof parece congelado Ponto de montagem NFS com o servidor em baixo (15 s por montagem por omissão) -S 5 ou -b -w; resolver a montagem a seguir
Disco cheio, du não encontra nada Ficheiro apagado ainda aberto por um processo sudo lsof +L1 e reiniciar o processo que o segura
lsof +D / demora minutos O +D percorre a árvore toda com stat(2) a cada nó Usar o nome do sistema de ficheiros (lsof /) ou +d no directório de topo
Contagem de wc -l errada Cabeçalho contado, ou linhas a faltar sem sudo lsof ... | tail -n +2 | wc -l, sempre com o mesmo privilégio
lsof -i lento Resolução de nomes DNS e de serviços em falta -n -P (e lsof -h para confirmar os valores por omissão)
umount: target is busy sem processo visível Ficheiro aberto em shell (cwd), socket ou processo com directório no disco lsof /ponto/de/montagem e lsof +D /ponto/de/montagem

Checklist

  • [ ] lsof -v responde com a revisão instalada (4.95.0 no Debian 12, 4.99.4 no Debian 13)
  • [ ] Quem segura um ficheiro: lsof /caminho/ficheiro (com sudo quando o ficheiro é de outro utilizador)
  • [ ] Portas: lsof -nP -i :PORTA para uma porta, lsof -iTCP -sTCP:LISTEN para o inventário de escuta
  • [ ] Processo: lsof -p PID e, sem PID, lsof -c nome
  • [ ] Filtros combinados com -a (o OR é o comportamento por omissão)
  • [ ] Ficheiros apagados: sudo lsof +L1, recuperação por /proc/PID/fd/N
  • [ ] Directórios: +d no topo, +D só em árvores pequenas (o manual avisa que pode ser lento)
  • [ ] NFS problemático: -S 5 ou -b -w antes de declarar o lsof bloqueado
  • [ ] Scripts: -t para PIDs a kill/xargs, exit code 0/1 para decisões, -r N para repetição
  • [ ] Inventário de segurança: lsof -iTCP -sTCP:LISTEN -P -n comparado com a baseline

Artigos Relacionados

Fontes Oficiais