tips – 実行時に共有ライブラリの優先順位を変える(シンボル重複時の動作)

Linux では複数の共有ライブラリ(*.so)に同じ関数が定義されている場合、重複する関数については先に読み込まれた共有ライブラリが利用され、その他のライブラリで定義される重複シンボルについては無視されます。
 
共有ライブラリのロード順序は ld でのリンク順になります。
また、既存の実行可能ファイルのロード順序を調べるには ldd を使います。

$ gcc src.c -o foo -lc -lm # libc.so, libm.so の順にロード
$ ldd foo # foo では libc.so が優先されていることを確認
        libc.so.6 => /lib/tls/libc.so.6 (0x00c07000)
        libm.so.6 => /lib/tls/libm.so.6 (0x00d35000)
        /lib/ld-linux.so.2 (0x00bed000)
$ gcc src.c -o bar -lm -lc # 同じソースに対してリンク順序を入れ替えて bar 作成。
$ ldd bar # bar では libm.so が優先されていることを確認
        libm.so.6 => /lib/tls/libm.so.6 (0x00d35000)
        libc.so.6 => /lib/tls/libc.so.6 (0x00c07000)
        /lib/ld-linux.so.2 (0x00bed000)

 
今回の本題、どうやって共有ライブラリを優先するかを実行時に決めるか?ですが、
LD_PRELOAD を使うことでコンパイル時のロード順を入れ替えることができます。
 

>

$ # LD_PRELOAD に /lib/tls/libc.so.6 (libc.so へのパス)を指定
$ LD_PRELOAD=/lib/tls/libc.so.6
$ ldd bar # 優先順位が変わっていることを確認
        /lib/tls/libc.so.6 (0x00c07000)
libm.so.6 => /lib/tls/libm.so.6 (0x00d35000)
        /lib/ld-linux.so.2 (0x00bed000)

ちなみに、LD_PRELOAD を設定すると、(setuid/setgid されたプログラムなど)一部を除くほとんどのプログラムで任意のライブラリを事前ロードできます。
これを利用すると任意のプログラムのライブラリ定義関数を置き換えることが可能です(参考:hook_tcp.so)。
 
参考:
共有ライブラリの作成(HP テクニカルドキュメント)
 
hook_tcp.so(チームチドリ)

What is hook_tcp.so:
LD_PRELOADを利用して、プログラム中で実行される connect()の接続先をsyslogへ記録するプログラムです。

とのことで、libc.so の CONNECT(2) を hook して動作します。
 
4.17. LIDS を使う時は、LD_PRELOAD 環境変数に注意した方がいいですか?(LIDS FAQ)

CUI 上の日本語表示/入力関係の ports

FreeBSD の CUI 環境から(X 一切なしで)コンソールで日本語入力ができないものか、と試行錯誤した結果次のような構成で落ち着きました。
  
OS: FreeBSD 6.2
日本語入力サーバ(Canna): japanese/canna (/etc/rc.conf で canna_enable=”YES” とする)
Canna 用辞書: japanese/cannadic (インストール方法は /usr/local/share/doc/cannadic/README.ja を参照)
日本語表示: japanese/kon2-16dot または japanese/kon2-14dot
日本語入力(UIM + Canna): japanese/uim-canna
  
CUI での日本語入力は kinput2 が主流ですが、X サーバが必要だったので今回は UIM を選択しました。
  
– その他あると便利なもの:

w3m: www/w3m-m17n
jless(less): japanese/jless
jvim (vi,vim): japanese/jvim3-canna
emcws (emacs): japanese/emacs-emcws

  
– 使い方:

$ kon
$ uim-fep
$ echo “ハローワールド”

とし、 canna[ C – R] のような文字列が下に表示されたら Ctrl-\ で日本語入力ができます。また、uim-fep は tty に依存しないのでリモートからも使えます。
 
ちなみに kon 以外の選択肢として, Linux の Framebuffer を用いた jfbtermがあり、FreeBSD 版も Yusuke Baba 氏により公開されています。)。
jfbterm と w3m-img for FreeBSD framebufferと組み合わせることで画像も表示できるようですが、jfbterm の画面切り替え時のオーバーヘッドに耐え切れず利用は断念しました。

権限があっても削除/変更不可能にする

Linux なら chattr, FreeBSD なら chflags を使うことで、 root 権限でも rm -f で削除不可にすることが可能です。
たとえば /bin ディレクトリ以下すべてを削除不可能にするには

# Linux
chattr +i /bin

 

# BSD
chflags schg /bin/* /bin

 
とすれば削除できなくなります。
 
参考:
http://www.linux.or.jp/JF/JFdocs/Chroot-BIND-HOWTO-2.html
UNIX の部屋 chflags
FreeBSD memo – jail の作り方
MANPAGE of chflags

Ethereal,Tethereal が FreeBSD の ports から消えてた

ローカルの ports で探してみて、net/ethereal にあったはずの Ethereal が見付からなくてアレッ!?と思って公式の cvsweb をあたって見たところ
次のように書いてました。
 
http://www.jp.freebsd.org/cgi/cvsweb.cgi/ports/net/ethereal/Attic/Makefile?hideattic=0

FILE REMOVED
 
Add wireshark and tshark after repocopies from ethereal and tethereal
respectively. Wireshark is a rename of ethereal after the principal
developer moved companies and lost the Ethereal copyright.
 
Messenger, don’t shoot!
 
Now the ethereal binary is called wireshark, the tethereal binary is
called tshark, and idl2eth is now idl2wrs. All other binaries have
kept the same name.
 
In addition to this name change, I have also changed the PREFIX from X11BASE
to LOCALBASE.

 
Ethereal(CUI 版: TEthereal) は主要な開発者が会社を辞めて商標権を失って wireshark(CUI 版: tshark) という別の名前で存続する事になった、ということです。
 
ということで ports を改めて見ると、 net/wireshark, net/wireshark-lite, net/tshark, net/tshark-lite が増えてました。
 
Wireshark の公式サイトは http://wireshark.org/ で、
現在、Ethereal 0.99 から更新された Wireshark 0.99.2 がリリースされています。
 
参考:
「Ethereal」は「Wireshark」に飲み込まれるのか?(ITpro)
Wireshark 公式サイト
Ethereal 公式サイト

portupgrade での unknown build error 対策

portversion でバージョンが一致していないにもかかわらず次のエラーが出る場合の対策メモです(環境はFreeBSD4.x)。

 p5-MIME-Base64-3.07 is already installed
 You may wish to “make deinstal and install this port again
 by “make reinstall
to upgrade it properly.
 If you really wish to overwrite the old port of converters/p5-MIME-Base64
 without deleting it first, set the variable “FORCE_PKG_REGISTER”
 in your environment or the “make install” command line.
 
 *** Error code 1
 
Stop in /usr/ports/converters/p5-MIME-Base64.
 *** Error code 1

こういうエラーが出る都度

pkg_deinstall -f “パッケージ名_バージョン”
portinstall “portのパッケージパス”

とかずっとやっていたのですが、perl 回りで頻発していて、へき易してきたので
説明にある通り環境変数 “FORCE_PKG_REGISTER” をセットして ad-hoc に回避。
 

# vi /usr/local/etc/pkgtools.conf

module PkgConfig の下あたりに

ENV[‘FORCE_PKG_REGISTER’] = ‘yes’

を追加して再度 portupgrade でエラーが出なくなります。
 
原因については未確認ですが、他の環境で発生しないなら cpan スクリプトでインストールしたモジュールあたりが原因かなと推測してますが、どうなんでしょう。

6.1 リリース

2006-05-08 にリリースアナウンスが出ていました。
安定性から 5.x はあんまり使おうという気になれなかったのですが、5.x から使えるようになった機能( gbde(4) など)も気になりますし、インストールしてみようかなぁと思案中です。
 
参考:
FreeBSD.org 本家
The FreeBSD Project(Japan)
FreeBSD 6.1-RELEASE登場(/.j)
 
ディスクパーティションの暗号化(FreeBSD.org)
gbde について。

pkgdb.rb での Segmentation Fault

[2006-02-01] の portsdb.rb での Segmentation Fault とほぼ同じ現象に再び遭遇。

$ portversion -vL=
—> Checking the package registry database
[Updating the pkgdb <format:bdb1_btree> in /var/db/pkg … – 249 packages found (-2 +0) (…)/usr/local/lib/ruby/site_ruby/1.8/pkgdb.rb:466: [BUG] Segmentation fault
ruby 1.8.4 (2005-12-24) [i386-freebsd4]
 
Abort trap (core dumped)

なんで bdb1_btree 見てるのか、と疑問に思いながらソースコードを追っていくとどうやら、PKG_DBDRIVER という変数を見ているもよう。portsdb では PORTS_DBDRIVER ですが、pkgdb ではこちらを使う、と。PORTS_DBDRIVER と同様、PKG_DBDRIVER も bdb_btree (bdb1_btree)がデフォルトで、これは freebsd5 でも変わっていないようです。

export PKG_DBDRIVER=bdb1_hash
pkgdb -aF

これで対処完了!
 
追記: pkgtools.conf に

ENV[‘PORTS_DBDRIVER’] = ‘bdb1_hash’
ENV[‘PKG_DBDRIVER’] = ‘bdb1_hash’

とするほうが設定がまとまっていいかもです。

Allowed memory size of 8388608 bytes exhausted

portupgrade 利用中に以下のエラーに遭遇。

# portinstall devel/pear
… (中略) ..
Fatal error: Allowed memory size of 8388608 bytes exhausted (tried to allocate 56 bytes) in /tmp/gopeypYZxF/PEAR/Registry.php on line 1006
Allowed memory size of 8388608 bytes exhausted (tried to allocate 5 bytes)
 *** Error code 1
 
Stop in /usr/ports/devel/pear.
 *** Error code 1
… (以下略)..

portinstall 中のことで一瞬何かと思いましたが、PHP 周りで 8388608bytes = 8M 制限といえば、php.ini の次の設定ですね。

memory_limit = 8M ; Maximum amount of memory a script may consume (8MB)

これを、一時的に 16M とかしたら問題なくインストールできました。