使进程读取具有相同文件名的其他文件


9

我有一个读取文件的应用程序。我们将其称为processname和文件〜/ .configuration。当processname运行时,它始终读取〜/ .configuration,并且不能进行其他配置。在运行进程名之前和之后,还有其他依赖于“〜/ .configuration”的应用程序,但在运行进程名时并不依赖

在脚本中包装进程名以替换〜/ .configuration的内容是一种选择,但是最近我断电(当内容被换出时),我丢失了该文件的先前内容,所以这不是可取的。

LD_DEBUG=files processname当尝试读取特定文件时,是否有一种方法(也许使用与?有密切关系的东西)来使进程欺骗以读取不同的内容?搜索和替换可执行文件中的文件名有点麻烦,但也应该可以。

我知道可以编写一个接管open()调用的内核模块(https://news.ycombinator.com/item?id=2972958),但是有没有更简单或更简洁的方法?

编辑:在processname可执行文件中搜索〜/ .configuration时,我发现它在读取〜/ .configuration之前试图读取另一个文件名。问题解决了。


2
可以通过LD_PRELOAD或FUSE 来完成,就像有类似的问题一样,但是我不知道任何现有的实现。
吉尔(Gilles)'所以

Answers:


6

在最近版本的Linux,你可以取消共享安装命名空间。也就是说,您可以启动以不同的方式查看虚拟文件系统的过程(以不同的方式安装文件系统)。

也可以使用完成此操作chroot,但unshare更适合您的情况。

像一样chroot,您需要将超级用户特权赋予unshare安装命名空间。

因此,假设您有~/.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上面的代码将以as身份运行rootsudo -u another-user that-cmd如果需要以其他用户身份运行,请使用。


我认为您的解决方案可能是迄今为止给出的两种解决方案中最好的(并且考虑到OP的要求,根据时间或检测过程的结果进行重定向对我来说似乎很困难),但是我认为他们想要的是单个文件以不同的方式出现。因此,他们可能不得不将其安装在其他位置并使用符号链接,并依靠不同的安装点作为实际的重定向点。
布拉奇利2013年

1
@JoelDavis,您可以绑定安装任何文件,而不仅仅是目录文件。
斯特凡Chazelas

瓷砖。但是,是否有安全控制措施?我使用了我所在的子目录(从/ etc / fstab进行绑定)尝试了它,并返回“ Not a directory”,但是我在下面做了几乎相同的事情,/test并且没有问题。
Bratchley13年

实际上,nm我可以看到不同之处,我第一次将其存储在目录中,然后将其存储在文件中。我以为它会适当地重定向/修改VFS。任何人,谢谢您的新玩具。
Bratchley13年

3

软链接。

创建两个配置文件,并在大多数时间使用软链接指向其中一个,但是在运行特殊应用程序时,将软链接更改为指向另一个。

(我知道这是一个可怕的骇客,但是它比更改文件内容要可靠得多)。

或者,操纵$ HOME。

在开始烦人过程的脚本中,将$ HOME设置为常规$ HOME目录下的内容,然后您的应用应使用该目录下的配置文件(经过测试,适用于基本的shell命令,〜扩展为$ HOME)。

取决于过程的其他用途,更改$ HOME可能会产生意想不到的后果(即,输出文件可能最终放置在错误的位置)。


1

您可以使用LD_PRELOAD技巧进行此操作。这是一个将以特定前缀开头的路径映射到另一个位置的实现。该代码也在github上

例如,您可以在/etc/没有root用户的情况下伪造文件的存在。这对于owncloud客户端是必要的,该客户端在文件/etc/ownCloud/sync-exclude.list不存在时拒绝工作。

它通过覆盖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);
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.