linuxbrewについて
既にいくつかの記事にも書かれています通り、linuxbrewは
- 管理者権限がなくてもパッケージのインストールが可能
- ホームディレクトリにインストールができる
- ディストロ非依存
というような一般人にとって大変ありがたいパッケージマネージャです。(参考)
使いどころとしては、レンタルサーバなどで使う方が多いかもしれませんが、計算機クラスタやスパコンを利用する場合にも、管理者権限を持つことは通常ないので重宝するかと思います。
ところが、お使いの環境によっては上手く動作してくれない場合があるようです(してくれませんでした)。こんなに便利なものを使えないままにしておくのはもったいないので、なんとか動作するように工夫したことを紹介したいと思います。
注意
実際にソースコードに基づいて解決してはいないので、この記事で紹介するのはあくまで対処法です。これがベストな策とは言えません。試すときはシステムを壊したりしないようくれぐれも注意してください。
また、ここに書かれている方法以外にもっと良い方法があればぜひとも教えていただきたいと思っています。
症状と原因
まず、現象としては、linuxbrewを公式HPの方法に従って、管理者権限のない環境でインストールしたところ
$ brew update
-e:1:in `flock': No locks available (Errno::ENOLCK)
from -e:1:in `<main>'
Error: Another active Homebrew update process is already in progress.
Please wait for it to finish or terminate it to continue.
というエラーがでてしまうというものです。
もしお使いの環境が、計算機クラスタ等でNFSを利用してホームディレクトリを共有している環境である場合、flock(2)のmanページに記述のある
In Linux kernels up to 2.6.11, flock() does not lock files over NFS
(i.e., the scope of locks was limited to the local system).
あたりのことが原因かもしれません。このことは、linuxbrewのIssuesにも記載がありました。その解決策としてはflock
が正常に動作する領域を利用するという方針のようです。
対処編
さて、ここからが本題ですが、状況をそろえるという意味でも、もう一度 linuxbrewをインストールしなおしてみましょう。そんなの良いから早く解決策見せてみろという方は、真対処編へお進みください。
まずは,リモートマシンにログインします。自分の環境は、
- CentOS Linux release 7.4.1708 (Core)
- NFS:v3 (
nfsstat -m
コマンドで確認できます。そのとき、local_lock=none
とかなっているかもしれません) - rubyなし
です。それではインストールしていきます。
1. ホームディレクトリへrubyのインストール
公式HPにはsh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"
を実行しろとありますが、いきなり無視します。というのも、このスクリプトではrubyの有無を確認して、あればシステムのものを使うような仕様ですが、何かとホーム以下のものを使ったほうがエラーの対処がしやすいかと思います。そこで、
$ cd $HOME
$ curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh -o brew_install.sh
$ more brew_install.sh
#!/bin/sh
set -eu
which ruby >/dev/null || eval "`curl -fsSL https://raw.githubusercontent.com/Linuxbrew/
install/master/install-ruby`"
exec ruby -e "`curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/in
stall`"
このようにすると、install.sh
がなにをしているかわかります。スクリプト2行目でrubyの有無を調べ、なければインストールする流れになっていますが、今回は有無にかかわらずインストールしてもらうために、which ruby >/dev/null ||
の部分と後半のbrew本体部分を削除します。改変後のスクリプトは以下のようになります。
$ more ruby_install.sh
#!/bin/sh
set -eu
eval "`curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install-ru
by`"
これを実行します。
==> Installing successful
==> /users/username/.linuxbrew/Homebrew/Library/Homebrew/vendor/portable-ruby/2.3.3/bin/ruby
ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-linux]
==> Add Ruby to your PATH by running:
PATH=/users/username/.linuxbrew/Homebrew/Library/Homebrew/vendor/portable-ruby/2.3.3/bin:$PATH
最後の行にあるように今インストールしたrubyのパスを.bashrc
等に追加します。再ログインorsource .bashrc
でパスを反映させ、which ruby
でパスを通したところになっていることを確認します。これで、ホーム以下へのrubyのインストールができました。
2.homebrew本体のインストール
続いて、homebrew 本体を入れていきます。こちらは、先程保存したスクリプトをそのまま実行します。基本的に指示通り進めて、/home/username
以下にインストールしましょう。
Checking out files: 100% (1149/1149), done.
HEAD is now at 1d949e1 GlibcRequirement: Use OS::Linux::Glibc [Linux]
flock: 99: No locks available
Error: Another active Homebrew update process is already in progress.
Please wait for it to finish or terminate it to continue.
Failed during: /users/rshimura/.linuxbrew/bin/brew update --force
さて,このようなエラーを出すことができれば、無事__インストールは成功__です。
この時点で違うエラーが出てしまったり場合は、今までの手順を見直すか、そもそも、原因がflock以外にある可能性があるかもしれません(他の対処が必要)。
真対処編
対処としてはシンプルで、NFSでマウントしていないディレクトリである/var/tmp/
以下を利用します。
homebrewがファイルロックしたいディレクトリは.linuxbrew/var/homebrew/locks
です。よって、/var/tmp/
以下から.linuxbrew/var/homebrew/locks
へソフトリンクをはることで、対処することができます。
$ cd .linuxbrew/var/homebrew
$ mv locks bak.locks # 削除しても問題ないはずですが,一応とっておきます
$ mkdir /var/tmp/rshimura_locks
$ ln -s /var/tmp/rshimura_locks ./locks
これで、brew update
などとすると、正常に動いてくれるようになっているはずです。
小細工
さて,インストール自体は完了しましたが,先ほどリンクを貼った/var/tmp
は名前の通りテンポラリーなディレクトリなので,その下にあるものはシステムによって勝手に消されてしまうことがあります。毎度リンクを貼り直すのは面倒ですので,.bashrc
などに次のような関数・エイリアスを定義します。
lock_dir
は各自のお名前に変更してください。
alias brew='linuxbrew'
function linuxbrew(){
lock_dir=/var/tmp/user-name_lock
brew_path=$HOME/.linuxbrew/bin
if [ -d $lock_dir ]; then
$brew_path/brew $@
else
echo 'DO NOT exist lock file'
echo "make directory $lock_dir ..."
mkdir $lock_dir
echo "remove invalid symlink ..."
rm -rf $HOME/.linuxbrew/var/homebrew/locks
echo "symlink to $HOME/.linuxbrew/var/homebrew/locks"
ln -s $lock_dir $HOME/.linuxbrew/var/homebrew/locks
$brew_path/brew $@
fi
}
これで,/var/tmp/
にlockディレクトリが確保されている場合は通常通り実行し,削除されてしまった場合には,新たに作り直し,リンクを貼ったのち,brewを実行してくれるようになります。