⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 19.htm

📁 UNIX环境下C编程的详细详细介绍
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<p>程序19.1 SVR4的伪终端打开函数 </p>

<p>我们首先打开设备/dev/ptmx并得到伪终端主设备的文件描述符。打开这个</p>

<p>主设备 </p>

<p>自动锁定了对应的从设备。 </p>

<p>我们然后调用grantpt来改变从设备的权限。执行如下操作:(a)将从设备</p>

<p>的所 </p>

<p>有权改为有效用户ID;(b)将组所有权改为组tty;(c)将权限改为只允许</p>

<p>user </p>

<p>-read,user-write和group-write。将组所有权设置为tty并允许</p>

<p>group-write权限 </p>

<p>是因为程序wall(1)和write(1)的组标识符被设置为组tty。调用函数</p>

<p>grantpt执行 </p>

<p>/user/lib/pt_chmod。该程序的用户被设置为root因此它能够修改从设备</p>

<p>的所有者 </p>

<p>和权限。 </p>

<p>函数unlockpt用来清除从设备的内部锁。在打开从设备前我们必须做这件事</p>

<p>情。 </p>

<p>并且我们必须调用ptsname来得到从设备的名称。这个名称的格式是</p>

<p>/dev/pts/NNN </p>

<p>。 </p>

<p>文件中接下来的函数是ptys_open,该函数真正被用来打开一个从设备。在</p>

<p>SVR4系 </p>

<p>统中,如果调用者是一个还没有控制终端的会话,open就会分配一个从设备</p>

<p>作为控 </p>

<p>制终端。如果我们不希望函数自动做这件事,可以在调用时指明O_NOCTTY标</p>

<p>志。 </p>

<p>在打开从设备后,我们将三个流模块放在从设备的流上。Ptem是&quot;伪终端&quot;虚</p>

<p>拟模 </p>

<p>块,ldterm是终端行规程模块。这两个模块合在一起象一个真正的终端模块</p>

<p>一样工 </p>

<p>作。ttcompat提供了向老系统如V7、4BSD和Xenix的ioctl调用的兼容性。</p>

<p>这是一个 </p>

<p>可选的模块,但是因为它自动尝试控制台登录和网络登录(见程序12.10的输</p>

<p>出) </p>

<p>,我们将其加到从设备的流中。 </p>

<p>调用这两个函数的结果是得到:伪终端主设备的文件描述符和从设备的文件描</p>

<p>述 </p>

<p>符。 </p>

<p>19.3.2 4.3+BSD </p>

<p>在4.3+BSD系统中我们必须自己来确定第一个可用的伪终端主设备。为达到这</p>

<p>个目 </p>

<p>的,我们从/dev/ptyp0开始并不断尝试直到成功打开一个可用的伪终端主设</p>

<p>备或试 </p>

<p>完所有设备。在打开设备的时候,我们会看到两种可能的错误:EIO指设备已</p>

<p>经被 </p>

<p>使用;ENOENT表示设备不存在。在后一种情况,我们可以停止搜索,因为所</p>

<p>有的伪 </p>

<p>终端设备都在被使用中。一旦我们成功打开一个例如名为/dev/ptyMN的伪终</p>

<p>端主设 </p>

<p>备,那么对应的从设备的名称为/dev/ttyMN。 </p>

<p>程序19.2中的函数ptys_open打开该从设备。我们在该函数中调用chown和</p>

<p>chmod, </p>

<p>必须意识到调用这两个函数的进程必须有超级用户的权限。如果必须改变权限</p>

<p>标志 </p>

<p>,那么这两个函数必须放在一个set_user_ID的root用户的可执行程序中,</p>

<p>这类似 </p>

<p>于4.3+BSD系统下的grantpt函数。 </p>

<p>在4.3+BSD系统之下打开pty从设备不具有象分配作为控制终端的设备那样的</p>

<p>副作用 </p>

<p>。我们将在下一节探讨如何在4.3+BSD系统下分配控制终端。 </p>

<p>这个函数尝试16个不同的伪终端主设备:从/dev/ptyp0到/dev/ptyTf。具</p>

<p>体有效的 </p>

<p>pty设备号取决于两个因素:(a)在内核中配置的号码;(b)在/dev目录</p>

<p>下的特 </p>

<p>殊文件号。对于任何程序来说,有效的号码是(a)和(b)中较小的一个。</p>

<p>并且, </p>

<p>即使(a)和(b)中小的值大于64,许多现有的BSD应用(telnetd,</p>

<p>rlogind,等 </p>

<p>等)会搜索程序19.2中第一个for循环中的&quot;pqrs&quot;。 </p>

<p>_______________________________________________________________________</p>

<p>________ </p>

<p>#include &lt;sys/types.h&gt; </p>

<p>#include &lt;sys/stat.h&gt; </p>

<p>#include &lt;errno.h&gt; </p>

<p>#include &lt;fcntl.h&gt; </p>

<p>#include &lt;grp.h&gt; </p>

<p>#include &quot;ourhdr.h&quot; </p>

<p>使用;ENOENT表示设备不存在。在后一种情况,我们可以停止搜索,因为所</p>

<p>有的伪 </p>

<p>终端设备都在被使用中。一旦我们成功打开一个例如名为/dev/ptyMN的伪终</p>

<p>端主设 </p>

<p>备,那么对应的从设备的名称为/dev/ttyMN。 </p>

<p>程序19.2中的函数ptys_open打开该从设备。我们在该函数中调用chown和</p>

<p>chmod, </p>

<p>必须意识到调用这两个函数的进程必须有超级用户的权限。如果必须改变权限</p>

<p>标志 </p>

<p>,那么这两个函数必须放在一个set_user_ID的root用户的可执行程序中,</p>

<p>这类似 </p>

<p>于4.3+BSD系统下的grantpt函数。 </p>

<p>在4.3+BSD系统之下打开pty从设备不具有象分配作为控制终端的设备那样的</p>

<p>副作用 </p>

<p>。我们将在下一节探讨如何在4.3+BSD系统下分配控制终端。 </p>

<p>这个函数尝试16个不同的伪终端主设备:从/dev/ptyp0到/dev/ptyTf。具</p>

<p>体有效的 </p>

<p>pty设备号取决于两个因素:(a)在内核中配置的号码;(b)在/dev目录</p>

<p>下的特 </p>

<p>殊文件号。对于任何程序来说,有效的号码是(a)和(b)中较小的一个。</p>

<p>并且, </p>

<p>即使(a)和(b)中小的值大于64,许多现有的BSD应用(telnetd,</p>

<p>rlogind,等 </p>

<p>等)会搜索程序19.2中第一个for循环中的&quot;pqrs&quot;。 </p>

<p>_______________________________________________________________________</p>

<p>________ </p>

<p>#include &lt;sys/types.h&gt; </p>

<p>#include &lt;sys/stat.h&gt; </p>

<p>#include &lt;errno.h&gt; </p>

<p>#include &lt;fcntl.h&gt; </p>

<p>#include &lt;grp.h&gt; </p>

<p>#include &quot;ourhdr.h&quot; </p>

<p>int </p>

<p>ptym_open(char *pts_name) </p>

<p>{ </p>

<p>int fdm; </p>

<p>char *ptr1, *ptr2; </p>

<p>strcpy(pts_name, &quot;/dev/ptyXY&quot;); </p>

<p>/* array index: 0123456789 (for references in following</p>

<p>code) */ </p>

<p>for (ptr1 = &quot;pqrstuvwxyzPQRST&quot;; *ptr1 != 0; ptr1++) { </p>

<p>pts_name[8] = *ptr1; </p>

<p>for (ptr2 = &quot;0123456789abcdef&quot;; *ptr2 != 0; ptr2++) { </p>

<p>pts_name[9] = *ptr2; </p>

<p>/* try to open master */ </p>

<p>if ( (fdm = open(pts_name, O_RDWR)) &lt; 0) { </p>

<p>if (errno == ENOENT) /* different from EIO */ </p>

<p>return(-1); /* out o </p>

<p>pty devices */ </p>

<p>else </p>

<p>continue; /* try n </p>

<p>xt pty device */ </p>

<p>} </p>

<p>pts_name[5] = 't'; /* change &quot;pty&quot; to &quot;tty&quot; */ </p>

<p>return(fdm); /* got it, return fd of master * </p>

<p>} </p>

<p>} </p>

<p>return(-1); /* out of pty devices */ </p>

<p>} </p>

<p>int </p>

<p>ptys_open(int fdm, char *pts_name) </p>

<p>{ </p>

<p>struct group *grptr; </p>

<p>int gid, fds; </p>

<p>if ( (grptr = getgrnam(&quot;tty&quot;)) != NULL) </p>

<p>gid = grptr-&gt;gr_gid; </p>

<p>else </p>

<p>gid = -1; /* group tty is not in the group file */ </p>

<p>/* following two functions don't work unless we're root </p>

<p>/ </p>

<p>chown(pts_name, getuid(), gid); </p>

<p>chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP); </p>

<p>if ( (fds = open(pts_name, O_RDWR)) &lt; 0) { </p>

<p>close(fdm); </p>

<p>return(-1); </p>

<p>} </p>

<p>return(fds); </p>

<p>} </p>

<p>_______________________________________________________________________</p>

<p>________ </p>

<p>程序19.2 4.3+BSD系统下的伪终端open函数 </p>

<p>19.4 pty_fork函数 </p>

<p>现在我们使用上一节中的两个函数:ptym_open和ptys_open,编写我们称</p>

<p>之为pty </p>

<p>_fork的函数。这个新函数具有了如下功能:打开主设备和从设备,建立作为</p>

<p>会话 </p>

<p>管理者的子进程并使其具有控制终端。 </p>

<p>#include &lt;sys/types.h&gt; </p>

<p>#include &lt;termios.h&gt; </p>

<p>#include &lt;sys/ioctl.h&gt; /* 4.3+BSD系统中,在这里定义了winsize结</p>

<p>构 */ </p>

<p>#include &lt;ourhdr.h&gt; </p>

<p>pid_t pty_fork(int *ptrfdm, char *slave_name, </p>

<p>const struct termios *slave_termios, </p>

<p>const struct winsize *slave_winsize); </p>

<p>返回:在子进程返回0;在父进程返回子进程的进程ID;遇到错误返回-1 
</p>

<p>Pty主设备的文件描述符通过ptrfdm指针返回。 </p>

<p>如果slave_name不为空,从设备的名称被存放在该指针指向的存储区中。调</p>

<p>用者必 </p>

<p>须为该存储区分配空间。 </p>

<p>如果指针slave_termios不为空,该指针所引用的结构将从设备的终端行规</p>

<p>程初始 </p>

<p>化。如果该指针为空,系统将从设备的termios结构初始化为一个由具体应用</p>

<p>定义 </p>

<p>的初始状态。类似的,如果slave_winsize指针不为空,该指针所引用的结</p>

<p>构将从 </p>

<p>设备的窗口大小初始化。如果该指针为空,winsize结构通常被初始化为0。</p>

<p>程序19.3显示了这个程序的代码。调用相应的ptym_open和ptys_open函</p>

<p>数,这个函 </p>

<p>数在SVR4和4.3+BSD系统下都可以使用。 </p>

<p>在打开伪终端主设备后,fork将被调用。正如前面提到的,我们要等到调用</p>

<p>setid </p>

<p>建立新的会话后才调用ptys_open。当调用setid时,子进程还不是一个进程</p>

<p>组的l </p>

<p>eader(想一想为什么?)因此第9.5节列出的三个操作被使用:(a)子进</p>

<p>程作为 </p>

<p>对话的管理者创建一个新的对话;(b)子进程创建一个新的进程组;(c)</p>

<p>子进程 </p>

<p>没有控制终端。在SVR4系统中,当调用ptys_open时,从设备成为了控制终</p>

<p>端。在 </p>

<p>4.3+BSD系统中,我们必须调用ioctl并使用参数TIOCSCTTY来分配一个控制</p>

<p>终端。 </p>

<p>然后termios和winsize这两个结构在子进程中被初始化。最后从设备的文件</p>

<p>描述符 </p>

<p>被复制到子进程的标准输入、标准输出和标准出错中。这表示由子进程所</p>

<p>exec的进 </p>

<p>程都会将上述三个句柄同伪终端从设备联系起来。 </p>

<p>在调用fork后,父进程返回伪终端主设备的描述符并返回。在下一节我们将</p>

<p>在pty </p>

<p>程序中使用pty_fork。 </p>

<p>_______________________________________________________________________</p>

<p>________ </p>

<p>#include &lt;sys/types.h&gt; </p>

<p>#include &lt;termios.h&gt; </p>

<p>#ifndef TIOCGWINSZ </p>

<p>#include &lt;sys/ioctl.h&gt; /* 44BSD requires this too */ </p>

<p>#endif </p>

<p>#include &quot;ourhdr.h&quot; </p>

<p>pid_t </p>

<p>pty_fork(int *ptrfdm, char *slave_name, </p>

<p>const struct termios *slave_termios, </p>

<p>const struct winsize *slave_winsize) </p>

<p>{ </p>

<p>int fdm, fds; </p>

<p>pid_t pid; </p>

<p>char pts_name[20]; </p>

<p>if ( (fdm = ptym_open(pts_name)) &lt; 0) </p>

<p>err_sys(&quot;can't open master pty: %s&quot;, pts_name); </p>

<p>if (slave_name != NULL) </p>

<p>strcpy(slave_name, pts_name); /* return name of slave */ </p>

<p>if ( (pid = fork()) &lt; 0) </p>

<p>return(-1); </p>

<p>else if (pid == 0) { /* child */ </p>

<p>if (setsid() &lt; 0) </p>

<p>err_sys(&quot;setsid error&quot;); </p>

<p>/* SVR4 acquires controlling terminal on </p>

<p>open() */ </p>

<p>if ( (fds = ptys_open(fdm, pts_name)) &lt; 0) </p>

<p>err_sys(&quot;can't open slave pty&quot;); </p>

<p>err_sys(&quot;dup2 error to stderr&quot;); </p>

<p>if (fds &gt; STDERR_FILENO) </p>

<p>close(fds); </p>

<p>return(0); /* child returns 0 just like fork() */ </p>

<p>} else { /* parent */ </p>

<p>*ptrfdm = fdm; /* return fd of master */ </p>

<p>return(pid); /* parent returns pid of child */ </p>

<p>} </p>

<p>} </p>

<p>_______________________________________________________________________</p>

<p>________ </p>

<p>程序19.3 pty_fork函数 </p>

<p>19.5 pty程序 </p>

<p>写pty程序的目的是为了用键入 </p>

<p>pty prog arg1 arg2 </p>

<p>来代替 </p>

<p>prog arg1 arg2 </p>

<p>这样使我们可以用pty来执行另一个程序,该程序在一个自己的会话中执行,</p>

<p>并和 </p>

<p>一个伪终端连接。 </p>

<p>让我们看以下pty程序的源代码。程序19.4包含main函数。它调用上一节的</p>

<p>pty_f </p>

<p>ork函数。 </p>

<p>_______________________________________________________________________</p>

<p>________ </p>

<p>#include &lt;sys/types.h&gt; </p>

<p>#include &lt;termios.h&gt; </p>

<p>#ifndef TIOCGWINSZ </p>

<p>#include &lt;sys/ioctl.h&gt; /* 44BSD requires this too */ </p>

<p>#endif </p>

<p>#include &quot;ourhdr.h&quot; </p>

<p>static void set_noecho(int); /* at the end of this file */ </p>

<p>void do_driver(char *); /* in the file driver.c */ </p>

<p>void loop(int, int); /* in the file loop.c */ </p>

<p>int </p>

<p>main(int argc, char *argv[]) </p>

<p>{ </p>

<p>int fdm, c, ignoreeof, interactive, noecho, </p>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -