BSD界隈四方山話

第31回 FreeBSDのソースコードを調べる方法

この記事を読むのに必要な時間:およそ 3 分

ソースコードを調べる

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行までとなっています。このため,解決できる名前と解決できない問題がでていて,問題を特定することが難しく,ソースコードをまで調べることになった,という状況だったりします。

コメント

コメントの記入