ぶていのログでぶログ

思い出したが吉日

reddish-shell v0.11.0-beta3 開発進捗 | コマンドの実装とRust 1.56.0

今の進捗↓

  • コマンドの実行を実装
  • 変数を利用できるようにした
  • cmd1 && cmd2 と cmd1 || cmd2を実装
  • if/unless/while/until/for文を実装
  • コマンド履歴機能を有効化
  • Rust 1.56.0 / 2021 editionを使うようにした

最低限の機能を実装したので少しはシェルっぽくなってきた。 ここらへんの実装は今まで作ってきた機能の組み合わせになってくるので作っていてとても楽しい。 パイプやバックグラウンド実行、各構文のリダイレクト機能は めんどうでまだ実装になっている。

コミット

github.com

システムコールのテスト

コマンドを実行するときのfork/waitpid/execveや、リダイレクトの処理をするopen/dup2/closeなどシステムコールをする部分がある。 これらをテストするのは副作用があるため非常に大変である。 色々考えた結果mockallを使ってモックすることにした。

通常のコードとモックコードを使い分けするためにWrapperという構造体を一枚噛ませている。 cfg(test)のときはこのWrapperはMockSysCallWrapperのaliasとしている。 このMockSysCallWrapperはコード上には定義がないがmockallが自動的に定義する構造体になっている。

定義部分: https://github.com/buty4649/reddish-shell/blob/8372810b16f55b658015069d8fca8a206bdb7f70/src/exec/syscall.rs

Rust 1.56.0 / 2021 edition

10/21にRust 1.56.0がリリースされた 🎉

blog.rust-lang.org

reddish-shellも早速Rust 1.56.0 / 2021 editionを使うように変更した。 幸い影響を受けるようなコードを書いてはいなかったのですんなりアップデートできた。

次の実装

簡単なコマンドの実装ができたので、パイプやシェル構文のリダイレクト、バックグラウンド実行とジョブコントロールあたりを実装しようかと思っている。 パイプの実装はパイプをつなげているコマンドの実行順序に気をつければすんなり実装できるはず・・・はず。 これを実装すると副次的にコマンド置換(command とか $(command))とかも実装できるはず。

シェル構文のリダイレクトは少しめんどくさくて、通常のコマンドのリダイレクトはforkしているので設定したリダイレクトのあとのことを考える必要がないのだけど、シェルの構文の場合シェルと同じプロセス内で実行するのでリダイレクト処理をするとそのまま残ってしまい後続の処理に影響がでてしまう。 なので、構文の実行が終わったらリダイレクト処理を元に戻すかなにかしないといけない。

バックグラウンド実行はwaitpidしなければいいだけの話なのだけど、そうなるとゾンビプロセスになってしまう。 waitpidにWNOHANGをつけてチェックするか、スレッドなりでwaitpidするのが良いのかなぁっと思う。 そうなってくると、それらのスレッドを管理するジョブコントローラーが必要になってくる。 ついに、Rustで非同期処理を書く必要がでてくるという感じ。