Программно получить абсолютный путь для приложения командной строки OS X
В Linux приложение может легко получить свой абсолютный путь, запросив /proc/self/exe
. На FreeBSD это больше связано с тем, что вам нужно создать вызов sysctl:
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
char buf[1024];
size_t cb = sizeof(buf);
sysctl(mib, 4, buf, &cb, NULL, 0);
но это все еще вполне выполнимо. Однако я не могу найти способ определить это на OS X для приложения с командной строкой. Если вы работаете из пакета приложений, вы можете определить его, запустив [[NSBundle mainBundle] bundlePath]
, но поскольку приложения из командной строки не находятся в связках, это не помогает.
(Примечание: консультация argv[0]
не является разумным ответом, так как при запуске из символической ссылки argv[0]
будет эта символьная ссылка, а не конечный путь к исполняемому вызову. argv[0]
также может лежать, если немое приложение использует вызов exec()
и забывает инициализировать argv правильно, что я видел в дикой природе.)
Ответы
Ответ 1
Функция _NSGetExecutablePath
вернет полный путь к исполняемому файлу (GUI или нет). Путь может содержать символические ссылки "..
" и т.д., Но функция realpath
может быть используемые для их очистки, если это необходимо. Подробнее см. man
3
dyld
.
char path[1024];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0)
printf("executable path is %s\n", path);
else
printf("buffer too small; need size %u\n", size);
Секрет этой функции заключается в том, что ядро Дарвина запускает исполняемый путь в стек процесса сразу после массива envp
, когда он создает этот процесс. Редактор динамической компоновки dyld
захватывает это при инициализации и сохраняет указатель на него. Эта функция использует этот указатель.
Ответ 2
Я считаю, что есть намного более элегантное решение, которое действительно работает для любого PID, а также возвращает абсолютный путь напрямую:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libproc.h>
int main (int argc, char* argv[])
{
int ret;
pid_t pid;
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
pid = getpid();
ret = proc_pidpath (pid, pathbuf, sizeof(pathbuf));
if ( ret <= 0 ) {
fprintf(stderr, "PID %d: proc_pidpath ();\n", pid);
fprintf(stderr, " %s\n", strerror(errno));
} else {
printf("proc %d: %s\n", pid, pathbuf);
}
return 0;
}
Ответ 3
Похоже, ответ заключается в том, что вы не можете этого сделать:
Я пытаюсь добиться чего-то вроде lsof и собрать целая куча статистики и информации о запущенных процессах. Если lsof были не такими медленными, я был бы счастлив придерживаться с ним.
Если вы переопределяете lsof, вы найдете что он медленный, потому что он делает много работы.
Я предполагаю, что на самом деле не потому, что lsof это пользовательский режим, это больше, что он должен сканировать через адресное пространство задачи ищет вещи, поддерживаемые внешний пейджер. Быстрее ли способ сделать это, когда я нахожусь в ядро?
Нет. lsof не является глупым; он делает что он должен делать. Если вы просто хотите подмножество его функциональности, вы можете хочу рассмотреть возможность начать с lsof source (который доступен) и обрезая его, чтобы встретить требования.
Из любопытства, p_textvp
используется в все? Похоже, он настроен на parent p_textvp
в kern_fork
(и затем освобождение?), но это не попадание в любой из kern_exec
подпрограммы.
p_textvp
не используется. В Дарвине proc не является корнем адреса пространство; задача есть. Здесь нет концепция "vnode" для задачи адресное пространство, поскольку оно не обязательно изначально населенных отображение одного.
Если exec должен был заполнить p_textvp, это будет потворствовать предположению, что все процессы поддерживаются vnode. Тогда программисты предположили бы, что это было возможно получить путь к vnode, и оттуда это короткий переходим к предположению, что текущий путь к vnode - это путь из которого он был запущен, и что обработка текста на строке может привести к названию прикладного пакета... все из которых было бы невозможно гарантия без существенного штрафа.
— Майк Смит, Darwin Drivers список рассылки
Ответ 4
Невозможно гарантировать, что я думаю.
Если argv [0] является символической ссылкой, вы можете использовать readlink().
Если команда выполняется через $PATH, тогда можно
попробуйте некоторые из: search (getenv ( "PATH" )), getenv ( "_" ), dladdr()
Ответ 5
Поздно, но [[NSBundle mainBundle] executablePath]
отлично работает для несвязанных программ командной строки.
Ответ 6
Почему бы не просто realpath(argv[0], actualpath);
? Правда, realpath имеет некоторые ограничения (задокументированные на странице руководства), но отлично справляется с символическими ссылками. Протестировано на FreeBSD и Linux
% ls -l foobar
lrwxr-xr-x 1 bortzmeyer bortzmeyer 22 Apr 29 07:39 foobar -> /tmp/get-real-name-exe
% ./foobar
My real path: /tmp/get-real-name-exe
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <libgen.h>
#include <string.h>
#include <sys/stat.h>
int
main(argc, argv)
int argc;
char **argv;
{
char actualpath[PATH_MAX + 1];
if (argc > 1) {
fprintf(stderr, "Usage: %s\n", argv[0]);
exit(1);
}
realpath(argv[0], actualpath);
fprintf(stdout, "My real path: %s\n", actualpath);
exit(0);
}
Если программа запускается через PATH, см. решение pixelbeat.
Ответ 7
http://developer.apple.com/documentation/Carbon/Reference/Process_Manager/Reference/reference.html#//apple_ref/c/func/GetProcessBundleLocation
GetProcessBundleLocation, похоже, работает.