打開僞終端設備pts


p align="JUSTIFY">19.3 打開僞終端設備

  在SVR4和4.3+BSD系統中打開僞終端設備的方法有所不同。我們提供兩個函數來處理所有細節:ptym_open用來打開下一個有效的僞終端主設備,ptys_open用來打開相應的從設備。

#include ourhdr.h
int ptym_open(char *pts_name);

  返回:如果操作成功,返回僞終端主設備文件述符;否則返回-1

int ptys_open(int fdm, char *pts_name);

  返回:如果操作成功,返回僞終端從設備文件述符;否則返回-1

  通常我們不直接調用這兩個函數--函數pty_fork(19.4節)調用它們並fork出一個子進程。ptym_open決定下一個有效的僞終端主設備並打開該設備。這個調用必須分配一個數組來存放主設備或從設備的名稱,並且如果調用成功,相應的主設備或從設備的名稱會通過pts_name返回。這個名稱和ptym_open返回的文件描述符將傳給ptys_open,該函數用來打開一個從設備。

  在我們講解pty_fork函數之後,使用兩個函數來打開這兩個設備的原因將會很明顯。通常,一個進程調用ptym_open來打開一個主設備並且得到從設備的名稱。該進程然後fork子進程,子進程在調用setid建立新的會話後調用ptys_open來打開從設備。這就是從設備如何成爲子進程的控制終端的過程。

19.3.1 系統V的版本4

  所有在SVR4系統下的僞終端的流實現細節在ATT[1990d]的第十二章中有所說明。三個函數在下列手冊頁中描述:grantpt(3),unlockpt(3),和ptsname(3)。僞終端主設備是/dev/ptmx。這是一個流的增殖設備。這意味着當我們打開該增殖設備,其open例程自動決定第一個未被使用的僞終端主設備並打開這個設備。(在下一節我們將看到在Berkeley系統中,我們必須自己找到第一個未被使用的僞終端主設備。)

________________________________________________________
#include
#include
#include
#include
#include
#include ourhdr.h
extern char *ptsname(int); /* prototype not in any system header */
int > ptym_open(char *pts_name)
{
char *ptr;
int fdm;
strcpy(pts_name, /dev/ptmx); /* in case open fails */
if ( (fdm = open(pts_name, O_RDWR)) 0)return(-1);
if (grantpt(fdm) 0) { /* grant access to slave */
close(fdm);
return(-2);
}
if (unlockpt(fdm) 0) { /* clear slaves lock flag */
close(fdm);
return(-3);
}
if ( (ptr = ptsname(fdm)) == NULL) { /* get slaves name */
close(fdm);
return(-4);
}
strcpy(pts_name, ptr); /* return name of slave */
return(fdm); /* return fd of master */
}
int
ptys_open(int fdm, char *pts_name)
{
int fds;
/* following should allocate controlling terminal */
if ( (fds = open(pts_name, O_RDWR)) 0) {
close(fdm);
return(-5);
}
if (ioctl(fds, I_PUSH, ptem) 0) {
close(fdm);
close(fds);
return(-6);
}
if (ioctl(fds, I_PUSH, ldterm) 0) {
close(fdm);
close(fds);
return(-7);
}
if (ioctl(fds, I_PUSH, ttcompat) 0) {
close(fdm);
close(fds);
return(-8);
}
return(fds);
}
_______________________________________________________________
程序19.1 SVR4的僞終端打開函數

  我們首先打開設備/dev/ptmx並得到僞終端主設備的文件描述符。打開這個主設備自動鎖定了對應的從設備。

  我們然後調用grantpt來改變從設備的權限。執行如下操作:(a)將從設備的所有權改爲有效用戶ID;(b)將組所有權改爲組tty;(c)將權限改爲只允許user-read,user-write和group-write。將組所有權設置爲tty並允許group-write權限是因爲程序wall(1)和write(1)的組標識符被設置爲組tty。調用函數grantpt執行/user/lib/pt_chmod。該程序的用戶被設置爲root因此它能夠修改從設備的所有者和權限。

  函數unlockpt用來清除從設備的內部鎖。在打開從設備前我們必須做這件事情。並且我們必須調用ptsname來得到從設備的名稱。這個名稱的格式是/dev/pts/NNN。文件中接下來的函數是ptys_open,該函數真正被用來打開一個從設備。在SVR4系統中,如果調用者是一個還沒有控制終端的會話,open就會分配一個從設備作爲控制終端。如果我們不希望函數自動做這件事,可以在調用時指明O_NOCTTY標誌。

  在打開從設備後,我們將三個流模塊放在從設備的流上。Ptem是僞終端虛擬模塊,ldterm是終端行規程模塊。這兩個模塊合在一起象一個真正的終端模塊一樣工作。ttcompat提供了向老系統如V7、4BSD和Xenix的ioctl調用的兼容性。這是一個可選的模塊,但是因爲它自動嘗試控制檯登錄和網絡登錄(見程序12.10的輸出),我們將其加到從設備的流中。

  調用這兩個函數的結果是得到:僞終端主設備的文件描述符和從設備的文件描述符。19.3.2 4.3+BSD在4.3+BSD系統中我們必須自己來確定第一個可用的僞終端主設備。爲達到這個目的,我們從/dev/ptyp0開始並不斷嘗試直到成功打開一個可用的僞終端主設備或試完所有設備。在打開設備的時候,我們會看到兩種可能的錯誤:EIO指設備已經被使用;ENOENT表示設備不存在。在後一種情況,我們可以停止搜索,因爲所有的僞終端設備都在被使用中。一旦我們成功打開一個例如名爲/dev/ptyMN的僞終端主設備,那麼對應的從設備的名稱爲/dev/ttyMN。

  程序19.2中的函數ptys_open打開該從設備。我們在該函數中調用chown和chmod,必須意識到調用這兩個函數的進程必須有超級用戶的權限。如果必須改變權限標誌,那麼這兩個函數必須放在一個set_user_ID的root用戶的可執行程序中,這類似於4.3+BSD系統下的grantpt函數。

  在4.3+BSD系統之下打開pty從設備不具有象分配作爲控制終端的設備那樣的副作用。我們將在下一節探討如何在4.3+BSD系統下分配控制終端。這個函數嘗試16個不同的僞終端主設備:從/dev/ptyp0到/dev/ptyTf。具體有效的pty設備號取決於兩個因素:(a)在內核中配置的號碼;(b)在/dev目錄下的特殊文件號。對於任何程序來說,有效的號碼是(a)和(b)中較小的一個。並且,即使(a)和(b)中小的值大於64,許多現有的BSD應用(telnetd,rlogind,等等)會搜索程序19.2中第一個for循環中的pqrs。

______________________________________________________
#include
#include
#include
#include
#include
#include ourhdr.h

  使用ENOENT表示設備不存在。在後一種情況,我們可以停止搜索,因爲所有的僞終端設備都在被使用中。一旦我們成功打開一個例如名爲/dev/ptyMN的僞終端主設備,那麼對應的從設備的名稱爲/dev/ttyMN。

  程序19.2中的函數ptys_open打開該從設備。我們在該函數中調用chown和chmod,必須意識到調用這兩個函數的進程必須有超級用戶的權限。如果必須改變權限標誌,那麼這兩個函數必須放在一個set_user_ID的root用戶的可執行程序中,這類似於4.3+BSD系統下的grantpt函數。

  在4.3+BSD系統之下打開pty從設備不具有象分配作爲控制終端的設備那樣的副作用。我們將在下一節探討如何在4.3+BSD系統下分配控制終端。

  這個函數嘗試16個不同的僞終端主設備:從/dev/ptyp0到/dev/ptyTf。具體有效的pty設備號取決於兩個因素:(a)在內核中配置的號碼;(b)在/dev目錄下的特殊文件號。對於任何程序來說,有效的號碼是(a)和(b)中較小的一個。並且,即使(a)和(b)中小的值大於64,許多現有的BSD應用(telnetd,rlogind,等等)會搜索程序19.2中第一個for循環中的pqrs。

_________________________________________________________
#include
#include
#include
#include
#include
#include ourhdr.h
int
ptym_open(char *pts_name)
{
int fdm;
char *ptr1, *ptr2;
strcpy(pts_name, /dev/ptyXY);
/* array index: 0123456789 (for references in following code) */
for (ptr1 = pqrstuvwxyzPQRST; *ptr1 != 0; ptr1++) {
pts_name[8] = *ptr1;
for (ptr2 = 0123456789abcdef; *ptr2 != 0; ptr2++) {
pts_name[9] = *ptr2;
/* try to open master */
if ( (fdm = open(pts_name, O_RDWR)) 0) {
if (errno == ENOENT) /* different from EIO */
return(-1); /* out opty devices */
else
continue; /* try nxt pty device */
}pts_name[5] = t;
/* change pty to tty */return(fdm);
/* got it, return fd of master */
}
}
return(-1); /* out of pty devices */
}
int
ptys_open(int fdm, char *pts_name)
{
struct group *grptr;
int gid, fds;
if ( (grptr = getgrnam(tty)) != NULL)gid = grptr-gr_gid;
else
gid = -1; /* group tty is not in the group file */
/* following two functions dont work unless were root/
chown(pts_name, getuid(), gid);
chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP);
if ( (fds = open(pts_name, O_RDWR)) 0) {
close(fdm);
return(-1);
}
return(fds);
}
_______________________________________________________
程序19.2 4.3+BSD系統下的僞終端open函數

發佈了13 篇原創文章 · 獲贊 4 · 訪問量 36萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章