
У меня есть программа, которая хранит свои настройки, и ~/.config/myprogram
я использую ее как в интерактивном режиме, так и с пакетной системой очередей. При интерактивном запуске я хочу, чтобы эта программа использовала мои файлы конфигурации (и она это делает). Но при запуске в пакетном режиме файлы конфигурации не нужны, потому что я указываю параметры командной строки, которые перезаписывают все соответствующие настройки. Кроме того, доступ к файлам конфигурации по сети увеличивает время запуска программы на несколько секунд; если файлы отсутствуют, программа запускается намного быстрее (поскольку каждое задание занимает всего около минуты, это существенно влияет на пропускную способность пакетного задания). Но поскольку я также использую программу в интерактивном режиме, я не хочу постоянно перемещать/удалять свои файлы конфигурации. В зависимости от того, когда мои пакетные задания планируются в кластере (на основе использования другими пользователями), я могу захотеть использовать программу в интерактивном режиме и как часть пакетного задания одновременно.
(Кстати: низкая производительность сетевых файлов, вероятно, является ошибкой, но я всего лишь пользователь кластера, поэтому могу только обойти ее, но не исправить.)
Я мог бы создать версию программы, которая не читает файлы конфигурации (или имеет опцию командной строки, чтобы не читать) для пакетного использования, но среда сборки этой программы плохо спроектирована и сложна в настройке. Я бы предпочел использовать двоичные файлы, установленные через менеджер пакетов моей системы.
Как мне обмануть отдельные экземпляры этой программы, чтобы они делали вид, что мои файлы конфигурации не существуют (без изменения программы)? Я надеюсь на оболочку в форме pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options...
, но я открыт для других решений.
решение1
Эта программа, вероятно, определяет путь к этому файлу из $HOME/.config/myprogram
. Таким образом, вы можете указать ей, что ваш домашний каталог находится в другом месте, например:
HOME=/nowhere your-program
Теперь, возможно, your-program нуждается в каком-то другом ресурсе в вашем домашнем каталоге. Если вы знаете, что это за ресурс, вы можете подготовить фальшивый дом для your-program со ссылками на ресурс, который ей нужен.
mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram
решение2
Если все остальное не сработает, напишите библиотеку-обертку, которую вы будете внедрять LD_PRELOAD
, чтобы вызов open("/home/you/my-program/config.interactive")
был перехвачен, но любой другой прошел. Это работает для любого типа программы, даже для скриптов оболочки, поскольку она будет фильтровать системные вызовы.
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;
}
}
Примечание: я не тестировал этот код и не уверен на 100%, что эта errno
часть работает.
Посмотрите, какfakeroot
делает это для вызовов типа getuid(2)
и stat(2)
.
По сути, компоновщик свяжет это приложение с вашей библиотекой, что переопределит символ open
. Поскольку вы не можете использовать две разные функции, названные open
в вашей собственной библиотеке, вам придется разделить их во второй части (например, get_real_open
), которая в свою очередь свяжет с исходным open
вызовом.
Оригинал:./Application
Application -----> libc.so
open()
Перехвачено:LD_PRELOAD=yourlib_wrap.so ./Application
Application -----> yourlib_wrap.so --------------> yourlib_impl.so -----> libc.so
open() get_real_open() open()
Редактировать:ВидимоСуществует ld
флаг, который можно включить ( --wrap <symbol>
), который позволяет писать оболочки, не прибегая к двойному связыванию:
/* 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;
}
}
решение3
Уберите свой конфигурационный файл и напишите оболочку сценария оболочки для интерактивного использования, которая копирует файл в его обычное место назначения, запускает программу и удаляет ее при выходе.
решение4
Переименуйте файл конфигурации в eg config.interactive
. Создайте еще один пустой файл с именем eg config.script
.
Теперь создайте мягкую ссылку под названием config
(или как приложение ожидает ее в качестве файла конфигурации) на любую реальную конфигурацию, которая вам нужна, и запустите свое приложение.
ln -s config.interactive config
Не забудьте потом привести ссылку в порядок.