
Eu tenho um programa que armazena suas configurações e ~/.config/myprogram
uso de forma interativa e com um sistema de enfileiramento em lote. Ao executar de forma interativa, quero que este programa use meus arquivos de configuração (e usa). Mas ao executar no modo em 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 (como cada trabalho leva apenas cerca de um minuto, isso terá um impacto significativo no rendimento do trabalho em lote). Mas como também uso o programa de forma interativa, 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), talvez eu queira usar o programa de forma interativa e como parte de um trabalho em lote ao mesmo tempo.
(Além disso: o desempenho do arquivo de rede é tão lento que provavelmente é um bug, mas sou apenas um usuário do cluster, então só posso contornar isso, não corrigi-lo.)
Eu poderia construir uma versão do programa que não leia os arquivos de configuração (ou tenha uma opção de linha de comando para não fazê-lo) para uso em lote, mas o ambiente de construção deste programa é mal projetado e difícil de configurar. Eu prefiro usar os binários instalados através do gerenciador de pacotes do meu sistema.
Como posso enganar instâncias específicas deste programa para que finjam que meus arquivos de configuração não existem (sem modificar o programa)? Espero um wrapper no formato pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options...
, mas estou aberto a outras soluções.
Responder1
Esse programa provavelmente resolve o caminho para esse arquivo de $HOME/.config/myprogram
. Então você poderia dizer que seu diretório inicial está em outro lugar, como:
HOME=/nowhere your-program
Agora, talvez o seu programa precise de algum outro recurso no seu diretório inicial. Se você souber quais são, poderá preparar uma casa falsa para o seu programa com links para os recursos necessários.
mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram
Responder2
Se tudo mais falhar, escreva uma biblioteca wrapper que você injetará LD_PRELOAD
para que a chamada open("/home/you/my-program/config.interactive")
seja interceptada, mas qualquer outra passe. Isso funciona para qualquer tipo de programa, até mesmo scripts de shell, pois 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: não testei esse código e não tenho 100% de certeza de que a errno
peça funcione.
Veja comofakeroot
faz isso para chamadas como getuid(2)
e stat(2)
.
Basicamente, o vinculador vinculará esse aplicativo à sua biblioteca, que substituirá o open
símbolo. Como você não pode usar duas funções diferentes nomeadas open
em sua própria biblioteca, você deve separá-las em uma segunda parte (por exemplo, get_real_open
) que por sua vez será vinculada à open
chamada 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:Aparentementeexiste um ld
sinalizador que você pode ativar ( --wrap <symbol>
) que permite escrever wrappers sem precisar 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;
}
}
Responder3
Tire seu arquivo de configuração 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.
Responder4
Renomeie o arquivo de configuração para, por exemplo config.interactive
, . Crie outro arquivo vazio chamado, por exemplo config.script
, .
Agora, crie um soft link chamado config
(ou o que o aplicativo espera como arquivo de configuração) para qualquer configuração real necessária e execute seu aplicativo.
ln -s config.interactive config
Lembre-se de arrumar seu link depois.