8.10 exec函数

用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其m a i n函数开始执行。因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。

有六种不同的exec函数可供使用,它们常常被统称为exec函数。这些exec函数都是U N I X进程控制原语。用fork可以创建新进程,用exec可以执行新的程序。exit函数和两个wait函数处理终止和等待终止。这些是我们需要的基本的进程控制原语。在后面各节中将使用这些原语构造另外一些如popen和system之类的函数。

#include <unistd.h>

int execl(const char *pathname, const char * a rg 0, ... /* (char *) 0 */);

int execv(const char *pathname, char *const a rgv [] );

int execle(const char *pathname, const char * a rg 0, ...

/* (char *)0, char *const envp [] */);

int execve(const char *pathname , char *const a rgv [], char *consten vp [] );

int execlp(const char *filename, const char * a rg 0, ... /* (char *) 0 */);

int execvp(const char *filename, char *const a rgv [] );

//六个函数返回:若出错则为- 1,若成功则不返回

可以看出这些函数的区别是前4个取路径名为参数,后2个则取文件名作为参数。

当指定filename时:

• 如果filename中包含/,则就将其视为路径名。

• 否则就按PAT H环境变量,在有关目录中搜寻可执行文件。

PAT H变量包含了一张目录表(称为路径前缀),目录之间用冒号( : )分隔。例如下列n a m e = value环境字符串:

P A T H = / bin : / u s r / bin : / u s r / l o c a l / bin :.

如果execlp和exec v p中的任意一个使用路径前缀中的一个找到了一个可执行文件,但是该文件不是由连接编辑程序产生的机器可执行代码文件,则就认为该文件是一个shell脚本,于是试着调用/bin/sh,并以该filename作为shell的输入。不是可执行代码就是shell脚本。

第二个区别与参数表的传递有关( l表示表( l i s t ),v表示矢量( vector ) )。函数execl、execlp和execle要求将新程序的每个命令行参数都说明为一个单独的参数。这种参数表以空指针结尾。对于另外三个函数( exec v, exec v p和exec v e ),则应先构造一个指向各参数的指针数组,然后将该数组地址作为这三个函数的参数。

在使用ANSI C原型之前,对execl , execle和execlp三个函数表示命令行参数的一般方法是:

char * arg0 , char *arg 1, ..., char *arg n, (char *) 0

应当特别指出的是:在最后一个命令行参数之后跟了一个空指针。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则它将被解释为整型参数。如果一个整型数的

长度与char *的长度不同,exec函数实际参数就将出错。

最后一个区别与向新程序传递环境表相关。以e结尾的两个函数( execle和exec v e)

可以传递一个指向环境字符串指针数组的指针。其他四个函数则使用调用进程中的environ变量为新程序复制现存的环境。(回忆7 . 9节及表7 - 2中对环境字符串的讨论。其中曾提及如果系统支持s e t e n v和p u t e n v这样的函数,则可更改当前环境和后面生成的子进程的环境,但不能影响父进程的环境。)通常,一个进程允许将其环境传播给其子进程,但有时也有这种情况,进程想要为子进程指定一个确定的环境。例如,在初始化一个新登录的shell时, login程序创建一个只定义少数几个变量的特殊环境,而在我们登录时,可以通过shell起动文件,将其他变量加到环境中。在使用ANSI C 原型之前, execle 的参数是:

char * pathname, char *arg 0, ⋯, char *arg n, (char *)0, char *envp[ ]

从中可见,最后一个参数是指向环境字符串的各字符指针构成的数组的指针。而在ANSI C原型中,所有命令行参数,包括空指针, envp指针都用省略号(⋯)表示。

这六个exec函数的参数很难记忆。函数名中的字符会给我们一些帮助。字母p表示该函数取filename作为参数,并且用PAT H环境变量寻找可执行文件。字母l表示该函数取一个参数表,它与字母v互斥。v表示该函数取一个argv[ ]。最后,字母e表示该函数取envp[ ] 数组,而不使用当前环境。表8 - 4显示了这六个函数之间的区别。

函数

pathname

filename

参数表

argv[]

environ

envp[]

execl

·

·

·

execlp

·

·

·

execle

·

·

·

execv

·

·

·

execvp

·

·

·

execve

·

·

·

字母表示

p

v

e

每个系统对参数表和环境表的总长度都有一个限制。在表2 - 7中,这种限制是A R G _ M A X。在P O S I X . 1系统中,此值至少是4 0 9 6字节。当使用shell的文件名扩充功能产生一个文件名表时,可能会受到此值的限制。例如,命令

grep _POSIX_SOURCE /usr/include/*/*.h

在某些系统上可能产生下列形式的shell错误:

arg list too long

前面曾提及在执行exec后,进程ID没有改变。除此之外,执行新程序的进程还保持了原进程的下列特征:

• 进程ID和父进程ID。

• 实际用户ID和实际组ID。

• 添加组ID。

• 进程组ID。

• 对话期ID。

• 控制终端。

• 闹钟尚余留的时间。

• 当前工作目录。

• 根目录。

• 文件方式创建屏蔽字。

• 文件锁。

• 进程信号屏蔽。

• 未决信号。

• 资源限制。

• tms_utime, tms_stime, tms_cutime以及t m s _ u s time值。

对打开文件的处理与每个描述符的exec关闭标志值有关。见图3 - 1以及3 . 1 3 节中对F D _ C L O EXEC的说明,进程中每个打开描述符都有一个exec关闭标志。若此标志设置,则在执行exec时关闭该描述符,否则该描述符仍打开。除非特地用f c n t l设置了该标志,否则系统的默认操作是在exec后仍保持这种描述符打开。

P O S I X . 1明确要求在exec时关闭打开目录流(见4 . 2 1节中所述的o p e n d i r函数)。这通常是由o p e n d i r函数实现的,它调用f c n t l函数为对应于打开目录流的描述符设置exec关闭标志。

注意,在exec前后实际用户ID和实际组ID保持不变,而有效ID是否改变则取决于所执行程序的文件的设置-用户- ID位和设置-组- ID位是否设置。如果新程序的设置-用户- ID位已设置,则有效用户ID变成程序文件所有者的ID,否则有效用户ID不变。对组ID的处理方式与此相同。在很多U N I X实现中,这六个函数中只有一个exec v e是内核的系统调用。另外五个只是库函数,它们最终都要调用系统调用。这六个函数之间的关系示于图8 - 2中。在这种安排中,库函数execlp 和execvp 使用PAT H环境变量查找第一个包含名为filename的可执行文件的路径名前缀。

6个exec函数之间的关系

程序8 - 8例示了exec函数。

#include <unistd.h>

#include <stdlib.h>

#include <sys/wait.h>

char *env_init[] = { "USER=unknown", "PATH=/tmp", NULL };

int main(void)

{

      pid_t pid;

if ((pid = fork()) < 0) {

           perror("fork error");

      } else if (pid == 0) {    /* specify pathname, specify environment */

if (execle("/usr/bin/lscpu", "lscpu", "myarg1",

"MY ARG2", (char *) 0, env_init) < 0)

                 perror("execle error");

      }

if (waitpid(pid, NULL, 0) < 0)

           perror("wait error");

if ((pid = fork()) < 0) {

           perror("fork error");

      } else if (pid == 0) {    /* specify filename, inherit environment */

if (execlp("ls", "ls", ".", (char *) 0) < 0)

                 perror("execlp error");

      }

      exit(0);

}

在该程序中先调用execle,它要求一个路径名和一个特定的环境。下一个调用的是execlp,它用一个文件名,并将调用者的环境传送给新程序。execlp在这里能够工作的原因是因为目录/ bin是当前路径前缀之一。注意,我们将第一个参数(新程序中的a rgv [0])设置为路径名的文件名分量。某些shell将此参数设置为完全的路径名。

在程序8 - 8中要执行两次的程序e c h o a l l示于程序8 - 9中。这是一个普通程序,它回送其所有命令行参数及其全部环境表。

#include <stdio.h>

#include <stdlib.h>

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

{

int i;

char **ptr;

extern char **environ;

for (i = 0; i < argc; i++)    /* echo all command-line args */

           printf("argv[%d]: %s\n", i, argv[i]);

for (ptr = environ; *ptr != 0; ptr++)   /* and all env strings */

           printf("%s\n", *ptr);

      exit(0);

}

转载于:https://www.cnblogs.com/shaoguangleo/archive/2011/10/22/2806020.html

8.10 exec函数相关推荐

  1. python exec函数_Python3 exec 函数

    Python3 exec 函数 描述 exec 执行储存在字符串或文件中的 Python 语句,相比于 eval,exec可以执行更复杂的 Python 代码. 语法 以下是 exec 的语法: ex ...

  2. linux基础知识——exec函数

    1.exec函数 \qquadfork()函数在执行之后,父子进程其实还是执行同一个程序,不同的只是同一个程序的不同分支.如果要想让子进程执行另外一个不同的程序,这时候需要调用exec函数,这时候子进 ...

  3. Python eval 与 exec 函数的区别 - Python零基础入门教程

    目录 一.Python eval 与 exec 函数的区别 二.价值 10 个亿的智能机器人核心代码 三.猜你喜欢 基础 Python 学习路线推荐 : Python 学习目录 >> Py ...

  4. Python eval 与 exec 函数区别 - Python零基础入门教程

    目录 一.Python eval 与 exec 函数的区别 二.价值 10 个亿的智能机器人核心代码 三.猜你喜欢 基础 Python 学习路线推荐 : Python 学习目录 >> Py ...

  5. Python eval 与 exec 函数 - Python零基础入门教程

    目录 一.前言 二.Python eval 与 exec 函数简介 三.Python eval 与 exec 函数使用 1.exec 函数执行代码段 2.exec 函数执行 py 文件 四.猜你喜欢 ...

  6. 程序清单 8-8 exec函数实例,a.out是程序8-9产生的可执行程序

    1 /* 2 ============================================================================ 3 Name : test.c ...

  7. 进程(四)exec函数

    一.为什么要用exec族函数,有什么用  (1)一个父进程希望复制自己,使父.子进程同时执行不同的代码段. 这在网络服务进程种是常见的--父进程等待客户端的服务请求. 当这种请求到达时,父进程调用fo ...

  8. Python exec函数

    标题又有非法字符!服了 Python exec()函数 描述: python exec()函数能执行储存在字符串或文件中的 Python 语句,相比于 eval()函数,exec可以执行更复杂的 Py ...

  9. Python的exec函数

    exec函数介绍 exec函数是Python中的自带函数,与eval相比,有着更大的优越性.例如eval函数只能执行计算数学表达式的结果,exec能执行一句或一段Python代码. exec函数功能 ...

最新文章

  1. 大数据+机器学习#x3D;天下无敌!
  2. 货郎担问题TSP(dp解法)
  3. 大数据分析-裙子颜色蓝黑还是白金是怎么炒作起来的?
  4. 014_Collections常用方法
  5. Hibernate Validator用法
  6. Java中通过命令行启动jar包时指定编码
  7. Tomcat tomcat-users.xml详解
  8. qq2440 cs8900移植
  9. 利用nginx搭建RTMP视频点播、直播、HLS服务器
  10. 用SecureCRT实现真机跟虚拟机的文件传输
  11. 【POJ - 2376】Cleaning Shifts (贪心)
  12. Android找工作系列之自定义View
  13. idea中将java项目中的单个类打包成jar包
  14. 如何掌握openGauss数据库核心技术?秘诀一:拿捏SQL引擎(3)
  15. 2017.10.1 蚯蚓 思考记录
  16. nefu 120 梅森素数
  17. 公司管理系列--最难挖的阿里,最好挖的百度;最难走的360,最易走的腾讯
  18. 解决问题最高明的方法:打开自己
  19. 《软件登记测试报告》可以作为软件第三方检测报告使用吗
  20. kermit的安装、配置、使用 .

热门文章

  1. bzoj 1233: [Usaco2009Open]干草堆tower【dp+单调栈】
  2. C# 语句中的各种单例模式代码
  3. poj 2288 Islands and Bridges_状态压缩dp_哈密尔顿回路问题
  4. 唐骏管理学之感动员工
  5. unittest 出报告 并配合 jenkins,发现有用例错误,但是构建没出现红点 的解决方法
  6. 串口端口被占用的解决方法
  7. 【svn】svn报错:“Previous operation has not finished; run ‘cleanup‘ if it was interrupted“ 的解决方法
  8. zookeeper适用场景:zookeeper解决了哪些问题
  9. Tomcat 跨域问题的解决
  10. Win10系统下软件UI显示不完整解决方案