【Linux】进程的程序替换(execl、execlp、execle、execvpe等替换函数)

文章目录

    • 1、进程程序替换
      • 1.1 理解进程替换原理
      • 1.2 进程相应替换函数
      • 1.3 进一步理解程序替换

1、进程程序替换

父进程创建子进程的目的:
1.想让子进程执行父进程代码的一部分。(子承父业)
2.想让子进程执行一个全新的程序。

进程程序替换讨论的就是子进程执行一个全新程序的情况。

1.1 理解进程替换原理

进程替换主要是通过调用库函数中众多exec类函数来实现的。
首先让我们来看看其中最简单的

#include 
int execl(const char *path, const char *arg, ...);

将指定的程序加载到内存中,让指定进程进行执行。
其中
path:是如何找到程序的路径
arg:是可变参数列表:arg[0]、arg[1]、arg[2],最后一个跟NULL结束

返回值:函数调用失败返回-1,成功的返回值没有意义。
如:

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 
  4 int main()
  5 {
  6     printf("process is running...\n");
  7     execl("/usr/bin/ls", "ls", "--color=auto", "-a", "-l", NULL);
  8     printf("process running done...\n");                                                                                                            
  9                                                                                                                                          
 10     return 0;                                                                                                                            
 11 }

【Linux】进程的程序替换(execl、execlp、execle、execvpe等替换函数)_第1张图片
只允许第一行打印,随后执行对应命令,进程代码被替换最后一行不打印,结果没错。

进程替换原理也其实很简单,就是将原来进程数据代码内容给替换了
【Linux】进程的程序替换(execl、execlp、execle、execvpe等替换函数)_第2张图片

1.2 进程相应替换函数

下面对应进程替换函数都属于前缀exec的

首先看exec中列表类的,命名理解:

  • -l 代表列表(对于arg,得写多个参数)
  • -p 代表文件名 (相对于path,可以直接通过文件名在环境变量中找程序)
  • -e 代表环境变量 (可以给替换的程序自己组环境变量)
#include 
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[]);

execlp只需要修改路径为程序名。

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 
  4 int main()
  5 {
  6     printf("process is running...\n");
  7     execlp("ls", "ls", "--color=auto", "-a", "-l", NULL);                                                                                           
  8     printf("process running done...\n");
  9 
 10     return 0;
 11 }

execle需要自己指定环境变量,如果不写默认继承进程的环境变量。

//mybin.c中
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 int main()
  5 {
  6     printf("PATH:%s\n", getenv("PATH"));
  7     printf("PWD:%s\n", getenv("PWD"));
  8     printf("MYENV:%s\n", getenv("MYENV"));                                                                                                          
  9     return 0;
 10 }
//myexe.c中
  1 #include <stdio.h>
  2 #include <unistd.h>
  3 
  4 int main()
  5 {
  6     char* const envp_[] = {(char*)"MYENV=12235", NULL};
  7     execle("./mybin", "mybin", NULL, envp_);
  8     return 0;                                                                                                                                       
  9 }

在这里插入图片描述
可以看到,这里替换成了自己写的mybin程序,并且指定了自己组装envp_环境变量。

除了列表类的,还是数组类的。

exec中数组类的,命名理解:

  • -v 代表数组
  • -p 代表文件名 (相对于path,可以直接通过文件名在环境变量中找程序)
  • -e 代表环境变量 (可以给替换的程序自己组环境变量)
#include 
int execv(const char *path, char* const argv[]);
int execvp(const char *file, char* const argv[]);
int execvpe(const char *path, char* const argv[], char* const envp[]);

例子:

//mybin.c
    1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <string.h>
    4 
    5 int main(int argc, char* argv[])
    6 {
    7     printf("PATH:%s\n", getenv("PATH"));
    8     printf("PWD:%s\n", getenv("PWD"));
    9     printf("MYENV:%s\n", getenv("MYENV"));
   10 	 
   11     if(strcmp(argv[1], "-t") == 0)                                                                                                                
   12     {
   13         printf("使用了-t\n");
   14     }
   15     return 0;
   16 }


//myexec.c
  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <sys/wait.h>
  5 #include <assert.h>
  6 
  7 int main()
  8 {
  9     printf("process is running...\n");
 10     pid_t id = fork();
 11     assert(id != -1);
 12 
 13     if(id == 0)
 14     {
 15         extern char** environ;
 16         char* const myargc_[] = {(char*)"mybin", (char*)"-t", NULL}; //自己组建命令行参数
 17         execvpe("./mybin", myargc_, environ);   //调用继承的环境变量                                                                                                    
 18         exit(1);  //mush failed
 19     }
 20 
 21     int status = 0;
 22     pid_t ret = waitpid(id, &status, 0);
 23     if(ret > 0)
 24     {
 25         printf("wait success: exit code: %d, sig: %d\n", (status>>8)&0xFF, status & 0x7F);
 26     }
 27     return 0;

【Linux】进程的程序替换(execl、execlp、execle、execvpe等替换函数)_第3张图片

如果我们即想用系统的环境变量,又想用自己的怎么办?
通过putenv(),将定义的环境变量加入到系统中,environ指向的表。

#include 
int putenv(char* string);
//通过在之前代码中加入putenv
 15         extern char** environ;
 16         char* const myargc_[] = {(char*)"mybin", (char*)"-t", NULL};
 17         putenv("MYENV=1234");                                                                                                                       
 18         execvpe("./mybin", myargc_, environ);                                                                       
 19         exit(1);  //mush failed 

【Linux】进程的程序替换(execl、execlp、execle、execvpe等替换函数)_第4张图片

1.3 进一步理解程序替换

通过以上知道了,系统通过exec系列的函数,将硬盘中的程序替换到内存中。程序加载到内存中,这是体系结构规定的,很好理解。

那么回到main函数.

int execve(const char* filename, char* const argv[], char* const envp[]);

int main(int argc, char* argv[], char* env[]);

其实,在main函数被调用之前,先加载了exec系列中的函数,并且main中的参数其实也是由exec函数加载的。

最后一个
通过man 3 exec库函数手册可以看到这些,但似乎少了一个execve。
【Linux】进程的程序替换(execl、execlp、execle、execvpe等替换函数)_第5张图片

再通过man 2 execve 系统手册可以看到它
在这里插入图片描述
其实execve才是真正的系统调用,其它的都是通过它的封装,为了给我们满足多种应用场景的。

你可能感兴趣的:(Linux,linux,运维,服务器)