apue 第19章 伪终端

Posted 思而不学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了apue 第19章 伪终端相关的知识,希望对你有一定的参考价值。

 伪终端是指对于一个应用程序而言,他看上去像一个终端,但事实上它并不是一个真正的终端。

  • 进程打开伪终端设备,然后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章 伪终端的主要内容,如果未能解决你的问题,请参考以下文章

apue 第4章 文件和目录

apue 第10章 信号signal

APUE第3章 文件I/O

Android高级终端开发学习笔记(《疯狂Android讲义》第11章-第17章)

Unix编程第7章 进程环境

Ryzen APU驱动安装笔记