简体   繁体   English

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

[英]Linux fork/exec to application in same directory

Is there an exec variant that will use the current application directory to locate the target program? 是否有一个exec变体将使用当前的应用程序目录来定位目标程序?

I am using C++ and Qt to implement a "last ditch" error reporting system. 我正在使用C ++和Qt来实现“最后沟渠”错误报告系统。 Using Google Breakpad , I can create a minidump and direct execution to a handler. 使用Google Breakpad ,我可以创建一个minidump并将其直接执行到处理程序。 Because my application is in an unstable state, I just want to fork and start a separate error handling process using minimal dependencies. 因为我的应用程序处于不稳定状态,所以我只想使用最小的依赖项来分叉并启动一个单独的错误处理过程。 The error reporting application will be deployed in the same directory as the application executable. 错误报告应用程序将部署在与应用程序可执行文件相同的目录中。

I am quite unfamiliar with the fork and exec options, and am not finding an exec option that includes the current application directory in the search path. 我对forkexec选项很不熟悉,并且没有找到包含搜索路径中当前应用程序目录的exec选项。 Here is what I have so far: 这是我到目前为止:

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;
}

Any other suggestions on best practices for using fork and exec would be appreciated as well; 关于使用forkexec 最佳实践的任何其他建议也将受到赞赏; this is my first introduction to using them. 这是我第一次使用它们。 I'm only concerned about Linux (Ubuntu, Fedora) at this point; 我现在只关心Linux(Ubuntu,Fedora); I will work on handlers for other operating systems later. 我稍后会处理其他操作系统的处理程序。

What you asked for is actually quite easy: 你要求的实际上很容易:

{
  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;
}

but it doesn't do what you want. 但它没有做你想要的。 The current working directory is not necessarily the same thing as the directory containing the current executable -- in fact, under almost all circumstances, it won't be. 当前工作目录不一定与包含当前可执行文件目录相同 - 事实上,在几乎所有情况下,它都不会。

What I would recommend you do is make error_reporter_path a global variable, and initialize it at the very beginning of main , using your "option 2" code 我建议你做的是使error_reporter_path成为一个全局变量,并使用你的“选项2”代码在main的最开始初始化它

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

The QString object (not just its constData ) then has to live for the lifetime of the program, but that shouldn't be a problem. 然后QString对象(不仅仅是它的constData )必须在程序的生命周期中存在,但这应该不是问题。 Note that you should be converting to UTF-8, not Latin1 (I guess QString uses wide characters?) 请注意,您应该转换为UTF-8,而不是Latin1(我猜QString使用宽字符?)

I think you have 2 choices: 我认为你有两个选择:

  1. Add '.' 添加'。' to $PATH. 到$ PATH。
  2. Prepend the result of getcwd() to the executable name. getcwd()的结果前置到可执行文件名。

You should build the path to your helper executable at your program's startup, and save it somewhere (in a global or static variable). 您应该在程序启动时构建辅助程序可执行文件的路径,并将其保存在某个地方(在全局变量或静态变量中)。 If you only need to run on Linux, you can do this by reading /proc/self/exe to get the location of your executable. 如果您只需要在Linux上运行,可以通过读取/ proc / self / exe来获取可执行文件的位置。 Something like this: 像这样的东西:

// 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";

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

  1. Never, ever, under any circumstances add "." 永远不会在任何情况下添加“。” to $PATH !! $ PATH !!

  2. If you prepend getcwd() to the executable name (argv[0]), you have to do is as the first thing in main, before anything has the chance to change the current working directory. 如果你将getcwd()添加到可执行文件名(argv [0])中,那么在必须有机会更改当前工作目录之前,你必须做的是main中的第一件事。 Then you have to consider what to do about symbolic links in the resulting filename. 然后,您必须考虑如何处理生成的文件名中的符号链接。 And even after that you can never be sure that argv[0] is set to the command used to execute your program 即便如此,您仍然无法确定argv [0]是否设置为用于执行程序的命令

Option 3: 选项3:

Hardcode the full filename in your executable, but use the configure script to set the filename. 硬编码可执行文件中的完整文件名,但使用configure脚本设置文件名。 (You are using a configure script, right?) (您正在使用配置脚本,对吧?)

Option 4; 备选案文4;

Don't call exec. 不要叫exec。 You don't have to call exec after a fork. 您不必在fork之后调用exec。 Just pretend you have just entered "main", and call "exit" when your error reporting has finished. 只是假装你刚输入“main”,并在错误报告完成后调用“exit”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM