Linux C程序修改进程名称

Linux C程序修改进程名称
1、前言
2、命令行参数(argc, argv)以及环境变量(environ)介绍
2.1、C程序典型的存储空间布局
2.2、argc, argv介绍
2.3、environ介绍
2.4、编写程序验证修改进程名是否可以成功
2.5、查看进程名变长之后影响了那部分内存的数据
2.6、结论
3、Redis修改进程名的做法
4、总结
1、前言
Linux C程序运行时,进程的名称通常就是argv[0],而通过修改内存中argv[0]存储的内容就可以修改进程名了。下面对此作详细介绍。

2、命令行参数(argc, argv)以及环境变量(environ)介绍
2.1、C程序典型的存储空间布局
如图所示,是C程序典型的存储空间布局,可以很明显看到命令行参数和环境变量处在最顶端,而且是挨在一起的,命令行参数后面紧接着就是环境变量,具体的内容大家可以自行看一下《UNIX环境高级编程》第七章,下图也是从里面摘录出来的

在这里插入图片描述
2.2、argc, argv介绍
每个C语言程序都必须有一个称为main的函数,一般形式为int main(int argc, char* argc[]),改函数作为程序启动的起点。执行程序时,命令行参数通过argc和argv这两个两个入参传递给main函数。第一个表示命令行参数的个数,而第二个参数则是一个指向命令行参数的指针数组,每一参数都是C类型字符串,以空字符\0结尾的,而最后一个参数argc[argv]则是一个空指针NULL。其中第一个字符串(argv[0]),则是该程序的名称,也就是运行时的进程名。 

内存示例如图所示

在这里插入图片描述
2.3、environ介绍
每一个进程都有与其相关的称为环境列表(environment list)的字符串数组。其中每个字符串都以名称=值(name=value)形式定义。新进程在创建时,会继承其父进程的环境副本,子进程创建后,父、子进程均可更改各自的环境变量,且这些变更对对方而言不再可见。
在C程序中,可以使用全局变量extern char** environ获取环境变量表(C运行时启动代码定义了该变量并以当前环境列表位置为其赋值)environ与argv参数比较相似,是一个指针数组,数组每个成员指向C类型字符串,最后一个指针也是一个NULL。 

内存示例如图所示

在这里插入图片描述
2.4、编写程序验证修改进程名是否可以成功
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

 

int main(int argc, char* argv[])
{
    sleep(8);
    strcpy(argv[0], "112233445566");
    while (1);                                                                                                           
 
    return 0;
}

代码如上,可以看到,程序先休眠8秒钟,然后修改argv[0]的值,编译运行一下,运行结果如下,可以看到,一开始进程名是./all,8秒后就变成了112233445566,修改成功,而且我们也能看出一点细节,那就是修改后的进程名超过了原先的进程名也没有报错,有可能的原因是argc[0]后面的内存也是可用的(其实从内存布局就可以看出来可用了)

在这里插入图片描述
2.5、查看进程名变长之后影响了那部分内存的数据
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

 extern char** environ;

int main(int argc, char* argv[])
{
    printf("begin environ:\n");
    for (int i = 0; environ[i] != NULL && i < 5; i++)
        printf("%s\n", environ[i]);

    sleep(5);
    strcpy(argv[0], "112233445566");
    printf("\n\n");

    printf("end environ:\n");
    for (int i = 0; environ[i] != NULL && i < 5; i++)
        printf("%s\n", environ[i]);

    return 0;
}

代码如上,为了方便显示,环境变量只打印前五个,看看效果就行。运行结果如下图所示,可以看到,一开始打印的第一个环境变量为XDG_SESSION_ID=3585,当修改完进程名之后,该变量变为445566,原先进程名为./all,加上结束符是6个字节,剩余四个字节的内容也就是445566刚好把第一个环境变量的内存给覆盖了(这里没有传入参数,所以覆盖的是环境变量的内存)。

在这里插入图片描述
2.6、结论
Linux C程序中传入参数和环境变量是存放在一段连续的内存空间的,而argv和environ这两个指针数组里面存放的指针就是指向这些内存的

 

3、Redis修改进程名的做法
Redis作为一个优秀的企业级存储框架,里面有许多值得学习的地方,而里面也有一段代码修改进程名的,接下来看看Redis是如何实现的

extern char **environ;

static struct {
    /* original value */
    const char *arg0;

    /* title space available */
    char *base, *end;

     /* pointer to original nul character within base */
    char *nul;

    _Bool reset;
    int error;
} SPT;

void spt_init(int argc, char *argv[]) {
    char **envp = environ;
    char *base, *end, *nul, *tmp;
    int i, error, envc;

    if (!(base = argv[0]))
        return;

    nul = &base[strlen(base)];
    end = nul + 1;

    for (i = 0; i < argc || (i >= argc && argv[i]); i++) {
        if (!argv[i] || argv[i] < end)
            continue;

        if (end >= argv[i] && end <= argv[i] + strlen(argv[i]))
            end = argv[i] + strlen(argv[i]) + 1;
    }

    for (i = 0; envp[i]; i++) {
        if (envp[i] < end)
            continue;

        if (end >= envp[i] && end <= envp[i] + strlen(envp[i]))
            end = envp[i] + strlen(envp[i]) + 1;
    }
    envc = i;

    if (!(SPT.arg0 = strdup(argv[0])))
        goto syerr;

    if (!(tmp = strdup(program_invocation_name)))
        goto syerr;

    program_invocation_name = tmp;

    if (!(tmp = strdup(program_invocation_short_name)))
        goto syerr;

    program_invocation_short_name = tmp;

    /* Now make a full deep copy of the environment and argv[] */
    if ((error = spt_copyenv(envc, envp)))
        goto error;

    if ((error = spt_copyargs(argc, argv)))
        goto error;

    SPT.nul  = nul;
    SPT.base = base;
    SPT.end  = end;

    return;
syerr:
    error = errno;
error:
    SPT.error = error;
}


从代码中可以看出以下几点:

base指向的是argv[0],nul指向argv[1],而end经过两个for循环遍历之后指向的是传入参数+环境变量内存空间的最末尾
使用strdup函数将原本的进程名复制给SPT.arg0
spt_copyenv和spt_copyargs函数的作用是将原先的传入参数(从argv[1]开始)和环境变量复制到一个新的内存区域,然后原先的指针数组里元素指向新的内存地址,完成了数据的迁移
经过上面的步骤之后,argv[0]还是指向原来的地址,而其他的传入参数以及环境变量均指向新的内存空间了,现在就可以任意修改进程名而不影响其他数据了
4、总结
本文介绍了如何修改Linux C程序的进程名,以及Redis源代码中是如何在保持原有传入参数以及环境变量的情况下,对程序的进程名进行修改。测试代码比较简单,大家可以自行编写程序去进行测试验证
————————————————
版权声明:本文为CSDN博主「彼  方」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43798887/article/details/116722941

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: jar 启动是指使用 Java 命令行工具来执行一个打包好的 Java 应用程序,而在执行过程中,进程名称可能会显示为 Java 应用程序的默认名称,如 java.exe 或 javaw.exe,而如果想要修改进程名称,可以采用以下方法: 1. 使用 Java 的 ProcessBuilder 类来创建一个新的进程并指定进程名称。 2. 使用 Java 的 Runtime 类的 exec 方法来执行操作系统命令,如 Windows 下的 taskkill 命令、Linux 下的 kill 命令来关闭指定进程,并使用命令行参数来指定修改后的进程名称。 3. 使用 Java 的 JNI(Java Native Interface)机制来调用本地 C/C++ 代码,并通过操作系统的系统调用来修改进程名称。 需要注意的是,修改进程名称的方法因操作系统而异,例如在 Windows 中,可以使用 Process Explorer 工具来修改进程名称,而在 Linux 中,则可以通过修改 /proc/PID/cmdline 文件来修改进程名称。而在 Java 中,则需要借助以上所述的方法来实现。 ### 回答2: 在Java应用程序中,JAR文件是常用的归档文件格式,它可以将类、资源和元数据打包成一个文件。当运行JAR文件时,Java虚拟机会创建一个进程来运行该应用程序。 如果需要修改JAR进程名,可以通过在启动命令中使用Java启动参数来实现。具体方法如下: 1.在命令中添加启动参数“-Dorg.eclipse.swt.internal.gtk.cairoGraphics=false”,该参数可以在Linux系统中启用AWT/Swing窗口,同时在Windows系统中不会影响应用程序的正常运行。 2.使用“-Djava.awt.headless=true”参数禁用图形用户界面,防止程序在无控制台环境中启动时崩溃。 3.使用“-Dfile.encoding=UTF-8”参数将JVM编码设置为UTF-8,以避免在Windows系统中使用中文路径和非ASCII字符时出现问题。 4.使用“-Dsun.java.command=新的进程名”参数设置进程名称,这个名称将显示在进程列表中。 总之,通过修改JVM启动参数来修改JAR进程名是完全可行的,只需要在启动命令中正确设置相关参数即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值