ps -f
normalmente mostra a lista de argumentos passada para a última chamada de sistema execve()
que o processo ou qualquer um dos seus antecessores fez.
Quando você executa um comando xxx arg1 arg2
em um prompt do shell, seu shell geralmente bifurca um processo que procura um comando pelo xxx
name e o executa como:
execve("/path/to/that/xxx", ["xxx", "arg1", "arg2"], @exported_variables)
Deve-se notar que o primeiro argumento é xxx
.
Após a execução, toda a memória do processo é apagada e esses argumentos (e ambiente) são encontrados na parte inferior da pilha do processo.
Você obtém os primeiros 4096 bytes desses argumentos em /proc/<the-pid>/cmdline
e é de onde ps
obtém isso.
Em um fork ou clone, o filho herda toda a memória de seu pai, incluindo essa lista de argumentos.
Você recebe o [xxx]
quando /proc/<the-pid>/cmdline
está vazio. Nesse caso, em vez de exibir a lista arg, ps
exibe o nome do processo que encontra em /proc/<the-pid>/stat
(para comandos executados, são os primeiros 16 bytes da base do arquivo executável passado para o último execve()
). Isso pode acontecer por três razões (que eu posso pensar):
-
O processo ou qualquer um de seus ancestrais nunca executou nada. Esse é o caso dos encadeamentos do kernel (e só pode ser o caso dos encadeamentos do kernel, pois todos os outros processos são descendentes de
init
(que é executado)).$ ps -fp2 UID PID PPID C STIME TTY TIME CMD root 2 0 0 Jan13 ? 00:00:00 [kthreadd]
-
O processo executou um comando com uma lista vazia de argumentos. Isso geralmente nunca acontece porque geralmente os programas sempre passam pelo menos um argumento, o nome do comando, mas você pode forçá-lo com, por exemplo:
int main(int argc, char *argv[]) { if (argc) execve("/proc/self/exe",0,0); else system("ps -fp $PPID"); }
Depois de compilado e executado:
$ test1 UID PID PPID C STIME TTY TIME CMD stephane 31932 29296 0 15:16 pts/5 00:00:00 [exe]
-
O processo sobrescreve seu
argv[]
em sua pilha.Os argumentos são sequências terminadas em NUL na memória. Se você tornar o último caractere da lista arg não nulo, por exemplo, com
envp[0][-1]=1
(os valoresenvp[]
seguem osargv[]
na pilha), então o kernel assume que você o modificou e só retorna em/proc/xxx/cmdline
o primeiro argumento até o primeiro caractere NUL. Entãoint main(int argc, char* argv[], char *envp[]) { envp[0][-1]=1; argv[0][0]=0; system("ps -fp $PPID"); }
Também mostraria
[xxx]
.Dado que o arglist (e environ) estão na parte inferior da pilha, esse tipo de cenário pode acontecer se você tiver um bug no código que faz com que você escreva na pilha após o final do que ele pretendia escreva, por exemplo, se estiver usando
strcpy
em vez destrncpy
. Para depurar esse tipo de problema,valgrind
é muito útil.