1

我有一个可以由多个应用程序加载的插件。

现在我想让插件知道调用应用程序的名称(注册一些服务)。

当应用程序启动时,它可以获得它自己的名称作为第一个参数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]);
4

3 回答 3

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
于 2013-07-18T19:57:19.687 回答
1

Duck 的回答(使用readlink("/proc/self/exe",...))让您确定正在执行的实际二进制文件的(完整路径)。从中读取第一个以 NUL 结尾的字符串/proc/self/cmdline会给您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 atomic 内置插件来确保即使两个线程碰巧同时运行也能正常工作,并且不会泄漏内存等)

最后,还有第三种选择:使用线程名称。

线程名称限制为 15 (16) 个字符,并且可以使用pthread_setname_np(thread, name)or显式设置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 字符缓冲区。(由于名称是特定于线程的,因此缓冲区也是特定于线程的。)

希望您觉得这个有帮助。

于 2013-07-19T00:43:17.530 回答
-2

您可以使用 getprogname()... 请参阅以下网站。

http://www.nxmnpg.com/3/getprogname

于 2013-07-18T19:49:56.083 回答