Wie kann ich einen Prozess dahingehend täuschen, dass eine Datei nicht existiert?

31

Ich habe ein Programm, in dem die Einstellungen gespeichert sind ~/.config/myprogramdass ich sowohl interaktiv als auch mit einem Batch-Queuing-System verwende. Wenn ich interaktiv laufe, möchte ich, dass dieses Programm meine Konfigurationsdateien verwendet (und das tut es auch). Im Batch-Modus sind die Konfigurationsdateien jedoch nicht erforderlich, da ich Befehlszeilenoptionen spezifiziere, mit denen alle relevanten Einstellungen überschrieben werden. Darüber hinaus verlängert der Zugriff auf die Konfigurationsdateien über das Netzwerk die Startzeit des Programms um einige Sekunden. Wenn die Dateien nicht vorhanden sind, wird das Programm viel schneller gestartet (da jeder Job nur etwa eine Minute dauert, hat dies erhebliche Auswirkungen auf den Durchsatz von Batch-Jobs). Da ich das Programm aber auch interaktiv verwende, möchte ich meine Konfigurationsdateien nicht ständig verschieben / löschen. Abhängig davon, wann meine Stapeljobs im Cluster geplant werden (basierend auf der Verwendung durch andere Benutzer),

(Abgesehen davon, dass die Leistung von Netzwerkdateien so langsam ist, ist wahrscheinlich ein Fehler, aber ich bin nur ein Benutzer des Clusters, sodass ich ihn nur umgehen und nicht reparieren kann.)

Ich könnte eine Version des Programms erstellen, die die Konfigurationsdateien nicht liest (oder keine Befehlszeilenoption hat), aber die Build-Umgebung dieses Programms ist schlecht entwickelt und schwierig einzurichten. Ich würde es vorziehen, die Binärdateien zu verwenden, die über den Paketmanager meines Systems installiert wurden.

Wie kann ich bestimmte Instanzen dieses Programms dazu bringen, so zu tun, als ob meine Konfigurationsdateien nicht existieren (ohne das Programm zu ändern)? Ich hoffe auf einen Umschlag des Formulars pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options..., bin aber offen für andere Lösungen.

Jeffrey Bosboom
quelle
2
Sie können es als Benutzer ausführen, der nicht zum Lesen der Datei berechtigt ist.
Psimon
1
@psimon Als "nur ein Benutzer" des Clusters kann ich keinen neuen Benutzer erstellen, unter dem ich meinen Stapeljob ausführen kann. Das ist eine clevere Idee, und wenn es keine besseren Vorschläge gibt, werde ich den Cluster-Administrator bitten, dies für mich zu tun.
Jeffrey Bosboom
Oder richten Sie ein Skript ein, das zuerst die Konfigurationsdatei umbenennt, das Programm ausführt und dann die Konfigurationsdatei erneut umbenennt.
Psimon
@psimon Ich glaube, ich hätte klarer sein können: Ich verwende das Programm möglicherweise interaktiv und gleichzeitig im Batch-Modus, je nachdem, wann meine Batch-Jobs im Cluster geplant werden.
Jeffrey Bosboom
1
Ja, wenn es dynamisch verknüpft ist, können Sie einen LD_PRELOADHook verwenden. Das ist einfacher (Sie können das in ein oder zwei Stunden implementieren, wenn Sie C kennen) als die Alternative ptrace. Sie könnten wahrscheinlich auch fakechroot verwenden, um dies zu tun (das ist, glaube ich, LD_PRELOAD).
Derobert

Antworten:

33

Dieses Programm löst wahrscheinlich den Pfad zu dieser Datei aus $HOME/.config/myprogram. Sie können also sagen, dass sich Ihr Home-Verzeichnis an einem anderen Ort befindet, z. B .:

HOME=/nowhere your-program

Vielleicht benötigt Ihr Programm eine andere Ressource in Ihrem Home-Verzeichnis. Wenn Sie wissen, um welche es sich handelt, können Sie ein falsches Zuhause für Ihr Programm mit Links zu der Ressource vorbereiten, die es dort benötigt.

mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram
Stéphane Chazelas
quelle
5
Diese Antwort löst mein Problem, daher habe ich sie akzeptiert, obwohl sie keine allgemeine Antwort auf die Frage im Titel dieser Frage ist. Ein Vorspannhaken, wie in einer anderen Antwort beschrieben, ist eine allgemeinere (aber auch aufwändigere) Lösung.
Jeffrey Bosboom
28

Wenn alles andere fehlschlägt, schreiben Sie eine Wrapperbibliothek, die Sie mit einfügen, LD_PRELOADdamit der Aufruf von open("/home/you/my-program/config.interactive")abgefangen wird, aber alle anderen durchgelassen werden. Dies funktioniert für jede Art von Programm, auch für 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 zu 100% sicher, dass das errnoTeil funktioniert.

Schau mal wie fakerootes bei Anrufen getuid(2)und geht stat(2).

Grundsätzlich verknüpft der Linker diese Anwendung mit Ihrer Bibliothek, wodurch das openSymbol überschrieben wird . Da Sie nicht zwei verschiedene Funktionen verwenden können, die openin Ihrer eigenen Bibliothek benannt sind, müssen Sie sie in einem zweiten Teil (z. B. get_real_open) trennen, der wiederum auf den ursprünglichen openAufruf verweist.

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: Anscheinend gibt es ein ldFlag, das Sie aktivieren können ( --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; 
  }
}
sleblanc
quelle
2

Verschieben Sie Ihre Konfigurationsdatei aus dem Weg und schreiben Sie einen Shell-Script-Wrapper für den interaktiven Anwendungsfall, der die Datei an ihren normalen Speicherort kopiert, das Programm ausführt und beim Beenden löscht.

basteln
quelle
Siehe meine letzte Änderung: Ich habe keine Kontrolle über die Stapelplanung, daher benutze ich das Programm möglicherweise interaktiv und gleichzeitig als Teil eines Stapeljobs.
Jeffrey Bosboom
1

Dies sollte mit unionfs / aufs möglich sein. Sie erstellen eine chrootUmgebung für den Prozess. Sie verwenden das echte Verzeichnis als Nur-Lese-Ebene und legen ein leeres darüber. Anschließend mounten Sie das unionfs-Volume in das entsprechende Verzeichnis in der chrootUmgebung und löschen die Datei dort. Der Prozess wird es nicht sehen, aber alle anderen tun es.

Hauke ​​Laging
quelle
0

Benennen Sie die Konfigurationsdatei um in zB config.interactive. Erstellen Sie eine weitere leere Datei mit dem Namen z config.script.

Erstellen Sie nun einen Softlink mit dem Namen config(oder was auch immer die Anwendung als Konfigurationsdatei erwartet) zu der richtigen Konfiguration, die Sie benötigen, und führen Sie Ihre Anwendung aus.

ln -s config.interactive config

Denken Sie daran, Ihren Link danach aufzuräumen.

garethTheRed
quelle
Siehe meine letzte Änderung: Ich habe keine Kontrolle über die Stapelplanung, daher benutze ich das Programm möglicherweise interaktiv und gleichzeitig als Teil eines Stapeljobs. Diese Antwort entspricht im Wesentlichen dem Verschieben der Dateien entweder manuell oder mithilfe eines Skripts.
Jeffrey Bosboom
1
Doh! Ich muss schneller denken und tippen. Ist es eine große Anwendung? Könnte es in eine Chroot übertragen und von dort interaktiv ausgeführt werden? Es hängt alles davon ab, womit das Programm interagiert, nehme ich an. Es könnte auch eine sehr mühsame Aufgabe sein, alles, was es braucht, in eine Chroot zu bringen. (Ich denke, ich habe mich aus dieser Option geredet!)
garethTheRed
0

Wenn Sie genau festgelegt haben, wie Ihr Programm die Konfigurationsdatei verwendet, habe ich sie übersehen. Viele Programme (wie z. B. bashund vi) suchen sofort beim Start nach einer Konfigurationsdatei. Wenn die Datei vorhanden ist, lesen Sie sie und schließen Sie sie. Diese Programme greifen nie wieder auf diese Initialisierungsdateien zu. Wenn Ihr Programm so ist, lesen Sie weiter.

Ich weiß, dass Sie Antworten abgelehnt haben, die die Konfigurationsdatei wirklich nicht existent machen (indem Sie sie umbenennen), aber ich habe eine Falte, die ich von keinem anderen vorgeschlagen habe. Gehen Sie folgendermaßen vor, wenn Sie das Programm im Batch-Modus aufrufen:

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

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

Dies verschiebt die Konfigurationsdatei aus dem Weg, verschiebt sie jedoch eine Sekunde später wieder zurück, auch wenn sie myprogramnoch ausgeführt wird. Dadurch wird ein sehr kurzes Zeitfenster erstellt, in dem die Datei nicht verfügbar ist. Mit welcher Wahrscheinlichkeit führen Sie das Programm in diesem Fenster interaktiv aus? (Selbst wenn Sie dies tun, können Sie einfach beenden und neu starten, und die Konfigurationsdatei wird wahrscheinlich wieder vorhanden sein.)

Dies schafft eine Rennbedingung; Wenn das Programm zu lange braucht, um die Datei zu öffnen, wird möglicherweise die eigentliche Datei abgerufen. Wenn dies häufig genug vorkommt, um ein Problem zu verursachen, erhöhen Sie einfach den Wert von DELAY_TIME.

Scott
quelle
1
Was ist das Schlimmste, was schief gehen könnte? Ich habe das buchstäblich gesehen. In Produktion.
Henk Langeveld
-1

Ich mag Stephane Antwort, aber das wird Trick jedes Programm zu glauben , jede Datei ist leer - (weil seine dentry vorübergehend auf eine Datei zeigt , dass tatsächlich leer ist) :

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

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

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

Du könntest auch:

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

Wenn du wolltest.

mikeserv
quelle
Dies entspricht im Wesentlichen ein paar der früheren Antworten (mit der Ausnahme, dass der Benutzer dafür privilegiert sein muss, glaube ich). Das OP lehnte diese anderen Antworten ab, weil er keinen Prozess austricksen möchte - er möchte den Stapelaufruf des Programms austricksen, während der interaktive Aufruf die Konfigurationsdatei normal anzeigen soll.
Scott
@Scott - ich bin anderer Meinung - jede andere Antwort vor dieser empfahl eine Variation mvder Datei - die andere Konsequenzen haben könnte als die Beeinflussung ihres Eintrags, wie das tatsächliche Abschneiden der Datei oder anderer und so weiter -, während dies nichts anderes als funktioniert. Trotzdem, ich denke ich sollte unsharedas mount...
mikeserv