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
640
Idobata on GKE - Moving an Ordinary Rails App
hibariya
0
120
Using Docker for your Rails Development Environment
hibariya
1
3.2k
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.6k
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
dynamic!
moro
10
8k
いま中途半端なSwift 6対応をするより、Default ActorやApproachable Concurrencyを有効にしてからでいいんじゃない?
yimajo
2
430
作って理解するGOCACHEPROG / Go Conference 2025(Workshop)
mazrean
0
100
kiroとCodexで最高のSpec駆動開発を!!数時間で web3ネイティブなミニゲームを作ってみたよ!
mashharuki
0
470
20251016_Rails News ~Rails 8.1の足音を聴く~
morimorihoge
1
350
Serena MCPのすすめ
wadakatu
4
1k
Claude Agent SDK を使ってみよう
hyshu
0
340
品質ワークショップをやってみた
nealle
0
270
はじめてのDSPy - 言語モデルを『プロンプト』ではなく『プログラミング』するための仕組み
masahiro_nishimi
2
480
コードとあなたと私の距離 / The Distance Between Code, You, and I
hiro_y
0
170
組込みだけじゃない!TinyGo で始める無料クラウド開発入門
otakakot
0
270
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
350
Featured
See All Featured
A better future with KSS
kneath
239
18k
Gamification - CAS2011
davidbonilla
81
5.5k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Being A Developer After 40
akosma
91
590k
Statistics for Hackers
jakevdp
799
220k
Stop Working from a Prison Cell
hatefulcrawdad
271
21k
Balancing Empowerment & Direction
lara
4
690
How To Stay Up To Date on Web Technology
chriscoyier
791
250k
Typedesign – Prime Four
hannesfritz
42
2.8k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
23
1.5k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
657
61k
Unsuck your backbone
ammeep
671
58k
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;