我有一个可以由多个应用程序加载的插件。
现在我希望插件知道调用应用程序的名称(注册一些服务)。
当应用程序启动时,它可以将它自己的名称作为main()
的第一个参数,但是我没有机会将它转发给插件(我既不是调用应用程序的作者也不是插件API)
很容易获得当前进程的PID(使用getpid()
),但是如何从那里继续获取应用程序名称?
我知道我可以阅读/proc/${PID}/cmdline
,但我真的不喜欢这个,因为它需要我打开文件并解析一个已经解析过的字符串。
所以我真的在寻找类似的东西:
pid_t pid=getpid();
int argc=get_argcfrompid(pid);
char**argv=get_argvfrompid(pid);
if(argc)
printf("my name is '%s'\n", argv[0]);
答案 0 :(得分:1)
对不起。 readlink / proc / self / exe是你最好的选择。
size_t buflen = 1024;
char buff[buflen];
ssize_t len = readlink("/proc/self/exe", buff, buflen);
if (len != -1)
buff[len] = '\0';
else
//oops, error
答案 1 :(得分:1)
Duck的答案(使用readlink("/proc/self/exe",...)
)可以确定正在执行的实际二进制文件的(完整路径)。从/proc/self/cmdline
读取第一个以NUL结尾的字符串会为您提供argv[0]
。
例如,如果程序是通过符号链接执行的,那么Duck的答案将产生实际二进制文件的路径,而/proc/self/cmdline
将产生用于执行二进制文件的原始命令(符号链接或路径)。
从/proc/self/cmdline
读取第一个字符串并不是那么复杂:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
static char *argv0_str = NULL;
const char *argv0(void)
{
int fd, result;
size_t len, max;
char *str, *tmp;
ssize_t n;
/* Already known? */
str = __sync_fetch_and_or(&argv0_str, (char *)0);
if (str)
return (const char *)str;
/* Open /proc/self/cmdline. */
do {
fd = open("/proc/self/cmdline", O_RDONLY);
} while (fd == -1 && errno == EINTR);
if (fd == -1)
return NULL;
str = NULL;
len = max = 0;
while (1) {
/* Make sure there is room in the buffer. */
if (len >= max) {
max = (len | 1023) + 1025;
tmp = realloc(str, max);
if (!tmp) {
free(str);
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
errno = ENOMEM;
return NULL;
}
str = tmp;
}
n = read(fd, str + len, max - len);
if (n > (ssize_t)0)
len += n; /* Read n more chars. */
else
if (n == (ssize_t)0)
break; /* All read. */
else
if (n != (ssize_t)-1 || errno != EINTR) {
/* Error. */
const int err = (n == (ssize_t)-1) ? errno : EIO;
free(str);
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
errno = err;
return NULL;
}
}
/* Close. */
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1) {
const int err = errno;
free(str);
errno = err;
return NULL;
}
/* Nothing? */
if (len < 1) {
free(str);
errno = ENOENT;
return NULL;
}
/* Let's be paranoid: the kernel says the last char
* must be '\0'. Let's make sure. */
str[len-1] = '\0';
/* Then, we only pick the first string. */
len = strlen(str);
/* Optimize. */
max = len + 1;
tmp = realloc(str, max);
if (!tmp) {
free(str);
errno = ENOMEM;
return NULL;
}
/* Replace current argv0_str. */
if (__sync_bool_compare_and_swap(&argv0_str, (char *)0, str))
return (const char *)str;
/* Oops. Another thread already did this work. */
free(str);
/* Return what the other thread did. */
return (const char *)__sync_fetch_and_or(&argv0_str, (char *)0);
}
调用argv0()
(即使从多个线程并发)也会为您提供argv[0]
的静态副本。 (我使用旧式的GCC原子内置函数来确保即使两个线程碰巧并发运行,也不会泄漏内存等。)
最后,还有第三种选择:使用线程名称。
线程名称限制为15(16)个字符,可以使用pthread_setname_np(thread, name)
或prctl(PR_SET_NAME, name, 0L, 0L, 0L)
(需要内核2.6.11或更高版本)显式设置,但默认为basename(argv[0])
。它可以通过pthread_getname_np()
或prctl(PR_GET_NAME,)
获得:
#include <sys/prctl.h>
static __thread char thread_name_buffer[17] = { 0 };
const char *thread_name(void)
{
/* Try obtaining the thread name.
* If this fails, we'll return a pointer to an empty string. */
if (!thread_name_buffer[0])
prctl(PR_GET_NAME, thread_name_buffer, 0L, 0L, 0L);
return (const char *)thread_name_buffer;
}
由于文档不同意(在pthread_getname_np()
和prctl()
之间)是否跟随NUL字节是否包含在16个字符的限制中,我认为最好使用17-char缓冲区初始化为全零。 (由于名称是特定于线程的,因此缓冲区也是特定于线程的。)
希望你觉得这很有用。
答案 2 :(得分:-2)
您可以使用getprogname()...请参阅以下网站。