2009-06-01 2 views
131

Есть ли способ в C/C++ найти местоположение (полный путь) текущей исполняемой программы?Как найти местоположение исполняемого файла в C?

(Проблема argv[0] в том, что он не дает полный путь.)

+11

какая операционная система? – 2009-06-01 07:38:12

+6

Хороший ответ здесь также: http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe/1024937#1024937 – ergosys

+0

Этот вопрос («Как найти местоположение моего программа в SETTING X? ") может * действительно * использовать тег; трудно найти ключевые слова! – SamB

ответ

178

Резюмируя:

  • На Unixes с /proc действительно прямо и добросовестным способом заключается в следующем:

    • readlink("/proc/self/exe", buf, bufsize) (Linux)

    • readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)

    • readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)

  • На Unixes без /proc (т.е. если выше не выполнено):

    • Если argv [0] начинается с «/» (абсолютный путь), это путь.

    • В противном случае, если argv [0] содержит «/» (относительный путь), добавьте его в cwd (при условии, что он еще не изменен).

    • В противном случае поиск каталогов в $PATH для исполняемого файла argv[0].

    Впоследствии может быть разумным проверить, не является ли исполняемый файл фактически символической ссылкой. Если это решение относительно каталога symlink.

    Этот шаг не требуется в методе/proc (по крайней мере, для Linux). Там процилинговая ссылка proc указывает на исполняемый файл.

    Обратите внимание, что до вызова процесса необходимо правильно установить argv[0]. Правильно в большинстве случаев, однако есть случаи, когда вызывающему процессу нельзя доверять (например, исполняемый файл setuid).

  • В Windows: используйте GetModuleFileName(NULL, buf, bufsize)

+0

+1 хороший острый ответ – 2009-06-01 10:06:06

+20

Все, что зависит от argv [0], являющееся именем программы, не является надежным. Он будет работать большую часть времени, но не * каждый раз. Эта проблема сложна для unixes без/proc – dmckee

+7

Не все unixes с proc имеют/proc/self/exe. Макет/proc полностью зависит от ОС, и все они делают это по-другому. Например, FreeBSD предоставляет/proc/curproc/файл, который работает так же, как Linux/proc/self/exe. Но другие могут вообще не делать этого. – MarkR

6

Во многих системах POSIX вы можете проверить SimLink, расположенный в/Proc/PID/ехе. Несколько примеров:

# file /proc/*/exe 
/proc/1001/exe: symbolic link to /usr/bin/distccd 
/proc/1023/exe: symbolic link to /usr/sbin/sendmail.sendmail 
/proc/1043/exe: symbolic link to /usr/sbin/crond 
+11

/proc не является POSIX, и он не очень стандартизирован. У многих современных Unices есть это, некоторые нет. –

+0

Всегда хорошо учиться чему-то новому. Благодарю. Есть ли более «программный» способ сделать это? – eran

+0

@ Dietrich: Вы правы, это не posix. Согласно Unix-подобным системам Wikipedia, это: Linux, AIX, BSD, Solaris, QNX. Тем не менее, не указано, имеют ли все эти системы/proc/*/cmd simlink. – 2009-06-01 08:00:33

17

Используйте функцию GetModuleFileName(), если вы используете Windows.

+2

Спасибо, но я использую linux и unix. – eran

15

Обратите внимание, что следующие комментарии являются unix-only.

Педантичный ответ на этот вопрос состоит в том, что нет способ правильно ответить на этот вопрос во всех случаях. Как вы обнаружили, argv [0] может быть вообще настроен на родительский процесс и поэтому не должен иметь никакого отношения к фактическому имени программы или ее местоположению в файловой системе.

Однако следующий эвристический часто работает:

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

Обратите внимание, что все они могут быть обойденный процессом, который вызвал эту программу. Наконец, вы можете использовать специфичные для Linux методы, например, упомянутые emg-2. В других операционных системах, вероятно, есть эквивалентные методы.

Даже если предположить, что приведенные выше шаги дают вам правильное имя пути, вы все равно можете не иметь имя пути, которое вы действительно хотите (так как я подозреваю, что то, что вы на самом деле хотите сделать, это найти файл конфигурации где-нибудь). Наличие жестких ссылок означает, что вы можете иметь следующую ситуацию:

-- assume /app/bin/foo is the actual program 
$ mkdir /some/where/else 
$ ln /app/bin/foo /some/where/else/foo  # create a hard link to foo 
$ /some/where/else/foo 

Теперь, подход выше (в том числе, как я подозреваю,/Proc/$ PID/ех) даст /some/where/else/foo как реальный путь к программе , И, фактически, это a реальный путь к программе, просто не тот, который вы хотели. Обратите внимание, что эта проблема не возникает с символическими ссылками, которые на практике гораздо более распространены, чем жесткие ссылки.

Несмотря на то, что этот подход в принципе ненадежный, он работает достаточно хорошо на практике для большинства целей.

3

Помните, что в системах Unix двоичная могут быть удалены, так как он был запущен. Это совершенно законно и безопасно для Unix. Последнее, что я проверил, Windows не позволит вам удалить исполняемый двоичный файл.

/proc/self/exe будет по-прежнему доступен для чтения, но это не будет работать с символической ссылкой. Это будет ... странно.

+0

сделать Unix загружать всю исполняемую программу в память перед запуском? В этом случае, как у него достаточно памяти для запуска очень больших программ, таких как некоторые самораспаковывающиеся архивы –

+1

Обычно нет. Исполняемый файл заблокирован (попытка открыть для записи дает «текстовый файл занят») и «память отображена», что означает, что * выглядит так, как будто это все в памяти, но при первом доступе к странице памяти она будет загружена лениво. Если это страница только для чтения (как правило, код), ядро ​​может «забыть» данные, если им нужна память, и повторно загружать их, когда к ним снова обращаются. Похоже на замену, но поскольку код не изменен, он никогда не будет записан на диск. – Thomas

+0

Я предполагаю, что в этом случае, если страница с незагруженной памятью будет загружена в память после удаления файла, произойдет серьезное событие –

9

На самом деле это не ответ, а просто примечание, которое нужно иметь в виду.

Как мы могли видеть, проблема поиска местоположения исполняемого исполняемого файла довольно сложна и специфична для платформы в Linux и Unix. Перед этим нужно подумать дважды.

Если вам нужен исполняемый месторасположению некоторые конфигурации или ресурсные файлы, возможно, вы должны следовать по пути Unix размещения файлов в системе: положить конфиги в /etc или /usr/local/etc или в текущей домашней директории пользователя, и /usr/share является хорошим место для размещения ваших файлов ресурсов.

0

Я

1) Используйте функцию базовое(): http://linux.die.net/man/3/basename
2) Chdir() в этот каталог
3) Используйте getpwd(), чтобы получить текущий каталог

Таким образом, вы 'получите каталог в аккуратной, полной форме, а не ./ или ../bin/.

Возможно, вам захочется сохранить и восстановить текущий каталог, если это важно для вашей программы.

3

Для Linux вы можете найти /proc/self/exe способ делать вещи укутаны в хорошей библиотеке под названием binreloc, вы можете найти библиотеку по адресу:

+0

+1 для библиотеки BinReloc. –

+1

ссылка мертва. :( –