Estou perguntando porque as comparações de string são lentas, mas a indexação é rápida e muitos scripts que escrevo estão no bash, que, pelo que sei, executa uma pesquisa de string completa para cada chamada executável. Todos esses ls
'se grep
' seriam um pouco mais rápidos sem executar uma pesquisa de string em cada etapa. Claro, isso agora se aprofunda na otimização do compilador.
De qualquer forma, existe uma maneira de invocar diretamente um programa no Linux usando apenas seu número de inode (supondo que você tenha que procurá-lo apenas uma vez para todas as invocações)?
A resposta curta é não.
A resposta mais longa é que a API do usuário linux não suporta o acesso a arquivos por qualquer método usando o número do inode. O único acesso ao número do inode é normalmente por meio da chamada de sistema stat() que expõe o número do inode, o que pode ser útil para identificar se dois nomes de arquivo são o mesmo arquivo, mas não é usado para mais nada.
Acessar um arquivo por inode seria uma violação de segurança, pois ignoraria as permissões nos diretórios que contêm o arquivo vinculado ao inode.
O mais próximo que você pode chegar disso seria acessar um arquivo pelo identificador de arquivo aberto. Mas você também não pode executar um programa a partir dele, e isso ainda exigiria a abertura do arquivo por um caminho. (Conforme observado nos comentários, essa funcionalidade foi adicionada ao Linux por motivos de segurança junto com o restante das chamadas *at do sistema, mas não é portátil.)
Também existem várias maneiras de usar o número do inode para encontrar o arquivo (basicamente, rastrear o sistema de arquivos e usar stat) e executá-lo normalmente, mas isso é o oposto do que você deseja, pois é muito mais caro do que apenas acessar o arquivo por nome de caminho e também não remove esse custo.
Dito isto, preocupar-se com esse tipo de otimização provavelmente é discutível, pois o Linux já otimizou bastante a pesquisa interna do inode. Além disso, tradicionalmente, os shells fazem o hash da localização do caminho dos executáveis para que não precisem procurá-los em todos os diretórios o
$PATH
tempo todo.Sim, é possível executar um arquivo pelo seu inode:
O desempenho motivou a pergunta, porém, e o acima não é performático. Não apenas a estrutura do diretório é percorrida para encontrar um arquivo com esse inode (e pode haver vários), mas sob o capô, o número do inode é resolvido para um caminho e o caminho é fornecido ao kernel para executar. Mas por que?
O kernel expõe a família exec de funções (
execl
,execvp
, etc), que envolvem a função do kernelexecve
. Essa função substitui a imagem do processo atual por uma nova imagem do processo, uma que foi inicializada pela leitura do conteúdo de um determinado caminho de arquivo . Portanto, todas as maneiras que o kernel fornece para executar um programa exigem que seja fornecido por caminho. Ao usar o caminho do arquivo como ponto de entrada, obtemos todos os benefícios de controle de acesso associados aos caminhos do arquivo e, por isso, a API "by path" é a única no Linux para executar um programa.No entanto, existe um mecanismo complicado e não garantido para funcionar em todos os ambientes que permite invocar um programa de dentro da memória . Como qualquer coisa na memória é necessariamente mais rápida do que qualquer coisa no disco, isso leva ao cerne da questão: como executar um programa o mais rápido possível.
No início de 2002, um (famoso) hacker conhecido como grugq introduziu o conceito de userland exec. Esta não é uma função do shell
exec
: é uma emulação de cada etapa que aexecve
função do kernel executa, apenas escrita em userland. Isso é ideal para hackers que desejam ocultar sua atividade, pois permite a execução de um programa fora do mecanismo de controle de acesso usual doexecve
.A implementação desse método requer vários auxiliares que podem limpar o espaço de endereço, carregar o vinculador dinâmico, se necessário, inicializar a pilha e assim por diante. O mecanismo também requer que o código desejado seja carregado em certos tipos de memória.
Também existem contra-medidas para tornar esse tipo de coisa difícil, mas, observe, não impossível. Tudo o que é necessário é que o sistema de destino tenha memória alinhada à página, a capacidade de marcar a memória como executável e a capacidade de pular para pontos arbitrários na memória. Esses requisitos geralmente se traduzem em: você deve escrevê-lo em C e usá-lo em um sistema sem SELinux ou sem o SELinux estar completamente habilitado. Não entrarei em detalhes de implementação aqui, mas fornecerei links que permitem que você explore por conta própria.
Portanto, se o seu sistema Linux atender aos requisitos acima, você poderá executar o código na memória:
find / -inum 242 -exec cat {} \;
O kernel, o sistema de arquivos e o shell foram todos ajustados para tornar a pesquisa e a execução de programas uma fração insignificante da sobrecarga total necessária para realizar o trabalho. Carregar um programa na memória e executá-lo a partir daí não está realmente no domínio do caso de uso médio, então, a menos que faça isso por diversão, eu diria que você deseja comparar o desempenho antes de investir tempo tentando.
Referências:
Esta não é uma resposta direta à pergunta sobre i-nodes, mas sim uma maneira possível de evitar procurar os caminhos de utilitários padrão em scripts de shell.
BusyBox é um programa que combina muitos utilitários padrão do Unix em um único executável que é muito menor do que o tamanho combinado de todas as ferramentas que ele substitui. É muito popular no mundo embarcado, onde o tamanho do disco costuma ser muito importante. Em um sistema típico baseado em BusyBox,
sh
,ls
egrep
são todos links simbólicos parabusybox
. Assim, um script de shell que chamals
egrep
chamariabusybox
a si mesmo apenas duas vezes.O BusyBox possui um recurso experimental chamado “shell autônomo”. Quando ativado, o BusyBox agindo como um shell não executa pesquisas de caminho para os utilitários que implementa. Em vez disso, ele apenas se executa
/proc/self/exe
com os parâmetros corretos. Por exemplo, se ele executar um script de shell que chamegrep
, em vez de procurargrep
em$PATH
, ele executará/proc/self/exe grep <arguments>
. Ainda há uma pesquisa de caminho no kernel para/proc/self/exe
, mas é sempre a mesma, independentemente do utilitário que está sendo chamado, e a imagem executável já está na memória, portanto não há necessidade de carregá-la.Observe, no entanto, que o BusyBox foi altamente otimizado para tamanho e não para velocidade; portanto, pode não ser sua melhor opção se você se preocupa em economizar alguns microssegundos. Além disso, como observado anteriormente, o recurso “shell autônomo” é rotulado como experimental.
Não, não é, e por um motivo simples: você está usando a forma singular " um programa" e " seu número de inode" em sua pergunta, mas os inodes não são únicos: pode haver vários arquivos no sistema com o mesmo inode número.
Portanto, pelo simples senso comum, o melhor que você pode fazer é "invocar diretamente um ou mais de um conjunto de programas usando apenas seus números de inode", mas você não pode invocar um programa específico sem informações de identificação adicionais sobre o referido programa para escolher o único programa do conjunto de programas.
Uma dessas informações de identificação, é claro, poderia ser seu caminho... ponto em que você está de volta à estaca zero.