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.
According to the documentation, an exec does not modify the pid of a process.
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.
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 .
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?)
I think you have 2 choices:
getcwd()
to the executable name.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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With