http://blog.chinaunix.net/uid-29482215-id-4120748.html
在编写网络服务器程序时,为了响应客户端的请求,我们经常需要新建进程来处理业务流程;而且又是为了关闭某个非法请求或者关闭长连接的客户端,这时就需要杀死进程 killall proc_name。 但是在新建进程时,子进程名与父进程名相同。因此需要由进程名及参数来区分客户端连接。
在linux中prctl可以满足这个要求,下满是man手册:
PR_SET_NAME (since Linux 2.6.9)
Set the process name for the calling process, using the value in
the location pointed to by (char *) arg2. The name can be up to
16 bytes long, and should be null terminated if it contains
fewer bytes.
点击(此处)折叠或打开
- #include <stdio.h>
- #include <sys/prctl.h>
- int main(int argc, char *argv[], char *envp[])
- {
- char *new_name = "abcdefghijklmnopqrstuvwxyz";
- getchar();
- prctl(PR_SET_NAME, new_name);
- getchar();
- return 0;
- }
/prco/$(PID)/status的值,而/prco/$(PID)/cmdline并没有改变。这种方式使用起来也是不方便的。
下面介绍另一种方式,可以与上面的方式互补。
首先看一下main函数的原型:int main(int argc, char *argv[]);
argv[0]存放的是终端执行的程序名称也就是进程名。argv[1...argc-1]存放的是命令行参数。
linux中main()还有一个隐藏参数就是环境变量信息,存放了运行时所需要的环境变量。
我们可以通过以下来访问这个变量
点击(此处)折叠或打开
- extern char **environ;
点击(此处)折叠或打开
#include<stdio.h> extern char** environ; int main(int argc, char *argv[]) { int i; for (i = 0; i < argc; ++i) { printf("argv[%d](0x%x):%s\n" , i , argv[i], argv[i]); } printf("\n\n"); char** t = environ; for(i=0;environ[i];i++) { printf("environ[%d] (0x:%x) is %s \n", i, environ[i], environ[i]); } printf("i: %d \n",i); return 0; }
(gdb) p argv[0]
$11 = 0x7fffffffe7d7 "/home/bwei/c/a.out"
(gdb) p argv[1]
$12 = 0x0
(gdb) p argv[2]
$13 = 0x7fffffffe7ea "build=/home/C3/platform/trunk/projects/stream_serv/build"
(gdb) p argv[3]
$14 = 0x7fffffffe823 "HOSTNAME=localhost.localdomain"
(gdb) p argv[4]
$15 = 0x7fffffffe842 "SHELL=/bin/bash"
(gdb) p argv[5]
$16 = 0x7fffffffe852 "TERM=xterm"
(gdb) p t
$7 = (char **) 0x7fffffffe598
(gdb) p t[0]
$8 = 0x7fffffffe7ea "build=/home/C3/platform/trunk/projects/stream_serv/build"
比argv[0]长我们需要两步:
1、申请新内存保存环境变量信息和argv[1...argc-1]参数信息
2、修改argv[0],将新名称往后到environ的最后一项清0
以下是参考代码:
点击(此处)折叠或打开
- #include <unistd.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <stdlib.h>
- #include <sys/prctl.h>
- # define MAXLINE 2048
- extern char **environ;
- static char **g_main_Argv = NULL; /* pointer to argument vector */
- static char *g_main_LastArgv = NULL; /* end of argv */
- void setproctitle_init(int argc, char **argv, char **envp)
- {
- int i;
- for (i = 0; envp[i] != NULL; i++) // calc envp num
- continue;
- environ = (char **) malloc(sizeof (char *) * (i + 1)); // malloc envp pointer
- for (i = 0; envp[i] != NULL; i++)
- {
- environ[i] = malloc(sizeof(char) * strlen(envp[i]));
- strcpy(environ[i], envp[i]);
- }
- environ[i] = NULL;
- g_main_Argv = argv;
- if (i > 0)
- g_main_LastArgv = envp[i - 1] + strlen(envp[i - 1]);
- else
- g_main_LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
- }
- void setproctitle(const char *fmt, ...)
- {
- char *p;
- int i;
- char buf[MAXLINE];
- extern char **g_main_Argv;
- extern char *g_main_LastArgv;
- va_list ap;
- p = buf;
- va_start(ap, fmt);
- vsprintf(p, fmt, ap);
- va_end(ap);
- i = strlen(buf);
- if (i > g_main_LastArgv - g_main_Argv[0] - 2)
- {
- i = g_main_LastArgv - g_main_Argv[0] - 2;
- buf[i] = '\0';
- }
- (void) strcpy(g_main_Argv[0], buf);
- p = &g_main_Argv[0][i];
- while (p < g_main_LastArgv)
- *p++ = '\0';
- g_main_Argv[1] = NULL;
- prctl(PR_SET_NAME,buf);
- }
- int main(int argc, char *argv[])
- {
- char argv_buf[MAXLINE] = {0}; // save argv paramters
- for(int i = 1; i < argc; i++)
- {
- strcat(argv_buf, argv[i]);
- strcat(argv_buf, " ");
- }
- setproctitle_init(argc, argv, environ);
- setproctitle("%s@%s %s", "new_name", "ip", argv_buf);
- for (int i = 0; environ[i] != NULL; i++)
- free(environ[i]);
- getchar();
- return 0;
- }
应用场景:
1、标识父子进程名称,防止被误杀
2、构造假的进程名及参数,引导非法进入人员到蜜罐系统,取证