linux--exec函数族浅析

本篇博客经参考资料1整理、修改而成。

1       exec 函数执行时,是用一个全新的程序代替了当前进程的正文、数据、堆栈段,但是它并没有改变进程ID,执行后进程ID依旧是之前的进程ID。其函数原型如下:

     #include <unistd.h>

       extern char **environ;

       int execl(const char *pathname, const char *arg, ...
                       /* (char  *) NULL */);
       int execlp(const char *file, const char *arg, ...
                       /* (char  *) NULL */);
       int execle(const char *pathname, const char *arg, ...
                       /*, (char *) NULL, char *const envp[] */);
       int execv(const char *pathname, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[],
                       char *const envp[]);

此6个函数按照exec后面的参数可以分为以下3类:

(1)带‘l’的。l是list,是指函数的参数以list的形式出现的,参数形式如下:arg0,arg1...argn,最后一个参数须以(char *)NULL结束。主要函数有execl(), execlp(), execle()。通常情况下,第一个参数是路径名,如果是完整路径名,则执行完整路径名,如果只是文件名,则从进程当前工作目录寻找。

程序1:execl.c

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

int main(int argc, char *argv[])
{

        printf("before execl\n");
        if(execl("/bin/ls","ls","-l",(char *)0)==-1)
                {
        fprintf(stderr,"execl error ,error is %d,msg is %s\n",errno,strerror(errno));
                }
        printf("after execl\n");
        exit(0);
}

程序执行后,会用全新的程序替代当前进程,执行结果如下:

可以看出,程序执行结束后,"after execl" 没有打印出来,因为进

程上下文已被切换成新的,原程序不再执行。如果pathname 使用文件名,当从当前工作目录查找,如果查找不到,便会出错。

修改execl.c源文件中的execl行为(execl2.c):

 if(execl("ls","ls","-l",(char *)0)==-1)

显示找不到文件,后main继续执行,打印出了“after execl”。如果更改工作目录为/bin,因为/bin目录有ls的执行文件,所以程序执行结果一样成功,类似第一个结果截图。

(2)带‘v’的,v 是vector,代表参数是以vector的形式出现,参数个数总数为2个,第二个参数为指针数组char *const argv[],代表了后面的参数以指数组的形式出现,并且以空指针NULL结束。主要函数有execv(), execvp(), execvpe()。第一个参数pathname的意义与execl的第一个参数pathname 相同。

源程序execv.c

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

int main(void)
{

        printf("before execl\n");
        char *argv[]={"ls","-l",(char *)0};
        if(execv("/bin/ls",argv)==-1)
                {
        fprintf(stderr,"execv error ,error is %d,msg is %s\n",errno,strerror(errno));
                }
        printf("after execl\n");
        exit(0);
}

执行结果如下:

(3)带‘p’的,p 代表“PATH”,是指程序的第一个参数filename ,是从当前环境变量PATH值寻找,即如果第一个参数不是完整路径的话,将从PATH寻找可执行文件,也包括当前工作目录。如果第一个参数中有‘/’,则PATH寻找过程被忽略。主要函数有:execlp(), execvp(), execvpe()。

源程序execlp.c

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

int main(int argc, char *argv[])
{

        printf("before execl\n");
        if(execlp("ls","ls","-l",(char *)0)==-1)
                {
        fprintf(stderr,"execlp error ,error is %d,msg is %s\n",errno,strerror(errno));
                }
        printf("after execl\n");
        exit(0);
}

执行结果如下

因为新建的文件越来越多,所以输出结果会相应的增加。

(4)带‘e’的。'e'代表environment,是指程序将当前的环境变量替换为参数char *const envp[]指向的环境表,并执行程序。这样的函数都有带有一个参数char *const envp[],出现在函数参数表中的位置均为最后一个位置。主要的函数有两个execle(), execvpe(),就是其它四个函数是用调用进程的环境表environ来执行,而这两个函数是用envp 代替environ 来执行,envp 是一个指针数组,以NULL 结束。

以下程序先打印当前环境表envrion的值,然后创建新环境表,并打印出来。

源程序:printenv.c

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

extern char **environ;

int main(void)
{
char **p=environ;
while(*p)
{
printf("%s\n",*p);
p++;
}
exit(0);
}

输出执行文件,gcc printenv.c -o printenv ,

源程序execl3.c,先打印当前进程的环境表

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

int main(int argc, char *argv[])
{

        printf("before execl\n");
        if(execl("printenv","printenv",(char *)0)==-1)
                {
        fprintf(stderr,"execl error ,error is %d,msg is %s\n",errno,strerror(errno));
                }
        printf("after execl\n");
        exit(0);
}

输出结果是进程中当前环境表的值

然后利用execle 函数打印新环境表的值

源程序execle.c

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

int main(int argc, char *argv[])
{

        printf("before execl\n");
        char * envp[]={"AA=11","BB=22","cc=33",NULL};
        if(execle("printenv","printenv",(char *)0,envp)==-1)
                {
        fprintf(stderr,"execle error ,error is %d,msg is %s\n",errno,strerror(errno));
                }

        printf("after execl\n");
        exit(0);
}

输出结果如下:

可以看到环境表已经替换。

2 函数返回值。

上述6个函数,没有正确返回值,只有出错返回值,出错时,函数返回-1,并赋值errno,常见的错误码如下:

(1)E2BIG:envp,arg0等参数表太大

(2)EACCES :第一个参数执行权限不允许

(3)ENOENT:第一个参数文件或路径不存在

(4)ENOEXE 执行文件出错

3 补充

exec函数执行成功时,执行新程序的进程除了进程ID 不变外,还有下面项保持不变。

(1)进程ID 和父进程ID

(2)实际用户ID和实际组ID

(3)附加组ID

(4)进程组ID
(5)会话ID

(6)控制终端

(7)闹钟尚预留时间

(8)当前工作目录

(9)根目录

(10)文件模式创建屏蔽字

(11)文件锁

(12)进程信号屏蔽

(13)未处理信号

(14)资源限制

(15)tms_utime、tsm_stime、tms_cutime、tms_cstime

  (16)environ(带‘e’函数的除外)。

 

 

参考资料:

(1)https://www.cnblogs.com/mickole/p/3187409.html

(2)https://man7.org/linux/man-pages/man3/execl.3.html

(3)https://man7.org/linux/man-pages/man2/execve.2.html

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值