写在前面:代码比较简单,实际上修改的进程名字也是有限制,可以看到ngx_setproctitle中拷贝时有长度限制,超过原始内存长度时会被截断。。。
=========================================================================
转自: />
Linux下用ps命令可以看到显示的进程名字。这个进程的名字会体现在它的main()函数的入参中。main函数的原型:
-
int main(int argc, char *const *argv)
argc是表示命令行参数的个数;argv[]则用于以字符串形式存储所有的命令行参数内容,Linux中进程的名称就存储在argv[0]中。Linux还有个环境变量参数信息,表示进程执行需要的所有环境变量信息,通过一个全局变量Char **environ;来访问环境变量。
而argv[]与environ两个变量所占的内存是连续的,并且是environ紧跟在argv[]后面。测试如下:
-
#include <stdio.h>
-
#include <string.h>
-
-
extern char **environ;
-
-
int main(int argc , char *argv[])
-
{
-
int i;
-
-
printf("argc:%d\n" , argc);
-
-
for (i = 0; i < argc; i++)
-
{
-
printf("argv[%d]:%s\t0x%x\n" , i , argv[i], argv[i]);
-
}
-
-
for (i = 0; i < argc && environ[i]; i++)
-
{
-
printf("evriron[%d]:%s\t0x%x\n" , i , evriron[i], evriron[i]);
-
}
-
-
return 0;
-
}
测试结果如下:
修改进程名称
修改进程名称,正常只需要修改argv[0]指向的内存的值为所需要的值即可。但当要修改的值超过argv[0]所指向的内存空间大小时,直接修改可能覆盖掉后面的内容。
此时必须重新分配一块连续的内存空间,把arg和environ的参数复制到新的空间,然后修改argv[0]
看一下Nginx是怎么做的
-
extern char **environ; // 全局变量,看完上面,你懂得
-
-
static char *ngx_os_argv_last; // 指向argv[]最后一个变量
-
-
/* 先做初始化,完成environ的内容拷贝到新的内存空间 */
-
ngx_int_t ngx_init_setproctitle(ngx_log_t *log)
-
{
-
u_char *p;
-
size_t size;
-
ngx_uint_t i;
-
-
size = 0;
-
-
/* 计算environ[]的总大小 */
-
for (i = 0; environ[i]; i++) {
-
size += ngx_strlen(environ[i]) + 1;
-
}
-
-
/* 申请同environ大小的内存空间 */
-
p = ngx_alloc(size, log);
-
if (p == NULL) {
-
return NGX_ERROR;
-
}
-
-
/* 初始化argv[]首尾指针 */
-
ngx_os_argv_last = ngx_os_argv[0];
-
-
/* 移动argv_last指针到argv[]尾部 */
-
for (i = 0; ngx_os_argv[i]; i++) {
-
if (ngx_os_argv_last == ngx_os_argv[i]) {
-
ngx_os_argv_last = ngx_os_argv[i] + ngx_strlen(ngx_os_argv[i]) + 1;
-
}
-
}
-
-
/* 将environ的内容拷贝到刚申请的内存中去 */
-
for (i = 0; environ[i]; i++) {
-
if (ngx_os_argv_last == environ[i]) {
-
-
size = ngx_strlen(environ[i]) + 1;
-
ngx_os_argv_last = environ[i] + size;
-
-
ngx_cpystrn(p, (u_char *) environ[i], size);
-
environ[i] = (char *) p; // 这一步就是将environ中的变量重新指向刚分配的内存
-
p += size;
-
}
-
}
-
-
ngx_os_argv_last--;
-
-
return NGX_OK;
-
}
完成上面的初始化后,就可以放心修改argv[0]的内容,然后看下具体的ngx_setproctitle()函数
-
void ngx_setproctitle(char *title)
-
{
-
u_char *p;
-
-
/* 针对Solaris系统 */
-
#if (NGX_SOLARIS)
-
-
ngx_int_t i;
-
size_t size;
-
-
#endif
-
-
ngx_os_argv[1] = NULL;
-
-
/* 注意ngx_os_argv_last目前指向原始environ内存的最后一个参数,此时ngx_os_argv_last - ngx_os_argv[0]是原始argv和environ的总体大小 */
-
p = ngx_cpystrn((u_char *) ngx_os_argv[0], (u_char *) "nginx: ",
-
ngx_os_argv_last - ngx_os_argv[0]);
-
-
p = ngx_cpystrn(p, (u_char *) title, ngx_os_argv_last - (char *) p);
-
-
/* 针对Solaris系统,显示的进程名字方式不一样而已,不看了,原理一样的 */
-
#if (NGX_SOLARIS)
-
-
size = 0;
-
-
for (i = 0; i < ngx_argc; i++) {
-
size += ngx_strlen(ngx_argv[i]) + 1;
-
}
-
-
if (size > (size_t) ((char *) p - ngx_os_argv[0])) {
-
-
/*
-
* ngx_setproctitle() is too rare operation so we use
-
* the non-optimized copies
-
*/
-
-
p = ngx_cpystrn(p, (u_char *) " (", ngx_os_argv_last - (char *) p);
-
-
for (i = 0; i < ngx_argc; i++) {
-
p = ngx_cpystrn(p, (u_char *) ngx_argv[i],
-
ngx_os_argv_last - (char *) p);
-
p = ngx_cpystrn(p, (u_char *) " ", ngx_os_argv_last - (char *) p);
-
}
-
-
if (*(p - 1) == ' ') {
-
*(p - 1) = ')';
-
}
-
}
-
-
#endif
-
-
/* 在原始argv和environ的连续内存中,将修改了的进程名字之外的内存全部清零 */
-
if (ngx_os_argv_last - (char *) p) {
-
ngx_memset(p, NGX_SETPROCTITLE_PAD, ngx_os_argv_last - (char *) p);
-
}
-
-
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
-
"setproctitle: \"%s\"", ngx_os_argv[0])
阅读(1433) | 评论(0) | 转发(0) |