这是伪终端的混乱世界。
在本地,当您调整终端大小时,您的前台进程组会得到一个SIGWINCH
,您可以使用它ioctl
来获取新大小。但这与远程vim 进程有什么关系?
这个主题非常复杂,但要点是删除服务器(sshd)这样做:
posix_openpt
使用(或openpty
)打开一个主psedoterminal设备
- 分叉一个新的孩子(通常这一定会成为一个外壳)
- 使用
setsid()
- 打开成为其控制终端的终端设备(在步骤 1 中创建)
- 用步骤 4 中的 fd替换标准描述符(
STDIN_FILENO
和朋友)
此时,服务器进程写入主端的任何内容最终都会作为从端的输入,但带有终端线路规则,因此内核在编写某些组合时会做一些魔术 - 比如发送信号,您也可以发出ioctl
调用具有有用的效果。
考虑这一点的最佳方法是探索openssh
套件。
客户端监听SIGWINCH
- 查看clientloop.c
并received_window_change_signal = 1
在收到时设置
该函数client_check_window_change
检查该标志并告诉服务器:
packet_start(SSH_CMSG_WINDOW_SIZE);
packet_put_int((u_int)ws.ws_row);
...
所以现在服务器应该收到一个指定(可能是新的)大小的数据包。
服务器使用接收到的大小进行调用pty_change_window_size
,这具有真正的魔力:
struct winsize w;
w.ws_row = row;
...
(void) ioctl(ptyfd, TIOCSWINSZ, &w); /* This is it! */
这将设置从属设备的新窗口大小。如果新大小与旧大小不同,内核将向与该 pty 关联的前台进程组发送一个。SIGWINCH
因此vim
也获得了该信号并可以更新其对终端大小的想法。