【问题标题】:Change process name in Linux在 Linux 中更改进程名称
【发布时间】:2011-08-30 05:52:52
【问题描述】:

我在 Linux 上,我正在从我的 C spawn 应用程序中分叉/执行一个新进程。是否也可以更改这些新子进程的命名?

我希望能够识别正在启动的进程,以防出现问题并且我需要手动终止它。目前它们都具有相同的名称。

【问题讨论】:

  • 进程没有名字
  • 谢谢尼尔。当我查看系统监视器时,它确实向我显示了我所指的名称。那我会用什么方法呢?
  • 我怀疑这是创建进程的可执行文件的文件名 - 您无法更改。
  • 你可以,我只是不知道这是否是个好主意。 :)
  • @nbt: 如果进程没有名称,那么调用prctl(PR_SET_NAME, ..) 或更改argv[0] 会发生什么变化? (看ps axo comm,args)一些环境提供setproctitle(3) function。它的multi-platform implementation is possible

标签: c linux process


【解决方案1】:

根据this commentprctl(PR_SET_NAME) 只影响线程的“短名称”。和写/proc/self/comm的效果一样。

要更改“长名称”(/proc/self/cmdlinehtopps u 实际使用),您需要一些丑陋的 hack(该评论中提到但链接已失效)。可以在 Chromium 源代码中找到这种 hack 的示例:https://source.chromium.org/chromium/chromium/src/+/master:content/common/set_process_title_linux.cc

【解决方案2】:

这是一个非便携式黑客:

/*
 * Sets process title, truncating if there is not enough space, 
 * rather than causing memory corruption.
 */
void set_title_np(int argc, char **argv, const char *title) {
    // calculate available size
    size_t space = 0;
    for (int i = 0; i < argc; i++) {
        size_t length = strlen(argv[i]);
        space += length + 1; // because of terminating zero 
    }
    memset(argv[0], '\0', space); // wipe existing args
    strncpy(argv[0], title, space - 1); // -1: leave null termination, if title bigger than space
} 

【讨论】:

    【解决方案3】:

    其中一个 cmets 提到了 prctl,但这确实值得自己回答,因为设置 argv[0] 并非在所有情况下都有效(它在我的系统上没有任何作用)。

    在 Linux 中至少有两个库调用来设置线程的名称,都限制在 15 个字符加上终止 NUL 字节:

    1. glibc 特定:pthread_setname_np(...) 其中np 代表“非便携式”,但这可能存在于其他一些操作系统上:https://linux.die.net/man/3/pthread_setname_np
    2. Linux 特定:prctl(PR_SET_NAME...) 也是不可移植的:https://linux.die.net/man/2/prctl

    示例

    这是对不同方法的测试(没有错误处理):

    // gcc pstest.c -o pstest -O2 -Wall -Wextra -Werror -Wno-unused -Wno-unused-result -std=gnu99 -pthread -D_GNU_SOURCE 
    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <sys/prctl.h>
    
    int main(int argc, char *argv[])
    {
        puts("Initial ps output:");
        system("ps | grep pstest");
    
        puts("\npthread_setname_np");
        pthread_setname_np(pthread_self(), "setname");
        system("ps | grep setname");
    
        puts("\nprctl");
        prctl(PR_SET_NAME, (unsigned long)"prctl", 0, 0, 0);
        system("ps | grep prctl");
    
        puts("\nargv[0]");
        argv[0] = "argv0";
        system("ps | grep argv0");
    
        return 0;
    }
    

    注意argv[0]之后没有输出:

    ./pstest
    Initial ps output:
    17169 pts/0    00:00:00 pstest
    
    pthread_setname_np
    17169 pts/0    00:00:00 setname
    
    prctl
    17169 pts/0    00:00:00 prctl
    
    argv[0]
    

    在野外

    Here's an example in production code(和往常一样,在查看 GitHub 上的代码时一定要注意许可证)

    另见

    另请参阅这些问题和答案:

    【讨论】:

    • argv[0] 部分是错误的:您必须直接覆盖内存,而不仅仅是更改指针:strcpy(argv[0], "argv[0]");。这就是为什么 Chromium 版本有这个丑陋的 hack,它将 argv 中不同参数的所有空间相加,以允许比程序最初调用的名称更长的名称。它利用了在 Linux 中所有 argv 都在连续内存中的事实(即 argv[1] == argv[0] + strlen(argv[0]) + 1)
    【解决方案4】:

    以下代码示例会将进程的名称更改为“测试”。

        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
    
        int main (int argc, char *argv[]) {
        char* temp = (char*) malloc (20);
        strcpy(temp, "Testing");
        temp[7] = 0;
        printf("Argv[0] --> %s\n", argv[0]);
        argv[0] = temp;
        printf("Argv[0] --> %s\n", argv[0]);    
        return 0;
        }
    

    上述程序的输出是:

    ./a.out

    Argv[0] --> ./a.out

    Argv[0] --> 测试

    argv[0] 包含进程的名称。

    【讨论】:

    • 不幸的是,这不会改变ps中的输出。
    • 您无法更改argv[0] 指向的位置。您必须更改argv[0] 指向的内存。显然这是有问题的,因为它可能不够大,因此需要其他更复杂的解决方案。
    【解决方案5】:

    我认为这应该可行,以说明原理...

    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      argv[0][0] = 65;
      sleep(10);
    }
    

    将更改名称,并用“A”代替第一个字母。 CtrlZ 暂停,然后运行ps 以查看名称已更改。我不知道,但这似乎有些危险,因为有些事情可能取决于argv[0]

    另外,我尝试将指针本身替换为另一个字符串;没有雪茄。所以这只适用于strcpy 和比原始名称更短或相等的字符串。

    可能有也可能没有更好的方法。我不知道。

    编辑:非文字解决方案:如果您要分叉,您知道孩子的 PID(孩子的getpid(),父母的fork() 的结果)。只需将其输出到您可以阅读的地方,然后通过 PID 杀死孩子。

    另一个非文字解决方案:使用另一个名称 (ln -s a.out kill_this_a.out) 对可执行文件进行软链接,然后在执行时执行链接。该名称将是链接的名称。

    【讨论】:

    • 感谢 Amadan,+1 这是一个非常聪明的主意。你以前试过吗。我的意思是,它可能会导致任何问题吗?
    • @Frank:这是支持的,如果你观察你的系统,你会发现一些程序可以做到这一点。您受到现有参数大小的限制:您可以只覆盖单个字符,而不是调整缓冲区大小或使用不同的。
    • 重用环境变量以获得额外空间有一些丑陋的技巧,例如here。对于最近的内核,您也可以使用 prctl(PR_SET_NAME, (unsigned long) "My Process", 0, 0, 0); - 但并非所有实用程序都使用该名称作为默认显示名称(top 使用,ps 没有)并且它有 16 个字符的限制。
    • @Frank:添加了一些其他选项 - 不完全回答您的问题,但可能回答了您的问题。
    • 包含应该是unistd.h,而不是stdio.h
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-06
    • 1970-01-01
    • 1970-01-01
    • 2021-08-27
    • 2014-07-21
    相关资源
    最近更新 更多