1. 程式人生 > >apue 第19章 偽終端

apue 第19章 偽終端

fcntl 文件 分享 奇偶校驗 solaris file 訪問 tde for

偽終端是指對於一個應用程序而言,他看上去像一個終端,但事實上它並不是一個真正的終端。

  • 進程打開偽終端設備,然後fork。子進程建立一個新的會話,打開一個相應的偽終端從設備。復制輸入、輸出和標準錯誤文件描述符,調用exec,子進程從設備編程偽終端。
  • 偽終端能像終端一樣,但是無意義的函數調用如改變波特率、發送中斷符、設置奇偶校驗將被忽略。
  • 偽終端可以做輸入和輸出。

posix_opent函數提供了一種可移植的方法來打開下一個可用偽終端主設備

#include <stdlib.h>
#include <fcntl.h>

int posix_openpt(int flags);
返回值:成功返回下一個可用的PTY主設備文件描述符,出錯
-1 flags:設備操作標記,可以是0或者以下兩項的之一,O_RDWR允許對設備同時進行讀寫操作,此標記通常需要指定
O_NOCTTY不將設備作為進程的控制終端

在偽終端從設備可用之前,它的權限必須設置,以便應用程序可以訪問它。

改變指定master對應從設備的屬主與訪問權限

#define _XOPEN_SOURCE
#include <stdlib.h>

int grantpt(int fd);
int unlockpt(int fd);
返回值:成功0,出錯-1
fd:文件描述符

ptsname返回PTY從設備的名字

#define _XOPEN_SOURCE
#include 
<stdlib.h> char *ptsname(int fd); #define _GNU_SOURCE #include <stdlib.h> int ptsname_r(int fd, char *buf, size_t buflen);
fd:文件描述符

apue寫的函數,打開下一個可用的PTY主設備。調用者必須分配一個數組來存放主設備或從設備名字。

#include "apue.h"

int ptym_open(char *pts_name, int pts_namesz);
返回值:成功返回PTY主設備文件描述符,出錯-1
int ptys_open(char
*pts_name);
返回值:成功返回PTY設備文件描述符,出錯-1
pts_name:打開設備的名字
pts_namesz:緩沖區字節長度

實現函數:

技術分享圖片
#include "apue.h"
#include <errno.h>
#include <fcntl.h>
#if defined(SOLARIS)
#include <stropts.h>
#endif

int ptym_open(char *pts_name, int pts_namesz)
{
    char *ptr;
    int fdm, err;

    if((fdm = posix_openpt(O_RDWR)) < 0)
        return(-1);
    if(grantpt(fdm) < 0)
        goto errout;
    if(unlock(fdm) < 0)
        goto errout;
    if((ptr = ptsname(fmd)) == NULL)
        goto errout;

    strncpy(pts_name, ptr, pts_namesz);
    pts_name[pts_namesz - 1] = \0;
    return(fdm);
errout:
    err = errno;
    close(fdm);
    errno = err;
    return(-1);
}

int ptys_open(char *pts_name)
{
    int fds;
#if defined(SOLARIS)
    int err, setup;
#endif

    if((fds = open(pts_name, O_RDWR)) < 0)
        goto errout; 

    if(setup == 0) {
        if(ioctl(fds, I_PUSH, "ptem") < 0)
            goto errout;
        if(ioctl(fds, I_PUSH, "ldterm") < 0)
            goto errout;
        if(ioctl(fds, I_PUSH, "ttcompat") < 0) {
errout:
            err = errno;
            close(fds);
            errno = err;
            return(-1);
        }
    }
#endif
    return(fds);
}
pty_open

用fork調用打開主設備和從設備,創建作為會話首進程的子進程並使其具有控制終端。

#include "apue.h"
#include <termios.h>

pid_t pty_fork(int *ptrfdm, char *slave_name, int slave_namesz,
    const struct termios *slave_termios,
    const struct winsize *slave_winsize);

pty_fork函數

技術分享圖片
 1 #include "apue.h"
 2 #include <termios.h>
 3 
 4 pid_t pty_fork(int *ptrfdm, char *slave_name, int slave_namesz,
 5         const struct termios *slave_termios,
 6         const struct winsize *slave_winsize)
 7 {
 8     int fdm, fds;
 9     pid_t pid;
10     char pts_name[20];
11 
12     if((fdm = ptym_open(pts_name, sizeof(pts_name))) < 0)
13         err_sys("can‘t open master pty: %s, error %d", pts_name, fdm);
14 
15     if(slave_name != NULL) {
16         strncpy(slave_name, pts_name, slave_namesz);
17         slave_name[slave_namesz - 1] = \0;
18     }
19 
20     if((pid = fork()) < 0)
21         return(-1);
22     else if(pid == 0) {                /* childe */
23         if(setsid() < 0)
24             err_sys("setsid error");
25 
26         if((fds = ptys_open(pts_name)) < 0)
27             err_sys("can‘t open slave pty");
28         close(fdm);
29 #if defined(BSD)
30         if(ioctl(fds, TIOCSCTTY, (char *)0) < 0)
31             err_sys("TIOCSCTTY error");
32 #endif
33         if(slave_termios != NULL) {
34             if(tcsetattr(fds, TCSANOW, slave_termios) < 0)
35                 err_sys("tcsetattr error on slave pty");
36         }
37         if(slave_winsize != NULL) {
38             if(ioctl(fds, TIOCSWINSZ, slave_winsize) < 0)
39                 err_sys("TIOCSWINSZ error on slave pty");
40         }
41 
42         if(dup2(fds, STDIN_FILENO) != STDIN_FILENO)
43             err_sys("dup2 error to stdin");
44         if(dup2(fds, STDOUT_FILENO) != STDOUT_FILENO)
45             err_sys("dup2 error to stdout");
46         if(dup2(fds, STDERR_FILENO) != STDERR_FILENO)
47             err_sys("dup2 error to stderr");
48         if(fds != STDIN_FILENO && fds  != STDOUT_FILENO &&
49             fds != STDERR_FILENO)
50             close(fds);
51         return(0);
52     } else {
53         *ptrfdm = fdm;
54         return(pid);
55     }
56 }
pty_fork

apue 第19章 偽終端