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

时间:2011-02-08 15:29:01

标签: c++ linux qt exec fork

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

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

我对forkexec选项非常不熟悉,并且找不到包含搜索路径中当前应用程序目录的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);我稍后会处理其他操作系统的处理程序。

4 个答案:

答案 0 :(得分:6)

你要求的实际上很容易:

{
  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成为一个全局变量,并使用“选项2”代码在main的最开始初始化它

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

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

答案 1 :(得分:2)

我认为你有两个选择:

  1. 添加'。'到$ PATH。
  2. getcwd()的结果添加到可执行文件名。

答案 2 :(得分:1)

您应该在程序启动时构建辅助程序可执行文件的路径,并将其保存在某个地方(在全局变量或静态变量中)。如果您只需要在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

答案 3 :(得分:0)

  1. 永远不会在任何情况下添加“。”到$ PATH !!

  2. 如果你将getcwd()添加到可执行文件名(argv [0]),你需要做的是在main中的第一件事,在任何事情有机会改变当前的工作目录之前。然后,您必须考虑如何处理生成的文件名中的符号链接。即便如此,您仍然无法确定argv [0]是否设置为用于执行程序的命令

  3. 选项3:

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

    选项4;

    不要叫exec。您不必在fork之后调用exec。只是假装你刚输入“main”,并在错误报告完成后调用“exit”。