ptmx/pts
来源:互联网 发布:深圳软件开发外包公司 编辑:程序博客网 时间:2024/06/05 03:45
简介
ptmx,pts pseudo terminal master and slave
ptmx与pts配合实现pty(伪终端)
在telnet,ssh等远程终端工具中会使用到pty,通常的数据流是这样的 telnetd进程 ---> /dev/ptmx(master) ---> /dev/pts/?(slave) ---> getty
telnetd进程收到网络中的数据后,将数据丢给ptmx,ptmx像管道一样将数据丢给pts/?,getty进程从pts/?读取数据传递给shell去执行。
linux支持的两种pty
a. UNIX98 pseudoterminal,使用的是devpts文件系统,挂载在/dev /pts目录
b. 在UNIX98 pseudoterminal之前,master pseudoterminal名字为/dev/ptyp0,…,slave pseudoterminal名字为/dev/ttyp0,…,这个方法需要预先分配好很多的设备节点。
只有在open /dev/ptmx程序不退出的情况下,/dev/pts/目录下才会有对应的设备节点
在程序执行”open /dev/ptmx”的时候会在/dev/pts/目录下生成一个设备节点,比如0,1…,但是当程序退出的时候这个设备节点就消失了。可以通过如下一个例子演示在”open /dev/ptmx”的时候在/dev/pts目录下生成的设备节点
$ ls /dev/pts; ls /dev/pts </dev/ptmx0 1 2 ptmx0 1 2 3 ptmx
可见在重定向/dev/ptmx的时候在/dev/pts目录下多了个设备节点3,而当上面这个shell结束的时候再次ls /dev/pts目录,设备节点3又消失了。
程序
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <pty.h>int main(){ int fd_m, fd_s; int len; const char *pts_name; char send_buf[64] = "abc\ndefghijk\nlmn"; char recv_buf[64] = {0}; fd_m = open("/dev/ptmx", O_RDWR | O_NOCTTY); if (fd_m < 0) { printf("open /dev/ptmx fail\n"); return -1; } if (grantpt(fd_m) < 0 || unlockpt(fd_m) < 0) { printf("grantpt and unlockpt fail\n"); goto err; } pts_name = (const char *)ptsname(fd_m); fd_s = open(pts_name, O_RDONLY | O_NOCTTY); if (fd_s < 0) { printf("open /dev/ptmx fail\n"); goto err; } len = write(fd_m, send_buf, strlen(send_buf)); printf("write len=%d\n", len); len = read(fd_s, recv_buf, sizeof(recv_buf)); printf("read len=%d, recv_buf=[%s]\n", len, recv_buf); len = read(fd_s, recv_buf, sizeof(recv_buf)); printf("read len=%d, recv_buf=[%s]\n", len, recv_buf); close(fd_m); close(fd_s); return 0;err: if (fd_m) close(fd_m); if (fd_s) close(fd_s); return -1;}
上面这段程序的输出如下:
read只有遇到换行符’\n’的时候才会返回,否则遇不到的话一直阻塞在那里。
每open /dev/ptmx就会得到一个新的文件描述符,并且在/dev/pts/目录下生成一个与这个文件描述符对应的新的设备节点
当进程open “/dev/ptmx”的时候,获得了一个新的pseudoterminal master(PTM)的文件描述符,同时会在/dev/pts目录下自动生成一个新的pseudoterminal slave(PTS)设备。每次open “/dev/ptmx”会得到一个不同的PTM文件描述符(多次open会得到多个文件描述符),并且有和这个PTM描述符关联的PTS。
grantpt, unlockpt: 在每次打开pseudoterminal slave的时候,必须传递对应的PTM的文件描述符。grantpt以获得权限,然后调用unlockpt解锁
ptsname: 将PTM的文件描述符作为参数,会得到该描述符对应的PTS的路径
向PTM写的数据可以从PTS读出来,向PTS写的数据可以从PTM读出来。
原理
对ptmx执行open操作,将创建一对tty主从设备
tty_init cdev_init(&ptmx_cdev, &ptmx_fops);//创建了/dev/ptmx设备节点 //此时/dev/ptmx设备节点的open函数为ptmx_fops.ptmx_open()static int ptmx_open(struct inode *inode, struct file *filp){ ... idr_ret = idr_get_new(&allocated_ptys, NULL, &index); ... //NR_UNIX98_PTY_DEFAULT也就是4096个 if (index >= pty_limit) { ... } ... mutex_lock(&tty_mutex); //以index为pts的设备索引号,创建成对的主从设备ptmx和pts retval = init_dev(ptm_driver, index, &tty); mutex_unlock(&tty_mutex); ... retval = ptm_driver->open(tty, filp); ...
所以在fd_m = open("/dev/ptmx", O_RDWR)
操作之后,将产生一个成对的ptmx和pts主从pty设备,并返回ptmx对应的文件描述符。
调用ioctl获得与ptmx对应的pts的设备节点
tty_ioctl tty->driver->ioctl //在unix98_pty_init()中,仅对ptmx主设备赋予了ioctl操作,`ptm_driver->ioctl =pty_unix98_ioctl;` pty_unix98_ioctlstatic int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ switch (cmd) { case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ return pty_set_lock(tty, (int __user *)arg); case TIOCGPTN: /* Get PT Number */ //当前tty对应的为ptmx结构,它的index就是与之配对的pts return put_user(tty->index, (unsigned int __user *)arg); } return -ENOIOCTLCMD;}
看看glibc库中如何封装ptsname函数
char* ptsname( int fd ){ unsigned int pty_num; static char buff[64]; //最终调用上面的pty_unix98_ioctl获取当前ptmx主设备对应的pty从设备号. if ( ioctl( fd, TIOCGPTN, &pty_num ) != 0 ) return NULL; //格式化为/dev/pts/0,/dev/pts/1等,即:pts对应的文件全路径. snprintf( buff, sizeof(buff), "/dev/pts/%u", pty_num ); return buff;}
adb中遇到的场景
我在移植adb到linux平台的时候,涉及到pts、ptmx,需要在内核中配置如下:
Device driver` Character devices [*]Enable TTY [*]Unix98 PTY support [*]Support multiple instances of devptsConfig busybox setting Busybox Setting General Configuration Use the devpts filesystem for unix98 PTYs
选项选择好编译,再次去除这些选项之后再编译会出问题,报如下错误:
WARNING: arch/rlx/bsp/built-in.o(.text+0x4): Section mismatch in reference from the function >disable_early_printk() to the variable .init.data:promcons_output The function disable_early_printk() references the variable __initdata promcons_output. This is often because disable_early_printk lacks a __initdata annotation or the annotation of promcons_output is wrong. WARNING: arch/rlx/bsp/built-in.o(.text+0x10): Section mismatch in reference from the function >disable_early_printk() to the variable .init.data:promcons_output The function disable_early_printk() references the variable __initdata promcons_output. This is often because disable_early_printk lacks a __initdata annotation or the annotation of promcons_output is wrong. WARNING: arch/rlx/bsp/built-in.o(.data+0x1710): Section mismatch in reference from the variable >rts1_camera_device to the variable .init.rodata:rts1_soc_camera_pdata The variable rts1_camera_device references the variable __initconst rts1_soc_camera_pdata If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: _template, _timer, _sht, _ops, _probe, _probe_one, *_console
解决办法:
不用去修改这些文件的错误,虽然这些文件本身编译可能有问题。
可以这么做,在busybox和linux内核目录下做make clean和make distclean
然后再重新编译。
实际上后来发现,busybox中不需要配置,只要在内核中配置就行了。
内核配置并且编译之后,系统支持pts
进入终端执行:mount -t devpts none /dev/pts
如果没有/dev/pts这个目录的话,执行mkdir -p /dev/pts创建一个目录
参考文章
- ptmx(4) - Linux man page
- Linux中的伪终端编程
- 浅析terminal创建时ptmx和pts关系
- linux-3.14/Documentation/filesystems/devpts.txt 5.
- ptmx/pts
- tty pty pts ptmx
- Linux下tty/pty/pts/ptmx详解
- Linux下tty/pty/pts/ptmx详解
- Linux下tty/pty/pts/ptmx详解
- Linux下tty/pty/pts/ptmx详解
- 浅析terminal创建时ptmx和pts关系
- 浅析terminal创建时ptmx和pts关系
- termial创建时ptmx与pts的关系
- 浅析terminal创建时ptmx和pts关系
- Linux下tty/pty/pts/ptmx详解(转)
- 伪终端设备ttySx/ttyx/ptyMN/ttyMN/ptmx/(pts/x)
- Linux下tty/pty/pts/ptmx详解(转)
- 浅析ptmx代码级open如何运作ptyp,ttyp,pts伪终端(转载)
- pts/0 pts/1
- DTS/PTS
- pts & dts
- DTS/PTS
- MFC库参考 典型HTTP客户端应用程序中的步骤
- 嵌入式操作系统与物联网演进之路
- 阿里云配置JAVA开发环境并部署WAR包
- php5.2 、5.3、5.4、5.5、5.6 各个版本升级不兼容点
- Date格式的时间,后面有个.0的处理方式
- ptmx/pts
- Highcharts应用--百分比条形图
- 关于jw和e^jwt的领悟
- PHP的ECSHOP商城的改造成MVC添加商品功能总结
- Tensorflow常识
- 团队用过最好的bug管理软件-delbug管理
- centos7使用setup
- 记微信开发牢骚
- PyQt4学习笔记---------------Day_1(Demo_1.pyw)