[Linux] Process program replacement

[Linux] Process program replacement

The meaning of process program replacement

After using the fork system function to create a child process under the Linux system, the child process can only execute part of the inherited code of the parent process. If you want the child process to execute a separate code, you must replace the process program.

Meet Process Program Replacement

The header files and functions replaced by the process program are as follows:

image-20230831104800830

Write the following code to see process program replacement:

#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  printf("进程程序替换前\n");
  printf("进程程序替换前\n");
  execl("/bin/ls", "ls", "-a", "-l", NULL);
  printf("进程程序替换后\n");
  printf("进程程序替换后\n");
  printf("进程程序替换后\n");
  return 0;
}

Compile the code and run to see the results:

image-20230831104439925

It can be seen that after the process program is replaced, the process no longer executes the original code but instead executes the replaced code. The code after the process replacement function is no longer executed. Therefore, it can be seen that the program replacement is an overall replacement . After the replacement, the original code and data no longer exist.

The principle of process program replacement

Process program replacement is to transfer the code and data of the executable program in the disk to the memory without modifying the ID in the process pcb, replace the original code and data of the process, and modify the page table mapping to complete the process program. replacement, the schematic diagram is as follows:

image-20230831104507648

  • From a process perspective: code and data are replaced by the operating system.
  • From a program perspective: its own code and data are loaded into memory.

The principle of program loading: Under the Linux operating system, any process started is a child process of the shell process. To start the process, the shell process first creates a pcb of the child process, and then uses the code and data of the process we have written. Replace the child process of this shell process to complete the loading and startup of the process.

Copy-on-write in process program replacement

In order to experience copy-on-write in process program replacement, write the following code:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    
    
  pid_t id = fork();
  if (id == 0)
  {
    
    
    //子进程
    printf("我是子进程,我的pid:%d\n", getpid());
    execl("/bin/ls", "ls", "-a", "-l", NULL);
  }
  waitpid(id, NULL, 0);
  printf("我是父进程,我的pid:%d\n", getpid());
  return 0;
}

Compile the code, run it and view the results:

image-20230831104608439

It can be seen that process program replacement does not affect the code and data of the parent process, because when replacing the code and data of the child process, copy-on-write occurs. In addition, it can be seen that the data in the code area can actually be modified.

Introducing the process program replacement interface

return value

The process program replacement function will only return a value when the execution fails. If the process program replacement fails, it will return -1 and set an error code. Since the process program replacement function is successfully replaced, the return code inside the function is also replaced, so there will be no return value once the execution is successful. Once the replacement fails, since the process program replacement will not modify the pcb, it will not affect the parent process receiving the exit code of the child process.

Write the following code for testing:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>

int main()
{
    
    
  pid_t id = fork();
  if (id == 0)
  {
    
    
    //子进程
    int n = execl("/bin/lsss", "lsss", "-a", "-l", NULL);
    printf("我是子进程,我的id:%d, 程序替换失败,n: %d\n", getpid(), n);
    exit(1);
  }
  int status = 0;
  waitpid(id, &status, 0);
  printf("我是父进程,子进程退出码:%d\n", WEXITSTATUS(status));
  return 0;
}

Compile the code, run it and see the results:

image-20230831104523903

Because the replacement program we passed in was wrong, the process program replacement failed, a return value of -1 was received, and the parent process also received the exit code -1 normally.

Then write the following code for testing:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>

int main()
{
    
    
  pid_t id = fork();
  if (id == 0)
  {
    
    
    //子进程
    int n = execl("/bin/ls", "ls", "hello.txt", NULL);//该文件不存在
    printf("我是子进程,我的id:%d, 程序替换失败,n: %d\n", getpid(), n);
    exit(1);
  }
  int status = 0;
  waitpid(id, &status, 0);
  printf("我是父进程,子进程退出码:%d\n", WEXITSTATUS(status));
  return 0;
}

Compile the code, run it and see the results:

image-20230831102532182

It can be seen that even if the program replacement is successful, it will not affect the receipt of the exit code of the child process.

execl function

//execl函数声明
int execl(const char *path, const char *arg, ...);
  • path parameter – the path of the program to be replaced
  • arg parameter – variable parameter, receiving the command line parameters of the replacement program, terminated by NULL

Write the following code for testing:

#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  execl("/bin/ls", "ls", "-a", "-l", NULL);
  printf("进程程序替换失败\n");
  return 0;
}

Compile the code, run it and see the results:

image-20230831102536883

execv function

//execv函数声明
int execv(const char *path, char *const argv[]);
  • path parameter – the path of the program to be replaced
  • argv parameter – receives the command line arguments of the program to be replaced, terminated by NULL

Write the following code for testing:

#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  //execl("/bin/ls", "ls", "-a", "-l", NULL);
  char * const argv[] = {
    
    
    "ls",
    "-a",
    "-l",
    "-n",
    NULL
  };
  execv("/bin/ls", argv);
  printf("进程程序替换失败\n");
  return 0;
}

Compile the code, run it and see the results:

image-20230831104539226

execlp function

//execlp函数声明
int execlp(const char *file, const char *arg, ...);
  • file parameter – the name of the program to be replaced, the program will automatically be found in the path of the environment variable
  • arg parameter – variable parameter, receiving the command line parameters of the replacement program, terminated by NULL

Write the following code for testing:

#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  execlp("ls", "ls", "-l", "-n", NULL);
  printf("进程程序替换失败\n");
  return 0;
}

Compile the code, run it and see the results:

image-20230831104738842

execvp function

//execvp函数声明
int execvp(const char *file, char *const argv[]);
  • file parameter – the name of the program to be replaced, the program will automatically be found in the path of the environment variable
  • argv parameter – receives the command line arguments of the program to be replaced, terminated by NULL

Write the following code for testing:

#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  char * const argv[] = {
    
    
    "ls",
    "-l",
    "-n",
    NULL
  };
  execvp("ls", argv);
  printf("进程程序替换失败\n");
  return 0;
}

Compile the code, run it and see the results:

image-20230831093047903

execle function

//execle函数声明
int execle(const char *path, const char *arg, ..., char * const envp[]);
  • path parameter – the path of the program to be replaced
  • arg parameter – variable parameter, receiving the command line parameters of the replacement program, terminated by NULL
  • envp parameter – receives the environment variables passed to the replacement program, ends with NULL, and is passed in as an overwrite. The receiving process will only have the environment variables passed in.

Write the following file directory structure:

image-20230831100637858

Use the myproc program and otherproc program for testing. The code content is as follows

//myproc
#include <stdio.h>
#include <unistd.h>

int main()
{
    
    
  printf("进程程序替换前\n");
  char * const envp[] = {
    
    
    "MYENV=YOUCANSEEME",
    NULL 
  };
  execle("../otherproc/otherproc", "otherproc", NULL, envp);
  printf("进程程序替换失败\n");
  return 0;
}
//otherproc
#include <iostream>
#include <stdlib.h>

using namespace std;

int main()
{
    
    
  cout << " MYENV: " << (getenv("MYENV")==NULL?"NULL":getenv("MYENV")) << endl;
  cout << " PATH: " << (getenv("PATH")==NULL?"NULL":getenv("PATH")) << endl;
  return 0;
}

Use the otherproc program to replace the myproc program, and only pass in the parameter envp which contains only one environment variable.

Compile the code, run it and see the results:

image-20230831101123814

Since the execle function uses overwriting to pass in the environment variables, the replacement program only has one environment variable passed in.

Replenish:

  • You can use global variables environto let the replacement program obtain all environment variables of the parent process.
  • When the shell process creates a child process, it also calls such a system interface to pass in environment variables.

execvpe function

int execvpe(const char *file, char *const argv[], char *const envp[]);
  • file parameter – the name of the program to be replaced, the program will automatically be found in the path of the environment variable
  • argv parameter – receives the command line arguments of the program to be replaced, terminated by NULL
  • envp parameter – receives the environment variables passed to the replacement program, ends with NULL, and is passed in as an overwrite. The receiving process will only have the environment variables passed in.

Supplementary knowledge

Naming rules for program replacement functions:

  • l suffix – receives command line arguments to the replacement program as variadic arguments
  • v suffix – receives command line arguments to the replacement program as an array of pointers
  • p suffix – pass in the program name of the replacement program and it will automatically be searched in the path of the environment variable
  • e suffix – receives the replacement program’s environment variables as an array of pointers

All the above process program replacement system calls are execveencapsulation of system call functions. Different encapsulations are to be more suitable for different application scenarios.

Guess you like

Origin blog.csdn.net/csdn_myhome/article/details/132598332