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.3k
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
560
Idobata on GKE - Moving an Ordinary Rails App
hibariya
0
70
Using Docker for your Rails Development Environment
hibariya
1
2.6k
GraphQL Subscription with Relay and Action Cable
hibariya
1
2.2k
Various Services
hibariya
1
290
Building a Web API with GraphQL
hibariya
2
3k
My recent troubles in using Ember Data
hibariya
0
970
Idobata をもっと便利に 使うための tips
hibariya
0
1.3k
Control a Shell With pty-shell
hibariya
0
1.6k
Other Decks in Programming
See All in Programming
ローコードSaaSのUXを向上させるためのTypeScript
taro28
1
610
Enabling DevOps and Team Topologies Through Architecture: Architecting for Fast Flow
cer
PRO
0
310
Realtime API 入門
riofujimon
0
150
よくできたテンプレート言語として TypeScript + JSX を利用する試み / Using TypeScript + JSX outside of Web Frontend #TSKaigiKansai
izumin5210
6
1.7k
Jakarta EE meets AI
ivargrimstad
0
130
RubyLSPのマルチバイト文字対応
notfounds
0
120
受け取る人から提供する人になるということ
little_rubyist
0
230
とにかくAWS GameDay!AWSは世界の共通言語! / Anyway, AWS GameDay! AWS is the world's lingua franca!
seike460
PRO
1
860
CSC509 Lecture 11
javiergs
PRO
0
180
Macとオーディオ再生 2024/11/02
yusukeito
0
370
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
0
100
Creating a Free Video Ad Network on the Edge
mizoguchicoji
0
120
Featured
See All Featured
A designer walks into a library…
pauljervisheath
203
24k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
229
52k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.1k
Code Review Best Practice
trishagee
64
17k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
109
49k
Building an army of robots
kneath
302
43k
Building Your Own Lightsaber
phodgson
103
6.1k
Mobile First: as difficult as doing things right
swwweet
222
8.9k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
6
410
Fontdeck: Realign not Redesign
paulrobertlloyd
82
5.2k
Optimising Largest Contentful Paint
csswizardry
33
2.9k
Ruby is Unlike a Banana
tanoku
97
11k
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;