unix环境高级编程第8章 进程控制 下Word格式文档下载.docx
《unix环境高级编程第8章 进程控制 下Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《unix环境高级编程第8章 进程控制 下Word格式文档下载.docx(32页珍藏版)》请在冰豆网上搜索。
![unix环境高级编程第8章 进程控制 下Word格式文档下载.docx](https://file1.bdocx.com/fileroot1/2022-12/29/f719cb45-13a5-4d2c-bfe9-ac8e2e21be1b/f719cb45-13a5-4d2c-bfe9-ac8e2e21be1b1.gif)
根目录
文件方式创建屏蔽字
文件锁
进程信号
帘为?
末决信号
资源限制
tms-utime,tms-stime,tms-cutime以及tms-ustime值
对打开文件的处理与每个描述符的进程中每个在exec时关闭标志值有关。
回忆图3
2以及3
13节中对PD-CLOEXEC的说明,打开描述符都有一个在exec时关闭标志。
若此标志
设置,则
在执行exec时关闭该描述符,否则该描述符的打开除非特地用fcntl设置了该标志
,否则系
统的默认操作是在exec后仍保持这种描述符打开。
POSIX1明确要求在exec时关闭打开目录流。
(回忆42)节中所述的opendir函数
。
)这通常
是由opendir函数实现的,它调用fcntl函数为对应于打开目录流的描述符设置在e
xec时关闭
标志。
注意,在exec前后实际用户ID和实际组ID保持不变,而有效ID是否改变则取决于所
执行程序
的文件的设置用户ID位和设置组ID位是否设置。
如果新程序的设置用户ID位已设置
,则有效
用户ID变成程序文件属主的ID,否则有效用户ID不变。
对组ID的处理方式与此相同
在很多Unix实现中,这六个函数中只有一个execve是系统核的系统调用。
另外五个
只是库函
数,它们最终都要调用系统调用。
这六个函数之间的关系示于图86中。
在这种安
排中,库
函数execlp和execvp使用PATH环境变量查找第一个包含名为filename的可执行文件
的路径名
前缀。
P211
图86〓六个exec函数之间的关系
实际
程序88例示了exec函数。
程序88〓exec函数的实例
在该程序中先调用execle,它要求一个路径名和一个特定的环境。
下一个调用的是
execlp,
它用一个文件名,并将调用者的环境传送给新程序。
execlp在这里能够工作的原因
是因为目
录/home/stevens/bin是当前路径前缀之一。
注意,我们将第一个参数(在新程序中
的argv[
0])设置为路径名的文件名分量。
某些shell将此参数设置为完全的路径名。
在程序88中要执行两次的程序echoall示于程序89中。
这是一个普通程序,它
回送其所
有命令行参数及其全部环境表。
P212
程序89〓回送所有命令行参数和所有环境字符串
执行程序88时得到:
$
aout
argv[0]:
echoall
argv[1]:
myarg1
argv[2]:
MY
ARG2
USER=unknown
PATH=/tmp
only
1
arg
USer=stevens
HOME=/home/stevens
LOGNAME=stevens
31
more
lines
that
aren'
t
shown其中31行没有显示
EDITOR=/usr/ucb/vi
注意,shell提示出现在第二个exec打印argv[0]和argv[1]之间。
这是因为父
进程并不
等待该子进程结束。
810〓更改用户ID和组ID
可以用setuid函数设置实际用户ID和有效用户ID。
与此类似,可以用setgid函数设
置实际组
ID和有效组ID。
#include
<
sys/typesh>
unistdh>
int
setuid(uid
迹茫模*常病絫
uid);
setgid(gid
gid);
Both
return:
0
if
OK,-1
on
error两个函数返回:
若成功为0,出错为-1
关于谁能更改ID有若干规则。
现在先考虑有关改变用户ID的规则(在这里关于用户
ID所说明
的一切都适用于组ID)。
1若进程具有超级用户特权,则setuid函数将实际用户ID,有效用户ID,以前保
存的设置
用户ID设置为uid。
2若进程没有超级用户特权,但是uid等于实际用户ID或保存的设置用户ID,则s
etuid只将
有效用户ID设置为uid。
不改变实际用户ID和保存的设置用户ID。
3如果上面两个条件都不满足,则errno设置为EPERM,并出错返回。
在这里假
摇迹茫模*常病絇OSIX
迹茫模*常病絊AVED
迹茫模*常病絀DS为真。
如果没有
提供这种功能,则上面所说的关于保存的设置用户ID的部分都无效。
FIPS
151-1要求此功能。
SVR4支持
迹茫模*常病絇OSIX
迹茫模*常病絀DS功能。
关于系统核所维护的三个用户ID,还要注意下列几点:
1只有超级用户进程可以更改实际用户ID。
通常,实际用户ID是在用户登录时,
由login(1
)程序设置的,而且决不会改变它。
因为login是一个超级用户进程,当它调用set
uid时,设
置所有三个用户ID。
2仅当对程序文件设置了设置-用户-ID位时,exec函数再设置有效用户ID。
如果
设置-用户
-ID位没有设置,则exec函数不会改变有效用户ID,而将其维持为原先值。
任何时
候都可以
调用setuid,将有效用户ID设置为或者实际用户ID,或者保存的设置-用户-ID。
自
然,不能
将有效用户ID设置为任一随机值。
3保存的设置-用户-ID是由exec从有效用户ID复制的。
在exec按文件用户ID设置
了有效用
户ID后,即进行这种复制,并将此副本保存起来。
图87摘要列出了改变这三个用户ID的不同方法。
P214
图87〓改变三个用户ID的不同方法
注意,用82节中所述的getuid和geteuid函数只能获得实际用户ID和有效用户ID
的当前值
我们不能获得所保存的设置-用户-ID的当前值。
实例
为了说明保存的设置-用户-ID特征的用法,让我们先观察一个使用该特征的程序。
我们所观
察的是贝克莱tip
(1)程序(系统V的cu
(1)程序与此类似。
)这两个程序都连接到一个
远程系统
,或者是直接连接,或者是拨号一个调制解调器。
当tip使用一个调制解调器时,
它必须通
过使用锁文件来独占使用它。
此锁文件是与UUCP共享的,因为这两个程序可能在同
时要使用
同一调制解调器。
将发生下列步骤:
1tip程序文件是由用户uucp拥有的,并且其设置-用户-ID位已设置。
当exec此程
序时,则
关于用户ID得到下列结果:
实际用户ID=我们的用户ID
有效用户ID=UUCP
保存设置用户ID=UUCP
2tip存取所要求的锁文件。
这些锁文件是由名为UUCP的用户所拥有的,因为有效
用户ID是
UUCP,所以tip可以存取这些锁文件。
3tip执行setuid(getuid())。
因为tip不是超级用户进程,所以这仅仅改变有效
用户ID。
此时得到:
实际用户ID=我们的用户ID(未改变)
有效用户ID=我们的用户ID(未改变)
保存设置用户ID=UUCP(未改变)
现在,tip进程是以我们的用户ID作为其有效用户ID而运行的。
这就意味着能存取
的只是我
们通常可以存取的,没有附加的存取权。
4当执行完我们所需的操作后,tip执行setuid(uucpuid),其中uucpuid是用户u
ucp的数值
用户ID(tip很可能在起动时调用geteuid,得到uucp的用户ID,然后将其保存起来
,我们并
不认为tip会搜索口令字文件以得到这一数值用户ID。
)因为setuid的参数等于保存
的设置-
用户-ID,所以这种调用是许可的(这就是为什么需要保存的设置-用户-ID的原因。
)现在得
到:
实际用户ID=我们的用户ID(末改变)
有效用户ID=uucp
保存设置用户ID=uucp(末改变)
5tip现在可对其锁文件进行操作以释放它们,因为tip的有效用户ID是。
以这种方法使用保存的设置-用户-ID,在进程的开始和结束部分就可以使用由于程
序文件的
设置用户ID而得到的额外的优先权。
但是,进程在其运行的大部分时间只具有普通
的许可权
如果进程不能在其结束部分切换回保存的设置-用户-ID,那么就不得不在全部运
行时间都
保持额外的许可权(这可能会造成麻烦)。
让我们来看一看如果在tip运行时为我们生成一个shell进程(先fork,然后exec)将
发生什么
因为实际用户ID和有效用户ID都是我们的普通用户ID(上面的第三步),所以该s
hell没有
额外的许可权。
它不能存取tip运行时设置成uucp的保存的设置-用户-ID,因为该
shell的保
存的设置-用户-ID是由exec复制有效用户ID而得到的。
所以在执行exec的子进程中
,所有三
个用户ID都是我们的普通用户ID。
如若程序是设置-用户-ID为root,那么我们关于
tip如何使
用setuid所作的说明是不正确的。
因为以超级用户特权调用setuid就会设置所有三
个用户ID
使上述实例按我们所说明的进行工作,只需setuid设置有效用户ID。
setreuid和setregid函数
43+BSD支持函数,其功能是交换实际用户ID和有效用户ID的值。
sys/sypesh>
setreuid(uid
ruid,uid
euid);
setregid(gid
rgid,gid
egid);
error〓两个函数返回:
其作用很简单:
一个非特权用户总能交换实际用户ID和有效用户ID。
这就允许一个
设置-用
户-ID程序转换成只具有用户的普通许可权,以后又可再次转换回设置-用户-ID所
得到的额
外许可权。
POSIX1引进了保存的设置-用户-ID特证后,其作用也相应加强,它也
允许一个
非特权用户将其有效用户ID设置为保存的设置-用户-ID。
SVR4在其BSD兼容库中也提供这两个函数。
43BSD并没有上面所说的保存的设置-用户-ID功能。
它用setreuid和setregid来
代替。
这
就允许一个非特权用户前、后交换这二个用户ID的值,而43BSD中的tip程序就是
用这种功
能编写的。
但是要知道,当此版本生成shell进程时,它必须在exec之前,先将实
际用户ID
设置为普通用户ID。
如果不这样做的话,那么实际用户ID就可能是uucp(由setreu
id的交换
操作造成。
)然后shell进程可能会调用setreuid交换两个用户ID值并取得uucp许可
权。
作为
一个保护性的程序设计措施,tip将子进程的实际用户ID和有效用户ID都设置成普
通用户ID
seteuid和setegid函数
在对POIX1的建议更改中包含了两个函数seteuid和setegid。
它们只更改有效用
户ID和有
效组ID。
seteuid(uid
setegid(gid
一个非特权用户可将其有效用户ID设置为其实际用户ID或其保存的设置-用户-ID。
对于一个
特权用户则可将有效用户ID设置为uid。
(这区别于setuid函数,它更改三个用户I
D。
)这一
建议更改也要求支持保存的设置-用户-ID。
SVR4和43+BSD都支持这两种函数。
图88〓摘要列出了本节所述的修改三个不同的用户ID的各个函数。
P217
图88〓设置不同的用户ID的各函数摘要
组ID
至此,在本章中所说明的一切都以类似方式适用于各个组ID。
添加组ID不受setgi
d函数的影
响。
811〓解释器文件
SVR4和43+BSD都支持解释器文件。
这种文件是文本文件,其起始行的形式是:
#!
pathname[optional-argument]
在骛叹号和pathname之间的空格是可任选的。
最常见的是以下列行开始:
#!
/bin/sh
pathname通常是个绝对路径名,对它不进行什么特殊的处理(不使用PATH进行路径
搜索)。
对
这种文件的识别是由系统核作为exec系统调用处理的一部分来完成的。
系统核使调
用exec函
数的进程实际执行的文件并不是该解释器文件,而是在该解释器文件的第一行中p
athname所
指定的文件。
一定要将解释器文件(文本文件,它以#!
开头)和解释器(由该解释器
文件第一
行中的pathname指定)区分开来。
要了解,很多系统对解释器文件第一行有长度限止(32个字符)。
这包括#!
,path
name,选
择参数以及空格数。
让我们观察一个实例,从中了解当被执行的文件是个解释器文件时,系统核对exe
c函数的参
数及该解释器文件第一行的可任选参数作何种处理。
程序810调用execl执行一个
解释器文
件。
P218
程序810〓执行一个解释器文件的程序
下面先显示要被执行的该解释器文件(只有一行)的内容,接着是运行程序810的
结果。
cat
/home/stevens/bin/testinterp
#!
/home/stevens/bin/echoarg
foo
/home/stevens/bin/echoarg
argv[3]:
argv[4]:
程序ecboarg(解释器)回送每一个命令行参数。
(它就是程序72。
)注意,当系统
核exec该
解释器(/home/stevens/bin/ecboarg)时,argv[0]是该解释器的路径名,argv[
1]是解
释器
文件中的可任选择参数,其余参数是路径名(/bome/stevens/bin/testinterp),以
及程序8
10中调用execl的第二和第三个参数(myarg1,和MY
ARG2)。
调用execl时的argv[
1]和arg
v[2]和argv[3]已向右移了两个位置。
注意,系统核取了execl中的路径名以代替第一个参数(testinterp),因为一般路
径名包含
了较第一个参数更多的信息。
在解释器路径名(pathname)后可跟随任选参数,它们常用于为支持-f任选项的程序
指定该任
选项。
例如,可以以下列方式执行awk
(1)程序:
awk
-f
myfile
它告诉awk从文件myfile中读awk程序
在很多系统中,有awk的两个版本。
awk常常被称为"
老awk"
,它是与version
7一起
分发的
原始版本。
nawk(新awk)包含了很多增强功能,对应于在Aho,Kernighan和Weinber
ger[1988
]
中说明的语言。
此新版本提供了对命令行参数的存取,这是下面的例子所需的。
S
VR4提供了
两者,老的awk既可用awk也可用oawk调用,但是SVR4已说明在将来的版本中awk将
是nawk。
P
OSIX2章节中将新awk语句就称为awk,这正是在本书中所使用的。
在解释器文件中使用-f任选项,使我们可以写出:
/bin/awk
-f
(在此解释器文件中后随awk程序)
例如,程序811是一个在/usr/local/bin/awkexample解释器文件中的程序。
程序811〓在一个解释器文件中的awk程序。
如果路径前缀之一是/usr/local/bin,则可以下列方式执行程序811(假定我们已
打开了该
文件的执行位):
awkexample
filel
FILENAME2
f3
ARGV[0]=/bin/awk
ARGV[1]=file1
ARGV[2]=FILENAME2
ARGV[3]=f3
执行/bin/awk时,其命令行参数是:
/bin/awk
/usr/local/bin/awkexample
file1
解释器文件的路径名(/usr/local/bin/awkexample)传送给解释器。
因为不能期望
该解释器(
在本例中是/bin/awk)会使用PATH变量定位该解释器文件,所以只传春路径名中的
文件名是
不够的。
当awk读解释器文件时,因为'
#'
是awk的注释字符,所以在awk读解释器
文件时
,它忽略第一行。
可以用下列命令验证上述命令行参数。
su〓〓成为超级用户
Password:
〓输入超级用户口令
#
mv/bin/awk
/bin/awksave〓保存原先的程序
cp
/bin/awk〓暂时代换它
suspend〓用作业控制挂起超级用户shell
[1]+Stopped〓〓su
/bin/awk
/usr/local/bin/awkexample
file1
FILENAME2
argv[5]:
fg〓〓用作业控制恢复超级用户shell
su
mv
/bin/awksave
/bin/awk〓恢复原先的程序
exit〓终止超级用户shell
在此例子中,解释器的-f任选项是需要的。
正如前述,它告诉awk在什么地方得到
awk程序
如果在解释器文件中删除-f任选面,则其结果是:
/bin/awk:
syntax
error
at
source
line
1
context
if
>
/user/local
/bin/awkexample
bailing
out
因为在这种情况下命令行参数是:
/usr/local/bin/awkexampel
于是awk企图将字符串/usr/local/bin/awkexample解释为一个awk程序。
如果不能
向解释器
至少传递一个可任选参数(在本例中是-f),那么这些解释器文件只有对shell才是
有用的。
是否一定需要解释器文件呢?
那也不完全如此。
但是它们确实使用户得到效率方面
的好处,
其代价是系统核的额外开销(因为系统核需要识别解释器文件)。
由于下述理由,解
释器文件
是有用的。
1某些程序是用某种语言写的脚本,这一事实可以隐藏起来。
例如,为了执行程
序811,
只需使用下列命令行:
optional-arguments
而并不需要知道该程序实际上是一个awk脚本,否则我们就要以下列方式执行该程
序:
2解释器脚本在效率方面也提供了好处。
再考虑一下前面的例子。
我们仍旧隐藏
该程序是
一个awk脚本的事实,但是将其放在一个shell脚本中:
'
BEGIN
{
for(i=0;
i<
ARGC;
i++)
printf
"
ARGV[%d]=%s\n"
i,ARGVp[i]
exit
}'
$*
这种解决方法的问题是要求做更多的工作。
首先,shell读此命令,然后试图exec
lp此文件
名。
因为shell脚本是一个可执行文件,但却不是机器可执行的,于是返回一个错
误;
然后
,execlp就认为该文件是一个shell脚本(它实际上就是这种文件)。
然后,exec
/
bin/sh,
并以该Shell脚本的路径名作为其参数。
shell正确地解释执行我们的shell脚本,
但是为了
运行awk程序,它调用fork,exec和wait。
用一个shell脚本代替解释器脚本有更多
的开销。
3解释器脚本使我们可以使用除/bin/sh以外的其它shell来编写shell脚本。
当e
xeclp找到
一个非机器可执