27.Linux/Unix 系统编程手册(上) -- 程序的执行

1.执行新程序:execve(const char *pathname, char *const argv[], char *const envp[])
	系统调用 execve 可以将新程序加载到某一进程的内存空间内。这一操作过程中,将丢弃旧的程序,
  而进程的栈,数据以及堆段会被新程序的相应部件所替换。
    Linux 所持有的 /proc/PID/exe 是一个符号链接,包含PID 对应进程中正在运行的可执行文件的绝对路径。
    如果对 pathname 所指定的程序文件设置了 set-user-ID 权限位,那么系统调用此执行文件时将进程的有效用户
  设置为程序文件的属主ID,利用这一机制,可令用户在运行特定程序时临时获得特权。
    由于是将调用程序取而代之,对 execve()的成功调用将永不返回。也无需检查execve()的返回值,因为该值总是-1.

    ELF(executable and linking format) 是一种广为实现的标准,描述了可执行文件的布局。在执行期间,进程映像
  通常是由可执行文件的各段构造而成的。不过,ELF 规格也允许定义一个解释器来运行程序。如果定义了解释器,内核则基于
  指定的解释器可执行文件的各段来构建进程映像,转而由解释器负责加载和执行程序。


2.exec()库函数
	execle();
	execlp();
	execvp();
	execv();
	execl();

	p(path) 结尾的,可以只提供文件名,然后在环境变量 PATH 中查找。
	有 l(list)的,要求在调用时以字符串列表形式来指定参数,而不适用数组来描述 argv 列表。
	有 v 的,则允许开发者通过 envp 为新程序显示指定环境变量。

3.解释器脚本
	所谓解释器,就是能够读取并执行文本格式命令的程序。各种Unix Shell,以及诸如 awk,sed,perl,python和ruby 之类的程序,
  都属于解释器。除了能够交互式的读取和执行命令之外,解释器通常还具备一种能力:从被称为脚本的文本文件中读取和执行命令。
    Unix 内核运行解释器脚本的方式和二进制程序无异,前提是脚本必须满足下面2点要求:
    	1.首先,必须赋予脚本文件可执行权限
    	2.其次,文件的起始行必须指定运行脚本解释器的路径名,格式如下:
    	  #! 解释器路径 参数...
    	  字符 #1 必须置于起始行处,这2个字符串和解释器路径名之间可以以空格分隔。在解释该路径时不会使用环境变量PATH,所以
    	一般应采用绝对路径。解释器路径名后还可以跟随可选参数。

4.文件描述符和exec()
	默认情况下,由 exec() 的调用程序所打开的所有文件描述符在 exec() 执行过程中依然会保持打开状态,且在新程序中依然有效。
  这通常很实用,因为调用程序可能会以特定的描述符来打开文件,而在新程序中这些文件将自动有效,无需再了解文件名或是把它们重新打开。
    ls /tmp > dir.txt
    shell 运行该命令,可能执行了如下步骤:
    1.调用 fork 创建子进程,子进程也会运行 shell 的一份拷贝。
    2.子 shell 以描述符1打开文件 dir.txt 用于输出。可能会采取以下任意方式:
    	1.子shell关闭描述符1,然后打开 dir.txt。因为 open 在为描述符取值时,总是取最小值。
    	2.shell 打开 dir.txt,获取一个新的描述符。用 dup2 强制将标志输出复制为新描述符的副本,关闭新描述符。
    3.子 shell 执行程序 ls. ls 将其结果输出到标志输出,即 dir.txt。

    此处对 shell 处理 IO 重定向的解释有所简化。特使是某些命令,如 shell 内置命令,是由 shell 直接运行的,并未调用 fork或者 exec。
  将某一命令实现为 shell 内置命令,不外乎2个目的:效率以及对 shell 产生副作用。一些频繁使用的命令(如 pwd,echo)逻辑都很简单,放在shell
  内部实现效率会更高。将其他命令至于内置shell实现,则是希望影响shell进程的运行。例如,cd 命令必须改变shell自身的工作目录,故而不应在一个独立
  进程中执行。

5.执行时关闭(close-on-exec)标志(FD_CLOEXEC)
	在执行 exec 之前,程序有时候需要确保关闭某些特定的文件描述符。尤其是在特权进程中调用 exec来启动一个未知程序时,亦或者启动程序并不需要使用这些
  已打开的文件描述符。

6.信号与 exec
	exec 在执行时会将现有的进程的文本的丢弃。该文本段可能包含了由调用进程创建的信号处理程序。既然处理器不知所踪,内核会将所有已设置信号的处理重置为
  SIG_DFL。而对其他所有信号的处置则不变。
    老程序的数据段,堆以及栈悉数被毁,这也意味着通过 sigaltstack()所创建的任何信号备选栈都丢失。
    在调用 exec 期间,进程信号掩码以及挂起信号的设置均得以保存。这一特性允许新程序的信号进行阻塞和排队处理。

7.执行 shell 命令 : system()
	程序可通过调用 system()函数来执行任意的 shell 命令。
	使用 system() 运行的命令需要至少创建2个进程。一个用于运行shell,另外一个或多个用于shell所执行的命令。
	当设置了用户ID和组ID的程序在特权模式下运行时,决不能调用 system()。



fexecve();

猜你喜欢

转载自blog.csdn.net/enlyhua/article/details/82926887