Linux 执行新程序:execve() 函数

系统调用execve()函数作用

在Linux程序中,通过调用execve(),进程能够以全新程序来替换当前运行的程序。再次过程中,将丢弃旧有程序,进程的栈.数据以及堆段会被新程序所替换。这个 exec 函数族就提供了一个在进程中启动另一个程序执行的方法。
它根据指定的文件名或目录名找到可执行文件,并用它来代替当前进程的执行映像。也就是说,exec调用并没有生成新进程,一个进程一旦调用 exec函数,它本身就“死亡”了,系统把代码段替换成新程序的代码,放弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,惟一保留的就是进程的 ID。也就是说,对系统而言,还是同一个进程,不过执行的已经是另外一个程序了。

execve()函数原型

#include <unistd.h>
int execve(const char *filename, char *const argv[],
                  char *const envp[]);
  1. filename:包含准备载入当前进程空间的新程序的路径名。既可以是绝对路径,又可以是相对路径。
  2. argv[]:指定了传给新进程的命令行参数,该数组对应于c语言main函数的argv参数数组,格式也相同,argv[0]对应命令名,通常情况下该值与filename中的basename(就是绝对路径的最后一个)相同。
  3. envp[]:最后一个参数envp指定了新程序的环境列表。参数envp对应于新程序的environ数组。

实例1

下面的每个代码我都放到了github上,欢迎大家fork/star
GeneralSandman
t_execve.c

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<string.h>
int main(int argc,char * argv[]){
    char * argVec[10];
    char * envVec[]={"环境变量1","环境变量2",NULL};
    argVec[0]=argv[0];
    argVec[1]=argv[1];
    argVec[2]="参数1";
    execve(argv[1],argVec,envVec);
    printf("the progress can't to here\n");
    exit(EXIT_SUCCESS);
}

envargs.c
下面的每个代码我都放到了github上,欢迎大家fork/star
GeneralSandman

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
extern char ** environ;
int main(int argc,char * argv[]){
    int i=0;
    char ** ep;
    printf("new progress\n");
    printf("参数\n");
    for(i=0;i<argc;i++)
        printf("\t%s\n",argv[i]);
    printf("环境变量:\n");
    for(ep=environ;*ep!=NULL;ep++)
        printf("\t%s\n",*ep);
    printf("new progress over\n");
    exit(EXIT_SUCCESS);
    return 0;
}

运行结果

这里写图片描述

程序说明

运行t_execve程序,会调用execve()函数,函数将会调用进程argv[1],也就是调用envargs,并将自己的环境变量,参数传递给他。我们发现,printf(“the progress can’t to here\n”); 永远不会被执行(除非调用execve()失败),因为调用execve(),会转到新的进程,自己会被“杀死”;

实例2

t_execve2.c
下面的每个代码我都放到了github上,欢迎大家fork/star
GeneralSandman

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
int main(int argc,char * argv[],char ** environ){
    pid_t pid;
    printf("the example!!!\n");
    switch(fork()){
    case -1:
        printf("fork error\n");
        exit(EXIT_FAILURE);
    case 0:
        printf("child is running\n");
        printf("child pid=%d, child parent pid=%d\n",getpid(),getppid());
        printf("child uid=%d, child gid=%d\n",getuid(),getpid());
        execve(argv[1],argv,environ);
        printf("child can't in here\n");
        break;
    default:
        wait(NULL);
        printf("parent is running\n");
        break;
    }
    exit(EXIT_SUCCESS);
}

envargs2.c
下面的每个代码我都放到了github上,欢迎大家fork/star
GeneralSandman

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<string.h>
int main(int argc,char * argv[],char ** environ){
    int i;
    printf("running after the execve()\n");
    printf(" pid=%d,  parent pid=%d\n",getpid(),getppid());
    printf(" uid=%d,  gid=%d\n",getuid(),getpid());
    printf("the immage over\n");
    exit(0);
}

运行结果

这里写图片描述

程序说明

运行t_execve2程序,fork()之后,子进程会调用execve()函数,而父进程会等待子进程退出(也就是等待envargs2退出)。我们发现:执行新程序保持了原来进程的进程 ID、父进程ID、实际用户 ID 和实际组 ID。同时还可以看到,当调用新的可执行程序后,原有的子进程的映像被替代,不再被执行。

执行新程序后的进程除了保持原来的进程 ID、父进程 ID、实际用户 ID 和实际组 ID 之外,进程还保持了许多原有的特征,主要有:

  1. 当前工作目录
  2. 根目录
  3. 创建文件时使用的屏蔽字
  4. 进程信号屏蔽字
  5. 未决警告
  6. 和进程相关的使用处理器的时间
  7. 控制终端
  8. 文件锁

exec族

有 6 个以 exec 开头的函数族,他们之间的语法有细微的差别,函数原型如下所示:

  1. int execl(const char *path, const char *arg, …)
  2. int execv(const char *path, char *const argv[])
  3. int execle(const char *path, const char *arg, … , char *const envp[])
  4. int execve(const char *path, char *const argv[], char *const envp[])
  5. int execlp(const char *file, const char *arg, …)
  6. int execvp(const char *file, *const argv[])

区别

这里写图片描述

实际上有关exec是一个函数族,包括execle,execlp,execvp,execv,execl但是他们具体的实现都是调用execve()之上。它们的区别就在于对路径名,参数以及环境变量的指定上。下面分别从这三个方面来区分这几个函数:
- 路径名:带p的表示可以通过环境变量PATH去查找,所以我们可以不用绝对路径,比如execlp和execvp就可以直接用filename。
- 参数:带l的execle()和execlp()以及execl()要求在调用中以字符串形式指定参数。首个参数相当于新程序main中的argv[0],因而通常与filename中的basename相同(就是绝对路径的最后一个)。
- 环境变量:以e结尾的允许我们通过envp为新程序显式的指定环境变量,其中envp必须以NULL结尾。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值