unix环境高级编程第8章 进程控制 下.docx
- 文档编号:5608333
- 上传时间:2022-12-29
- 格式:DOCX
- 页数:32
- 大小:35.02KB
unix环境高级编程第8章 进程控制 下.docx
《unix环境高级编程第8章 进程控制 下.docx》由会员分享,可在线阅读,更多相关《unix环境高级编程第8章 进程控制 下.docx(32页珍藏版)》请在冰豆网上搜索。
unix环境高级编程第8章进程控制下
发信人:
scircle (yuanyuan), 信区:
Security
标 题:
unix环境高级编程--第8章 进程控制 (下)
发信站:
BBS 水木清华站 (Mon Mar 27 15:
59:
57 2000)
P209
图85〓六个exec函数之间的区别
每个系统对参数表和环境表的总长度都有一个限制。
在图27中,这种限制是ARG
-MAX。
在P
OSIX1系统中,此值至少是4096字节。
当使用shell的文件名扩充功能产生一个文
件名表时
,可能会受到此值的限制。
例如,此命令
grep -POSIX 迹茫模*常病絊OURCE〓/usr/include/*/*h
在某些系统上可能产生下列形式的shell错:
arg〓〓list〓〓too〓〓long
由于历史原因,系统V中此限制是5120字节。
43BSD和43+BSD在分发时此限制是
20,480
字节。
作者所用的系统则允许多至一兆字节!
(见程序21的输出)
前面曾提及在执行exec后,进程ID没有改变。
除此之外,执行新程序的进程还保持
了原进程
的下列特征:
·进程ID和父进程ID
·实际用户ID和实际组ID
·添加组ID
·进程组ID
·对话期ID
·控制终端
·闹钟尚余留的时间
·当前工作目录
·根目录
·文件方式创建屏蔽字
·文件锁
·进程信号 帘为?
·末决信号
·资源限制
·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函数。
P211
程序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
argv[0]:
echoall
$ argv[1]:
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
#include
int setuid(uid 迹茫模*常病絫 uid);
int 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 迹茫模*常病絊AVED 迹茫模*常病絀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的值。
#include
#include
int setreuid(uid 迹茫模*常病絫 ruid,uid 迹茫模*常病絫 euid);
int setregid(gid 迹茫模*常病絫 rgid,gid 迹茫模*常病絫 egid);
Both return:
0 if OK,-1 on error〓两个函数返回:
若成功为0,出错为-1
其作用很简单:
一个非特权用户总能交换实际用户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。
#include
#include
int seteuid(uid 迹茫模*常病絫 uid);
int setegid(gid 迹茫模*常病絫 gid);
Both return:
0 if OK,-1 on error〓两个函数返回:
若成功为0,出错为-1
一个非特权用户可将其有效用户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
$ aout
argv[0]:
/home/stevens/bin/echoarg
argv[1]:
foo
argv[2]:
/home/stevens/bin/testinterp
argv[3]:
myarg1
argv[4]:
MY ARG2
程序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解释器文件中的程序。
P218
程序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 -f /usr/local/bin/awkexample file1 FILENAME2 f3
解释器文件的路径名(/usr/local/bin/awkexample)传送给解释器。
因为不能期望
该解释器(
在本例中是/bin/awk)会使用PATH变量定位该解释器文件,所以只传春路径名中的
文件名是
不够的。
当awk读解释器文件时,因为'#'是awk的注释字符,所以在awk读解释器
文件时
,它忽略第一行。
可以用下列命令验证上述命令行参数。
$ su〓〓成为超级用户
Password:
〓输入超级用户口令
# mv/bin/awk /bin/awksave〓保存原先的程序
# cp /home/stevens/bin/echoarg /bin/awk〓暂时代换它
# suspend〓用作业控制挂起超级用户shell
[1]+Stopped〓〓su
$ awkexample file1 FILENAME2 f3
argv[0]:
/bin/awk
argv[1]:
-f
argv[2]:
/usr/local/bin/awkexample
argv[3]:
file1
argv[4]:
FILENAME2
argv[5]:
f3
$ fg〓〓用作业控制恢复超级用户shell
su
# mv /bin/awksave /bin/awk〓恢复原先的程序
# exit〓终止超级用户shell
在此例子中,解释器的-f任选项是需要的。
正如前述,它告诉awk在什么地方得到
awk程序
。
如果在解释器文件中删除-f任选面,则其结果是:
$ awkexample file1 FILENAME2 f3
/bin/awk:
syntax error at source line 1
context if
>>> /user/local <<< /bin/awkexample
/bin/awk:
bailing out at source line 1
因为在这种情况下命令行参数是:
/bin/awk /usr/local/bin/awkexampel file1 FILENAME2 f3
于是awk企图将字符串/usr/local/bin/awkexample解释为一个awk程序。
如果不能
向解释器
至少传递一个可任选参数(在本例中是-f),那么这些解释器文件只有对shell才是
有用的。
是否一定需要解释器文件呢?
那也不完全如此。
但是它们确实使用户得到效率方面
的好处,
其代价是系统核的额外开销(因为系统核需要识别解释器文件)。
由于下述理由,解
释器文件
是有用的。
1某些程序是用某种语言写的脚本,这一事实可以隐藏起来。
例如,为了执行程
序811,
只需使用下列命令行:
awkexample optional-arguments
而并不需要知道该程序实际上是一个awk脚本,否则我们就要以下列方式执行该程
序:
awk -f awkexample optional-arguments
2解释器脚本在效率方面也提供了好处。
再考虑一下前面的例子。
我们仍旧隐藏
该程序是
一个awk脚本的事实,但是将其放在一个shell脚本中:
awk 'BEGIN {
for(i=0;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找到 一个非机器可执
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- unix环境高级编程第8章 进程控制 unix 环境 高级 编程 进程 控制