进程替换讲解

发布于:2025-05-15 ⋅ 阅读:(6) ⋅ 点赞:(0)

1. 基本概念

1.1 进程替换 vs. 进程创建

  • 进程创建:使用fork()clone()等系统调用创建一个新的子进程,子进程是父进程的副本,拥有相同的代码和数据。
  • 进程替换:使用exec系列函数在当前进程中加载并执行一个新的程序,替换掉当前进程的映像,但保留PID、文件描述符等资源。

1.2 exec系列函数

exec系列函数用于在当前进程中执行一个新程序。常见的exec函数包括:

这些函数的命名规则如下:

  • 前缀exec
  • 中间部分
    • l(list):参数以列表形式传递。
    • v(vector):参数以数组形式传递。
  • 后缀
    • e:允许传递环境变量。
    • p:使用PATH环境变量来查找可执行文件。

2. 常用的exec函数

2.1 execl()

函数原型:

 

#include <unistd.h>

int execl(const char *path, const char *arg, ... /* (char  *) NULL */);

参数:

  • path:要执行的可执行文件的路径。
  • arg:第一个参数,通常是程序名。
  • ...:可变参数列表,以NULL结尾。

 例子:

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

int main() {
    printf("Before execl\n");
    execl("/bin/ls", "ls", "-l", NULL);
    // 如果execl成功,以下代码不会执行
    perror("execl failed");
    return 1;
}

2.2 execv()

函数原型:

#include <unistd.h>

int execv(const char *path, char *const argv[]);

参数:

  • path:要执行的可执行文件的路径。
  • argv:参数数组,以NULL结尾。

例子:

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

int main() {
    char *args[] = { "ls", "-l", NULL };
    printf("Before execv\n");
    execv("/bin/ls", args);
    // 如果execv成功,以下代码不会执行
    perror("execv failed");
    return 1;
}

2.3 execlp()

函数原型:

#include <unistd.h>

int execlp(const char *file, const char *arg, ... /* (char  *) NULL */);

参数:

  • file:可执行文件名,会在PATH环境变量中查找。
  • arg:第一个参数,通常是程序名。
  • ...:可变参数列表,以NULL结尾。

例子:

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

int main() {
    printf("Before execlp\n");
    execlp("ls", "ls", "-l", NULL);
    // 如果execlp成功,以下代码不会执行
    perror("execlp failed");
    return 1;
}

2.4 execvp()

函数原型:

#include <unistd.h>

int execvp(const char *file, char *const argv[]);

参数:

  • file:可执行文件名,会在PATH环境变量中查找。
  • argv:参数数组,以NULL结尾。

例子:

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

int main() {
    char *args[] = { "ls", "-l", NULL };
    printf("Before execvp\n");
    execvp("ls", args);
    // 如果execvp成功,以下代码不会执行
    perror("execvp failed");
    return 1;
}

2.5 execle()

函数原型:

#include <unistd.h>

int execle(const char *path, const char *arg, ... /* (char  *) NULL, char * const envp[] */);

参数:

  • path:要执行的可执行文件的路径。
  • arg:第一个参数,通常是程序名。
  • ...:可变参数列表,以NULL结尾。
  • envp:环境变量数组。

例子:

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

int main() {
    char *env[] = { "PATH=/bin", NULL };
    printf("Before execle\n");
    execle("/bin/ls", "ls", "-l", NULL, env);
    // 如果execle成功,以下代码不会执行
    perror("execle failed");
    return 1;
}

2.6 execvpe()

#include <unistd.h>

int execvpe(const char *file, char *const argv[], char *const envp[]);
 参数
  • file:要执行的可执行文件的名称。如果 file 中包含斜杠 (/),则将其视为路径名,直接尝试执行。(如果 file 不包含斜杠,则会在 PATH 环境变量指定的目录中查找可执行文件。)

  • argv:参数数组,以 NULL 结尾。argv[0] 通常是程序名。

  • envp:环境变量数组,以 NULL 结尾。每个环境变量以 "NAME=VALUE" 的形式表示。

例子:

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

int main() {
    // 要执行的程序及其参数
    char *args[] = { "printenv", "MY_VAR", NULL };
    
    // 自定义环境变量
    char *env[] = { "MY_VAR=HelloWorld", "PATH=/bin:/usr/bin", NULL };
    
    printf("Before execvpe\n");
    
    // 执行程序
    if(execvpe("printenv", args, env) == -1) {
        perror("execvpe failed");
        exit(1);
    }
    
    // 如果 execvpe 成功,以下代码不会执行
    return 0;
}

 

 

 

2.7 execve()(这个上面查库没有,要单独查)

函数原型:

 

 

参数:

  • pathname:要执行的可执行文件的路径。
  • argv:参数数组,以NULL结尾。
  • envp:环境变量数组。

例子:

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

int main() {
    char *args[] = { "ls", "-l", NULL };
    char *env[] = { "PATH=/bin", NULL };
    printf("Before execve\n");
    execve("/bin/ls", args, env);
    // 如果execve成功,以下代码不会执行
    perror("execve failed");
    return 1;
}

 

3. 错误处理

大多数exec函数在成功时不会返回,如果失败则返回-1,并设置errno变量。常见的错误包括:

  • ENOENT:文件不存在。
  • EACCES:权限不足。
  • ENOEXEC:可执行文件格式错误。

例子:

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

int main() {
    if(execl("/bin/ls", "ls", "-l", NULL) == -1) {
        perror("execl failed");
    }
    // 如果execl成功,以下代码不会执行
    return 1;
}