您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 公司方案 > unix环境高级编程--第9章 进程关系
发信人:scircle(yuanyuan),信区:Security标题:unix环境高级编程--第9章进程关系发信站:BBS水木清华站(MonMar2716:00:582000)第九章〓进程关系〓引言在上一章我们已了解到进程之间具有关系。首先,每个进程有一个父进程。当子进程终止时,父进程会得到通知并能取得子进程退出状态。在节说明waitpicl函数时,我们也提到了进程组,以及如何等待进程组中的任一个进程终止。本章的更详细地说明进程组以及引进的对话期新概念。我们也将介绍loginshell(是我们登录时为我们调用的)和所有从loginshell起动的进程之间的关系。在说明这些关系时不可能不谈及信号,而谈论信号又需要很多本章介绍的概念。如果你不熟悉Unix信号,则可能先要浏览一下第十章。〓终端登录先看一看登录到Unix系统时所执行的各个程序。在早期的Unix系统中,例如Version7,用户用哑终端(通过RS-232连到主机)进行登录。终端或者是在地的(直接连接)或者是远程的(通过调制解调器连接)。在这两种情况下,login都经由系统核中的终端设备驱动程序。例如,在PDP-11上常用的设备是DH-11和DZ-11。因为连到主机上的终端设备数已经确定,所以同时的login数也就有了已知的上限。下面说明的登录过程适用于使用一个RS-232终端登录到Unix系统中。终端登录登录过程在过去十五年中并没有多少改变。系统管理者创建一个通常名为/etc/thys的文件,其中,每个终端设备有一行。每一行说明设备名和传到getty程序的参数。这些参数说明了终端的波特率等。当系统自举时,系统核创建进程ID1,也就是init进程。init进程供系统进入多用户状态。init读文件/etc/ttys,对每一个允许登录的终端设备,init拥有一次fork,它所生成的子进程则执行(exec)程序getty。这种情况示于图中。图init生成进程使终端可用于图中,各个进程的实际用户ID和有效用户ID都是0(也就是它们都具有超级用户特权)。init以空环境execgetty程序。getty对终端设备调用open画数。以读、写方式将终端打开。如果设备是调制解调器,则Open可能会在设备驱动程序中滞留,直到用户拨号调制解调器,并且线路被接通。一旦设备被打开,则文件描述符0,1,2就被设置到该设备。然后getty输出login之类的信息,并等待用户键入用户名。如果终端支持多种速度,则getty可以测试特殊字符以便适当地更改终端速度(波特率)。关于getty程序以及有关数据文件的细节,请参改Unix手册。当用户键入了用户名后,getty就完成了。然后它以类似于下列的方式调用login程序:execle(/usr/bin/login,login-p,username,(char*)O,enup);(在gettytab文件中可能会有一些选择项使其调用其它程序,但系统默认是login程序。)init以一个空环境调用getty。getty以终端名(例如TERM=foo,其中终端foo的类型取自gettytab文件)和在gettytab中的环境字符串为login创建一个环境(enup参数)。-p标志通知login保留传给它的环境,也可将其它环境字符串加到该环境中,但是不要代换它。图显示了在login刚被调用后这些进程的状态。图login刚被调用后各进程的状态因为init进程具有超级用户优先权,所以图中的所有进程都有超级用户优先权。图中底部三椎是一个进程,它们的进程ID和父进程ID都不会因执行exec而改变。login的工作主要是:因为它得到了用户名,所以就能调用getpwnam取得相应用户的口令字文件登记项。然后调用getpass(3)以显示提示Password;接着读用户键入的口令字(自然,禁止回适用户键入的口令字)。它调用crypt(3)将用户键入的口令字转换成密码,并与该用户口令字文件中的登记项的pw迹茫模*常病絧asswd字段相比较。如果用户几次键入的口令字都无效,则login以参数1调用exit表示登录过程失败。父进程(init)了解到子进程的终止情况后,将再次调用fork,其后又跟随着execgetty,对此终端重复上述过程。如果用户正确登录,login就将当前工作目录更改为该用户的起始目录(chdir)。它也调用chown改变该终端的属主关系,使该用户成为属主和组属主。将对该终端设备的存取许可权改变成:用户读、写和组写。调用setgid及initgroups设置进程的组ID。然后用legin所得到的所有信息初始化环境:起始目录(HOME)、shell(SHELL)、用户名(USER和LOGNAME)、以及一个系统默认路径(PATH)。最后,login进程改变为登录用户的用户ID(setuid)并调用该用户的登录shell,其方式类似于:execl(/bin/sh,-sh,(charargv[o]的第一个字符'-'是一个标志,表示该shell被调用为登录shell。shell可以查看此字符,并相应地修改其起动过程。login所做的比上面说的要多。它可选地打印message-of-the-day文件,检查新邮件以及其它一些功能。但是考虑到本市的内容,我们主要关心上面所说的功能。回忆在节中对setuid函数的讨论,因为setuid是由超级用户调用的,它更改所有三个用户ID:实际、有效和保存的用户ID。login在较早时间调用的setgid对所有三个组ID也有同样效果。到此为止,登录用户的loginshell开始运行。其父进程ID是init进程ID(进程ID1),所以当此loginshell终止时,init会得到通知(接到SIGCHLD信号),它会对该终端重复全部上述过程。登录shell的文件描述符0,1和2设置为终端设备。图显示了这种安排。图终端登录结束后的有关进位现在,loginshell读其启动文件(Bourneshell和Kornshell是profile,Cshell是Cshrc和login)。这些启动文件通常改变某些环境变量,加上一些环境变量。例如,很多用户设置他们自己的PATH,常常提示实际终端类型(TERM)。当执行完启动文件后,用户最后得到shell的提示符,并能键入命令。SVR4终端登录SVR4支持两种形成的终端登录:(a)getty方式,这与上面对+BSD所说明的一样,(b)ttymon登录,这是SVR4的一种新功能。通常,getty用于控制台,ttymon则用于其它终端的登录。ttymon是名为SAF(ServiceAccessFacility,服务存取设施)的一部分。按照本市的目的,我们只简单说明从init到loginshell之间工作过程,最后结果与图中所示相似。init是sac(服务存取控制器)的文进程,sac调用fork,然后其子进程execttymon程序,此时系统进入多用户状态。ttymon监视列于配置文件中的所有终端端口,当用户键入login名时,它调用一次fork。在此之后该子进程又exec登录用户的loginshell,于是到达了图中所示的位置。一个区别是loginshell的父进程现在是ttymon,而gettylogin中,loginshell的父进程是init。〓网终登录+BSD网络登录在上节所述的终端登录中,init知道哪些终端设备可用来进行登录,并为每个设备生成一个getty进程。但是,对网络登录则情况有所不同,所有登录都绎由系统核的网络界面驱动程序(例如:以太网驱动程序),事先并不知道将会有多少这样的登录。不是使一个进程等待每一个可能的登录,而是必须等待一个网络连接请求的到达。在+BSD中,有一个称为inetd的进程(有时称为Internetsuperserver),它等待大多数网络连接。在本市中,我们将说明的网络登录中所涉及的进程序列)。关于这些进程的网络程序设计方面的细节请参阅Sterens[1990]。作为系统起动的一部分,init调用一个shell执行shell脚本etc/rc。由此shell脚本起动一个精灵进程inetd。一旦此shell脚本终止,inetd的父进程就变成init。inetd等待TCP/IP连接请求到达主机,而当一个连接请求到达时,它fork-子进程,然后该子进程exec适当的程序。我们假定到达了一个对于TELNET服务器的一个TCP连接请求。TELNET是使用TCP协议的远程登录应用程序。在另一个主机(它通过某种形成的网络,连接到服务器主机上)上的用户,或在同一个主机上的一个用户籍起动TELNET客户进程(client)起动登录过程:telnet该客户打开一个到名为hostname的主机的TCP连接,在hostname主机上起动的程序被称为TELNET服务器。然后,客户进程和服务器进程之间使用TELNET应用协议通过TCP连接交换数据。所发生的是起动的用户现在登录到了服务器进程的主机(自然,用户需要在服务器进程主机上有一个有效的账号。)图显示了在执行TELNET服务器进程(称为telnetd)中所涉及的进程序列。然后,telnetd进程打开一个伪终端设备,并用fork生成一个子进程(在十九章中将详细说明伪终端。)父进程处理通过网络连接的通信,子进程则execlogin程序。父子进程通过伪终端相连接。在调用exec之前,子进程使其文件描述符0,1,2与伪终端相连。如果登录正确,login就执行在节中所述的同样步骤-更改当前工作目录为起始目录,设置登录用户的组ID和用户ID,以及登录用户的初始环境。然后login用exec将其自身代换为登录用户的。图9显示了到达这一点时进程安装。图执行TELNET服务者中涉及的进程序列图为网络login设置了fd0,1,2后的进程安排很明显,在伪终端设备驱动程序和终端实际用户之间有很多事情在进行看。在第十九章中较详细地说明伪终端之前,我们会介绍与这种安排相关的所有进程。需要理解的重要之点是:当通过终端(图或网络(图登录时,我们得到一个loginshell,其标准输入、输出和标准出错连接到或者一个终端设备上或者一个伪终端设备上。在下一节中我们会了解到这一loginshell是一个对话期的开始,而此终端或伪终端则是对话期的控制终端。SVR4网络登录SVR4中网络登录的情况与中的几乎一样。同样使用了inetd服务器进程,但是在SVR4中inetd是作为一种服务由服务存取控制器调用的,其父进程不是init。最后得到的与图5中一样。〓进程组每个进程除了有一进程ID之外,还属于一个进程组,在第十章讨论信号时还会涉及进程组。一个进程组是一个或多个进程的集合。每个进程组有一个唯一的进程组ID。进程组ID类似于进程ID-它是一个正整数,并可存放在pid-t数据类型中。函数getpgrp返回调用进程的进程组ID。#includesys/#includepid迹茫模*常病絫返回:调用进程的进程组在很多贝壳莱类的系统中,包括,这一函数的参数是pid,返回该进程的进程组。上面所示的原型号版本。每个进程组有一个组长进程。组长进程的标识是,其进程组ID等于其进程ID。进程组组长可以创建一个进程组,创建该组中的进程,然后终止。只要在某个进程组中有一个进程存在,则该进程组就存在,这与其组长进程是否终止无关。从进程组创建开始到其中最后一个进程离开为止的时间区间称为进程组的生命期。在某个进程组中的最后一个进程可以终止,或者参加另一个进程组。一个进程调用setpgid可以参加一个现存的组或者创建一个新进程组。(下一节中将说明用setsid也可以创建一个新的进程组。#includesys/intsetpgid(pid迹茫模*常病絫pid,pid迹茫模*常病絫pgid);返回:若成功为0,出错为-这将pid进程的进程组ID设置为pgid。如果这两个参数相等,则由pid指定的进程变成进程组组长。一个进程只能为它自己或它的子进程设置进程组ID。在它的子进程调用了exec后,它就不再能改变该子进
本文标题:unix环境高级编程--第9章 进程关系
链接地址:https://www.777doc.com/doc-3398765 .html