Replace exec process image
In the process of creating the Unix uses a unique approach, which will process creates and loads a new process image separation. The advantage is that there is more room for the two operations management.
When we create a process, the child process usually replaced with a new process image, which can be used to perform the function exec series. Of course, the series can also be a function exec will replace the current process.
exec family of functions
Header file <unistd.h>
function can be replaced with the current process exec function as a new process. exec name is a complete series consists of multiple correlation function of composition
原型
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,
..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
参数
* path参数表示你要启动程序的名称包括路径名
* arg参数表示启动程序所带的参数
* 带'l'的表示可变参数列表(argument list(仅仅自己理解方便记忆))
* 带'v'的表示参数是(char* argv[](仅仅自己理解方便记忆))
* 带‘p'的表示 会从环境变量中搜索是否有这个程序存在
* 带’e'的表示 会传一个环境信息
返回值:
* 成功 0
* 失败 -1
Code segment, the data segment is replaced, after the code will not be executed
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[])
{
printf("Entering main ...\n");
execlp("ls","ls","-hl",NULL);
printf("Exiting main ...\n");
return 0;
}
Replace a process does not modify the original process id
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("pid : %d\n",getpid());
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[])
{
printf("Entering main ...\n");
printf("before replace pid : %d\n",getpid());
//代码段、数据段被替换
//int ret = execlp("./hello","hello",NULL);
//linux默认情况下是在环境变量(echo $PATH)下搜索源程序
int ret = execlp("hello","hello",NULL);
if(ret == -1)
perror("execlp error");
printf("Exiting main ...\n");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[])
{
char* const args[] = {"ls","-l",NULL};
printf("Entering main ...\n");
"第一个参数可以是绝对路径,也可以是相对路径,也可以不带路径"
//int ret = execlp("ls","ls","-l",NULL);
int ret = execvp("ls",args);
if(ret == -1)
perror("execlp error");
printf("Exiting main ...\n");
return 0;
}
Example 1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[])
{
printf("Entering main ...\n");
//带'p'的表示会从环境变量或指定的路径获取文件
//execlp("ls","ls","-hl",NULL);
char *const args[] = {"ls", "-hl", NULL};
//execvp("ls", args);
// 并不会在环境变量中搜索,这个地方必须给出一个路径(相对路径和绝对路径都可以)
//int ret = execv("ls", args);
//int ret = execl("ls","ls","-hl",NULL);
if( ret < 0 )
{
perror("execl");
}
printf("Exiting main ...\n");
return 0;
}
Example 2
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[])
{
printf("Entering main ...\n");
//execl执行hello,会将当前的环境信息传递给hello,
//而当前进程的环境信息,是从shell中继承下来的
//简单的说,就是执行“execl”这个程序的的时候,shell会被做为参数,传递到进程中,
//在进程中又调用execl,执行"hello"这个程序,“execl”又将shell作为参数传递到“hello"这个进程中
/* int ret = execl("./hello", "hello", NULL);
if(ret == -1)
{
perror("execl");
} */
//设置自己的环境变量信息
char* const envp[] = {"AA=1", "BB=2", NULL};
int ret = execle("./hello", "hello", NULL, envp);
if(ret == -1)
{
perror("execl");
}
printf("Exiting main ...\n");
return 0;
}
Example 3
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
//全部变量,C库中已存在,此处声明下就可以
extern char** environ;
int main(int argc, char const *argv[])
{
printf("hello! pid = %d\n",getpid());
int i;
for(i=0; environ[i] != NULL; ++i)
{
printf("%s\n",environ[i]);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[])
{
printf("Entering main ...\n");
/*
man 2 fcntl;
File descriptor flags
The following commands manipulate the flags associated with a file descriptor. Currently, only one such flag
is defined: FD_CLOEXEC, the close-on-exec flag. If the FD_CLOEXEC bit is 0, the file descriptor will remain
open across an execve(2), otherwise it will be closed.
*/
//如果将一个文件描述符设置为FD_CLOEXEC,当我们调用execve进行替换的时候,文件描述符会被关闭
int ret = fcntl(1, F_SETFD, FD_CLOEXEC);//置1
if(ret == -1)
{
perror("fcntl");
}
//execlp替换成功,但是因为设置了FD_CLOEXEC,调用hello的时候,1号文件描述符被关闭了,所以”hello"程序无法输出
//对于open()函数,在打开文件的时候,我们可以加O_CLOEXEC,表示将FD_CLOEXEC置为1,当调用exec系列会自动关闭文件描述符
ret = execlp("./hello", "hello", NULL);
if(ret == -1)
{
perror("execl");
}
printf("Exiting main ...\n");
return 0;
}