4クロックで支度しな

脊髄反射で思ったことを書き垂れます。68060とか名乗っときながら4クロックはヌルいとか言わないで。

Windows7 SP1(64bit) でStack newに失敗しまくってハマった件

随分遅ればせながら、Haskell Platform 2014.2.0.0からstack-1.2.0へ移行してみたところ、いくつか不具合があったので記しておく。

stack setupでハマる

stack-1.2.0のインストーラからstackをインストールし、
$ stack setup
しようとするも、
TlsException (HandshakeFailed (Error_Protocol ("certificate has unknown CA",True,UnknownCa)))
とか出てGHCがインストールできない。

これはどうもインストールするべきGHCのパッケージ群のバージョン等の情報を与えていないせいのようで、適当なディレクトリに
https://github.com/commercialhaskell/stack/blob/master/stack-8.0.yaml
をDL。stack.yamlにリネームした上でカレントディレクトリに置き、
$ stack setup
を実行すると、上手くGHCのインストールが出来た。

stack newでハマる

適当にHello worldでもするかと思い、ホームディレクトリで
$ stack new helloworld
としようとするも、またしても
TlsException (HandshakeFailed (Error_Protocol ("certificate has unknown CA",True,UnknownCa)))
グーグル先生曰く、一度IEで適当なHTTPSのサイトを訪問するべしとか書いてあるけれど改善しない。

で、最終的にやってみたのが、stack newの時に参照するsnapshotのURL
https://www.stackage.org/download/snapshots.json
IEで訪問する(ファイルを開くか保存するか聞いてくるので、適当に保存しておく)という方法。

これをやった後、再度
$ stack new helloworld
すると、なんとか上手く動作した。

もし同様にハマった方は一度お試しあれ。

補足

stack newの時にやった、shapshotへのアクセスを最初にやっておけば、stack setupの時もstack-8.0.yamlの導入は要らないかもしれない。

Raspberry PiでUSBに繋いだストレージ(USBメモリ・HDD・SSDなど)をマウントするちょっと素敵な方法

きっかけ

Raspberry Pi内のデータをUSBメモリにバックアップしたり、大きいデータを持つためにHDDをつないだりして、USBに複数のストレージデバイスが接続された時に、

  • 各ストレージデバイスを一意に識別する方法
    • 特に、全く同じ機種を複数接続したときに、それぞれを識別する方法
  • 同じデバイスに対して、常に同じやり方でマウントできるようにする方法
    • 特に、挿したUSBポートや、挿した順番とかに依存しない方法

を得たい。
Raspbianでは、/dev がUDEVによって管理されるので、その辺の設定ファイルを書く事で対処できる。

第1章 各デバイスのSERIAL IDが異なる場合

1. USBからストレージデバイスを全部外した状態で、Raspberry Piを起動。

コマンドライン

ls /dev/sd*

で、「sdなんちゃら」(「なんちゃら」の所はアルファベット1文字になる)が出てこないのを確認。

2. 任意のストレージデバイスを1個だけ繋いでみる

コマンドライン

ls /dev/sd*

すると、「sda」とか「sda1」とか出てくるはず。
場合によっては「sdb」とか「sdb1」とかかも。
ここでは「sda」「sda1」として話を進める。

3. マウントしてみて、どのデータを収めたデバイスなのかを確認する

※新品のデバイス2つを新たに接続したい場合とかのように、確認が不要な場合はこの項目は飛ばして下さい。

コマンドライン

sudo mount /dev/sda1 /mnt

とか、

ls /mnt

とかやって、繋いだストレージデバイスがどれなのかを特定する。
確認したら、

sudo umount /dev/sda1

で、デバイスをアンマウントしておく(デバイス内のファイルやディレクトリを開いていたら、閉じておく)。

4. デバイスのIDを調べる

コマンドライン

sudo udevadm info -q all -n /dev/sda

を実行すると、デバイスに関する情報がずらずらと表示される。
必要なのは、

E: ID_SERIAL=

の行。例えば、わたしの環境では、SanDiskUSBメモリを繋いでいるので、

E: ID_SERIAL=SanDisk_Cruzer_Fit_00000000000000000000-0:0

みたいになる(数字の部分は適当に改変してます)。
「=」から右の部分をメモっておくとGOOD。

5. デバイスを外す

普通にUSB端子からズブッと抜いちゃいます。

6. デバイスの固有の名前を考える。

/dev ディレクトリ内に存在しないファイル名にする必要あり。
例えば、

usbmem_backup

とか。

7. UDEVのルールを書く

/etc/udev/rules.d 内に、このデバイスに6.で考えた名前を割り当てるためのルールファイルを書く。
ファイル名の先頭に出来るだけ大きな2桁の数字(99とか)を付ける。例えば、

99-usbmem_backup.rules

とか。
内容は以下を参考に。

SUBSYSTEM=="block",
ENV{ID_BUS}=="usb",
ENV{ID_SERIAL}=="SanDisk_Cruzer_Fit_00000000000000000000-0:0", 
SYMLINK+="usbmem_backup%n"

長いので行を分けているけれど、実際は一行で記述。
個別に変更する必要があるのは、

  • 「ENV{ID_SERIAL}==」の右の部分。4.で調べたID_SERIALを使用。
  • 「SYMLINK+=」の右の部分。6.で考えた名前を使用。
    • ただし、最後に%nを付けておく。これは、デバイス内のパーティションを指すデバイスファイル(例えば「/dev/sda1」とか)も一緒に生成させるために使う。

なおこのディレクトリはパーミッションの問題でrootしか書き込めないので、

  • エディタをsudoで起動し、ファイルを作成する
  • 他の場所にファイルを作成し、sudo cp でファイルをコピーする

のどちらかで対応。

8. 2~7を、接続したいデバイスそれぞれに対し実施する

9. 完了

特にudevを再起動する必要とかはなし。
バイスを挿した時ごとに、/etc/udev/rules.d 内を実行する模様。
あとは /etc/fstab に書くなり、必要なときにmountするなり、ご自由に。

第2章 デバイスが同じSERIAL IDを持つ場合

そんな場合があるのかどうか確かめてはいないが、もしそうであった場合には、各デバイスを識別するには他の方法を使うしかない。
例えば、USBのどのポートに繋いだかという情報を元に設定するとか。

1. USBからストレージデバイスを全部外した状態で、Raspberry Piを起動。

第1章の1.と同じ。

2. 任意のストレージデバイスを1個だけ繋いでみる

第1章の2.と同じ。ただし、デバイスごとに違うUSBポートに接続すること。

3. マウントしてみて、どのデータを収めたデバイスなのかを確認する

第1章の3.と同じ。

4.デバイスの刺さっているUSBポート番号を調べる

第1章と同様に、コマンドライン

sudo udevadm info -q all -n /dev/sda

を実行すると、デバイスに関する情報がずらずらと表示される。
今度は、必要なのは、

E: ID_PATH_TAG=

の行。例えば、わたしの環境では、SanDiskUSBメモリを繋いでいるので、

E: ID_PATH_TAG=platform-bcm2708_usb-usb-0_1_2_1_0-scsi-0_0_0_0

とか、別のポートにつなぐと、

E: ID_PATH_TAG=platform-bcm2708_usb-usb-0_1_3_1_0-scsi-0_0_0_0

「=」から右の部分をメモっておくとGOOD。

5. デバイスを外す

第1章と同じ。

6. デバイスの固有の名前を考える。

第1章と同じ。

7. UDEVのルールを書く

/etc/udev/rules.d 内に、このデバイスに6.で考えた名前を割り当てるためのルールファイルを書く。
ファイル名の先頭に出来るだけ大きな2桁の数字(99とか)を付ける。例えば、

99-usbmem_backup.rules

とか。
内容は以下を参考に。

SUBSYSTEM=="block",
ENV{ID_BUS}=="usb",
ENV{ID_PATH_TAG}=="platform-bcm2708_usb-usb-0_1_2_1_0-scsi-0_0_0_0", 
SYMLINK+="usbmem_backup%n"

長いので行を分けているけれど、実際は一行で記述。
個別に変更する必要があるのは、

  • 「ENV{ID_PATH_TAG}==」の右の部分。4.で調べたID_PATH_TAGを使用。
  • 「SYMLINK+=」の右の部分。6.で考えた名前を使用。
    • ただし、最後に%nを付けておく。これは、デバイス内のパーティションを指すデバイスファイル(例えば「/dev/sda1」とか)も一緒に生成させるために使う。

なおこのディレクトリはパーミッションの問題でrootしか書き込めないので、

  • エディタをsudoで起動し、ファイルを作成する
  • 他の場所にファイルを作成し、sudo cp でファイルをコピーする

のどちらかで対応。

8. 2~7を、接続したいデバイスそれぞれに対し実施する

9. 完了

第1章と同じ。
ただし、USBのポート番号だけで判別している(何が挿さっているか見ていない)ので、実際に運用する場合には挿すUSBのポートを変えないように。
ちなみに、UDEVのルールにはワイルドカードが使えるので、

  • USBのポート2か3に繋いだデバイスに指定の名前を付けたい

というような場合には、例えば

SUBSYSTEM=="block",
ENV{ID_BUS}=="usb",
ENV{ID_PATH_TAG}=="platform-bcm2708_usb-usb-0_1_[23]_1_0-scsi-0_0_0_0", 
SYMLINK+="usbmem_backup%n"

とかやると、USBのポート2か3に接続されたデバイスを、「/dev/usbmem_backup」等の名前にすることが可能。

さらに、

  • USBの特定のポート(複数可)に接続された
  • あるSERIAL IDを持ったデバイ

に対するルールも定義可能。
例えば、

SUBSYSTEM=="block",
ENV{ID_BUS}=="usb",
ENV{ID_PATH_TAG}=="platform-bcm2708_usb-usb-0_1_[23]_1_0-scsi-0_0_0_0", 
ENV{ID_SERIAL}=="SanDisk_Cruzer_Fit_00000000000000000000-0:0", 
SYMLINK+="usbmem_backup%n"

とか書いたら、USBのポート2か3に接続された、指定のSERIAL IDを持つデバイスを「usbmem_backup」等の名前にすることが可能。

最後に

UDEVのルールに書けるワイルドカードは「[]」の他にも、「*」「?」があったり、「%n」の他にも様々な置換文字列が存在するので、デバイス名により凝った名前を付けたい、というような人は「udev 置換文字列」などでググられたし。

2016/11/16 追記

以前Amazonで購入したSanDiskのCruzer Fitの32GBを再度購入してみたところ、
ID_SERIALの内容が微妙に変わっていた(SanDisk_Cruzer_Fit_ 以降の数字の部分)。
同じ製品でもロットによってID_SERIALが異なるケースがあるようなので、
USBメモリの寿命などにより同じものを買い直した場合でも、デバイスの情報を再度取得してみて確認することをオススメする。

Raspberry Piでユーザアカウントを追加する正しい方法

Linux Boxとして使うには罠が多い件について

Raspberry Pi2を買うまでは玄箱でちまちまやってきたわたしとしては、 /etc/shadow とか知らなかったのですよ。
で、ググりつつユーザアカウントでも追加してみるかと思ったところ、ハマってしまったわけで。

$ sudouseradd -m -g users -G adm,dialout,cdrom,sudo,audio,video,plugdev,games,netdev,input,spi,gpio foo

で、アカウントを有効化しようと思ったら、passwdコマンドかusermodコマンドでパスワードを設定しないといけない。
まず、passwdを使おうと思って、

$ sudo su - foo
$ passwd
foo 用にパスワードを変更中
現在のUNIXパスワード:

・・・今はパスワードなんか無いと言うに。
で、usermodの方を調べてみると、

  • p password
  crypt(3) の返り値である暗号化パスワード。

とか書いてあるわけですよ。どないせえと。
で、強引に /etc/shadow のパスワードエントリをユーザpiからコピペしてきたりすると、 /etc/passwd との不整合が起こって、

$ sudo pwconv

とかやる羽目になったり。

正しい方法

で、色々見てて、passwdコマンドのmanpageを見てやっと分かった次第。それは、

  • rootがpasswdコマンドを使う場合、現在のパスワードの入力を省略できる。

・・・これ。これをもっとアピールしてくれれば、・・・
で、正しい手順

  1. sudo useradd でユーザアカウントを作成する
  2. sudo passwd でパスワードを設定する
    • パスワードを設定したらアカウントは有効化されるので、sudo usermod -U とかはしなくて良い

少しでもまともなUnixを触った人なら常識なんだろうけれど、シャドウパスワードとか何それ?、と言う人も恐らく触っていると思うので、誰かの役に立つことを願って。

Eclipse CDTで複数のMinGW環境を使い分ける(Windows)

悲しい出来事

Haskell Platform 2014.2.0.0をWindows7 Pro 64bitにインストールしたら、どうも内部でMinGWを使っている&環境変数PATHに登録してしまうようで、EclipseのCDTがこれをデフォルトのMinGW環境と認識してしまう模様。
で、既に入れてあったMinGW32/MSYSと、MinGW-w64を選択しようとしても、選択肢すら出てこない。
これを回避可能にするために、バッチファイルで対処してみたと言う話。

何をどうしたか

ひとまず、

  • 環境変数PATHにHaskell Platform同梱のMinGWへのパスが通っているのはまずい
  • Eclipseが起動するためには、JREへのパスが通っていないといけない
  • 環境変数CPATH、CPLUS_INCLUDE_PATH、LIBRARY_PATH辺りはバッチファイルで設定する(Eclipseの環境設定ではしない)
  • Win32用とWin64用のどちらをビルドするか選択したい
    • その際、共通化できるものはしておきたい
  • MinGWのアップグレードなどに対応しやすくしたい(同じ設定を複数ファイルに書かない)

ので、バッチファイルをWin32環境用とWin64環境用に分け、さらにそれぞれを3つのバッチファイルから構成する。

├┬ Win32
│├ ○メインのバッチファイル eclipse_cdt_mingw32.bat
│├ ○環境変数PATH設定用(Win32/Win64共通部分) common_path.bat
│└ ○GCC環境変数設定用 mingw32_gcc_envval.bat
└┬ Win64
 ├ ○メインのバッチファイル eclipse_cdt_mingw64.bat
 ├ ○環境変数PATH設定用(Win32/Win64共通部分) common_path.bat
 └ ○GCC環境変数設定用 mingw64_gcc_envval.bat

以下、バッチファイルの例。

  • common_path.bat
rem 後で更新することを考えて、パスを1つずつ追加していく

rem これは個人的な設定の例です
set PATH=C:\bin
set PATH=%PATH%;C:\bin32

rem Windowsのコマンド類用
set PATH=%PATH%;%SystemRoot%\system32
set PATH=%PATH%;%SystemRoot%
set PATH=%PATH%;%SystemRoot%\System32\Wbem
set PATH=%PATH%;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\

rem JDK8u45では、以下のパスにJREの実行ファイルへのショートカットがインストールされる(それ以前のバージョンについては未調査)
rem Eclipseが起動するためには必須
set PATH=%PATH%;C:\ProgramData\Oracle\Java\javapath
rem ...
rem まず共通のパスを設定
call common_path.bat

rem MinGW32独自のパス設定
rem ※バッチファイル内と環境変数で記述順が逆になるのに注意

rem おまけ:AMDのAPP SDKとか使っている人向け
set PATH=C:\Program Files (x86)\AMD APP SDK\2.9-1\bin\x86;%PATH%
set PATH=C:\opt\APPSDK\AMD APP SDK\2.9-1\bin\x86;%PATH%
set PATH=C:\Program Files (x86)\AMD APP SDK\2.9-1\bin\x86;%PATH%

rem MinGW32用のパス設定を追加
rem 具体的なパスは各自のインストール先フォルダの設定とか参照してください(これはかなり独自の設定なので)
set PATH=C:\opt32\MinGW\bin;%PATH%
set PATH=C:\opt32\MinGW\msys\1.0\bin;%PATH%
set PATH=C:\opt32\MinGW\msys\1.0\local\lib;%PATH%
set PATH=C:\opt32\MinGW\msys\1.0\local\bin;%PATH%

rem GCC周りの環境変数を設定
call mingw32_gcc_envval.bat

rem Eclipseを起動
rem ※このバッチファイルはEclipseのインストール先フォルダに置かれている
start eclipse.exe
  • mingw32_gcc_envval.bat
rem GCC周りの環境変数を設定
rem PATHと同じく、変更に対応しやすいよう1個ずつ設定
rem ※バッチファイル内と環境変数で記述順が逆になるのに注意
set CPATH=C:\Program Files (x86)\AMD APP SDK\2.9-1\include
set CPATH=C:\opt32\MinGW\mingw32\include;%CPATH%
set CPATH=C:\opt32\MinGW\lib\gcc\mingw32\4.8.1\include;%CPATH%
set CPATH=C:\opt32\MinGW\include;%CPATH%
set CPATH=C:\opt32\MinGW\msys\1.0\include;%CPATH%
set CPATH=C:\opt32\MinGW\msys\1.0\local\include;%CPATH%

set CPLUS_INCLUDE_PATH=C:\opt32\MinGW\lib\gcc\mingw32\4.8.1\include\c++

set LIBRARY_PATH=C:\Program Files (x86)\AMD APP SDK\2.9-1\lib\x86_64
set LIBRARY_PATH=C:\opt32\MinGW\mingw32\lib;%LIBRARY_PATH%
set LIBRARY_PATH=C:\opt32\MinGW\lib;%LIBRARY_PATH%
set LIBRARY_PATH=C:\opt32\MinGW\lib\gcc\mingw32\4.8.1;%LIBRARY_PATH%
set LIBRARY_PATH=C:\opt32\MinGW\msys\1.0\lib;%LIBRARY_PATH%
set LIBRARY_PATH=C:\opt32\MinGW\msys\1.0\local\lib;%LIBRARY_PATH%
rem まず共通のパスを設定
call common_path.bat

rem MinGW-w64独自のパス設定
rem ※バッチファイル内と環境変数で記述順が逆になるのに注意

rem おまけ:AMDのAPP SDKとか使っている人向け
set PATH=C:\Program Files (x86)\AMD APP SDK\2.9-1\bin\x86_64;%PATH%
set PATH=C:\opt\APPSDK\AMD APP SDK\2.9-1\bin\x86_64;%PATH%
set PATH=C:\Program Files (x86)\AMD APP SDK\2.9-1\bin\x86_64;%PATH%

rem MinGW-w64用のパス設定を追加
rem 具体的なパスは各自のインストール先フォルダの設定とか参照してください(これはかなり独自の設定なので)
set PATH=C:\Program Files (x86)\AMD APP SDK\2.9-1\bin\x86_64;%PATH%
set PATH=C:\opt32\MinGW\msys\1.0\bin;%PATH%
set PATH=C:\opt32\MinGW\bin;%PATH%
set PATH=C:\opt32\MinGW\msys\1.0\local\bin;%PATH%
set PATH=C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\opt\bin;%PATH%
set PATH=C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\bin;%PATH%
set PATH=C:\usr\local\lib;%PATH%
set PATH=C:\usr\local\bin;%PATH%

rem GCC周りの環境変数を設定
call mingw64_gcc_envval.bat

rem Eclipseを起動
rem ※このバッチファイルはEclipseのインストール先フォルダに置かれている
start eclipse.exe
  • mingw64_gcc_envval.bat
rem GCC周りの環境変数を設定
rem PATHと同じく、変更に対応しやすいよう1個ずつ設定
rem ※バッチファイル内と環境変数で記述順が逆になるのに注意
set CPATH=C:\Program Files (x86)\AMD APP SDK\2.9-1\include
set CPATH=C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\opt\include;%CPATH%
set CPATH=C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\opt\lib\libffi-3.1\include;%CPATH%
set CPATH=C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\lib\gcc\x86_64-w64-mingw32\4.9.2\include;%CPATH%
set CPATH=C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\x86_64-w64-mingw32\include;%CPATH%
set CPATH=C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\include;%CPATH%
set CPATH=C:\usr\local\include;%CPATH%

set CPLUS_INCLUDE_PATH=C:\usr\local\include\boost-1_58
set CPLUS_INCLUDE_PATH=C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\x86_64-w64-mingw32\include\c++;%CPLUS_INCLUDE_PATH%

set LIBRARY_PATH=C:\Program Files (x86)\AMD APP SDK\2.9-1\lib\x86_64
set LIBRARY_PATH=C:\usr\local\lib;C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\lib;%LIBRARY_PATH%
set LIBRARY_PATH=C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\x86_64-w64-mingw32\lib;%LIBRARY_PATH%
set LIBRARY_PATH=C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\opt\lib;%LIBRARY_PATH%
set LIBRARY_PATH=C:\opt\mingw-w64\x86_64-4.9.2-posix-seh-rt_v4-rev2\mingw64\lib\gcc\x86_64-w64-mingw32\4.9.2;%LIBRARY_PATH%

・・・うん、分かる人には既に分かっているし、知りたい人には分からないような例ですな(汗
Win32Win64のどちらのバージョンをビルドするかで、 eclipse_cdt_mingw32.bat と eclipse_cdt_mingw64.bat を使い分けられたし(Eclipseを起動してから変更するとか、器用なことは出来ない)。