Linux fork/exec 到同一目录中的应用程序

Posted

技术标签:

【中文标题】Linux fork/exec 到同一目录中的应用程序【英文标题】:Linux fork/exec to application in same directory 【发布时间】:2011-02-08 15:29:01 【问题描述】:

是否有exec 变体会使用当前应用程序目录来定位目标程序?

我正在使用 C++ 和 Qt 来实现“最后一搏”错误报告系统。使用Google Breakpad,我可以创建一个小型转储并直接执行到处理程序。因为我的应用程序处于不稳定状态,我只想使用最少的依赖项来分叉并启动一个单独的错误处理过程。错误报告应用程序将部署在与应用程序可执行文件相同的目录中。

我对@9​​87654323@ 和exec 选项非常陌生,并且在搜索路径中找不到包含当前应用程序目录的exec 选项。这是我目前所拥有的:

static bool dumpCallback(const char* /*dump_path*/,
                         const char* /*minidump_id*/,
                         void* /*context*/,
                         bool succeeded)

  pid_t pid = fork();
  if (pid == 0)
  
    // This is what I would *like* to work.
    const char* error_reporter_path = "error_reporter";

    // This works, but requires hard-coding the entire path, which seems lame,
    // and really isn't an option, given our deployment model.
    //
    // const char* error_reporter_path = "/path/to/app/error_reporter";

    // This also works, but I don't like the dependency on QApplication at this
    // point, since the application is unstable.
    //
    // const char* error_reporter_path =
    //     QString("%1/%2")
    //    .arg(QApplication::applicationDirPath())
    //    .arg("error_reporter").toLatin1().constData();

    execlp(error_reporter_path,
           error_reporter_path,
           (char *) 0);
  
  return succeeded;

关于使用forkexec最佳实践的任何其他建议也将不胜感激;这是我第一次使用它们。在这一点上,我只关心 Linux(Ubuntu、Fedora);稍后我将研究其他操作系统的处理程序。

【问题讨论】:

【参考方案1】:

你要求的其实很简单:


  pid_t pid = fork();
  if (pid == 0)
  
    const char* error_reporter_path = "./error_reporter";
    execl(error_reporter_path,
          error_reporter_path,
          (char *) 0);
    _exit(127);
  
  else
    return pid != -1;

但它不会做你想做的事。 当前工作目录不一定与包含当前可执行文件的目录相同——事实上,几乎在所有情况下都不会。

我建议您将error_reporter_path 设为全局变量,并在main 的开头使用您的“选项2”代码对其进行初始化

     QString("%1/%2")
    .arg(QApplication::applicationDirPath())
    .arg("error_reporter").toLatin1().constData();

QString 对象(不仅仅是它的constData)必须在程序的整个生命周期内都存在,但这应该不是问题。请注意,您应该转换为 UTF-8,而不是 Latin1(我猜 QString 使用宽字符?)

【讨论】:

【参考方案2】:

我认为你有两个选择:

    添加“.”到 $PATH。 将getcwd() 的结果添加到可执行文件名称中。

【讨论】:

【参考方案3】:

您应该在程序启动时构建您的助手可执行文件的路径,并将其保存在某处(在全局或静态变量中)。如果您只需要在 Linux 上运行,您可以通过读取 /proc/self/exe 来获取可执行文件的位置。像这样的:

// Locate helper binary next to the current binary.
char self_path[PATH_MAX];
if (readlink("/proc/self/exe", self_path, sizeof(self_path) - 1) == -1) 
  exit(1);

string helper_path(self_path);
size_t pos = helper_path.rfind('/');
if (pos == string::npos) 
  exit(1);

helper_path.erase(pos + 1);
helper_path += "helper";

摘自此处的完整工作示例:http://code.google.com/p/google-breakpad/source/browse/trunk/src/client/linux/minidump_writer/linux_dumper_unittest.cc#92

【讨论】:

【参考方案4】:

    在任何情况下都不要添加“。”到 $PATH !!

    1234563然后你必须考虑如何处理结果文件名中的符号链接。即使在那之后,您也永远无法确定 argv[0] 是否设置为用于执行程序的命令

选项 3:

在您的可执行文件中硬编码完整的文件名,但使用配置脚本来设置文件名。 (您使用的是配置脚本,对吗?)

选项 4;

不要调用 exec。您不必在分叉后调用 exec 。假装你刚刚进入“main”,当你的错误报告完成后调用“exit”。

【讨论】:

感谢您的回答;你能详细说明一下:(选项1)如果我添加“。”会发生什么坏事到 $PATH? (选项 3)不,不使用配置脚本;您能否添加指向您最喜欢的文章的链接,其中概述了业务线应用程序的好处和实施? (选项4)对不起,不明白。为什么我在调用fork 之后还要假装进入main 当前工作目录及其内容由运行程序的人控制。因此,如果您 exec 当前工作目录中具有固定名称的程序 - 无论您如何操作;添加“。”到 $PATH 只是最明显的——你将你的程序拥有的任何额外特权交给其他人控制的程序。 -- 你实际上并不想要当前的工作目录。您将它与包含可执行文件的目录混淆了。看我的回答。 @Dave:关于为什么将当前目录“.”添加到您的$PATH 环境变量是一个安全漏洞的其他说明,请参见此处:fixunix.com/unix/88657-whats-wrong-having-my-path.html

以上是关于Linux fork/exec 到同一目录中的应用程序的主要内容,如果未能解决你的问题,请参考以下文章

Linux下进程的创建(system(); fork(); exec*())

Linux C fork exec介绍用法

Terraform 资源 AWS LAMBDA GO 错误:“fork/exec /var/task/main:没有这样的文件或目录”

fork,exec,vfork和线程池

使用fork+exec安全生成应用程序

perl fork() exec() ,子进程变得狂野