[Eject]Ejectコマンドで遊んだ
ある日、友人のれったーさんがこんなこと言ってました。
ってかかまぼこさん高専祭(☝ ՞ਊ ՞)☝ウイーンしません?
— Re: Re: Re: Re: Re: (@rettar6) September 3, 2014
れったーさん、ウィーンって何ですか。B737のフラップの稼動音か何かですか。
— かまぼこ@ぷよぐやみんぐだめです (@kamaboko123) September 3, 2014
Ejectしましょ
— Re: Re: Re: Re: Re: (@rettar6) September 3, 2014
というわけで、ここ数日間はEjectやってました。
※Ejectネタです。(☝ ՞ਊ ՞)☝ウィーン
以下、Ejectに興味のある頭のおかしい方向けです。
Ejectについて
- EjectとはLinuxのコマンドで光学ドライブからディスクを取り出すコマンドです。
- Ejectを使って工作を行うEjectコマンドユーザー会なるものが存在します。
何をやったのか
- Raspberry Piに光学ドライブを接続してEjectできるようにした
- WebからEjectできるようにした
- TwitterからのリプライでEjectできるようにした
- (工作までこぎつけてません)
「要するにEjectコマンドを呼べばいいのだな」
そんな適当な気持ちで始めました。
色々調べてみましたが、やはり有力な情報源はEjectコマンドユーザー会ですね。
過去の作例なども公開されています。
とりあえず、Webから実行できるのが、仕組み的にも一番楽そうだったので、PHPからシェルスクリプトを呼ぶことに。
RaspberryPiにSSHで接続、ApacheとPHPを適当にセットアップ、USBでDVDドライブも接続しました。
で、以下のスクリプトを実行。
1
2
3
|
<?php
exec('eject /dev/cdrom2');
?>
|
適当にもほどがあるスクリプトですね。まぁそれは置いといて。
ブラウザからアクセスしてあげると、トレイがゲロっと吐き出されるはずです。
というのは嘘です。
権限周りが結構面倒なんですよねこれ。
ドライブにディスクを挿入して、ディスクがマウントされている場合は、ejectの前にアンマウントして上げる必要があります。
ejectコマンドではアンマウントも同時にやってくれるのですが、アンマウントは管理者権限がないとできないんです。
でもApacheはまさかrootで実行してるわけではないと思うので、アンマウントで怒られるわけです。
じゃあディスク入れなけりゃいいじゃんってのは正しいのですが、後述する光学ドライブの開閉状態を確認するための方法に、「ディスクをマウントしてチェックする」という方法を使っているので、マウントは必須でした。
Apacheの実行ユーザーをrootにしようとか、umountコマンドの実行ファイルそのもにSUIDを指定しようとか色々考えました。
Apacheをrootで実行しようとすると、セキュリティの観点から起動時に怒られまました。
(デバッグオプション入れて再コンパイルしたらできるよとかも言われましたが、そんな面倒なことやりません。)
一番ラクだったのは、sudoersにApacheの実行ユーザーを登録してあげることでした。
/etc/sudoersにApacheの実行ユーザーを追記します。
セキュリティの観点からは好ましくないのですが、今回はローカルネットワーク下での実験なので以下の様にしました。
1 |
apache ALL=(ALL) NOPASSWD: ALL
|
これで、Apacheユーザーですべてのコマンドがsudoで実行可能になりました。
ejectをsudoで実行してあげることで、アンマウントでも怒られません。
簡単ですね、これだけでWebからEjectが可能になりました。
APIとして仕上げる
WebからEjectできるのは便利ですが、APIとしてXMLとかJSONとか吐いてくれると嬉しいですね。
というわけで、APIとして仕上げることに。
(PHPコードが消失してしまったので、ソースコードはご紹介できません。ごめんなさい)
とりあえずeject部分はシェルスクリプトにしましょう。
1
2
3
|
#!/bin/sh
sudo eject -T /dev/cdrom1
return $?
|
シンプル・イズ・ベストです。ejectコマンドの返り値をそのまま返却します。(PHPとシェルスクリプトで分ける必要があったのか)
このシェルスクリプトをexec()で実行し、結果をJSONとして出力してあげるようなAPIを仕上げました。
ドライブの状態を取得したい
ドライブの状態が取得できると便利だと思いますよね。
思わないとしたら、この記事を読むのをやめて病院へ行ってください。
というわけでドライブ開閉状態を取得します。
私には技術力がないので、ドライバに問い合わせるプログラムを書くなんて高度なことできません。
なので、もっと簡単に確認できる方法を模索する必要がありました。
[追記] こちらにシステムコールを利用して取得する方法を書きましたので合わせてどうぞ。
思いついた方法としては、「ディスクが挿入されたら自動的にマウントし、マウントの有無で判断する」という方法です。
自動マウントに関しては、autofs等の便利なサービスがありますのでそれを利用しましょう。
/etc/mtabには、現在マウント中のファイルシステムが記録されますので、マウントの有無はここをチェックしてあげるといいでしょう。
ここでも簡単なシェルスクリプトを書きます。
1
2
3
4
5
6
7
8
9
10
|
#!/bin/sh
mount=`cat /etc/mtab | grep /dev/sr0`
if [ "$mount" != "" ];
then
return 0
else
return 1
fi
|
/etc/mtabからgrepで/dev/sr0(光学ドライブ)の行を抽出します。
なければ、もしディスクがマウントされていればその行が抽出され、マウントされていなければ文字列は空となるので、それで判定できます。
問題点としては主に2つ。
- ディスクを入れておかないといけない
- マウントに5秒程度を要する
前者は工作する場合に問題になってきます。光学ドライブを傾けたり、裏返しで使う場合はディスクを入れておくことができないからです。
後者はステータスを取得する場合に、トレイが閉まっていてもタイミングによっては正しい結果が帰ってこないことがありますね。
現時点ではこれで良しとして、同じようにPHPでAPIを作成しました。
TwitterにEjectを実装する
Twitterから「Eject」とリプライを送られたら光学ドライブをゲロっと吐き出すようにします。
Streaming APIを使ってあげるのが一番楽です。Javaを使いました。
ここにアップロードしておきます。コメントもないし、コードもグチャグチャですがお許し下さい。
(ソースコード内のAPIへのURL等は私の環境のものなので、適当なものに変えてください)
JavaにはTwitter4Jという素晴らしいライブラリがあるので、それを利用しています。
(Twitter4Jに関しては詳しくないので、使い方はググってください)
主にやってる処理は以下。
- Twitter(UserStream)から@を見つけ出す
- さらにその中からejectと記載されているものを抽出
- 先ほど作ったPHPのAPIにアクセスして、ejectさせたり、statusを取得したりする。
- リプライをもらった相手に結果を返信
これもシンプルです。難しくはないです。
成果
- TwitterからEjectできるようになった。地球の裏側からでもEjectできる!
- Eject工作でできそうなことがわかってきた
今回は以上です。
次回はドライブの開閉状態を取得する方法についてもう少し詳しく考えてみたい思います。