
o utilitário ps, com um toque de eBPF e contexto de contêineres.
psc (ps container) é um scanner de processos rápido que usa iteradores eBPF e Google CEL para consultar o estado do sistema com precisão e contexto completo de contêineres.
psc usa iteradores eBPF para ler informações de processos e descritores de arquivo diretamente das estruturas de dados do kernel. Essa abordagem é:
/proc. Planejo adicionar também uma forma de acessar certos campos da task_struct sob demanda para uso avançado, mas isso é apenas uma ideia/proc, fornecendo visibilidade que não pode ser subvertida por rootkits em userland ou truques de LD_PRELOADFerramentas Linux tradicionais como ps, lsof e ss são poderosas, mas inflexíveis. Elas produzem formatos fixos que exigem extenso encadeamento com grep, awk e sed:
# Traditional: Find nginx processes owned by root
ps aux | grep nginx | grep root | grep -v grep
# psc: Express exactly what you mean
psc 'process.name == "nginx" && process.user == "root"'
# Traditional: Find processes with established connections on port 443
ss -tnp | grep ESTAB | grep :443 | awk '{print $6}' | cut -d'"' -f2
# psc: One clear expression
psc 'socket.state == established && socket.dstPort == 443'
psc usa a Common Expression Language (CEL) para filtrar processos. Expressões CEL são quase como linguagem natural, tornando seus scripts autodocumentados e fáceis de manter. Chega de decifrar pipelines complexos de grep | awk | sed | xargs.
A flag -o permite que você exiba exatamente os campos necessários, eliminando o pós-processamento por completo:
psc 'socket.state == listen' -o process.name,socket.srcPort
Predefinições de saída também estão disponíveis para imprimir rapidamente informações comuns:
psc 'socket.type == tcp && socket.dstPort == 443' -o sockets
Ferramentas tradicionais não têm noção de contêineres. Obter informações de contêineres exige interpretar caminhos de cgroup, consultar os runtimes de contêineres e correlacionar PIDs manualmente:
# Traditional: Find containerized processes (fragile, incomplete)
ps aux | xargs -I{} sh -c 'cat /proc/{}/cgroup 2>/dev/null | grep -q docker && echo {}'
# psc: Native container support
psc 'container.runtime == docker'
psc extrai o contexto do contêiner (ID, nome, imagem, runtime, labels) automaticamente para Docker, containerd, CRI-O e Podman. Depure processos, arquivos e conexões de rede de qualquer contêiner diretamente do host:
# Show all processes in a specific container
psc 'container.name == "my-app"' --tree
# Find containers running as root
psc 'container.runtime == docker && process.user == "root"'
# List containers with their images
psc 'container.id != ""' -o process.pid,process.name,container.name,container.image
No Debian/Ubuntu:
sudo apt-get install clang llvm libbpf-dev linux-headers-$(uname -r) linux-tools-$(uname -r)
No Fedora/RHEL:
sudo dnf install clang llvm libbpf-devel kernel-devel bpftool
# Generate vmlinux.h (required once per kernel version)
make vmlinux
# Build the binary
make build
Ou manualmente:
bpftool btf dump file /sys/kernel/btf/vmlinux format c > bpf/vmlinux.h
go generate ./...
go build -o psc
sudo make install
psc requer privilégios de root para carregar programas eBPF.
# List all processes
sudo psc
# List all processes as a tree
sudo psc --tree
Passe uma expressão CEL como primeiro argumento para filtrar processos:
# Filter by process name
psc 'process.name == "nginx"'
# Filter by user
psc 'process.user == "root"'
# Filter by command line content
psc 'process.cmdline.contains("--config")'
# Filter by PID range
psc 'process.pid > 1000 && process.pid < 2000'
# Combine conditions
psc 'process.name == "bash" || process.name == "zsh"'
# Show only containerized processes
psc 'container.id != ""'
# Filter by container runtime (constants: docker, containerd, crio, podman)
psc 'container.runtime == docker'
# Filter by container name
psc 'container.name == "nginx"'
# Filter by container image
psc 'container.image.contains("nginx:latest")'
# Show as tree to see container process hierarchy
psc 'container.runtime == docker' --tree
Entender por que um processo existe muitas vezes exige observar seus descritores de arquivo abertos e conexões de rede:
# Find processes with listening TCP sockets
psc 'socket.type == tcp && socket.state == listen'
# Find processes with established connections
psc 'socket.state == established'
# Find processes connected to a specific port
psc 'socket.dstPort == 443'
# Find processes using Unix sockets
psc 'socket.family == unix'
# Find processes with files open in /etc
psc 'file.path.startsWith("/etc")'
Campos de processo (process.X):
name - Nome do processo (string)pid - ID do processo (int)ppid - ID do processo pai (int)tid - ID da thread (int)euid - ID efetivo do usuário (int)ruid - ID real do usuário (int)suid - ID de usuário salvo (set-user-ID) (int)user - Nome de usuário (string)cmdline - Linha de comando completa (string)state - Estado do processo (uint)Campos de capacidade (process.capabilities.X):
effective - Máscara de bits das capacidades efetivas (uint)permitted - Máscara de bits das capacidades permitidas (uint)inheritable - Máscara de bits das capacidades herdáveis (uint)Campos de namespace (process.namespaces.X):
net - Inode do namespace de rede (int)pid - Inode do namespace de PID (int)mnt - Inode do namespace de montagem (int)uts - Inode do namespace UTS (int)ipc - Inode do namespace IPC (int)cgroup - Inode do namespace de cgroup (int)Campos de contêiner (container.X):
id - ID do contêiner (string)name - Nome do contêiner (string)image - Imagem do contêiner (string)runtime - Runtime do contêiner (string)labels - Labels do contêiner (mapa)Campos de arquivo/socket (file.X ou socket.X):
path - Caminho do arquivo (string)fd - Número do descritor de arquivo (int)srcPort - Porta de origem (int)dstPort - Porta de destino (int)type - Tipo de socket (tcp, udp)state - Estado do socket (para filtragem, use constantes como listen, established)family - Família de endereços (unix, inet, inet6)unixPath - Caminho do socket Unix (string)fdType - Tipo de FD (file_type, socket_type)Use estas sem aspas nas expressões:
docker, containerd, crio, podmantcp, udpunix, inet, inet6established, listen, syn_sent, syn_recv, fin_wait1, fin_wait2, time_wait, close, close_wait, last_ack, closingfile_type, socket_type