我有一个读取文件的应用程序。我们就这样称呼它吧进程名和文件~/.configuration。什么时候进程名运行它总是读取~/.configuration并且不能进行不同的配置。还有其他应用程序依赖“~/.configuration”,之前和之后,但不是 while进程名在跑。
包装进程名在替换内容的脚本中~/.configuration是一个选项,但我最近停电了(当内容被换出时),我丢失了该文件以前的内容,所以这是不可取的。
有没有一种方法(也许使用与 远相关的东西LD_DEBUG=files processname
?)来欺骗进程在尝试读取特定文件时读取不同的内容?在可执行文件中搜索和替换文件名有点过于侵入性,但应该也可以。
我知道可以编写一个内核模块来接管调用open()
(https://news.ycombinator.com/item?id=2972958),但是有没有更简单或更干净的方法呢?
编辑:搜索时~/.configuration在里面进程名可执行文件我发现它在读取之前尝试读取另一个文件名~/.configuration。问题解决了。
答案1
在最新版本的 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
上面将运行为root
,sudo -u another-user that-cmd
如果需要运行为另一个用户。
答案2
软链接。
创建两个配置文件,并在大多数情况下使用软链接指向其中一个,但在特殊应用程序运行时更改软链接以指向另一个。
(我知道这是一个可怕的黑客攻击,但它比更改文件内容稍微可靠一些)。
或者,操纵 $HOME。
在启动烦人进程的脚本中,将 $HOME 设置为常规 $HOME 目录下的某个内容,然后您的应用程序应该使用位于那里的配置文件(经过测试,适用于基本 shell 命令,~ 扩展为 $HOME)。
根据进程执行的其他操作,更改 $HOME 可能会产生意想不到的后果(即输出文件可能最终出现在错误的位置)。
答案3
您可以使用以下方法执行此操作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);
}
}