ソースコードを調べる
FreeBSDでなにか問題が発生したり解決したいことがでてきた場合には、オンラインマニュアルを読んだりFreeBSDハンドブックを読んだり、またはGoogleで検索して同じ問題とその解決方法が提示されていないか調べることがあります。こうした作業で問題が解決すれば御の字です。
しかし、希なケースの問題であったり、オンラインマニュアルに記載されていない場合、解決策を見つけるのが難しいです。オンラインマニュアルに書いてあることも常にソースコードの記述を正確に反映しているとは限らないため、そうした場合にはソースコードを調べる必要があります。
FreeBSDでソースコードを調べる方法はいくつかあります。ここでは3つの方法を採り上げて、どうやってソースコードを調べていくのか紹介します。想定するシナリオは、lpr(1)コマンドで印刷を行おうとしたところ「unable to get official name ~」といったエラーが出力されて印刷されないという問題が発生したというものです。
Subversionでソースコードをチェック
FreeBSDのソースコードはSubversionで管理されています。基本的にはSubversionを使って調査したい対象となるバージョンのFreeBSDのソースコードをダウンロードしてきて、grep(1)コマンドを使って全文検索を行います。現在のマシンは高速なので、FreeBSDのソースコード量であればgrep(1)による検索で実用的に利用できます。
まず、pkg install subversionのようにしてSubversionをインストールするか、システムにデフォルトでインストールされているsvnliteを使って対象となるバージョンのソースコードを取得します。svnliteを使う場合、svnコマンドの部分をsvnliteに置き換えてコマンドを実行してください。
svn(1)コマンドでFreeBSDのソースコードを取得
# FreeBSD 10.2系のソースコードを取得
svn checkout https://svn.FreeBSD.org/base/releng/10.2 ./
# FreeBSD 9.3系のソースコードを取得
svn checkout https://svn.FreeBSD.org/base/releng/9.3 ./
# FreeBSD 10.2-RELEASEのソースコードを取得
svn checkout https://svn.FreeBSD.org/base/release/10.2.0 ./
# FreeBSD 9.3-RELEASEのソースコードを取得
svn checkout https://svn.FreeBSD.org/base/release/9.3.0 ./
# 開発版のソースコードを取得
svn checkout https://svn.FreeBSD.org/base/head ./
# 10系安定版のソースコードを取得
svn checkout https://svn.FreeBSD.org/base/stable/10 ./
# 9系安定版のソースコードを取得
svn checkout https://svn.FreeBSD.org/base/stable/9 ./
あとは何も考えずにキーワードでgrep(1)検索を行います。次のようにlpr(1)コマンドのソースコードの1つである「common_source/net.c」というファイルの中に該当する部分があることがわかります。
grep(1)による全文検索で対象の絞り込み
# cd /usr/src/
# grep -r 'unable to get official' *
usr.sbin/lpr/common_source/net.c: asprintf(&error, "unable to get official name "
#
該当する部分をみると、checkremote()という関数の実装の中で、getaddrinfo(3)というライブラリ関数がエラーを返していることが原因になっていることがわかります。
問題が発生していた部分を特定
# cat -n usr.sbin/lpr/common_source/net.c
…略…
171 /*
172 * Figure out whether the local machine is the same
173 * as the remote machine (RM) entry (if it exists).
174 * We do this by counting the intersection of our
175 * address list and theirs. This is better than the
176 * old method (comparing the canonical names), as it
177 * allows load-sharing between multiple print servers.
178 * The return value is an error message which must be
179 * free()d.
180 */
181 char *
182 checkremote(struct printer *pp)
183 {
184 char lclhost[MAXHOSTNAMELEN];
185 struct addrinfo hints, *local_res, *remote_res, *lr, *rr;
186 char *error;
187 int ncommonaddrs, errno;
188 char h1[NI_MAXHOST], h2[NI_MAXHOST];
189
190 if (!pp->rp_matches_local) { /* Remote printer doesn't match local */
191 pp->remote = 1;
192 return NULL;
193 }
194
195 pp->remote = 0; /* assume printer is local */
196 if (pp->remote_host == NULL)
197 return NULL;
198
199 /* get the addresses of the local host */
200 gethostname(lclhost, sizeof(lclhost));
201 lclhost[sizeof(lclhost) - 1] = '\0';
202
203 memset(&hints, 0, sizeof(hints));
204 hints.ai_family = family;
205 hints.ai_socktype = SOCK_STREAM;
206 hints.ai_flags = AI_PASSIVE;
207 if ((errno = getaddrinfo(lclhost, NULL, &hints, &local_res)) != 0) {
208 asprintf(&error, "unable to get official name "
209 "for local machine %s: %s",
210 lclhost, gai_strerror(errno));
211 return error;
212 }
ようするに名前解決に失敗している、ということになります。名前解決には/etc/resolv.confや/etc/hosts、/etc/host.conf、/etc/hosts.*ファイルあたりが関係しています。/etc/printcapで指定したホスト名が間違っていたのかもしれません。
/etc/resolv.confで指定できる
# cd /usr/src/
# grep -r MAXNS * | grep define
include/resolv.h:#define MAXNS 3 /*%< max # name servers we'll track */
#
実はこれは実際にあった問題で、/etc/resolv.confでnameserverの指定が4行あったことが原因です。/etc/resolv.confで指定できるnameserverの数はMAXNSまでですので、現在のところ3行までとなっています。このため、解決できる名前と解決できない問題がでていて、問題を特定することが難しく、ソースコードをまで調べることになった、という状況だったりします。
svnwebでソースコードをチェック
すでにどこのソースコードを読めばよいか検討がついているという場合には、http://svnweb.freebsd.org/ を使うという方法もあります。FreeBSDのSubversionリポジトリの中身をそのままWebブラウザから閲覧できますし、変更履歴も見ることができます。
図 http://svnweb.freebsd.org/
Subversionを利用するのが面倒な環境を使っているとか、新しいソフトウェアのインストールが許されていない環境やデバイスを使っている場合なんかに使える方法です。ただ、これはある程度中身が把握できていないと難しいところがあるので、通常のユーザであれば次の紹介するGitHubを使う方法がよいでしょう。
GitHubでソースコードをチェック
FreeBSDのソースコード自体はSubversionで管理されていますが、GitHubへのエクスポートも実施されているので、ソースコードや開発の履歴そのものをGitHubで追っかけるといったことができます。今の開発者的にはこの方法が一番なじみやすい方法でしょう。
図 FreeBSDソースコード on GitHub
GitHubはソースコードの検索サービスを提供していますので、grep(1)検索で指定したのと同じキーワードを指定することで同じようにソースコードを絞り込むことができます。検索性能はこちらの方が柔軟でかつ高速です。
図 GitHubで検索
図 もちろんソースコードを読める。ブラウザの機能で検索もできる
最近、FreeBSDのエンジニアはGitHubの有用性を高く評価しています。今のところソースコードの管理方法自体をSubversionからGitHubに変更する動きは見られませんが、多くのエンジニアがGitHubの便利さを理解していることは間違いのないところです。
ソースコードは情報のかたまり
何も知らない状態ですとFreeBSDハンドブックのようにある程度のクオリティでまとめられた文章が有益ですし、ちょっと詳しくなってきたらオンラインマニュアルが役に立つと思います。しかしながら、そこから先はソースコードを読んだ方が近道です。
ソースコードの大半はC言語で記述されていますので、C言語が読めないと難しいところがありますが、コメントやマクロなどを追うだけでも多くの情報を得ることができます。GitHubを使う方法なんかは入りやすいところだと思いますし、ぜひ一度試してみてください。