Linux fork / exec для приложения в том же каталоге - PullRequest
6 голосов
/ 08 февраля 2011

Существует ли вариант exec, который будет использовать текущий каталог приложения для определения местоположения целевой программы?

Я использую C ++ и Qt для реализации системы отчетов об ошибках "последнего рывка".Используя Google Breakpad , я могу создать мини-дамп и напрямую выполнить обработчик.Поскольку мое приложение находится в нестабильном состоянии, я просто хочу раскошелиться и запустить отдельный процесс обработки ошибок с использованием минимальных зависимостей.Приложение для сообщения об ошибках будет развернуто в том же каталоге, что и исполняемый файл приложения.

Я совершенно не знаком с параметрами fork и 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;
}

Любые другие предложения по передовым практикам по использованию fork и exec также приветствуются;это мое первое знакомство с их использованием.На данный момент я обеспокоен только Linux (Ubuntu, Fedora);Позже я буду работать с обработчиками для других операционных систем.

Ответы [ 4 ]

6 голосов
/ 08 февраля 2011

То, что вы просили, на самом деле довольно просто:

{
  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 голосов
/ 08 февраля 2011

Я думаю, у вас есть 2 варианта:

  1. Добавить '.'к $ PATH.
  2. Добавить результат getcwd() к имени исполняемого файла.
1 голос
/ 24 февраля 2011

Вы должны построить путь к исполняемому файлу помощника при запуске программы и сохранить его где-нибудь (в глобальной или статической переменной). Если вам нужно работать только в 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

0 голосов
/ 08 февраля 2011
  1. Никогда, ни при каких обстоятельствах не добавляйте "."$ PATH !!

  2. Если вы добавляете getcwd () к имени исполняемого файла (argv [0]), вы должны сделать это как первое в main, прежде чем что-либо получитшанс изменить текущий рабочий каталог.Затем вы должны рассмотреть, что делать с символическими ссылками в результирующем имени файла.И даже после этого вы никогда не можете быть уверены, что argv [0] установлен на команду, используемую для выполнения вашей программы

Опция 3:

Жесткий код полного имени файла вВаш исполняемый файл, но используйте скрипт configure для установки имени файла.(Вы используете скрипт configure, верно?)

Вариант 4;

Не вызывать exec.Вам не нужно вызывать exec после разветвления.Просто представьте, что вы только что ввели "main", и вызовите "exit", когда ваше сообщение об ошибке закончится.

...