Estou tentando depurar um monitor de processo legado com falha que pesquisa processos em execução. Eu determinei que isso está sendo causado por algum comportamento misterioso do Linux. O processo que está sendo executado é /opt/my/path/directoryname/daemonname, mas por algum motivo estranho, ele aparece com espaços, não /, ao redor do nome do diretório. Muitos daemons estão sendo executados no mesmo diretório e aparecem com o caminho correto. É apenas um daemon específico em cada servidor.
ps -ef
mostra o seguinte para este daemon:
/opt/my/path directoryname daemonname --arg1 VALUE1 --arg-two VALUE.TWO --arg-three ARG.UMENT.THREE.ERR --worker daemonname --pid-role daemonname
Este daemon está sendo iniciado por um script perl. Comparando-o com outros, parece que o caminho do diretório está sendo fornecido usando exatamente a mesma variável env de todos os outros scripts, mas esses outros scripts resultam em um caminho correto como /opt/my/path/directoryname/daemonname
. As linhas Perl relevantes se parecem com exec => catfile( $settings->config("/directories/executables"), $daemon_name ),
e eu confirmei que o valor de config("/directories/executables") é o valor correto/opt/my/path/directoryname
Procurar por esta pergunta tem sido um pesadelo devido a todas as perguntas sobre nomes de diretórios com espaços. Isto não é isso. Nenhum caminho deve conter um espaço. ps mostra meu comando mkdir com um espaço onde eu tinha uma barra é o mais próximo que consegui encontrar, que não foi respondido.
Entre os campos retornados por
ps -f
está a lista de argumentos passados para a última execução do comando que o processo (ou um de seus ancestrais) realizou. Você pode conseguir exatamente isso comps -o args
.Quando um processo executa um arquivo, isso ocorre com a
execve()
chamada do sistema:arg0
por convenção é o nome do executável. Quando um shell interpreta um:linha de comando, ele chama
execve("/path/to/cmd", ["cmd", "arg", 0], ...)
. Quando isso é:Ele chama
execve("/path/to/cmd", ["/path/to/cmd", "arg", 0], ...)
.Essas strings (
cmd
,arg
) terminam na parte inferior da pilha do processo, delimitadas por NUL. Dentro do processo, é isso queargv[0]
...argv[1]
aponta.No Linux, essa área é exposta em
/proc/<pid>/cmdline
, e é daíps
que vem para oargs
campo.Tecnicamente,
ps
pega essa lista de strings e imprime-a unida com espaços para que no final osargs
campos se pareçam com a linha de comando do shell que seria usada para executar o comando.Aqui, se
ps
mostra:Esses espaços podem indicar um espaço real nessas strings, ou strings separadas ou o fato de que os espaços foram substituídos por NULs nessas strings.
O último é plausível se o processo usou a função padrão
strtok()
ou uma abordagem semelhante paraargv[0]
dividi-lo,/
possivelmente para descobrir o nome base do executável como ele foi executado ou os diferentes componentes do diretório de seu caminho.Por exemplo, se eu criar:
E compile e execute:
Você verá que os
/
s foram substituídos por espaços.Na verdade, eles foram substituídos por NULs, como pode ser verificado em:
Mas
ps
vi esses NULs e os interpretei como delimitadores para 3 argumentos diferentes que uniram com espaços.Então, supondo que essa seja a explicação correta, não é um comportamento estranho do Linux, é apenas o próprio aplicativo modificando-o
argv[0]
após ser iniciado (provavelmente substituindo/
s por NULs, provavelmente para extrair alguns componentes do caminho).No Linux, uma maneira mais confiável de descobrir qual executável um processo está em execução no momento é executar um
readlink()
on/proc/<pid>/exe
, por exemplo, com o utilitáriorealpath
orreadlink
ou ostat
integrado dezsh
:E a implementação do procps
ps
no Linux retorna comps -o exe
.Não existe uma maneira infalível de saber com certeza quais argumentos foram passados para o comando, pois o que é mostrado
/proc/<pid>/cmdline
pode ser modificado pelo processo.Os registros de auditoria podem conter as informações.