
Ich habe ein Programm, das seine Einstellungen speichert und ~/.config/myprogram
das ich sowohl interaktiv als auch mit einem Batch-Warteschlangensystem verwende. Wenn es interaktiv ausgeführt wird, möchte ich, dass dieses Programm meine Konfigurationsdateien verwendet (und das tut es auch). Aber wenn es im Batch-Modus ausgeführt wird, sind die Konfigurationsdateien nicht erforderlich, da ich Befehlszeilenoptionen angebe, die alle relevanten Einstellungen überschreiben. Außerdem erhöht der Zugriff auf die Konfigurationsdateien über das Netzwerk die Startzeit des Programms um mehrere Sekunden; wenn die Dateien nicht vorhanden sind, startet das Programm viel schneller (da jeder Job nur etwa eine Minute dauert, hat dies erhebliche Auswirkungen auf den Durchsatz des Batch-Jobs). Aber weil ich das Programm auch interaktiv verwende, möchte ich meine Konfigurationsdateien nicht ständig verschieben/löschen. Je nachdem, wann meine Batch-Jobs auf dem Cluster geplant werden (basierend auf der Nutzung anderer Benutzer), möchte ich das Programm möglicherweise gleichzeitig interaktiv und als Teil eines Batch-Jobs verwenden.
(Abgesehen davon: Die langsame Leistung der Netzwerkdateien ist wahrscheinlich ein Fehler, aber ich bin nur ein Benutzer des Clusters und kann das Problem daher nur umgehen, aber nicht beheben.)
Ich könnte eine Version des Programms erstellen, die die Konfigurationsdateien nicht liest (oder eine Befehlszeilenoption dafür hat), um sie für die Stapelverarbeitung zu verwenden, aber die Build-Umgebung dieses Programms ist schlecht entwickelt und schwer einzurichten. Ich würde viel lieber die Binärdateien verwenden, die über den Paketmanager meines Systems installiert wurden.
Wie kann ich bestimmte Instanzen dieses Programms dazu bringen, vorzutäuschen, dass meine Konfigurationsdateien nicht existieren (ohne das Programm zu ändern)? Ich hoffe auf einen Wrapper für das Formular pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options...
, bin aber auch für andere Lösungen offen.
Antwort1
Dieses Programm löst wahrscheinlich den Pfad zu dieser Datei auf $HOME/.config/myprogram
. Sie können ihm also mitteilen, dass sich Ihr Home-Verzeichnis woanders befindet, etwa:
HOME=/nowhere your-program
Nun benötigt Ihr Programm vielleicht noch eine andere Ressource in Ihrem Home-Verzeichnis. Wenn Sie wissen, um welche Ressource es sich handelt, können Sie ein Fake-Home-Verzeichnis für Ihr Programm mit Links zu der dort benötigten Ressource vorbereiten.
mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram
Antwort2
Wenn alles andere fehlschlägt, schreiben Sie eine Wrapper-Bibliothek, die Sie so einfügen, LD_PRELOAD
dass der Aufruf open("/home/you/my-program/config.interactive")
abgefangen wird, alle anderen jedoch durchkommen. Dies funktioniert für alle Programmtypen, sogar Shell-Skripte, da Systemaufrufe gefiltert werden.
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;
}
}
Hinweis: Ich habe diesen Code nicht getestet und bin nicht 100 % sicher, ob das errno
Teil funktioniert.
Schauen Sie sich an, wiefakeroot
tut dies für Anrufe wie getuid(2)
und stat(2)
.
Grundsätzlich verknüpft der Linker diese Anwendung mit Ihrer Bibliothek, wodurch das open
Symbol überschrieben wird. Da Sie nicht zwei verschiedene Funktionen verwenden können , die open
in Ihrer eigenen Bibliothek benannt sind, müssen Sie sie in einem zweiten Teil (z. B. get_real_open
) trennen, der wiederum mit dem ursprünglichen open
Aufruf verknüpft wird.
Original:./Application
Application -----> libc.so
open()
Abgefangen:LD_PRELOAD=yourlib_wrap.so ./Application
Application -----> yourlib_wrap.so --------------> yourlib_impl.so -----> libc.so
open() get_real_open() open()
Bearbeiten:ScheinbarSie können ein ld
Flag aktivieren ( --wrap <symbol>
), mit dem Sie Wrapper schreiben können, ohne auf doppelte Verknüpfungen zurückgreifen zu müssen:
/* 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;
}
}
Antwort3
Verschieben Sie Ihre Konfigurationsdatei aus dem Weg und schreiben Sie einen Shell-Skript-Wrapper für den interaktiven Anwendungsfall, der die Datei an ihr normales Ziel kopiert, das Programm ausführt und es beim Beenden löscht.
Antwort4
Benennen Sie die Konfigurationsdatei in zB um config.interactive
. Erstellen Sie eine weitere leere Datei mit dem Namen zB config.script
.
Erstellen Sie nun einen Softlink mit dem Namen config
(oder was auch immer die Anwendung als Konfigurationsdatei erwartet) zu der tatsächlich benötigten Konfiguration und führen Sie Ihre Anwendung aus.
ln -s config.interactive config
Denken Sie daran, Ihren Link anschließend aufzuräumen.