1. 终端设备
1.1 终端设备的设备号
-
终端设备的主设备号是4,譬如:
$ ls -l /dev/tty1
$ crw–w---- 1 root tty 4, 1 Jan 8 19:48 /dev/tty1 [主设备号4,次设备号1]$ ls -l /dev/ttyS11
crw-rw---- 1 root dialout 4, 75 Jan 8 19:48 /dev/ttyS11 [主设备号4,次设备号75]
1.2 打开终端设备作为控制终端
贴上一段内核代码:
if (!(flag & O_NOCTTY) &&
current->leader &&
current->tty<0 &&
tty->session==0) {
current->tty = min;
tty->session= current->session;
tty->pgrp = current->pgrp;
}
可见,一个进程想打开一个终端设备作为控制终端的约束条件
- 进程为会话首领
- 进程原来没有控制终端
- 指定的终端设备并没有被其它会话用作控制终端
2. [伪]终端设备
原则:
伪终端设备都成对存在 [主设备+从设备]
实现:
不同种类的操作系统,其伪终端接口大不相同。本节描述的代码基于Ubuntu 19.04
主设备文件:/dev/ptmx
$ ls -l /dev/ptmx
$ crw-rw-rw- 1 root tty 5, 2 Jan 9 01:34 /dev/ptmx 【设备号:5,2】
从设备文件:/dev/pts/*
$ ls -l /dev/pts/*
crw–w---- 1 jianleya tty 136, 0 Jan 8 19:48 0 【设备号:136,0】
crw–w---- 1 jianleya tty 136, 1 Jan 8 20:56 1
crw–w---- 1 jianleya tty 136, 10 Jan 8 19:48 10
crw–w---- 1 jianleya tty 136, 11 Jan 8 19:48 11
2.1 伪终端设备接口
01)打开pts主设备,同时在/dev/pts下创建一个pts从设备
#include <stdlib.h>
#include <fcntl.h>
int posix_openpt(int flags);
CONFORMING TO
POSIX.1-2001, POSIX.1-2008.
02)打开伪终端 从设备
Before opening the pseudoterminal slave, you must pass the master's file descriptor to
grantpt(3) and unlockpt(3).
首先:grantpt : grant access to the slave pseudoterminal
#include <stdlib.h>
int grantpt(int fd);
CONFORMING TO
POSIX.1-2001, POSIX.1-2008.
其次:unlockpt
#include <stdlib.h>
int unlockpt(int fd);
CONFORMING TO
POSIX.1-2001, POSIX.1-2008.
再后:ptsname 获取从设备名称
#include <stdlib.h>
char *ptsname(int fd);
POSIX.1-2001, POSIX.1-2008.
最后:打开从设备文件
调用open函数可读可写,即可!
2.2 打开伪终端设备作为控制终端
参考如下过程:编码
示例代码
父进程打印出从子进程递送过来的从终端设备名:
输出:
/dev/pts/17
#include <iostream>
#include <string>
using namespace std;
extern "C"
{
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
}
int main(void)
{
int fdm = posix_openpt(O_RDWR);
if(-1 == fdm)
{
cout << "open master pts devices failed" << endl;
return -1;
}
int res = grantpt(fdm);
if(-1 == res)
{
cout << "grant slave pts device failed" << endl;
return -1;
}
res = unlockpt(fdm);
if(-1 == res)
{
cout <<"unlock slave pts device failed" << endl;
return -1;
}
pid_t pid =fork();
if(-1 == pid)
{
cout << "fork failed" << endl;
return -1;
}
else if(0 == pid)
{
/*child process*/
int res = setsid();
if(-1 == res)
{
cout << "setsid failed" << endl;
return -1;
}
char *ps_str = ptsname(fdm);
if(NULL==ps_str)
{
cout << "get slave pts device name failed" << endl;
return -1;
}
int fds=open(ps_str,O_RDWR);
if(-1 == fds)
{
cout << "open slave pts device failed" << endl;
return -1;
}
res = dup2(fds,STDIN_FILENO);
if(-1==res)
{
cout << "child: dup2 stdin failed" << endl;
return -1;
}
res=dup2(fds,STDOUT_FILENO);
if(-1==res)
{
cout << "child: dup2 stdout failed" << endl;
return -1;
}
cout << ttyname(STDIN_FILENO) << endl;
}
else
{
/*father process*/
/*comunicate with slave pts device*/
res = dup2(fdm,STDIN_FILENO);
if(-1==res)
{
cout << "dup2 stdin failed" << endl;
return -1;
}
string said_something;
cin >> said_something;
cout << said_something << endl;
int status = 0;
int res = waitpid(pid,&status,0);
if(-1 == res)
{
cout << "wait failed" << endl;
return -1;
}
}
}