Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linux fork/exec to application in same directory

Tags:

c++

linux

fork

exec

qt

Is there an exec variant that will use the current application directory to locate the target program?

I am using C++ and Qt to implement a "last ditch" error reporting system. Using Google Breakpad, I can create a minidump and direct execution to a handler. 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. 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; this is my first introduction to using them. I'm only concerned about Linux (Ubuntu, Fedora) at this point; I will work on handlers for other operating systems later.

like image 590
Dave Mateer Avatar asked Feb 08 '11 15:02

Dave Mateer


People also ask

Does PID change after exec?

According to the documentation, an exec does not modify the pid of a process.

How do we use fork and exec together to implement a shell in Unix?

They are use together to create a new child process. First, calling fork creates a copy of the current process (the child process). Then, exec is called from within the child process to "replace" the copy of the parent process with the new process.

Does execl change PID?

Since all of the Unix exec functions replace the running process with the new one, the PID of the exec'd process is the same PID it was before. So you get the PID by using the getpid() call, before calling execl .


3 Answers

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

     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. Note that you should be converting to UTF-8, not Latin1 (I guess QString uses wide characters?)

like image 104
zwol Avatar answered Sep 30 '22 17:09

zwol


I think you have 2 choices:

  1. Add '.' to $PATH.
  2. Prepend the result of getcwd() to the executable name.
like image 43
trojanfoe Avatar answered Sep 30 '22 17:09

trojanfoe


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. 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

like image 37
Ted Mielczarek Avatar answered Sep 30 '22 16:09

Ted Mielczarek