如何欺骗进程认为文件不存在?

Jef*_*oom 31 files

我有一个程序将其设置存储在 ~/.config/myprogram我以交互方式和批处理排队系统使用。当以交互方式运行时,我希望这个程序使用我的配置文件(它确实如此)。但是在批处理模式下运行时,配置文件不是必需的,因为我指定了覆盖所有相关设置的命令行选项。此外,通过网络访问配置文件会使程序的启动时间增加几秒钟;如果文件不存在,程序启动速度会更快(因为每个作业只需要大约一分钟,这对批处理作业吞吐量有重大影响)。但是因为我也以交互方式使用该程序,所以我不想一直移动/删除我的配置文件。根据我的批处理作业在集群上的调度时间(基于其他用户的使用情况),

(另外:网络文件性能如此之慢可能是一个错误,但我只是集群的用户,所以我只能解决它,不能修复它。)

我可以构建一个不读取配置文件(或有一个不读取配置文件的命令行选项)的程序版本以供批量使用,但该程序的构建环境设计不佳且难以设置。我更喜欢使用通过我系统的包管理器安装的二进制文件。

我怎样才能欺骗这个程序的特定实例来假装我的配置文件不存在(不修改程序)?我希望有一个 form 的包装器pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options...,但我对其他解决方案持 开放态度。

Sté*_*las 33

该程序可能会解析该文件的路径$HOME/.config/myprogram。所以你可以告诉它你的主目录在别处,比如:

HOME=/nowhere your-program
Run Code Online (Sandbox Code Playgroud)

现在,您的程序可能需要您的主目录中的其他资源。如果您知道它们是哪个,您可以为您的程序准备一个假的家,并提供指向其中所需资源的链接。

mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram
Run Code Online (Sandbox Code Playgroud)

  • 这个答案解决了我的问题,所以我接受了它,即使它不是这个问题标题中问题的完全通用的答案。如另一个答案中所述,预加载挂钩是一种更通用(但也更费力)的解决方案。 (5认同)

sle*_*anc 28

如果所有其他方法都失败了,请编写一个包装库,您将使用LD_PRELOAD该库进行注入,以便open("/home/you/my-program/config.interactive")拦截对调用的调用,但其他任何调用都将通过。这适用于任何类型的程序,甚至是 shell 脚本,因为它会过滤系统调用。

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

注意:我还没有测试过这段代码,我也不是 100% 确定这errno部分能正常工作。

看看fakeroot它如何处理像getuid(2)和之类的调用stat(2)

基本上,链接器会将该应用程序链接到您的库,该库会覆盖该open符号。由于您不能使用open在您自己的库中命名的两个不同的函数,您必须在第二部分(例如get_real_open)中将其分开,这将依次链接到原始open调用。

原来的: ./Application

Application -----> libc.so
            open()
Run Code Online (Sandbox Code Playgroud)

拦截: LD_PRELOAD=yourlib_wrap.so ./Application

Application -----> yourlib_wrap.so --------------> yourlib_impl.so -----> libc.so
            open()                 get_real_open()                 open()
Run Code Online (Sandbox Code Playgroud)

编辑:显然有一个ld标志可以启用 ( --wrap <symbol>) 允许您编写包装器而不必求助于双重链接:

/* 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; 
  }
}
Run Code Online (Sandbox Code Playgroud)