Come posso indurre un processo a pensare che un file non esista?


31

Ho un programma in cui sono memorizzate le sue impostazioni ~/.config/myprogramche utilizzo sia in modo interattivo che con un sistema di accodamento batch. Quando corro in modo interattivo, voglio che questo programma usi i miei file di configurazione (e lo fa). Ma quando si esegue in modalità batch, i file di configurazione non sono necessari perché specifico le opzioni della riga di comando che sovrascrivono tutte le impostazioni pertinenti. Inoltre, l'accesso ai file di configurazione sulla rete aumenta il tempo di avvio del programma di alcuni secondi; se i file non esistono, il programma si avvia molto più velocemente (poiché ogni processo richiede solo circa un minuto, ciò ha un impatto significativo sulla velocità di elaborazione dei processi batch). Ma poiché utilizzo anche il programma in modo interattivo, non voglio spostare / eliminare i miei file di configurazione in ogni momento. A seconda di quando i miei lavori batch vengono programmati sul cluster (in base all'utilizzo di altri utenti),

(A parte: che le prestazioni dei file di rete sono così lente è probabilmente un bug, ma sono solo un utente del cluster, quindi posso solo aggirarlo, non risolverlo.)

Potrei costruire una versione del programma che non legge i file di configurazione (o ha un'opzione da riga di comando per non farlo) per l'uso in batch, ma l'ambiente di costruzione di questo programma è scarsamente ingegnerizzato e difficile da configurare. Preferirei di gran lunga usare i binari installati tramite il gestore dei pacchetti del mio sistema.

Come posso ingannare particolari istanze di questo programma fingendo che i miei file di configurazione non esistano (senza modificare il programma)? Spero in un wrapper del modulo pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options..., ma sono aperto ad altre soluzioni.


2
È possibile eseguirlo come un utente che non dispone delle autorizzazioni per leggere il file.
psimon,

1
@psimon Come "solo un utente" del cluster, non riesco a creare un nuovo utente per eseguire il mio lavoro batch come. Questa è un'idea intelligente, tuttavia, e se non ci sono suggerimenti migliori, baco l'amministratore del cluster per farlo per me.
Jeffrey Bosboom,

Oppure imposta uno script che prima rinomina il file di configurazione, esegue il programma e quindi rinomina nuovamente il file di configurazione.
psimon,

@psimon Immagino che avrei potuto essere più chiaro: potrei usare il programma in modo interattivo e in modalità batch allo stesso tempo, a seconda di quando i miei lavori batch vengono programmati sul cluster.
Jeffrey Bosboom,

1
Sì, se è collegato dinamicamente, puoi usare un LD_PRELOADhook. È più facile (puoi implementarlo in un'ora o due, se conosci C) rispetto all'alternativa, che è ptrace. Probabilmente potresti anche usare fakechroot per farlo (che è LD_PRELOAD, credo).
derobert,

Risposte:


33

Quel programma probabilmente risolve il percorso da quel file $HOME/.config/myprogram. Quindi potresti dire che la tua home directory è altrove, come:

HOME=/nowhere your-program

Ora, forse il tuo programma ha bisogno di qualche altra risorsa nella tua home directory. Se sai quali sono, puoi preparare una casa falsa per il tuo programma con collegamenti alla risorsa di cui ha bisogno.

mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram

5
Questa risposta risolve il mio problema, quindi l'ho accettato anche se non è una risposta completamente generale alla domanda nel titolo di questa domanda. Un hook di precarico, come descritto in un'altra risposta, è una soluzione più generale (ma anche di maggiore sforzo).
Jeffrey Bosboom,

28

Se tutto il resto fallisce, scrivi una libreria wrapper che ti verrà iniettata in LD_PRELOADmodo da open("/home/you/my-program/config.interactive")intercettare la chiamata a ma passerà qualsiasi altra. Funziona con qualsiasi tipo di programma, anche con gli script di shell, poiché filtra le chiamate di 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;
  }
}

Nota: non ho testato questo codice e non sono sicuro al 100% che la errnoparte funzioni.

Guarda come fakerootfunziona per chiamate come getuid(2)e stat(2).

Fondamentalmente, il linker collegherà l'applicazione alla tua libreria, che sovrascrive il opensimbolo. Poiché non è possibile utilizzare due diverse funzioni denominate opennella propria libreria, è necessario separarle in una seconda parte (ad es. get_real_open) Che a sua volta si collegherà alla openchiamata originale .

Originale: ./Application

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

intercettata: LD_PRELOAD=yourlib_wrap.so ./Application

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

Modifica: a quanto pare c'è un ldflag che puoi abilitare ( --wrap <symbol>) che ti consente di scrivere wrapper senza dover ricorrere al doppio collegamento:

/* 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; 
  }
}

2

Spostare il file di configurazione e scrivere un wrapper di script di shell per il caso d'uso interattivo che copia il file nella sua destinazione normale, esegue il programma ed eliminalo all'uscita.


Vedi la mia recente modifica: non controllo la pianificazione batch, quindi potrei utilizzare il programma in modo interattivo e contemporaneamente come parte di un processo batch.
Jeffrey Bosboom,

1

Ciò dovrebbe essere possibile con unionfs / aufs. Si crea un chrootambiente per il processo. Si utilizza la directory reale come layer di sola lettura e ne viene aggiunta una vuota. Quindi si monta il volume unionfs nella rispettiva directory chrootnell'ambiente e si elimina il file lì. Il processo non lo vedrà ma tutti gli altri lo fanno.


0

Rinominare il file di configurazione in es config.interactive. Crea un altro file vuoto chiamato ad es config.script.

Ora, crea un soft link chiamato config(o qualunque cosa l'applicazione si aspetti come file di configurazione) per qualsiasi configurazione reale ti serva ed esegui la tua applicazione.

ln -s config.interactive config

Ricorda di riordinare il link in seguito.


Vedi la mia recente modifica: non controllo la pianificazione batch, quindi potrei utilizzare il programma in modo interattivo e contemporaneamente come parte di un processo batch. Questa risposta è essenzialmente la stessa di spostare i file in giro, manualmente o con uno script.
Jeffrey Bosboom,

1
Doh! Ho bisogno di pensare e digitare più velocemente. È una grande applicazione? Potrebbe essere trasferito su un chroot e gestito da lì in modo interattivo? Tutto dipende da cosa interagisce il programma, suppongo. Potrebbe anche essere un compito molto noioso mettere tutto in un chroot troppo. (Penso di essermi parlato di
quell'opzione

0

Se hai caratterizzato con precisione come il tuo programma utilizza il file di configurazione, l'ho trascurato. Molti programmi (come bashe vi) controlleranno immediatamente un file di configurazione all'avvio; se il file esiste, leggilo e chiudilo. Questi programmi non accedono mai più a questi file di inizializzazione. Se il tuo programma è così, continua a leggere.

So che hai respinto le risposte che rendono il file di configurazione davvero inesistente (rinominandolo), ma ho una ruga che non ho visto proposta da nessun altro. Fallo quando invochi il programma in modalità batch:

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

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

Questo sposta il file di configurazione di mezzo, ma poi lo sposta di un secondo dopo, anche se myprogramè ancora in esecuzione. Questo crea una finestra temporale molto breve durante la quale il file non è disponibile - qual è la probabilità che eseguirai il programma in modo interattivo durante questa finestra? (Anche se lo fai, puoi semplicemente uscire e riavviare e il file di configurazione sarà probabilmente al suo posto.)

Questo crea una condizione di razza; se il programma impiega troppo tempo ad aprire il file, potrebbe ottenere il file reale. Se ciò accade abbastanza spesso da costituire un problema, aumenta semplicemente il valore di DELAY_TIME.


1
Qual è la cosa peggiore che potrebbe andare storto? L'ho visto letteralmente accadere. In produzione.
Henk Langeveld,

-1

Mi piace la risposta di Stephane, ma questo sarà ingannare qualsiasi programma a credere qualsiasi file è vuoto - (perché la sua dentry indica temporaneamente per un file che è in realtà vuoto) :

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

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

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

Potresti anche:

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

Se tu volessi.


Ciò equivale essenzialmente a un paio di risposte precedenti (tranne, credo, questo richiede che l'utente abbia il privilegio). L'OP ha respinto quelle altre risposte perché non vuole ingannare alcun processo: vuole ingannare l'invocazione batch del programma, lasciando che l'invocazione interattiva veda normalmente il file di configurazione.
Scott,

@Scott - non sono d'accordo - ogni altra risposta prima di questa raccomandava alcune variazioni sul mvfile - che potrebbe avere altre conseguenze oltre a influire sulla sua dentatura come troncare effettivamente il file o altri ed ecc. - mentre questo funziona solo su. Eppure, dovrei unshareche mountimmagino ...
mikeserv
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.