[Linux] Process program replacement


1. Introduction to process replacement

1. Why learn process replacement

We talked about how to create a child process before. Creating a child process can help our parent process complete some tasks, but the child process we created earlier has certain defects, that is, the child process we created can only execute the parent process. Part of the code, instead of executing a code that the parent process does not have independently of the parent process, if we want the child process to execute code different from the parent process, then we need to learn process program replacement !

2. The principle of process program replacement

Before learning process program replacement, let's experience process replacement first. Look at the following piece of code:

#include < stdio.h > 
#include < unistd.h > 
#include < stdlib.h > 
#include < sys / wait.h > 
#include < sys / types.h >
  int main() 
   {
    
    
       pid_t id = fork();
       if (id < 0) 
       {
    
    
           perror("fork() fail:");
           exit(-1);
       } 
       else if (id == 0) 
       {
    
    
           printf("我是子进程,我的pid是: %d\n", getpid());
           //进行程序替换
           int n = execl("/bin/ls", "ls", "-a", "-l", NULL);
           printf("我是子进程,我的pid是: %d\n", getpid());
           printf("我是子进程,我的pid是: %d\n", getpid());
           printf("我是子进程,我的pid是: %d\n", getpid());
           printf("我是子进程,我的pid是: %d\n", getpid());
           if (n == -1) 
           {
    
    
               printf("进程程序替换失败!\n");
               exit(-1);
           }
       }
       int status = 0;
       pid_t Pid = wait( & status);
       printf("我是父进程,等待子进程成功!子进程的pid是: %d\n", Pid);
       if (WIFEXITED(status)) 
       {
    
    
           printf("子进程正常退出,退出码为: %d\n", WEXITSTATUS(status));
       }
       else 
       {
    
    
  		 printf("子进程退出异常,退出信号为: %d\n", status & 0x7F);
	   }
	return 0;
}

Results of the:

insert image description here

We found that execlafter the following codes are all changed, lsand become the code to execute the command, that is to say, the code and data in the subprocess are replaced by the files on the disk, so that our subprocess The process executes a different code than the parent process.

Well, after reading the phenomenon, let's take a look at the principle of process replacement:

The replacement principle is shown in the figure:
insert image description here
when our sub-process is called, execlwe copy the code and data of another program on the disk to the sub-process. At this time, the sub-process has copy-on-write, and the code and data are copied to a new one. location, completely split from the parent process.

Here are a few key points to understand about process program replacement:

  • Program replacement is an overall replacement and not partial replacement . When program replacement is executed, new code and data are loaded, andexeclthe subsequent code belongs to the old code and is directly replaced. The opportunity was set!
  • The program replacement of the process does not create a new process ! Process program replacement only replaces the code and data of the original process.
  • The process is independent, and the program replacement of the child process will not affect the parent process

2. Interface for process program replacement

After understanding the principle of process program replacement , we will start to learn the use of process replacement. In Linux, we can use man execlcommands to see many interfaces related to process program replacement.

insert image description here

Here we can see that the C library provides us with 6 interfaces about process program replacement, let's learn one by one below!

function explanation

  • If these functions are called successfully, the new program will be loaded and executed from the startup code, and will not return.
  • Returns -1 if an error occurred.
  • So exec类the function only has an error return value and no success return value.

Naming understanding
These function prototypes seem to be easy to confuse, but it is easy to remember as long as you master the rules.

  • l(list) : Indicates that the parameter takes a list
  • v(vector) : array for parameters
  • p(path): If there is p, the program will automatically search the environment variable PATH
  • e(env): Indicates that you use your own maintenance environment variables

1. execl function

Function prototype:

int execl(const char *path, const char *arg, ...); //此函数的参数属于可变参数
  • The first parameter indicates the absolute path of the program to be replaced
  • The second parameter indicates who is the program to execute
  • The third parameter indicates how to execute this program, (you can not write)
  • Since it is a variable parameter, the last parameter in the parameter list must be written NULLto tell the function that the parameter is passed

Code example:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
    
    
 	printf("我是一个进程,我的pid是: %d\n", getpid());
 	int n = execl("/bin/ls", "ls", "-a", "-l", NULL);
	if(n == -1)
 	{
    
    
	 	perror("execl() fail:");
	 	exit(-1);                                                                                                                                        
	}
	return 0;
}

operation result:

insert image description here

2. execv function

Function prototype:

int execv(const char *path, char *const argv[]);
  • The first parameter indicates the absolute path of the program to be replaced
  • The second parameter is an array of pointers that cannot be changed, including who and how the program to be executed is executed.
  • The last element of this pointer array must point to NULL, which is convenient to tell the function that the parameters are passed

Code demo:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
 {
    
    
	   char* const argv[]={
    
    
			 "ls",
			 "-a",
			"-l",                                                                                                                                          
			  NULL
		};
	  printf("我是一个进程,我的pid是: %d\n", getpid());
	  int n = execv("/bin/ls", argv);
	  if(n == -1)
	  {
    
    
	    perror("execl() fail:");
	    exit(-1);
	  }
  return 0;
}

operation result:

insert image description here

3. execlp function

Function prototype:

int execlp(const char *file, const char *arg, ...);
  • The first parameter indicates the path of the program to be replaced. There is no need to bring an absolute path. At this time, the system will go back to the environment variable to automatically find the corresponding program.
  • The second parameter indicates who is the program to execute
  • The third parameter indicates how to execute this program, (you can not write)
  • Since it is a variable parameter, the last parameter in the parameter list must be written NULLto tell the function that the parameter is passed

Code example:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
	int main()
	{
    
    
		printf("我是一个进程,我的pid是: %d\n", getpid());
		int n = execlp("ls", "ls", "-a", "-l", NULL);                                                                                                    
		if(n == -1)
		{
    
    
		 perror("execl() fail:");
		 exit(-1);
		}
		return 0;
	}

operation result:

insert image description here

4. execvp function

Function prototype:

int execvp(const char *file, char *const argv[]);
  • The first parameter indicates the path of the program to be replaced. It is not necessary to bring an absolute path. At this time, the system will go back to the environment variable to automatically find the corresponding program.
  • The second parameter is an array of pointers that cannot be changed, including who and how the program to be executed is executed.
  • The last element of this pointer array must point to NULL, which is convenient to tell the function that the parameters are passed

Code example:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
 {
    
    
	   char* const argv[]={
    
    
			 "ls",
			 "-a",
			"-l",                                                                                                                                          
			  NULL
		};
	  printf("我是一个进程,我的pid是: %d\n", getpid());
	  int n = execvp("ls", argv);
	  if(n == -1)
	  {
    
    
	    perror("execl() fail:");
	    exit(-1);
	  }
  return 0;
}

insert image description here

5, execle function

Function prototype:

int execle(const char *path, const char *arg, ...,char *const envp[]);
  • The first parameter indicates the absolute path of the program to be replaced
  • The second parameter indicates who is the program to execute
  • The third parameter indicates how to execute this program, (you can not write)
  • Since it is a variable parameter, the penultimate parameter in the parameter list must be written NULLto tell the function that the parameter is passed
  • The last parameter is an array of pointers that cannot be changed, which records custom environment variables.

Let's take a look at the following code to understand this execlefunction:

#include<iostream>
#include<stdlib.h>
using namespace std;
 int main()
 {
    
    
    cout << "---------------------------" << endl;
    cout << "这时一个C++的进程,自定义的环境变量是MYNAME:" << endl;
    cout << (getenv("MYNAME") == NULL ? "NULL" : getenv("MYNAME")) << endl;
    cout << getenv("PATH") << endl;
    cout << "---------------------------" << endl;
   return 0;                                                                                                                                          
 }

When we run this program written in C++ alone, since the "MYNAME" environment variable is not passed, we can only see NULL, the environment variable corresponding to PATH.

insert image description here

When we run the following code, the environment variable argv is passed to the myproc program, and we can see the environment variable corresponding to "MYNAME", but there can only be one environment variable table, so we cannot see the default environment variable. .

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
   int main()
   {
    
    
	    printf("我是一个C进程\n");
	    char* const argv[]={
    
    
	      "MYNAME=you can see me?",                                                                                                                      
	        NULL
	    };
	    int n = execle("./practice/myproc", "myproc", NULL, argv);
	    if(n == -1)
	    {
    
    
	      perror("execl() fail:");
	      exit(-1);
	    }
	    return 0;
   }

operation result:

insert image description here

What if we want both default environment variables and custom environment variables? We have two methods, one is to use commands on the Linux command line exportto add the environment variables we want to add, and the other is to call putenv.

  • exportUsing the commands on the command line
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
   int main()
   {
    
    
  		extern char** environ;
	    printf("我是一个C进程\n");
	    int n = execle("./practice/myproc", "myproc", NULL, environ);
	    if(n == -1)
	    {
    
    
	      perror("execl() fail:");
	      exit(-1);
	    }
	    return 0;
   }

insert image description here

  • call putenvfunction

insert image description here

When the process calls this function, an environment variable will be added to the environment variable table of that process.

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
   int main()
   {
    
    
  		extern char** environ;
  		putenv("MYNAME=you can see me?");
	    printf("我是一个C进程\n");
	    int n = execle("./practice/myproc", "myproc", NULL, environ);
	    if(n == -1)
	    {
    
    
	      perror("execl() fail:");
	      exit(-1);
	    }
	    return 0;
   }

insert image description here

6. Summary

Having said that, execvpeI don't need to talk about functions, you can also refer to the previous functions to give the answer! But what happened when we found that there are missing functions in the
above class? We use the man manual to check. It is a function call. In the No. 2 manual, the function we just mentioned is a C library function, and the No. 3 manual is a library function of the C language. The underlying calls of the C library function class are all system calls.execexecve
insert image description here
execveexecexceve

3. Supplementary emphasis on program replacement

Process program replacement, we can replace executable programs written in any programming language, because process program replacement is a system call provided by the operating system, which is a system-level operation.

In the next chapter, we can use process program replacement to make a simple shell program to deepen our understanding of process program replacement and the operation of the shell.

Guess you like

Origin blog.csdn.net/qq_65207641/article/details/129686589