




版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、19.1引言第9章介紹進(jìn)行終端登錄時(shí),需要通過(guò)一個(gè)終端設(shè)備自動(dòng)提供終端的語(yǔ)義。在終端和運(yùn)行程序之間有一個(gè)終端行規(guī)程(見(jiàn)圖 11-2),通過(guò)這個(gè)規(guī)程能夠在終端上設(shè)置特殊字符(退格、行刪除、中斷等)。但是,當(dāng)一個(gè)登錄請(qǐng)求到達(dá)網(wǎng)絡(luò)連接時(shí),終端行規(guī)程并不是自動(dòng)被加載到網(wǎng)絡(luò)連接和登錄程序s語(yǔ)義。之間的。圖9-5顯示了一個(gè)偽終端設(shè)備驅(qū)動(dòng)程序被用來(lái)提供終端除了用于網(wǎng)絡(luò)登錄,偽終端還被用在其他方面,本章將對(duì)此進(jìn)行介紹。首先提供SVR4和4.3+BSD系統(tǒng)下用于創(chuàng)建偽終端的函數(shù),然后使用這些函數(shù)編寫(xiě)一個(gè)程序用來(lái)調(diào)用 pty。看到這個(gè)程序的各種使用:在輸入字符和終端顯示之間進(jìn)行轉(zhuǎn)換( BSD的碼轉(zhuǎn)換程序)和運(yùn)行協(xié)
2、同進(jìn)程來(lái)避免程序14-10中遇到的緩存問(wèn)題。19.2概述偽終端( pseudo terminal)這個(gè)名詞暗示了與一個(gè)應(yīng)用程序相比,它更加像一個(gè)終端。但事實(shí)上,偽終端并不是一個(gè)真正的終端。圖19-1顯示了使用偽終端的進(jìn)程的典型結(jié)構(gòu)。其中關(guān)鍵點(diǎn)如下:(1) 通常一個(gè)進(jìn)程打開(kāi)偽終端主設(shè)備然后調(diào)用fork。子進(jìn)程建立了一個(gè)新的,打開(kāi)用戶(hù)進(jìn)程用戶(hù)進(jìn)程一個(gè)相應(yīng)的偽終端從設(shè)備,將它成標(biāo)準(zhǔn)輸讀、寫(xiě)函數(shù)讀、寫(xiě)函數(shù)入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)出錯(cuò),然后調(diào)用 exec。偽終端從設(shè)備成為子進(jìn)程的控制終端。對(duì)于偽終端從設(shè)備之上的用戶(hù)進(jìn)程來(lái)說(shuō),其標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)出錯(cuò)都能當(dāng)作終端設(shè)備使用。用戶(hù)進(jìn)程能夠調(diào)用第 11章中講到的
3、所有輸入/輸出函數(shù)。但是因?yàn)樵趥谓K端從設(shè)備之下并沒(méi)有真正的設(shè)備,無(wú)意義的函數(shù)調(diào)用(改變波特率、發(fā)送中斷符、設(shè)置奇偶校驗(yàn)等)將被忽略。任何寫(xiě)到偽終端主設(shè)備的輸入都會(huì)作為從設(shè)備端的輸入,反之亦然。事實(shí)上所有從終端行規(guī)程內(nèi)核偽終端主設(shè)備偽終端從設(shè)備圖19-1 典型的偽終端進(jìn)程結(jié)構(gòu)設(shè)備端的輸入都來(lái)自備上的終端行規(guī)程使設(shè)備上的用戶(hù)進(jìn)程。這看起來(lái)就像一個(gè)流管道(見(jiàn)圖 15-3),但從設(shè)擁有普通管道之外的其他處理能力。圖19-1顯示了BSD系統(tǒng)中的偽終端結(jié)構(gòu)。19.3.2節(jié)將介紹如何打開(kāi)這些設(shè)備。在SVR4系統(tǒng)中偽終端是使用流系統(tǒng)來(lái)創(chuàng)建的(見(jiàn) 12.4節(jié))。圖19-2詳細(xì)描述了SVR4系統(tǒng)中各個(gè)偽終端模塊4
4、77之間的關(guān)系。虛線(xiàn)框中的兩個(gè)流模塊是可選的。請(qǐng)注意從設(shè)備上的三個(gè)流模塊同程序 12-10(網(wǎng)絡(luò)登錄)的輸出是一樣的。19.3.1節(jié)將介紹如何組織這些流模塊。從現(xiàn)在開(kāi)始將簡(jiǎn)化以上圖示,首先不再畫(huà)出圖 19-1的“讀、寫(xiě)功能”或圖19-2的流首。使用縮寫(xiě)“ pty”表示偽終端,并將圖 19-2中所有偽終端從設(shè)備之上的流模塊集合表示為“終端行規(guī)程”模塊。圖19-2 SVR4下的偽終端結(jié)構(gòu)19.2.1 網(wǎng)絡(luò)登錄服務(wù)器偽終端用于構(gòu)造網(wǎng)絡(luò)登錄服務(wù)器。典型的例子是netd和rlogind服務(wù)器。Stevens1990運(yùn)行在遠(yuǎn)端主機(jī)上,即到如圖 19-第15章詳細(xì)了提供rlogin服務(wù)的步驟。一旦登錄s3的
5、結(jié)構(gòu)。同樣的結(jié)構(gòu)也用于netd服務(wù)器。在rlogind服務(wù)器和登錄s間檢驗(yàn)用戶(hù)是否合法的。之間有兩個(gè)exec調(diào)用,這是因?yàn)閘ogin程序通常是在兩個(gè)exec之本圖的一個(gè)關(guān)鍵點(diǎn)是驅(qū)動(dòng)偽終端主設(shè)備的進(jìn)程通常同時(shí)在讀寫(xiě)另一個(gè) I/O流。本例中另一個(gè)I/O流是TCP/IP。這表示該進(jìn)程必然使用了某種形式的如 select或poll那樣的I/O多路轉(zhuǎn)接(見(jiàn)12.5節(jié)),或被分成兩個(gè)進(jìn)程?;貞?8.7節(jié)過(guò)的一個(gè)進(jìn)程和兩個(gè)進(jìn)程的比較。用戶(hù)進(jìn)程用戶(hù)進(jìn)程流首流首流模塊流模塊內(nèi)核流模塊流模塊偽終端主設(shè)備偽終端從設(shè)備478rlogind服務(wù)器登錄s標(biāo)準(zhǔn)輸出標(biāo)準(zhǔn)出錯(cuò)標(biāo)準(zhǔn)輸入TCP/IP協(xié)議終端行規(guī)程內(nèi)核網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)程
6、序pty主設(shè)備pty從設(shè)備網(wǎng)絡(luò)圖19-3rlogind服務(wù)器的進(jìn)程組織結(jié)構(gòu)19.2.2 script程序script程序是隨SVR4和4.3+BSD提供的,該程序?qū)⒔K端一個(gè)文件中做一個(gè)拷貝。它通過(guò)將自己置于終端和登錄 s作。圖19-4詳細(xì)描述了script程序相關(guān)的交互。這里特別期間所有的輸入和輸出信息在的一個(gè)新的調(diào)用之間來(lái)完成這個(gè)工script程序通常是從登錄s起動(dòng)的,該s然后等待程序的結(jié)束。script程序運(yùn)行時(shí),在偽終端從設(shè)備之上終端行規(guī)程的所有輸出都被到一個(gè) script文件中(通常叫做typescript)。因?yàn)閾翩I通常被行規(guī)程的模塊回顯,該 script文件也包括了輸入的內(nèi)容。但是
7、,因?yàn)榭诹畈槐换仫@,該script文件不會(huì)包含口令。script文件登錄sscript pro ss(休眠中)終端行規(guī)程終端行規(guī)程內(nèi)核pty從設(shè)備pty主設(shè)備終端設(shè)備驅(qū)動(dòng)終端上的用戶(hù)圖19-4 script程序479在19.5節(jié)開(kāi)發(fā)一個(gè)通用的pty程序后, script程序??吹揭粋€(gè)巧妙的s能夠?qū)⑺D(zhuǎn)化成一個(gè)19.2.3 expect程序偽終端可以用來(lái)使交互式的程序運(yùn)行在非交互的狀態(tài)中。許多程序需要一個(gè)終端來(lái)運(yùn)行, 18.7節(jié)中的call進(jìn)程就是一個(gè)例子。它假定標(biāo)準(zhǔn)輸入是一個(gè)終端并在起動(dòng)時(shí)將其設(shè)置為初始模式(見(jiàn)程序18-20)。該程序不能被s和注銷(xiāo)。同修改所有交互式程序來(lái)支持批處理模式的操作比
8、較,一個(gè)更好的解決方法是通過(guò)一個(gè) script來(lái)驅(qū)動(dòng)交互式程序。expect程序Libes 1990;1991提供了這樣的方法。類(lèi)似于19.5節(jié)的pty程序,它使用偽終端來(lái)運(yùn)行其他程序。并且, expect還提供了一種編程語(yǔ)言用于檢查程序的輸出,以確定用什么作為輸入發(fā)送給該程序。當(dāng)一個(gè)交互式的程序開(kāi)始從一個(gè)運(yùn)行時(shí),不能僅僅是將中的所有內(nèi)容輸入到程序中去。相應(yīng)的,要通過(guò)檢查程序的輸出來(lái)決定下一步輸入的內(nèi)容。19.2.4 運(yùn)行協(xié)同進(jìn)程在程序14-10所示的例子中,不能調(diào)用使用標(biāo)準(zhǔn)I/O庫(kù)進(jìn)行輸入、輸出的協(xié)同進(jìn)程,這是因?yàn)楫?dāng)通過(guò)管道與協(xié)同進(jìn)程進(jìn)行通訊時(shí),標(biāo)準(zhǔn) I/O庫(kù)會(huì)將標(biāo)準(zhǔn)輸入和輸出的內(nèi)容放到緩存
9、中,從而引起死鎖。如果協(xié)同進(jìn)程是一個(gè)已經(jīng)編譯的程序而又沒(méi)有源程序,則無(wú)法在源程序中加入fflush語(yǔ)句來(lái)解決這個(gè)問(wèn)題。圖8顯示了一個(gè)進(jìn)程驅(qū)動(dòng)協(xié)同進(jìn)程的情況。只需將一個(gè)偽終端放到兩個(gè)進(jìn)程之間,見(jiàn)圖19-5。協(xié)同進(jìn)程管道1標(biāo)準(zhǔn)輸入驅(qū)動(dòng)程序偽終端標(biāo)準(zhǔn)輸出管道2圖19-5 用偽終端驅(qū)動(dòng)一個(gè)協(xié)同進(jìn)程現(xiàn)在協(xié)同進(jìn)程的標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出就像終端設(shè)備一樣,所以標(biāo)準(zhǔn) I/O庫(kù)會(huì)將這兩個(gè)流設(shè)置為行緩存。父進(jìn)程有兩種不同的方法在自身和協(xié)同進(jìn)程之間獲得偽終端(這種情況下的父進(jìn)程可以類(lèi)似程序14-9,使用兩個(gè)管道和協(xié)同進(jìn)程進(jìn)行通訊;或者像程序 15-1那樣,使用一個(gè)流管道)。一個(gè)方法是父進(jìn)程直接調(diào)用 pty_fork函數(shù)
10、(見(jiàn)19.4節(jié))而不是fork。另法是exec該pty程序,將協(xié)同進(jìn)程作為參數(shù)(見(jiàn)19.5節(jié))。在說(shuō)明pty程序后介紹這兩種方法。19.2.5長(zhǎng)時(shí)間運(yùn)行程序的輸出使用任一個(gè)標(biāo)準(zhǔn)s,都可以將一個(gè)需要長(zhǎng)時(shí)間運(yùn)行的程序放到運(yùn)行。但是如果將該程序的標(biāo)準(zhǔn)輸出重定向到一個(gè)文件,并且如果它產(chǎn)生的輸出不多,就不能方便地程序本書(shū)中所有運(yùn)行程序并顯示其輸出的實(shí)例都是由 script程序?qū)崿F(xiàn)的,這樣避免了手動(dòng)拷貝程序輸出可能帶來(lái)的錯(cuò)誤。480的進(jìn)展,這是因?yàn)闃?biāo)準(zhǔn)I/O庫(kù)會(huì)將標(biāo)準(zhǔn)輸出放在緩存中保存。果,有時(shí)甚至可能是8192字節(jié)一塊??吹降膶⒅皇浅蓧K的輸出結(jié)如果有源程序,則可以加入fflush調(diào)用。另標(biāo)準(zhǔn)I/O庫(kù)認(rèn)為
11、輸出是終端。圖19-6說(shuō)明了這個(gè)結(jié)構(gòu),法是,可以在pty程序下運(yùn)行該程序,讓這個(gè)緩慢輸出的程序稱(chēng)為slowout。從登錄s到pty進(jìn)程的fort/exec箭頭用虛線(xiàn)表示,以強(qiáng)調(diào)pty進(jìn)程是作為任務(wù)運(yùn)行的。圖19-6 使用偽終端運(yùn)行一個(gè)緩慢輸出的程序19.3打開(kāi)偽終端設(shè)備在SVR4和4.3+BSD系統(tǒng)中打開(kāi)偽終端設(shè)備的方法有所不同。提供兩個(gè)函數(shù)來(lái)處理所有細(xì)節(jié):ptym_open用來(lái)打開(kāi)下一個(gè)有效的偽終端主設(shè)備, ptys_open用來(lái)打開(kāi)相應(yīng)的從設(shè)備。#include ourhdr.hptym_open(cha rpts*_name);返回:若成功則為偽終端主設(shè)備文件描述符,否則為 -1m, c
12、har *pts_name);返回:若成功則為偽終端從設(shè)備文件描述符,否則為 -1ptys_open( 通常不直接調(diào)用這兩個(gè)函數(shù) 函數(shù)pty_fork(見(jiàn)19.4節(jié))調(diào)用它們并fork出一個(gè)子進(jìn)程。ptym_open決定下一個(gè)有效的偽終端主設(shè)備并打開(kāi)該設(shè)備。這個(gè)調(diào)用必須分配一個(gè)數(shù)組來(lái)存放主設(shè)備或從設(shè)備的名稱(chēng),并且如果調(diào)用成功,相應(yīng)的主設(shè)備或從設(shè)備的名稱(chēng)會(huì)通過(guò) pts_name返回。這個(gè)名稱(chēng)和ptym_open返回的文件描述符將傳給ptys_open,該函數(shù)用來(lái)打開(kāi)一個(gè)從設(shè)備。輸出文件登錄spty進(jìn)程終端行規(guī)程終端行規(guī)程內(nèi)核終端設(shè)備pty主設(shè)備pty從設(shè)備驅(qū)動(dòng)程序終端上的用戶(hù)slowout481
13、在講解pty_fork函數(shù)之后,使用兩個(gè)函數(shù)來(lái)打開(kāi)這兩個(gè)設(shè)備的原因?qū)?huì)很明顯。通常,一個(gè)進(jìn)程調(diào)用ptym_open來(lái)打開(kāi)一個(gè)主設(shè)備并且得到從設(shè)備的名稱(chēng)。該進(jìn)程然后 fork子進(jìn)程,子進(jìn)程在調(diào)用setsid建立新的的控制終端的過(guò)程。后調(diào)用ptys_open來(lái)打開(kāi)從設(shè)備。這就是從設(shè)備如何成為子進(jìn)程19.3.1 SVR4SVR4系統(tǒng)下所有偽終端的流實(shí)現(xiàn)細(xì)節(jié)在A(yíng)T&T1990d第12章中有所說(shuō)明,還描述了以下三個(gè)函數(shù): grantpt(3),unlockpt(3),和ptsname(3)。偽終端主設(shè)備是/dev/ptmx。這是一個(gè)流的增殖設(shè)備( clone device)。這意味著當(dāng)打開(kāi)該增殖設(shè)備,其
14、open例程自動(dòng)決定第一個(gè)未被使用的偽終端主設(shè)備并打開(kāi)這個(gè)設(shè)備。(下一節(jié)將看到在系統(tǒng)中,須自己找到第一個(gè)未被使用的偽終端主設(shè)備。)程序19-1 SVR4的偽終端打開(kāi)函數(shù)482首先打開(kāi)設(shè)備/dev/ptmx并得到偽終端主設(shè)備的文件描述符。打開(kāi)這個(gè)主設(shè)備自動(dòng)鎖定了對(duì)應(yīng)的從設(shè)備。然后調(diào)用grantpt來(lái)改變從設(shè)備的權(quán)。執(zhí)行如下操作:(a)將從設(shè)備的所改為有效用戶(hù)ID;(b)將組所改為組tty;(c)將權(quán)改為只允許用戶(hù)-讀,用戶(hù)-寫(xiě)和組-寫(xiě)。將組所設(shè)置為tty并允許組-寫(xiě)權(quán)是因?yàn)槌绦騱all(1)和write(1)的設(shè)置-用戶(hù)-ID為組tty。調(diào)用函數(shù)grantpt執(zhí)行/usr/lib/pt_od。該
15、程序的設(shè)置-用戶(hù)-ID為root,因此它能夠修改從設(shè)備的所有者和權(quán)。函數(shù)unlockpt用來(lái)清除從設(shè)備的鎖。在打開(kāi)從設(shè)備前必須做這件事情。并且必須調(diào)用ptsname來(lái)得到從設(shè)備的名稱(chēng)。這個(gè)名稱(chēng)的格式是/dev/pts/NNN。文件中接下來(lái)的函數(shù)是ptys_open,該函數(shù)真正被用來(lái)打開(kāi)一個(gè)從設(shè)備。在 SVR4系統(tǒng)中,如果調(diào)用者是一個(gè)還沒(méi)有控制終端的期首進(jìn)程, open就會(huì)分配一個(gè)從設(shè)備作為控制終端。如果不希望函數(shù)自動(dòng)做這件事,可以在調(diào)用時(shí)指明O_NOCTTY標(biāo)志。打開(kāi)從設(shè)備后,將三個(gè)流模塊放在從設(shè)備的流上。 ptem是偽終端虛擬模塊, ldterm是終端行規(guī)程模塊。這兩個(gè)模塊合在一起像一個(gè)真正
16、的終端模塊一樣工作。 ttcompat提供了向老系統(tǒng)如V7、4BSD和Xenix的ioctl調(diào)用的兼容性。這是一個(gè)可選的模塊,但是因?yàn)樗詣?dòng)嘗試控制臺(tái)登錄和網(wǎng)絡(luò)登錄(見(jiàn)程序12-10的輸出),其加到從設(shè)備的流中。調(diào)用這兩個(gè)函數(shù)的結(jié)果是得到:偽終端主設(shè)備的文件描述符和從設(shè)備的文件描述符。19.3.2 4.3+BSD在4 . 3 +BSD系統(tǒng)中必須自己來(lái)確定第一個(gè)可用的偽終端主設(shè)備。為達(dá)到這個(gè)目的,從/dev/ptyp0開(kāi)始并不斷嘗試,直到成功打開(kāi)一個(gè)可用的偽終端主設(shè)備或試完所有設(shè)備。在打開(kāi)設(shè)備時(shí),將看到兩種可能的錯(cuò)誤: EIO指設(shè)備已經(jīng)被使用; ENOENT表示設(shè)備不存在。對(duì)于后一種情況,可以停
17、止搜索,因?yàn)樗械膫谓K端設(shè)備都在被使用中。一旦成功地打開(kāi)一個(gè)例如名為/dev/ptyMN的偽終端主設(shè)備,那么對(duì)應(yīng)的從設(shè)備的名稱(chēng)為/dev/ttyMN。程序19-2中的函數(shù)ptys_open打開(kāi)該從設(shè)備。在該函數(shù)中調(diào)用n和od,必須意識(shí)到調(diào)用這兩個(gè)函數(shù)的進(jìn)程必須有超級(jí)用戶(hù)權(quán)。如果必須改變所,那么這兩個(gè)函數(shù)調(diào)用必須放在一個(gè)設(shè)置-用戶(hù)-ID的root用戶(hù)的可執(zhí)行函數(shù)中,這類(lèi)似于4.3+BSD系統(tǒng)下的grantpt函數(shù)。483在4.3+BSD系統(tǒng)之下打開(kāi)pty從設(shè)備不具有像分配作為控制終端的設(shè)備那樣的副作用。下一節(jié)將探討如何在4.3+BSD系統(tǒng)下分配控制終端。這個(gè)函數(shù)嘗試16種不同的偽終端主設(shè)備:從/
18、dev/ptyp0到/dev/ptyTf。具體有效的pty設(shè)備號(hào)取決于兩個(gè):(a)內(nèi)核中配置的號(hào)碼;( b)/dev目錄下的特殊文件號(hào)。對(duì)于任何程序來(lái)說(shuō),有效的號(hào)碼是( a)和( b)中較小的一個(gè)。并且,即使( a)和( b)中小的值大于64,許多現(xiàn)有的BSD應(yīng)用(如等)會(huì)搜索程序19-2中第一個(gè)for循環(huán)中的pqrs。netd,rlogind等程序19-2 4.3+BSD的偽終端open函數(shù)48419.4pty_fork函數(shù)現(xiàn)在使用上一節(jié)介紹的兩個(gè)函數(shù): ptym_open和ptys_open,編寫(xiě)稱(chēng)之為pty_fork的函數(shù)。這個(gè)新函數(shù)具有如下功能:打開(kāi)主設(shè)備和從設(shè)備,建立作為具有控制終端
19、。期管理者的子進(jìn)程并使其#include #include #include #include /* 4.3+BSD defines struct winsize here */ ourhdr.h _t pty_fork( ptr*fdm, char *slave_name,const struct termio ssla*ve_termios,const struct winsiz esla*ve_winsize);返回:子進(jìn)程中為0,父進(jìn)程中為子進(jìn)程的進(jìn)程ID,若錯(cuò)誤則為-1pty主設(shè)備的文件描述符通過(guò)ptrfdm指針?lè)祷亍H绻鹲lave_name不為空,從設(shè)備的名稱(chēng)被存放在該指針指向的區(qū)
20、分配空間。區(qū)中。調(diào)用者必須為該如果指針slave_termios不為空,該指針?biāo)慕Y(jié)構(gòu)將初始化從設(shè)備的終端行規(guī)程。如果該指針為空,系統(tǒng)將從設(shè)備的termios結(jié)構(gòu)初始化為一個(gè)由具體應(yīng)用定義的初始狀態(tài)。類(lèi)似的,如果slave_winsize指針不為空,該指針?biāo)鶠榭?,winsize結(jié)構(gòu)通常被初始化為0。的結(jié)構(gòu)將初始化從設(shè)備的窗口大小。如果該指針程序19-3顯示了這個(gè)程序的代碼。調(diào)用相應(yīng)的 ptym_open和ptys_open函數(shù),這個(gè)函數(shù)在 SVR4和4.3+BSD系統(tǒng)下都可以使用。在打開(kāi)偽終端主設(shè)備后, fork將被調(diào)用。正如前面提到的,要等到調(diào)用 setid建立新的期后才調(diào)用ptys_ope
21、n。當(dāng)調(diào)用setsid時(shí),子進(jìn)程還不是一個(gè)進(jìn)程組的首進(jìn)程(想為什么?)期;( b)因此9.5節(jié)列出的三個(gè)操作被使用:(a)子進(jìn)程作為的管理者創(chuàng)建一個(gè)新的子進(jìn)程創(chuàng)建一個(gè)新的進(jìn)程組;( c)子進(jìn)程沒(méi)有控制終端。在SVR4系統(tǒng)中,當(dāng)調(diào)用ptys_open時(shí),從設(shè)備成為了控制終端。在 4.3+BSD系統(tǒng)中,必須調(diào)用ioctl并使用參數(shù)TIOCSCTTY來(lái)分配一個(gè)控制終端。然后termios和winsize這兩個(gè)結(jié)構(gòu)在子進(jìn)程中被初始化。最后從設(shè)備的文件描述符被到子進(jìn)程的標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)出錯(cuò)中。這表示由子進(jìn)程所 exec的進(jìn)程都會(huì)將上述三個(gè)句柄同偽終端從設(shè)備聯(lián)系起來(lái)。在調(diào)用fork后,父進(jìn)程返回偽
22、終端主設(shè)備的描述符并返回。下一節(jié)將在 pty程序中使用 pty_fork。485程序19-3 pty_fork函數(shù)48619.5pty程序編寫(xiě)pty程序的目的是為了用鍵入:pty prog arg1 arg2 來(lái)代替:prog arg1 arg2 這樣使可以用pty來(lái)執(zhí)行另一個(gè)程序,該程序在一個(gè)自己的偽終端連接。期中執(zhí)行,并和一個(gè)看一下pty程序的源碼。程序19-4包含main函數(shù)。它調(diào)用上一節(jié)的pty_fork函數(shù)。程序19-4 pty程序的main函數(shù)487下一節(jié)檢測(cè)pty程序的不同使用時(shí),將會(huì)探討多種的行命令選擇項(xiàng)。在調(diào)用pty_fork前,取得了termios和winsize結(jié)構(gòu)的值,
23、將其傳遞給pty_fork。通過(guò)這種方法,偽終端從設(shè)備具有和現(xiàn)在的終端相同的初始狀態(tài)。從pty_fork返回后,子進(jìn)程關(guān)閉了偽終端從設(shè)備的回顯,并調(diào)用 execvp來(lái)執(zhí)行命令行指定的程序。所有令行參數(shù)將成為程序的參數(shù)。488父進(jìn)程在調(diào)用exit時(shí)執(zhí)行原先設(shè)置的退出處理程序,它復(fù)原終端狀態(tài),將用戶(hù)終端設(shè)置為初始模式(可選)。下一節(jié)將do_driver函數(shù)。接下來(lái)父進(jìn)程調(diào)用函數(shù)loop(見(jiàn)程序19-5)。該函數(shù)僅僅是將所有標(biāo)準(zhǔn)輸入拷貝到偽終端主設(shè)備,并將偽終端主設(shè)備接收到的所有內(nèi)容拷貝到標(biāo)準(zhǔn)輸出。同 18.7節(jié)一樣,有兩個(gè)選擇 一個(gè)進(jìn)程還是兩個(gè)進(jìn)程?為了有所區(qū)別,這里使用兩個(gè)進(jìn)程,盡管使用 sel
24、ect或poll的單進(jìn)程也是可行的。程序19-5 loop函數(shù)489注意,當(dāng)使用兩個(gè)進(jìn)程時(shí),如果一個(gè)終止,那么它必須通知另一個(gè)。行這種通知。用 SIGTERM進(jìn)19.6使用pty程序接下來(lái)看一下pty程序的不同例子,了解一下使用不同命令行選擇項(xiàng)的必要性。如果使用KornS pty ksh,執(zhí)行:得到一個(gè)運(yùn)行在一個(gè)偽終端下的新的s。如果文件ttyname同程序11-7相同,可按如下方式執(zhí)行pty程序:$ whostevens stevens stevens stevens stevensstevensconsole ttyp0 ttyp1 ttyp2 ttyp3 ttyp4 Feb Feb Fe
25、b Feb Feb Feb 66666710:43 15:00 15:00 15:00 15:48 14:28 ttyp4是正在使用的最高終端設(shè)備在pty上運(yùn)行程序11-7ttyp5是下一個(gè)有效的pty設(shè)備號(hào)$ pty ttyname fd fd fd 0: 1: 2: /dev/ttyp5 /dev/ttyp5 /dev/ttyp5 19.6.1utmp文件6.7節(jié)了當(dāng)前UNIX系統(tǒng)登錄用戶(hù)的utmp文件。那么在偽終端上運(yùn)行程序的用戶(hù)是否被認(rèn)為登錄了呢?如果是登錄,netd和rlogind,顯然偽終端上的用戶(hù)應(yīng)該在utmp中擁有相應(yīng)條目。但是,從窗口系統(tǒng)或運(yùn)行 script程序,在偽終端上運(yùn)
26、行 s的用戶(hù)是否應(yīng)該在utmp中擁有相應(yīng)條目呢?這個(gè)問(wèn)題一直沒(méi)有一個(gè)的認(rèn)識(shí)。有的系統(tǒng)有,有的沒(méi)有。如果沒(méi)有的話(huà), who(1)程序一般不會(huì)顯示正在被使用的偽終端。除非utmp允許其他用戶(hù)的寫(xiě)權(quán),否則一般的程序?qū)⒉荒軐?duì)其進(jìn)行寫(xiě)操作。某些系統(tǒng)提供這個(gè)寫(xiě)權(quán)。19.6.2 作業(yè)控制交互當(dāng)在pty上運(yùn)行作業(yè)控制spty ksh 時(shí),它能夠正常地運(yùn)行。例如,490在pty上運(yùn)行KornS。能夠在這個(gè)新s下運(yùn)行程序和使用作業(yè)控制,如同在登錄 s中一樣。但如果在pty下運(yùn)行一個(gè)交互式程序而不是作業(yè)控制spty cat ,比如:一切正常直到鍵入作業(yè)控制的暫停字符。在 SVR4和4.3+BSD系統(tǒng)中作業(yè)控制暫停字
27、符將會(huì)被顯示為Z而被忽略。在SunOS4.1.2中,cat進(jìn)程終止,pty進(jìn)程終止,回到初始登錄s。為了明白其中的原因,需要檢查所有相關(guān)的進(jìn)程、這些進(jìn)程所屬的進(jìn)程組和期。圖19-7顯示了pty cat運(yùn)行的結(jié)構(gòu)圖。圖19-7pty cat的進(jìn)程組和期當(dāng)鍵入暫停字符( Ctrl-Z),它將被cat進(jìn)程下的行規(guī)程模塊所識(shí)別,這是因?yàn)?pty將終端(在pty父進(jìn)程之下)設(shè)置為初始模式。但內(nèi)核不會(huì)終止cat進(jìn)程,這是因?yàn)樗鼘儆谝粋€(gè)孤兒進(jìn)程組(見(jiàn)9.10節(jié))。cat的父進(jìn)程是pty的父進(jìn)程,屬于另一個(gè)期。不同的系統(tǒng)處理這種情況的方法也不同。在IX.1中這個(gè)SIGTSTP信號(hào)不被發(fā)送給進(jìn)程。早期的系統(tǒng)遞送
28、一個(gè)進(jìn)程甚至不能捕獲的SIGKILL。這就是在SunOS4.1.2中看到的。(IX.1 Rationale建議用SIGHUP作為更好的替代,因?yàn)檫M(jìn)程能夠捕獲它。)用程序8-17查看cat進(jìn)程的終止?fàn)顟B(tài),可以發(fā)現(xiàn)該進(jìn)程確實(shí)由SIGKILL信號(hào)終止。在SVR4和4.3+BSD系統(tǒng)中,修改了程序10-22來(lái)觀(guān)察結(jié)果。修改后的程序能夠在捕獲SIGTSTP后進(jìn)行打印,并在捕獲SIGCONT信號(hào)后再打印一次并繼續(xù)執(zhí)行。這說(shuō)明 SIGTSTP被進(jìn)程捕獲,但是當(dāng)進(jìn)程試圖發(fā)送信號(hào)給自己來(lái)暫停本進(jìn)程的時(shí)候,內(nèi)核立即發(fā)送 SIGCONT信號(hào)使之繼續(xù)執(zhí)行。內(nèi)核將不會(huì)讓進(jìn)程被作業(yè)控制停止。 SVR4和4.3+BSD系統(tǒng)
29、的這種處理方法比起發(fā)送一個(gè)SIGKILL的方法來(lái)顯得不那么激烈。當(dāng)使用pty來(lái)運(yùn)行作業(yè)控制s時(shí),被這個(gè)新s調(diào)用的作業(yè)將不是任何孤兒進(jìn)程組的成員,這是因?yàn)樽鳂I(yè)控制s總是屬于同一個(gè)期。在這種情況下, Ctrl-Z被發(fā)送到被s調(diào)用的進(jìn)程,而不是s本身。期期進(jìn)程組進(jìn)程組進(jìn)程組登錄ptyptys父進(jìn)程子進(jìn)程終端行規(guī)程終端行規(guī)程終端設(shè)備pty主設(shè)備pty從設(shè)備驅(qū)動(dòng)程序終端上的用戶(hù)cat491讓被pty調(diào)用的進(jìn)程能夠處理作業(yè)控制信號(hào)的唯一的方法是:另外增加一個(gè)命令行標(biāo)志讓 pty子進(jìn)程能夠自己認(rèn)識(shí)作業(yè)暫停字符,而不是讓該字符通過(guò)其他行規(guī)程模塊。19.6.3 檢查長(zhǎng)時(shí)間運(yùn)行程序的輸出另一個(gè)使用pty進(jìn)行作業(yè)控
30、制交互的例子見(jiàn)圖19-6。如果運(yùn)行一個(gè)程序:pty slowout file.out &進(jìn)程試圖從標(biāo)準(zhǔn)輸入(終端)讀入數(shù)據(jù)時(shí), pty進(jìn)程立刻停止運(yùn)行。這是因?yàn)樵撟鳂I(yè)終端時(shí)會(huì)使作業(yè)控制停止。如果將標(biāo)準(zhǔn)輸入重定向使得 pty是一個(gè)作業(yè)并且當(dāng)它試圖不從終端數(shù)據(jù),如:pty slowout file.out &那么pty程序立即終止,這是因?yàn)樗鼜臉?biāo)準(zhǔn)輸入到一個(gè)文件結(jié)束符。解決這個(gè)問(wèn)題的方法是使用-i選擇項(xiàng)。這個(gè)選擇項(xiàng)的含義是忽略來(lái)自標(biāo)準(zhǔn)輸入的文件結(jié)束符:pty -i slowout file.out &這個(gè)標(biāo)志導(dǎo)致在遇到文件結(jié)束符時(shí),程序 19-5的子進(jìn)程終止,但子進(jìn)程不會(huì)使父進(jìn)程也終止。相反的,父
31、進(jìn)程一直將偽終端從設(shè)備的輸出拷貝到標(biāo)準(zhǔn)輸出(本例中的 file.out)。19.6.4 script程序使用pty程序,可以用下面的方式實(shí)現(xiàn)BSD系統(tǒng)中的script(1)程序。#!/bin/shpty $S :-/bin/sh | tee typescript 一旦執(zhí)行這個(gè)script程序,即可以運(yùn)行ps來(lái)觀(guān)察進(jìn)程之間的關(guān)系。圖19-8顯示了這些關(guān)系。圖19-8 script s在這個(gè)例子中,假設(shè)S變量是KornS(可能是/din/ksh)。如前面所述, script僅僅是將新的s(和它調(diào)用的所有的子進(jìn)程)的輸出拷貝出來(lái),但是因?yàn)閭谓K端從設(shè)備上的行規(guī)程模塊通常允許回顯,故絕大多數(shù)鍵入都被寫(xiě)到
32、typescript文件中去。typescript文件登錄ptyptys父進(jìn)程子進(jìn)程管道行描述行描述ttyptypty主設(shè)備從設(shè)備用戶(hù)49219.6.5 運(yùn)行協(xié)同進(jìn)程在程序14-9中,不能讓協(xié)同進(jìn)程使用標(biāo)準(zhǔn) I/O函數(shù),其原因是標(biāo)準(zhǔn)輸入和輸出不是終端,其輸入和輸出將被放到緩存中。如果用if (execl(./pty, pty, -e, add2, (char *) 0) 0) 替代:if (execl(./add2, add2, (char *) 0) 0) 在pty下運(yùn)行協(xié)同進(jìn)程,該程序即使使用了標(biāo)準(zhǔn)I/O仍然可以正確運(yùn)行。圖19-9顯示了在使用偽終端作為協(xié)同進(jìn)程的輸入和輸出的情況??蛑械摹?/p>
33、驅(qū)動(dòng)程序”是前面提到過(guò)的改變了execl的程序14-9。這是圖19-5的一個(gè)擴(kuò)充,它顯示了所有的進(jìn)程間聯(lián)系和數(shù)據(jù)流。pty父進(jìn)程add2協(xié)同進(jìn)程pty子進(jìn)程驅(qū)動(dòng)程序管道2管道1終端行規(guī)程終端行規(guī)程終端設(shè)備驅(qū)動(dòng)程序pty主設(shè)備pty從設(shè)備終端上的用戶(hù)圖19-9運(yùn)行一協(xié)同進(jìn)程,以pty作為其輸入和輸出這個(gè)例子顯示了對(duì)于pty程序-e(不回顯)選擇項(xiàng)的重要性。 pty不以交互方式運(yùn)行,這是因?yàn)樗臉?biāo)準(zhǔn)輸入不是一個(gè)終端。在程序 19-4中eractive標(biāo)志默認(rèn)為false,這是因?yàn)閷?duì)isatty調(diào)用的返回結(jié)果是false。這意味著在真正的終端之上的行規(guī)程保持在典型模式下并允許回顯。指定-e選擇項(xiàng)后,
34、關(guān)掉了偽終端從設(shè)備上的行規(guī)程模塊的回顯。如果不這樣做,則鍵入的每一個(gè)字符都將被兩個(gè)行規(guī)程模塊顯示兩次。還要用-e選擇項(xiàng)關(guān)閉termios結(jié)構(gòu)的ONLCR標(biāo)志,防止所有的協(xié)同進(jìn)程的輸出被回車(chē)和換行符終止。在不同的系統(tǒng)上測(cè)試這個(gè)例子會(huì)遇到 12.8節(jié)描述readn和writen函數(shù)時(shí)提到。當(dāng)描述符不是普通的磁盤(pán)文件時(shí),從read返回的數(shù)據(jù)量可能因?qū)崿F(xiàn)不同而有所區(qū)別。協(xié)同進(jìn)程使用pty時(shí),如果調(diào)用通過(guò)管道的read而返回結(jié)果不到一行,將輸出不可的結(jié)果。解決的方法不是使用程序14-9而是使用修改過(guò)的使用標(biāo)準(zhǔn)I/O庫(kù)的習(xí)題14.5的程序,將兩個(gè)管道都設(shè)置為行緩存。這樣fgets函數(shù)將會(huì)讀完一個(gè)整行。程序
35、14-9的while循環(huán)假設(shè)送到協(xié)同進(jìn)程的每一行都會(huì)帶來(lái)一行的返回結(jié)果。19.6.6 用非交互模式驅(qū)動(dòng)交互式程序雖然讓pty運(yùn)行所有的協(xié)同進(jìn)程是非常的想法,但如果協(xié)同進(jìn)程是交互式的,就不能493正常工作。問(wèn)題在于pty只是將其標(biāo)準(zhǔn)輸入到pty,并將來(lái)自pty的到其標(biāo)準(zhǔn)輸出。而并不關(guān)心具體得到什么數(shù)據(jù)。舉個(gè)例子,可以在pty直接與調(diào)制解調(diào)器之下運(yùn)行18.7節(jié)的call客戶(hù)機(jī):pty call t2500 這樣做不比直接鍵入call t2500優(yōu)點(diǎn),但 可能希望用一個(gè) s 命令運(yùn)行call程序來(lái)取得調(diào)制解調(diào)器的一些 寄存器的內(nèi)容。如果t2500.cmd包括兩行:aatn?.第一行打印出調(diào)制解調(diào)器的
36、寄存器值,第二行終止call程序。但是如果運(yùn)行:pty -1 t2500.cmd call t2500 結(jié)果就不是 希望得到的。事實(shí)上文件 t2500.cmd的內(nèi)容首先被送到了調(diào)制解調(diào)器。當(dāng)交互運(yùn)行call程序時(shí) 等待調(diào)制解調(diào)器顯示“ Connected”,但是pty程序不知道這樣做。這就是為什么需要比pty更巧妙的程序,如expect,自 文件運(yùn)行交互式程序。在pty上即使運(yùn)行程序14-9也不能正常工作,這是因?yàn)槌绦?4-9認(rèn)為它在一個(gè)管道寫(xiě)入的每一行都會(huì)在另一個(gè)管道產(chǎn)生一行。而且, 14-9程序總是先發(fā)送一行到系統(tǒng)進(jìn)程,然后再 一行。在上面的例子中, 需要先收到行“ Connected”,
37、然后再發(fā)送數(shù)據(jù)。這里有一些使用s 命令驅(qū)動(dòng)交互式程序的方法??梢栽?pty上增加一種命令語(yǔ)言和一個(gè)解釋器。但是一個(gè)適當(dāng) 令語(yǔ)言可能十倍于 pty程序的大小。另法是使用命令語(yǔ)言并用pty_fork函數(shù)來(lái)調(diào)用交互式程序,這正是expect程序所做的。采用一種不同的方法,使用選擇項(xiàng)-d讓pty程序同一個(gè)管理輸入和輸出的驅(qū)動(dòng)進(jìn)程連接起來(lái)。該驅(qū)動(dòng)進(jìn)程的標(biāo)準(zhǔn)輸出是pty的標(biāo)準(zhǔn)輸入,反之亦然。這有點(diǎn)像協(xié)同進(jìn)程,只是在 pty的“另一邊”。此種進(jìn)程結(jié)構(gòu)與圖19-9中所示的幾乎相同,但是在這種情況下由 pty來(lái)完成驅(qū)動(dòng)進(jìn)程的fork和exec。而且在pty和驅(qū)動(dòng)進(jìn)程之間使用一個(gè)單獨(dú)的流管道,而不是兩個(gè)半雙工管道
38、。程序19-6是do_driver函數(shù)的源碼,該函數(shù)被pty(見(jiàn)程序19-4)的main函數(shù)在使用-d選項(xiàng)時(shí)調(diào)用。程序19-6 pty程序的do_driver函數(shù)494通過(guò)編寫(xiě)自己的驅(qū)動(dòng)程序的方法,可以隨意地驅(qū)動(dòng)交互式程序。即使驅(qū)動(dòng)程序有和 pty連接在一起的標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出,它仍然可以通過(guò) /dev/tty同用戶(hù)交互。這個(gè)解決方法仍不如 expect程序通用,但是它提供了一種不到50行代碼的選擇方案。19.7其他特性偽終端還有其他特性,在這里簡(jiǎn)略提一下。 AT&T1990d和4.3+BSD系統(tǒng)的操作手冊(cè)有更詳細(xì)的內(nèi)容。19.7.1 打包模式打包模式能夠使偽終端主設(shè)備了解到偽終端從設(shè)備的狀態(tài)
39、變化。在 SVR4系統(tǒng)中可以將流模塊pckt壓入主設(shè)備端來(lái)設(shè)置這種模式。圖 19-2顯示了這種可選模式。在 4.3+BSD系統(tǒng)中可以通過(guò)TIOCPKT的ioctl來(lái)設(shè)置這種模式。SVR4和4.3+BSD系統(tǒng)中具體的打包模式有所不同。在SVR4系統(tǒng)中,偽終端主設(shè)備的進(jìn)程必須調(diào)用getmsg從流中取得數(shù)據(jù),這是因?yàn)?pckt模塊將一些事件轉(zhuǎn)化為無(wú)數(shù)據(jù)的流消息。在4.3+BSD系統(tǒng)中每一次從偽終端主設(shè)備的讀操作都會(huì)在可選數(shù)據(jù)之后返回狀態(tài)字節(jié)。無(wú)論實(shí)現(xiàn)的方法是什么樣的,打包模式的目的是,當(dāng)偽終端從設(shè)備之上的行規(guī)程模塊出現(xiàn)以下事件時(shí),通知進(jìn)程從偽終端主設(shè)備數(shù)據(jù):讀入隊(duì)列被刷新;寫(xiě)出隊(duì)列被刷新;輸出被停止
40、(如: Ctrl-S);輸出重新開(kāi)始; XON/XOFF流開(kāi)關(guān)被關(guān)閉后重新打開(kāi); XON/XOFF流開(kāi)關(guān)被打開(kāi)后重新關(guān)閉。這些事件被rlogin客戶(hù)機(jī)和rlogid服務(wù)器等使用。19.7.2模式偽終端主設(shè)備可以用TIOCREMOTE的ioctl將偽終端從設(shè)備設(shè)置成模式。雖然SVR4和4.3+BSD系統(tǒng)使用同樣令來(lái)打開(kāi)或關(guān)閉這個(gè)特性,但是在SVR4系統(tǒng)中ioctl的第三個(gè)參數(shù)是一個(gè)整型數(shù),而4.3+BSD中是一個(gè)指向整型數(shù)的指針。495當(dāng)偽終端主設(shè)備將偽終端從設(shè)備設(shè)置成這種模式時(shí),它通知偽終端從設(shè)備之上的行規(guī)程模塊對(duì)從主設(shè)備收到的任何數(shù)據(jù)都不要進(jìn)行處理,無(wú)論它是不是從設(shè)備的 termios結(jié)構(gòu)的規(guī)范或非規(guī)范標(biāo)
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 基于人工智能的2025年智慧交通流量預(yù)測(cè)技術(shù)發(fā)展動(dòng)態(tài)報(bào)告
- 建筑施工安全監(jiān)測(cè)方法試題及答案
- 城市交通擁堵治理2025年公交優(yōu)先戰(zhàn)略的實(shí)施效果分析報(bào)告
- 匯和銀行筆試題庫(kù)及答案
- 黃巖區(qū)面試真題及答案
- 黃河委面試真題及答案
- 安全工程師考試常識(shí)題目試題及答案
- 工業(yè)互聯(lián)網(wǎng)背景下量子通信技術(shù)2025年應(yīng)用前景分析報(bào)告
- 物理學(xué)中的混沌現(xiàn)象研究試題及答案
- 智能建筑系統(tǒng)集成與節(jié)能降耗在體育場(chǎng)館中的應(yīng)用效果研究報(bào)告
- 廣東省珠海市2024-2025學(xué)年高二下學(xué)期期中教學(xué)質(zhì)量檢測(cè)英語(yǔ)試題(原卷版+解析版)
- 北京2025年中國(guó)環(huán)境監(jiān)測(cè)總站招聘(第二批)筆試歷年參考題庫(kù)附帶答案詳解
- 美國(guó)加征關(guān)稅從多個(gè)角度全方位解讀關(guān)稅課件
- “皖南八?!?024-2025學(xué)年高一第二學(xué)期期中考試-英語(yǔ)(譯林版)及答案
- 2025-2030中國(guó)安宮牛黃丸行業(yè)市場(chǎng)現(xiàn)狀分析及競(jìng)爭(zhēng)格局與投資發(fā)展研究報(bào)告
- 防洪防汛安全教育知識(shí)培訓(xùn)
- 安寧療護(hù)人文關(guān)懷護(hù)理課件
- 2025年廣東廣州中物儲(chǔ)國(guó)際貨運(yùn)代理有限公司招聘筆試參考題庫(kù)附帶答案詳解
- 商場(chǎng)物業(yè)人員缺失的補(bǔ)充措施
- 黑龍江省齊齊哈爾市龍江縣部分學(xué)校聯(lián)考2023-2024學(xué)年八年級(jí)下學(xué)期期中考試物理試題【含答案、解析】
- 《尋常型銀屑病中西醫(yī)結(jié)合診療指南》
評(píng)論
0/150
提交評(píng)論