Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PTY on Rust
Search
Hibariya Hi
July 12, 2015
Programming
1
1.4k
PTY on Rust
Hibariya Hi
July 12, 2015
Tweet
Share
More Decks by Hibariya Hi
See All by Hibariya Hi
Creating an Active Job Adapter for Cloud Run
hibariya
0
630
Idobata on GKE - Moving an Ordinary Rails App
hibariya
0
110
Using Docker for your Rails Development Environment
hibariya
1
3.1k
GraphQL Subscription with Relay and Action Cable
hibariya
1
2.4k
Various Services
hibariya
1
320
Building a Web API with GraphQL
hibariya
2
3.5k
My recent troubles in using Ember Data
hibariya
0
1k
Idobata をもっと便利に 使うための tips
hibariya
0
1.4k
Control a Shell With pty-shell
hibariya
0
1.8k
Other Decks in Programming
See All in Programming
Google I/O recap web編 大分Web祭り2025
kponda
0
2.9k
兎に角、コードレビュー
mitohato14
0
160
Improving my own Ruby thereafter
sisshiki1969
1
130
OSS開発者という働き方
andpad
5
1.5k
Honoアップデート 2025年夏
yusukebe
1
880
速いWebフレームワークを作る
yusukebe
2
300
Rancher と Terraform
fufuhu
2
150
AIエージェント開発、DevOps and LLMOps
ymd65536
1
370
Vue・React マルチプロダクト開発を支える Vite
andpad
0
110
Portapad紹介プレゼンテーション
gotoumakakeru
1
130
コンテキストエンジニアリング Cursor編
kinopeee
1
730
為你自己學 Python - 冷知識篇
eddie
1
310
Featured
See All Featured
Building an army of robots
kneath
306
46k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
15
1.6k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4k
Why Our Code Smells
bkeepers
PRO
339
57k
Six Lessons from altMBA
skipperchong
28
4k
The Language of Interfaces
destraynor
160
25k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
36
2.5k
Imperfection Machines: The Place of Print at Facebook
scottboms
268
13k
How to train your dragon (web standard)
notwaldorf
96
6.2k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
8
500
A designer walks into a library…
pauljervisheath
207
24k
Transcript
PTY on Rust 2015-07-12 Rust of Us - Chapter 2
@hibariya
やりたいこと • Rust で • PTY を使って • シェルの入出力を好きなようにする
こういうこと
こういうこと
入出力を好きなようにできると嬉しい • 何か入出力があるたびに音を鳴らせる • 出力を記録してあとで再現したりできる • ターミナルの表示を遠方の人と共有できる
方法 • パイプを使う • 親の端末につなぐ • システムコールを監視する • 新たな端末を割り付ける
方法 • パイプを使う • 親の端末につなぐ • システムコールを監視する • 新たな端末を割り付ける
パイプを使う 端末 <> 親 <> パイプ <> 子
パイプを使う • うまくいかない • デフォルトの端末はカノニカルモード (入力は行 ごとに親プロセスへ送られる) なので、改行が来 るまで入力を子プロセスへ送ることができない •
vi や nano が使えない • 端末に接続されていないのも都合が悪い
方法 • パイプを使う • 親の端末につなぐ • システムコールを監視する • 新たな端末を割り付ける
親の端末につなぐ 端末 <> 親 <> 子
親の端末につなぐ • うまくいかない • 入力はすぐに子プロセスへ届くが... • 親が子の入出力を捕捉できない • (方法を知らないだけ?)
方法 • パイプを使う • 親の端末につなぐ • システムコールを監視する • 新たな端末を割り付ける
システムコールを監視 自分 -> プロセス (write(2) を監視!)
システムコールを監視 github.com/hibariya/process_tail • ちょっと微妙 • 既に走っているプロセスにも使える • Linux と Mac
OS X で実装が別 • 環境によって微妙に動きが違うのができた • ちょっと重い気がする
方法 • パイプを使う • 親の端末につなぐ • システムコールを監視する • 新たな端末を割り付ける
新たな端末を割り付ける 端末 <> 親 <> 端末 <> 子 (親の端末は raw
モードに)
新たな端末を割り付ける note.hibariya.org/articles/20150628/pty.html • うまくいく • 既に走っているプロセスには使えない • 端末を想定しているコマンドも動作する • Linux
と Mac OS X でほぼ同じ実装 • 比較的シンプル
色々試した結果 • パイプを使う • 親の端末につなぐ • システムコールを監視する • 新たな端末を割り付ける
PTY (Pseudo terminal) • 疑似端末 • 端末をソフトウェアでエミュレートしたもの • ターミナルエミュレータなどが使っている •
/dev/pts/4 みたいな名前がついている
新たな端末を割り付ける 端末 <> 親 <> 端末 <> 子 (親の端末は raw
モードに)
Ruby で書くと1行 output, input, pid = PTY.spawn('bash')
Rust ではどうすれば • わからない • PTY.spawn は無かった • libc の
API を使えばやれそう • PTY の使い方を調べるところから
情報源 • script(1) のソース • Ruby の ext/pty/pty.c • APUE
第3版 18, 19章
PTY のしくみ • マスタとスレーブがある • 双方向パイプのように振る舞う • 親から子へ入力、子から親へ出力できる
PTY のしくみ マスタ <> スレーブ <> ラインディシプリン
PTY.spawn(‘bash’) のようなこと 1. 親でマスタ側を開いて fork 2. 子を新しいセッションに入れる 3. 子でスレーブ側を開く 4.
子でスレーブを標準入出力にする 5. 子で (bash を) exec 6. 親でマスタ越しに入出力を操作
PTY.spawn(‘bash’) のようなこと 1. 親でマスタ側を開いて fork 2. 子を新しいセッションに入れる 3. 子でスレーブ側を開く 4.
子でスレーブを標準入出力にする 5. 子で (bash を) exec 6. 親でマスタ越しに入出力を操作
親でマスタ側を開いて fork • posix_openpt (3) • スレーブを開くために grantpt (3), unlockpt
(3) も呼んでおく
PTY.spawn(‘bash’) のようなこと 1. 親でマスタ側を開いて fork 2. 子を新しいセッションに入れる 3. 子でスレーブ側を開く 4.
子でスレーブを標準入出力にする 5. 子で (bash を) exec 6. 親でマスタ越しに入出力を操作
子を新しいセッションに入れる • setsid (2) • セッションひとつにつき端末ひとつまで
PTY.spawn(‘bash’) のようなこと 1. 親でマスタ側を開いて fork 2. 子を新しいセッションに入れる 3. 子でスレーブ側を開く 4.
子でスレーブを標準入出力にする 5. 子で (bash を) exec 6. 親でマスタ越しに入出力を操作
子でスレーブ側を開く • ptsname (3) でスレーブの名前を得る • こっちは open(2) で開く
PTY.spawn(‘bash’) のようなこと 1. 親でマスタ側を開いて fork 2. 子を新しいセッションに入れる 3. 子でスレーブ側を開く 4.
子でスレーブを標準入出力にする 5. 子で (bash を) exec 6. 親でマスタ越しに入出力を操作
子でスレーブを標準入出力にする • dup (2) • この時点で入出力が端末につながる
PTY.spawn(‘bash’) のようなこと 1. 親でマスタ側を開いて fork 2. 子を新しいセッションに入れる 3. 子でスレーブ側を開く 4.
子でスレーブを標準入出力にする 5. 子で (bash を) exec 6. 親でマスタ越しに入出力を操作
PTY.spawn(‘bash’) のようなこと 1. 親でマスタ側を開いて fork 2. 子を新しいセッションに入れる 3. 子でスレーブ側を開く 4.
子でスレーブを標準入出力にする 5. 子で (bash を) exec 6. 親でマスタ越しに入出力を操作
できた • note.hibariya.org/articles/20150628/pty.html • Rust から同じものを FFI で呼べばよさそう
PTY on Rust FFI でライブラリの API を呼ぶ extern crate libc;
#[link(name = "c")] extern { pub fn posix_openpt(flags: libc::c_int) -> libc::c_int; pub fn grantpt(fd: libc::c_int) -> libc::c_int; pub fn unlockpt(fd: libc::c_int) -> libc::c_int; pub fn ptsname(fd: libc::c_int) -> *mut libc::c_schar; }
PTY on Rust • 目的の動作をするものはできた • unsafe 祭りになった • もっと簡単に書けるようにしたい
Crate にした • github.com/hibariya/pty-rs • let (child_process, pty_master) = pty::fork();
• おかしなところにパッチがほしい • もっといい API があれば改善したい
extern crate pty;