半日無駄になった [Raspberry Pi]
macOSをホストに、A/DとD/AコンバータをつないだRaspberry PiにWi-Fiで接続してアナログデータを読み書き表示するようなのを書いた。なんだか似たようなものばかり書いてるような気がする。ところが今日は動く動かない以前の問題で悩んだ。わかればつまらない原因だったんだけど、これで半日潰してしまった。残り時間が少ないというのに....
ホストのmacOSはまずRaspberry Piが起動してるかどうか調べる。それにはこんなことをした。
macOSのmanページには
生きていればサーバソフトを起動する。それは
つまりこれもさっきと同じでsshでログインして、サーバソフトを起動して終わる、というもの。sshはパスワードではなく公開鍵認証の設定をしてあるのでそのまま起動できる、というもの。
この文字列を手動でコマンドラインから入れれば動くのでなんの疑いもなくこれで起動しようとしたら、動かない。Xcodeのコンソールには
なんてぐちゃぐちゃしてる間に半日がすぎてしまった。ついさっきふと気がついた。macOS側のアプリはSandbox化してる。なぜかNSOpenPanelやNSSavePanelが動かないという問題があって、試行錯誤の結果、Sandboxに入れるとなんとか動くところまではできた。しばらく前からそうなってしまっていてずっとそうしてるが、なぜSandbox無しではNSSavePanelが動かないか、Sandboxに入れても動かないとこがあるけど何がいけないのか、そもそもなんで僕だけそうなのか(僕以外でこういう症状はググっても見つからない。Sandbox内ではAppKitではなくPowerBoxのNSSavePanelが使われるとあるけど、AppKitそのものが変わってるとしか思えない)とか、よくわからないままになっている。GigEやUSB3.1接続のカメラはSandbox内でも通るように設定できるので、Sandbox化自身はこれまでそれほど不便はなかった。
今回も何も考えずにSandbox対応していた。ところがそうすると、Sandbox内からは無関係なファイルを書くことどころか読むことさえできない。したがってsshの認証に使う秘密鍵id_rsaファイルにアクセスできない。そのせいでsshが失敗していた。これに気がつくのに半日もかかった。sshのエラーメッセージが「id_rsa can not be read」とかだったらすぐ気がついたのに。
で、どうすればいいか。いくつか考えられる。
サーバをRaspbianの上でsystemdで起動しておくというのは、やりかたとしては正しい。というか、これまではそうしていた。しかしデバグの時点では、ホスト側がクラッシュしたときの起動し直しとか、依存関係を考えてsystemctlを書き直す、というのは面倒。しかもそういうのってすぐ忘れてしまって、動かなくなった、なんでだ、と騒いだり、systemctlってどうやって書いたのか思い出せなくて、manページをひっくり返して、そんなことをやってると半日や1日すぐ過ぎてしまう。
どうすればいいんだろう....
ホストのmacOSはまずRaspberry Piが起動してるかどうか調べる。それにはこんなことをした。
- (BOOL)isServerAlive:(NSString *)hostName { NSString *pph = [NSString stringWithFormat:@"ping -q -t 2 %@", hostName]; int ret = system([pph cStringUsingEncoding:NSASCIIStringEncoding]); return (ret == 0); }まだSwiftじゃなくてObjective-Cで書いてるけど、それはいいとして(さくっと書こうとするとやっぱりどうしてもObjective-Cになってしまう)、pingで反応があるかどうかで判断してる。system()というのはunixに古くからあるユーティリティ関数で、与えられた文字列をsh用のコマンドとみなしてシェルをfork/execする。返り値はシェルのexit statusの値で、シェルのexit statusは最後に実行したコマンドのexit statusの値、すなわちこの場合はpingのものになる。
macOSのmanページには
The ping utility exits with one of the following values: 0 At least one response was heard from the specified host. 2 The transmission was successful but no responses were received. any other value An error occurred. These values are defined in <sysexits.h>.1回でも応答があればexit statusは0になるので、その場合は生きているとみなす。ちなみに、sysexits.hにはこれに役に立つ情報はあまりない。
生きていればサーバソフトを起動する。それは
- (BOOL)invokeCommandServer:(NSString *)hostName account:(NSString *)account serverPath:(NSString *)serverPath { NSString *sshPhrase = [NSString stringWithFormat: @"ssh %@@%@ %@ &" account, hostName, serverPath]; system([sshPhrase cStringUsingEncoding:NSASCIIStringEncoding]); sleep(1); // wait for server establishing return YES; }としている。sshPhraseという文字列は例えば
ssh pi@raspberrypi.local /home/pi/localServer &などということになる。
つまりこれもさっきと同じでsshでログインして、サーバソフトを起動して終わる、というもの。sshはパスワードではなく公開鍵認証の設定をしてあるのでそのまま起動できる、というもの。
この文字列を手動でコマンドラインから入れれば動くのでなんの疑いもなくこれで起動しようとしたら、動かない。Xcodeのコンソールには
2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 6.139/8.127/10.114/1.988 ms load pubkey "/Users/decafish/.ssh/id_rsa": Operation not permitted Host key verification failed. socket connect: Connection refused errno = 61となって、pingは動いてるのに、sshが失敗してる。おっかしいなあ。パーミッションの設定や、ファイルの中身を調べたけどおかしなところはない。だって、手動だと動くんだもんな。 そもそもエラーメッセージの意味が理解できない。~/.ssh/id_rsaは秘密鍵で公開鍵でも共通鍵でもない。「load pubkey」は何を言いたいんだ?ググってもこんなメッセージはヒットしない。
なんてぐちゃぐちゃしてる間に半日がすぎてしまった。ついさっきふと気がついた。macOS側のアプリはSandbox化してる。なぜかNSOpenPanelやNSSavePanelが動かないという問題があって、試行錯誤の結果、Sandboxに入れるとなんとか動くところまではできた。しばらく前からそうなってしまっていてずっとそうしてるが、なぜSandbox無しではNSSavePanelが動かないか、Sandboxに入れても動かないとこがあるけど何がいけないのか、そもそもなんで僕だけそうなのか(僕以外でこういう症状はググっても見つからない。Sandbox内ではAppKitではなくPowerBoxのNSSavePanelが使われるとあるけど、AppKitそのものが変わってるとしか思えない)とか、よくわからないままになっている。GigEやUSB3.1接続のカメラはSandbox内でも通るように設定できるので、Sandbox化自身はこれまでそれほど不便はなかった。
今回も何も考えずにSandbox対応していた。ところがそうすると、Sandbox内からは無関係なファイルを書くことどころか読むことさえできない。したがってsshの認証に使う秘密鍵id_rsaファイルにアクセスできない。そのせいでsshが失敗していた。これに気がつくのに半日もかかった。sshのエラーメッセージが「id_rsa can not be read」とかだったらすぐ気がついたのに。
で、どうすればいいか。いくつか考えられる。
- Sandboxを使わない
- id_rsaファイルをユーザに指定させる
- id_rsaファイルをSandbox内からでも読める場所に置く
- パスワード(共通鍵認証)に切り替える
- サーバの起動をsshを使わずに行う
- ~/Downloads
- ~/Pictures
- ~/Music
- ~/Movies
- アプリ自身のBundle内
サーバをRaspbianの上でsystemdで起動しておくというのは、やりかたとしては正しい。というか、これまではそうしていた。しかしデバグの時点では、ホスト側がクラッシュしたときの起動し直しとか、依存関係を考えてsystemctlを書き直す、というのは面倒。しかもそういうのってすぐ忘れてしまって、動かなくなった、なんでだ、と騒いだり、systemctlってどうやって書いたのか思い出せなくて、manページをひっくり返して、そんなことをやってると半日や1日すぐ過ぎてしまう。
どうすればいいんだろう....
2019-01-25 21:19
nice!(0)
コメント(0)
コメント 0