[Linux] Процесс замены программы

[Linux] Процесс замены программы

Смысл замены программы процесса

После использования системной функции fork для создания дочернего процесса в системе Linux дочерний процесс может выполнять только часть унаследованного кода родительского процесса. Если вы хотите, чтобы дочерний процесс выполнял отдельный код, вы должны заменить программу процесса .

Замена программы Meet Process

Заголовочные файлы и функции, замененные программой процесса, следующие:

изображение-20230831104800830

Напишите следующий код, чтобы увидеть замену программы процесса:

#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;
}

Скомпилируйте код и запустите, чтобы увидеть результаты:

изображение-20230831104439925

Видно, что после замены программы процесса процесс больше не выполняет исходный код, а вместо этого выполняет замененный код. Код после функции замены процесса больше не выполняется.Поэтому видно, что замена программы является полной заменой.После замены исходный код и данные больше не существуют.

Принцип замены программы процесса

Замена программы процесса заключается в передаче кода и данных исполняемой программы с диска в память без изменения идентификатора в печатной плате процесса, замене исходного кода и данных процесса и изменении отображения таблицы страниц для завершения программы процесса. .замены, принципиальная схема следующая:

изображение-20230831104507648

  • С точки зрения процесса: код и данные заменяются операционной системой.
  • С точки зрения программы: в память загружается собственный код и данные.

Принцип загрузки программы: В операционной системе Linux любой запущенный процесс является дочерним процессом процесса оболочки.Чтобы запустить процесс, процесс оболочки сначала создает печатную плату дочернего процесса, а затем использует код и данные процесса оболочки. процесс, который мы написали. Замените дочерний процесс этого процесса оболочки, чтобы завершить загрузку и запуск процесса.

Замена программы копирования при записи в процессе

Чтобы испытать копирование при записи при замене программы процесса, напишите следующий код:

#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;
}

Скомпилируйте код, запустите его и просмотрите результаты:

изображение-20230831104608439

Видно, что замена программы процесса не влияет на код и данные родительского процесса, так как при замене кода и данных дочернего процесса происходит копирование при записи.Кроме того, видно, что данные в область кода действительно может быть изменена.

Знакомство с интерфейсом замены программы процесса

возвращаемое значение

Функция замены программы процесса вернет значение только в случае сбоя выполнения. Если замена программы процесса не удалась, она вернет -1 и установит код ошибки. Поскольку функция замены программы процесса успешно заменена, код возврата внутри функции также заменяется, поэтому после успешного выполнения возвращаемого значения не будет. Если замена не удалась, поскольку замена программы процесса не приведет к изменению печатной платы, она не повлияет на родительский процесс, получающий код завершения дочернего процесса.

Напишите следующий код для тестирования:

#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;
}

Скомпилируйте код, запустите его и посмотрите результаты:

изображение-20230831104523903

Поскольку переданная нами программа замены была неправильной, замена программы процесса не удалась, было получено возвращаемое значение -1, а родительский процесс также нормально получил код завершения -1.

Затем напишите следующий код для тестирования:

#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;
}

Скомпилируйте код, запустите его и посмотрите результаты:

изображение-20230831102532182

Видно, что даже если замена программы пройдет успешно, это не повлияет на получение кода выхода дочернего процесса.

функция исключения

//execl函数声明
int execl(const char *path, const char *arg, ...);
  • параметр пути – путь к заменяемой программе
  • параметр arg – переменный параметр, получающий параметры командной строки программы замены, оканчивающийся NULL

Напишите следующий код для тестирования:

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

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

Скомпилируйте код, запустите его и посмотрите результаты:

изображение-20230831102536883

функция execv

//execv函数声明
int execv(const char *path, char *const argv[]);
  • параметр пути – путь к заменяемой программе
  • Параметр argv – получает аргументы командной строки заменяемой программы, завершающиеся NULL

Напишите следующий код для тестирования:

#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;
}

Скомпилируйте код, запустите его и посмотрите результаты:

изображение-20230831104539226

функция execlp

//execlp函数声明
int execlp(const char *file, const char *arg, ...);
  • параметр файла – имя заменяемой программы, программа автоматически будет найдена по пути переменной окружения
  • параметр arg – переменный параметр, получающий параметры командной строки программы замены, оканчивающийся NULL

Напишите следующий код для тестирования:

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

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

Скомпилируйте код, запустите его и посмотрите результаты:

изображение-20230831104738842

функция execvp

//execvp函数声明
int execvp(const char *file, char *const argv[]);
  • параметр файла – имя заменяемой программы, программа автоматически будет найдена по пути переменной окружения
  • Параметр argv – получает аргументы командной строки заменяемой программы, завершающиеся NULL

Напишите следующий код для тестирования:

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

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

Скомпилируйте код, запустите его и посмотрите результаты:

изображение-20230831093047903

исполняемая функция

//execle函数声明
int execle(const char *path, const char *arg, ..., char * const envp[]);
  • параметр пути – путь к заменяемой программе
  • параметр arg – переменный параметр, получающий параметры командной строки программы замены, оканчивающийся NULL
  • Параметр envp – получает переменные среды, передаваемые в программу замены, заканчивается на NULL и передается как перезапись.Приемному процессу будут переданы только переменные среды.

Напишите следующую структуру каталогов файлов:

изображение-20230831100637858

Для тестирования используйте программу myproc и программуotherproc.Содержимое кода следующее.

//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;
}

Используйте программуotherproc для замены программы myproc и передайте только параметр envp, который содержит только одну переменную среды.

Скомпилируйте код, запустите его и посмотрите результаты:

изображение-20230831101123814

Поскольку функция execle использует перезапись для передачи переменных среды, программе замены передается только одна переменная среды.

Пополнить:

  • Вы можете использовать глобальные переменные, environчтобы позволить программе замены получить все переменные среды родительского процесса.
  • Когда процесс оболочки создает дочерний процесс, он также вызывает такой системный интерфейс для передачи переменных среды.

функция execvpe

int execvpe(const char *file, char *const argv[], char *const envp[]);
  • параметр файла – имя заменяемой программы, программа автоматически будет найдена по пути переменной окружения
  • Параметр argv – получает аргументы командной строки заменяемой программы, завершающиеся NULL
  • Параметр envp – получает переменные среды, передаваемые в программу замены, заканчивается на NULL и передается как перезапись.Приемному процессу будут переданы только переменные среды.

Дополнительные знания

Правила именования функций замены программы:

  • Суффикс l – получает аргументы командной строки для программы замены в виде переменных аргументов.
  • суффикс v — получает аргументы командной строки для программы замены в виде массива указателей.
  • суффикс p – введите имя заменяющей программы, и она будет автоматически найдена в пути к переменной среды.
  • Суффикс e — получает переменные среды заменяющей программы в виде массива указателей.

Все вышеперечисленные системные вызовы замены программы процесса представляют собой execveинкапсуляцию функций системных вызовов. Различные инкапсуляции должны быть более подходящими для разных сценариев применения.

рекомендация

отblog.csdn.net/csdn_myhome/article/details/132598332
рекомендация