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
3k
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
新しいモバイルアプリ勉強会(仮)について
uetyo
1
250
Quality Gates in the Age of Agentic Coding
helmedeiros
PRO
1
120
Workers を定期実行する方法は一つじゃない
rokuosan
0
140
CEDEC 2025 『ゲームにおけるリアルタイム通信への QUIC導入事例の紹介』
segadevtech
2
740
ZeroETLで始めるDynamoDBとS3の連携
afooooil
0
150
Claude Code で Astro blog を Pages から Workers へ移行してみた
codehex
0
170
GitHub Copilotの全体像と活用のヒント AI駆動開発の最初の一歩
74th
6
1.7k
実践!App Intents対応
yuukiw00w
0
120
Amazon Q CLI開発で学んだAIコーディングツールの使い方
licux
3
170
変化を楽しむエンジニアリング ~ いままでとこれから ~
murajun1978
0
660
それ CLI フレームワークがなくてもできるよ / Building CLI Tools Without Frameworks
orgachem
PRO
17
3.7k
DataformでPythonする / dataform-de-python
snhryt
0
150
Featured
See All Featured
How to train your dragon (web standard)
notwaldorf
96
6.1k
Faster Mobile Websites
deanohume
308
31k
How to Ace a Technical Interview
jacobian
278
23k
Build your cross-platform service in a week with App Engine
jlugia
231
18k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
6k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
35
2.5k
How STYLIGHT went responsive
nonsquared
100
5.7k
A better future with KSS
kneath
238
17k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
44
2.4k
Build The Right Thing And Hit Your Dates
maggiecrowley
37
2.8k
Documentation Writing (for coders)
carmenintech
73
5k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
50
5.5k
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;