プロセスに同じファイル名の別のファイルを読み取らせる


9

ファイルを読み取るアプリケーションがあります。それをprocessnameとファイル〜/ .configurationと呼びましょう。ときProcessNameのは、走ることは常に読み込み〜/ .configurationをし、異なって設定することはできません。「〜/ .configuration」に依存する他のアプリケーションもありますが、プロセス名の実行中ではありません。

〜/ .configurationの内容を置き換えるスクリプトでプロセス名をラップすることはオプションですが、最近、停電があり(内容がスワップアウトされている間に)、上記のファイルの以前の内容が失われたため、これは望ましくありません。

LD_DEBUG=files processnameプロセスが特定のファイルを読み込もうとしたときに、プロセスをだましてさまざまなコンテンツを読み取らせる方法(おそらく、遠くに関連する何かを使用しますか)はありますか?実行可能ファイル内のファイル名を検索して置き換えることは少し侵略的ですが、同様に機能するはずです。

open()呼び出しを引き継ぐカーネルモジュール(https://news.ycombinator.com/item?id=2972958)を作成することは可能ですが、より簡単またはよりクリーンな方法はありますか?

編集:プロセス名実行可能ファイルで〜/ .configurationを検索すると、〜/ .configurationを読み取る直前に別のファイル名を読み取ろうとしていることがわかりました。問題が解決しました。


2
これはLD_PRELOADやや類似した問題同様に、またはFUSE を介して行うことができますが、既存の実装は知りません。
Gilles「SO-邪悪なことをやめなさい」2013

回答:


6

最近のバージョンのLinuxでは、マウント名前空間の共有を解除できます。つまり、仮想ファイルシステムを別の方法で表示するプロセスを開始できます(ファイルシステムのマウント方法が異なります)。

それはまたで行うことができますchrootが、unshareより多くのあなたのケースに適合されています。

のようchrootunshare、マウント名前空間に特権を持つスーパーユーザーが必要です。

では、ファイルがある~/.configurationとしましょう~/.configuration-for-that-cmd

~/.configuration実際にバインドマウントされているプロセスを開始して~/.configuration-for-that-cmd、そこで実行that-cmdすることができます。

お気に入り:

sudo unshare -m sh -c "
   mount --bind '$HOME/.configuration-for-that-cmd' \
                '$HOME/.configuration' &&
     exec that-cmd"

that-cmdそして、そのすべての子孫プロセスは異なるものを参照します~/.configuration

that-cmd上記はとして実行されます別のユーザーとして実行する必要がある場合にroot使用しますsudo -u another-user that-cmd


あなたの解決策はおそらくこれまでに与えられた2つの方が良いと思います(そして、OPが何であるかを考えると、時間に基づいてリダイレクトするか、検出プロセスの結果は私には不審に思えます)、彼らは単一のファイルを望んでいると思います別に表示されます。したがって、おそらく別の場所にマウントしてシンボリックリンクを使用し、リダイレクトの実際のポイントとして機能するために異なるマウントポイントを使用する必要があります。
Bratchley 2013年

1
@JoelDavis、ディレクトリファイルだけでなく、任意のファイルをバインドマウントできます。
ステファンChazelas

TIL。しかし、それにはセキュリティ制御がありますか?私がいる場所のサブディレクトリ(/ etc / fstabからのバインド)を使用して試してみたところ、「ディレクトリではありません」と返されましたが、ほとんど同じことを実行し/test、問題なく動作しました。
Bratchley 2013年

実際、nm私は違いを見ることができます、私は最初にディレクトリにそれをし、次にファイルにそれをしました。必要に応じてVFSをリダイレクト/変更するだけだと想定していました。とにかく、新しいおもちゃをありがとう。
Bratchley 2013年

3

ソフトリンク。

2つの構成ファイルを作成し、ほとんどの場合ソフトリンクでそれらの1つを指すようにしますが、特別なアプリが実行されているときにソフトリンクを変更して、もう1つを指すようにします。

(私はこれが恐ろしいハックであることを知っていますが、ファイルの内容を変更するよりも少し信頼性があります)。

または、$ HOMEを操作します。

煩わしいプロセスを開始するスクリプトで、$ HOMEを通常の$ HOMEディレクトリの下に設定すると、アプリはそこにある構成ファイルを使用する必要があります(テストされ、基本的なシェルコマンドで機能し、〜は$ HOMEに展開されます)。

プロセスが他に何をするかによっては、$ HOMEを変更すると予期しない結果が生じる可能性があります(つまり、出力ファイルが誤った場所に配置される可能性があります)。


1

これは、LD_PRELOADトリックを使用し行うことができます。これは、特定のプレフィックスで始まるパスを別の場所にマッピングする実装です。コードはgithubにもあります。

たとえば、/etc/root にならずにファイルの存在を偽ることができます。これは、ファイル/etc/ownCloud/sync-exclude.listが存在しないときに動作を拒否するowncloudクライアントに必要でした。

これは、open()およびopen64()関数をオーバーライドして、あるディレクトリを別のディレクトリにマップします。たとえば、へのすべてのopen()呼び出しを/etc/ownCloud/...にリダイレクトできます/home/user1/.etc/ownCloud/...

を調整path_mapし、libをプリロードしてプログラムをコンパイルして実行します。

gcc -std=c99 -Wall -shared -fPIC path-mapping.c -o path-mapping.so -ldl

LD_PRELOAD=/path/to/my/path-mapping.so someprogram

のソースコードpath-mapping.c

#define _GNU_SOURCE

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <dlfcn.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdarg.h>
#include <malloc.h>

// List of path pairs. Paths beginning with the first item will be
// translated by replacing the matching part with the second item.
static const char *path_map[][2] = {
    { "/etc/ownCloud/", "/home/user1/.etc/ownCloud/" },
};

__thread char *buffer = NULL;
__thread int buffer_size = -1;

typedef FILE* (*orig_fopen_func_type)(const char *path, const char *mode);
typedef int (*orig_open_func_type)(const char *pathname, int flags, ...);

static int starts_with(const char *str, const char *prefix) {
    return (strncmp(prefix, str, strlen(prefix)) == 0);
}

static char *get_buffer(int min_size) {
    int step = 63;
    if (min_size < 1) {
        min_size = 1;
    }
    if (min_size > buffer_size) {
        if (buffer != NULL) {
            free(buffer);
            buffer = NULL;
            buffer_size = -1;
        }
        buffer = malloc(min_size + step);
        if (buffer != NULL) {
            buffer_size = min_size + step;
        }
    }
    return buffer;
}

static const char *fix_path(const char *path)
{
    int count = (sizeof path_map) / (sizeof *path_map); // Array length
    for (int i = 0; i < count; i++) {
        const char *prefix = path_map[i][0];
        const char *replace = path_map[i][1];
        if (starts_with(path, prefix)) {
            const char *rest = path + strlen(prefix);
            char *new_path = get_buffer(strlen(path) + strlen(replace) - strlen(prefix));
            strcpy(new_path, replace);
            strcat(new_path, rest);
            printf("Mapped Path: %s  ==>  %s\n", path, new_path);
            return new_path;
        }
    }
    return path;
}


int open(const char *pathname, int flags, ...)
{
    const char *new_path = fix_path(pathname);

    orig_open_func_type orig_func;
    orig_func = (orig_open_func_type)dlsym(RTLD_NEXT, "open");

    // If O_CREAT is used to create a file, the file access mode must be given.
    if (flags & O_CREAT) {
        va_list args;
        va_start(args, flags);
        int mode = va_arg(args, int);
        va_end(args);
        return orig_func(new_path, flags, mode);
    } else {
        return orig_func(new_path, flags);
    }
}

int open64(const char *pathname, int flags, ...)
{
    const char *new_path = fix_path(pathname);

    orig_open_func_type orig_func;
    orig_func = (orig_open_func_type)dlsym(RTLD_NEXT, "open64");

    // If O_CREAT is used to create a file, the file access mode must be given.
    if (flags & O_CREAT) {
        va_list args;
        va_start(args, flags);
        int mode = va_arg(args, int);
        va_end(args);
        return orig_func(new_path, flags, mode);
    } else {
        return orig_func(new_path, flags);
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.