使用linux c 语言修改进程名字

       很多时候我们都需要更改进程的名字来达到方便管理程序。在linux下,用shell启动进程,进程的名字会以可执行文件的名字来命名。如果一个程序内有多个进程,这样每个进程的名字都是一样的,如果想kill掉某条特定的进程是无法做到的,这样会给程序管理带来不便。所以根据进程负责的不同功能需要给进程进行重新命名,这样不只方便程序的管理,在开发的时候也更方便调试,可以知道那条进程出问题,那个模块出问题了。下面来介绍一下如何在linux下使用c语言更改进程的名字。

        一、linux 进程的命令行参数

               在c语言中,main有多种形式如:int main()、void main()、int main(int argc, char *argv[])、int main(int argc, char *argv[], char *env[])。有过c语言开发的朋友都应该很熟悉前面几个main函数了,但最后一个main函数有些朋友是没有见过的。argc是指进程的参数个数,argv是参数的地址数组,env是进程环境变量的地址数组。简单地,如下图:

                

              其实从图中可以看到,进程的参数跟环境变量在同一个连续的内存地址上。进程的第一个参数是进程的名字,各个参数和环境变量以'\0'结束。按理来说,修改进程的名字只需要更改argv[0]的值即可。但当新的进程名字比原来的进程的名字要长的时候就会覆盖进程后面参数的值,所以当新的名字比原来的要长的时候需要别的处理方法。

        二、修改进程名字

                在网上查了很多关于修改进程名字的资料,都不怎么样而且有些还很傻逼。有的说要将进程的参数跟环境变量复制到新的连续的内存区域去,但真的有这个必要么?来分析一下。argv 是进程的参数,进程的参数主要是用户用来告诉进程要进程什么操作,如 -h 一般是显示帮助文档。这样对于进程来说,参数保存在哪里并不重要,只要参数的地址是连续的且以'\0'结束,对于linux c 语言解析进程参数的函数来说只认的是格式,不是参数地址。那环境变量呢?是不是一定要跟在参数后面?env的作用是告诉进程其有什么环境变量值。环境变量的格式一般都是key-value的形式,linux c 语言解析环境的函数会以key来找对应的value。在进程fork出子进程的时候,子进程会继承父进程的环境变量。所以对于环境变量来说,最主要是满足这些要求。在nginx的源代码里,进程的环境变量是被复制到新的地址上的且跟argv是不连续的。

                那怎么样修改进程的名字呢?其实很简单,因为进程的环境变量所占的空间是很大的,所以只要把环境变量复制到新的地址上,原来的保存进程参数和环境变量的连续空间用来保存新的进程名字和参数就可以了。

        三、代码实现

  1 extern char **environ;
  2 
  3 static char *smp_sys_argv_last = NULL;
  4 static char *smp_sys_env_last = NULL;
  5 
  6 
  7 /**
  8  *  将src copy n 个字节到dst中直到遇到src中的'\0', 如果n为0,返回dst。
  9  *  返回在dst中偏移到的地址
 10  **/
 11 
 12 u_char *smp_strcpyn(u_char *dst, const u_char *src, size_t n)
 13 {
 14     if (smp_unlikely(n == 0)) return dst;
 15 
 16     while (n--) {
 17         *dst = *src;
 18 
 19         if (*dst == '\0') return dst;
 20 
 21         dst++;
 22         src++;
 23     }
 24 
 25     *dst = '\0';
 26 
 27     return dst;
 28 }
 29 
 30 static SMP_VALUE smp_cpy_environs()
 31 {
 32     u_char *new_addr = NULL;
 33     size_t size = smp_sys_env_last - environ[0];
 34 
 35     if ((new_addr = smp_calloc(size)) == NULL) return SMP_FAILURE;
 36     else {    /* 复制环境变量到新的地址上 */
 37         u_char *current = new_addr;
 38         u_char *p = current;
 39         int i = 0;
 40 
 41         /* 复制进程的环境变量 */
 42         for (i = 0; environ[i]; i++) {
 43             current = smp_strcpyn(current, (u_char *) environ[i], strlen(environ[i]));
 44             environ[i] = (char *) p;
 45             current++;
 46             p = current;
 47         }
 48     }
 49 
 50     return SMP_OK;
 51 }
 52 
 53 static SMP_VALUE smp_init_set_proc_title(int argc, char **argv)
 54 {
 55     int i = 0;
 56 
 57     smp_sys_argv_last = argv[0];
 58 
 59     /* 解决argv[i]被修改后指向的非进程启动时的连续内存, 来自nginx */
 60     for (i = 0; i < argc; i++) {
 61         if (smp_sys_argv_last == argv[i]) {
 62             smp_sys_argv_last = argv[i] + strlen(argv[i]) + 1;    /* 加上1是为了补上最后的'\0' */
 63         }
 64     }
 65 
 66     smp_sys_env_last = smp_sys_argv_last;
 67 
 68     for (i = 0; environ[i]; i++) {
 69         if (smp_sys_env_last == environ[i]) {
 70             smp_sys_env_last = environ[i] + strlen(environ[i]) + 1;
 71         }
 72     }
 73 
 74     smp_sys_env_last--;
 75 
 76     return SMP_OK;
 77 }
 78 
 79 static SMP_VALUE smp_reset_proc_titel(const u_char *title, size_t tlen, int argc, char **argv)
 80 {
 81     u_char *params = NULL;
 82 
 83     if (argc <= 1) {    /* 没有参数时, 直接覆盖 */
 84         memset(argv[0], '\0', smp_sys_env_last - argv[0]);
 85         memcpy(argv[0], title, tlen);
 86         return SMP_OK;
 87     }else {
 88         u_char *current = NULL;
 89         u_char *p = NULL;
 90         size_t size = smp_sys_argv_last - argv[1];
 91         int i = 0;
 92 
 93         if ((params = malloc(size)) == NULL) return 0;
 94         current = params;
 95         p = current;
 96 
 97         for (i = 1; i < argc; i++) {    /* 备份程序参数 */
 98             current = smp_strcpyn(current, (u_char *) argv[i], strlen(argv[i]));
 99             argv[i] = (char *) p;
100             current++;
101             p = current;
102         }
103 
104         memset(argv[0], '\0', smp_sys_env_last - argv[0]);    /* 一致性全部置 '\0' */
105         current = smp_strcpyn((u_char *) argv[0], title, tlen);
106 
107         current++;    /* 加上1是为了补上最后的 '\0' */
108         p = current;
109 
110         for (i = 1; i < argc; i++) {
111             current = smp_strcpyn(current, (const u_char *) argv[i], strlen(argv[i]));
112             argv[i] = (char *) p;
113             current++;
114             p = current;
115         }
116     }
117 
118     return SMP_OK;
119 }
120 
121 SMP_VALUE smp_set_proc_titel(const char *title, int argc, char **argv)
122 {
123     size_t tlen = 0;
124 
125     if (title == NULL) return SMP_FAILURE;
126 
127     tlen = strlen(title);
128     if (tlen <= strlen(argv[0])) {
129         memset(argv[0], '\0', strlen(argv[0]));
130         memcpy(argv[0], title, tlen);
131         return SMP_OK;
132     }
133 
134     smp_init_set_proc_title(argc, argv);
135     smp_cpy_environs();
136     smp_reset_proc_titel((u_char *) title, tlen, argc, argv);
137 
138     return SMP_OK;
139 }

        ps:项目地址 https://github.com/dglAndlele/smpcil

               项目文档 http://www.dgllele.com/projects/smpcil/index.html

posted on 2015-10-10 17:21  spoofer  阅读(1372)  评论(0)    收藏  举报