如何获得自己的进程名称

时间:2013-07-18 19:43:38

标签: c linux process pid

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

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

当应用程序启动时,它可以将它自己的名称作为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]);

3 个答案:

答案 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()...请参阅以下网站。

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