Como posso enganar um processo para pensar que um arquivo não existe?

31

Eu tenho um programa que armazena suas configurações em ~/.config/myprogram que uso interativamente e com um sistema de enfileiramento em lote. Ao executar interativamente, eu quero que este programa use meus arquivos de configuração (e funciona). Mas ao executar no modo de lote, os arquivos de configuração não são necessários porque eu especifico opções de linha de comando que substituem todas as configurações relevantes. Além disso, acessar os arquivos de configuração pela rede aumenta o tempo de inicialização do programa em vários segundos; se os arquivos não existirem, o programa será iniciado muito mais rápido (já que cada trabalho leva apenas cerca de um minuto, isso tem um impacto significativo na taxa de transferência de trabalho em lote). Mas como também uso o programa interativamente, não quero mover / excluir meus arquivos de configuração o tempo todo. Dependendo de quando meus trabalhos em lote são agendados no cluster (com base no uso de outros usuários), posso querer usar o programa interativamente e como parte de um trabalho em lotes ao mesmo tempo.

(Além disso: o desempenho do arquivo de rede é tão lento provavelmente é um bug, mas eu sou apenas um usuário do cluster, então só posso contornar isso, não corrigi-lo.)

Eu poderia criar uma versão do programa que não lesse os arquivos de configuração (ou não tivesse uma opção de linha de comando) para uso em lote, mas o ambiente de compilação deste programa é mal projetado e difícil de configurar. Eu preferiria muito mais usar os binários instalados através do gerenciador de pacotes do meu sistema.

Como posso enganar determinadas instâncias deste programa para fingir que meus arquivos de configuração não existem (sem modificar o programa)? Eu estou esperando por um wrapper do formulário pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options... , mas estou aberto a outras soluções.

    
por Jeffrey Bosboom 26.06.2014 / 22:15

7 respostas

33

Esse programa provavelmente resolve o caminho para esse arquivo em $HOME/.config/myprogram . Então você poderia dizer que o seu diretório home está em outro lugar, como:

HOME=/nowhere your-program

Agora, talvez o seu programa precise de algum outro recurso em seu diretório pessoal. Se você sabe quais são, você pode preparar uma casa falsa para o seu programa com links para o recurso que precisa lá.

mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram
    
por 26.06.2014 / 22:55
28

Se tudo mais falhar, escreva uma biblioteca de wrapper que você vai injetar usando LD_PRELOAD para que a chamada para open("/home/you/my-program/config.interactive") seja interceptada, mas qualquer outra será transmitida. Isso funciona para qualquer tipo de programa, até mesmo scripts de shell, já que ele filtrará as chamadas do sistema.

extern int errno;

int open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    return get_real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1;
  }
}

Observação: eu não testei este código e não tenho 100% de certeza de que a parte errno funciona.

Veja como fakeroot o faz para chamadas como getuid(2) e stat(2) .

Basicamente, o vinculador vinculará esse aplicativo à sua biblioteca, que substituirá o símbolo open . Como você não pode usar duas funções diferentes denominadas open em sua própria biblioteca, é necessário separá-las em uma segunda parte (por exemplo, get_real_open ), que por sua vez vinculará à chamada open original.

Original: ./Application

Application -----> libc.so
            open()

Interceptado: LD_PRELOAD=yourlib_wrap.so ./Application

Application -----> yourlib_wrap.so --------------> yourlib_impl.so -----> libc.so
            open()                 get_real_open()                 open()

Editar: Aparentemente existe um ld flag que você pode ativar ( --wrap <symbol> ) que permite escrever wrappers sem ter que recorrer a links duplos:

/* yourlib.c */
#include <stdio.h>

int __real_open(const char *pathname, int flags)

int __wrap_open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    /* the undefined reference here will resolve to "open" at linking time */
    return __real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1; 
  }
}
    
por 26.06.2014 / 23:44
2

Mova seu arquivo de configuração para fora do caminho e escreva um wrapper de script de shell para o caso de uso interativo que copia o arquivo em seu destino normal, executa o programa e o exclui ao sair.

    
por 26.06.2014 / 22:32
1

Isso deve ser possível com unionfs / aufs. Você cria um ambiente chroot para o processo. Você usa o diretório real como camada somente leitura e coloca um vazio sobre ele. Em seguida, monte o volume unionfs no respectivo diretório no ambiente chroot e exclua o arquivo lá. O processo não o verá, mas todos os outros o fazem.

    
por 27.06.2014 / 23:54
0

Renomeie o arquivo de configuração para, por exemplo, %código%. Crie outro arquivo vazio chamado, por exemplo config.interactive .

Agora, crie um link simples chamado config.script (ou o que a aplicação espera como um arquivo de configuração) para qualquer configuração real que você precisar e execute seu aplicativo.

ln -s config.interactive config

Lembre-se de arrumar seu link depois.

    
por 26.06.2014 / 22:48
0

Se você tiver caracterizado com precisão como seu programa usa o arquivo de configuração, Eu esqueci isso. Muitos programas (como bash e vi ) irão procurar por um arquivo de configuração imediatamente após o início; se o arquivo existir, leia-o e feche-o. Esses programas nunca acessam esses arquivos de inicialização novamente. Se o seu programa é assim, continue lendo.

Eu sei que você rejeitou respostas que tornam o arquivo de configuração realmente inexistente (mudando o nome), mas eu tenho uma ruga que não vi proposta por mais ninguém. Faça isso quando invocar o programa no modo batch:

DELAY_TIME=1
REALPATH="~/.config/myprogram"
HOLDPATH="${REALPATH}.hold"

mv "$REALPATH" "$HOLDPATH"
(sleep "$DELAY_TIME"; mv "$HOLDPATH" "$REALPATH")&
myprogram

Isso move o arquivo de configuração para fora do caminho mas, em seguida, volta um segundo depois, mesmo que myprogram ainda esteja em execução. Isso cria uma janela de tempo muito breve, durante a qual o arquivo não está disponível - Qual é a probabilidade de você executar o programa interativamente durante esta janela? (Mesmo se você fizer isso, você pode simplesmente sair e reiniciar, e o arquivo de configuração provavelmente estará de volta no lugar.)

Isso cria uma condição de corrida; se o programa demorar muito para abrir o arquivo, ele pode pegar o arquivo real. Se isso acontecer com frequência suficiente para que isso seja um problema, basta aumentar o valor de DELAY_TIME.

    
por 27.06.2014 / 20:17
-1

Eu gosto da resposta de Stephane, mas isso irá enganar qualquer programa para acreditar que qualquer arquivo está vazio - (porque seu dentry aponta temporariamente para um arquivo que realmente é vazio) :

cat <./test.txt
###OUTPUT###
notempty

mount --bind /dev/null ./test.txt
cat <./test.txt
###NO OUTPUT###

umount ./test.txt
cat <./test.txt
###OUTPUT###
notempty

Você também pode:

mount --bind ./someotherconfig.conf ./unwanted.conf

Se você quisesse.

    
por 27.06.2014 / 20:51

Tags