ソースコード・リテラシーのススメ

第22回 ソースコード・リテラシー【実践編】

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

問題の特定と追跡

まずはエラーメッセージを手がかりに,どの部分がエラーを出しているかをgrepコマンドで調べます。ソースコード全体をチェックしたいので,findxargsと組み合わせて実行しました。

% find src | xargs grep ' is not removable'
src/policy.c:    fprintf( stderr, _("Error: device %s is not removable\n"), device );

デバイスファイル名(/dev/sdb1)の部分は変数になっているだろうから,エラーメッセージの後半部,'is not removable'を手がかりにsrcディレクトリ以下のファイルを全て調べたところ,src/policy.cにこのメッセージを出力している部分が見つかりました。該当箇所はこのファイルの463行目,device_removable関数内でした。

リスト1 src/policy.cのdevice_removable関数

 457  int
 458  device_removable( const char* device )
 459  {
 460    int removable = device_removable_silent(device);
 461 
 462    if( !removable )
 463      fprintf( stderr, _("Error: device %s is not removable\n"), device );
 464 
 465    return removable;
 466  }
 467 

この関数はdevice_removable_silent()という処理を実行した結果を変数removableに入れて,それが0ならエラーメッセージを出すだけのようなので,問題の箇所はむしろdevice_removable_silent()の方のようです。この関数は,device_removable()の直前にありました。

リスト2 src/policy.cのdevice_removable_silent関数

 430  /* The silent version of the device_removable function. */
 431  int device_removable_silent(const char * device)
 432  {
 433    struct sysfs_device *dev;
 434    static char* hotplug_buses[] = { "usb", "ieee1394", "mmc", "pcmcia", NULL };
 435    int removable;
 436    char blockdevpath[PATH_MAX];
 437 
 438    dev = find_sysfs_device( device, blockdevpath, sizeof( blockdevpath ) );
 439    if( !dev ) {
 440      debug( "device_removable: could not find a sysfs device for %s\n", device );
 441      return 0;
 442    }
 443 
 444    debug( "device_removable: corresponding block device for %s is %s\n",
 445           device, blockdevpath );
 446 
 447    /* check whether device has "removable" attribute with value '1' */
 448    removable = get_blockdev_attr( blockdevpath, "removable" );
 449 
 450    /* if not, fall back to bus scanning (regard USB and FireWire as removable) */
 451    if( !removable )
 452      removable = find_bus_ancestry( dev, hotplug_buses );
 453    sysfs_close_device( dev );
 454    return removable;
 455  }

この関数はデバイス名を引数に取って整数値 removable を返す作りになっています。removableに値を入れているのは 448 行目で,そこで値が入らなければ 452 行目で再チェックしているようです。まずは 448行目で呼び出しているget_blockdev_attr()関数を調べてみます。

リスト3 src/policy.cのget_blockdev_attr関数

 247  /**
 248   * Return whether attribute attr in blockdevpath exists and has value '1'.
 249   */
 250  int
 251  get_blockdev_attr( const char* blockdevpath, const char* attr )
 252  {
 253      char path[PATH_MAX];
 254      FILE* f;
 255      int result;
 256      char value;
 257 
 258      snprintf( path, sizeof( path ), "%s/%s", blockdevpath, attr );
 259 
 260      f = fopen( path, "r" );
 261      if( !f ) {
 262          debug( "get_blockdev_attr: could not open %s\n", path );
 263          return 0;
 264      }
 265 
 266      result = fread( &value, 1, 1, f );
 267      fclose( f );
 268 
 269      if( result != 1 ) {
 270          debug( "get_blockdev_attr: could not read %s\n", path );
 271          return 0;
 272      }
 273 
 274      debug( "get_blockdev_attr: value of %s == %c\n", path, value );
 275 
 276      return value == '1';
 277  }

get_blockdev_attr()は同じファイルの 251 行目にありました。この関数はblockdevpathとattrを引数に取って,それらをパス名とするファイルを開き,その値を調べて value を返すようです。

276行目まで進めば1が返るのでdevice_removable_silent()のremovableが1となり,device_removable()の462行目のチェックも通って,リムーバブルメディアであると認識される,という流れのようです。

これらの関数を眺めた限りではdevice_removable()device_removable_silent()get_blockdev_attr()と進んでいき,リムーバブルメディアの場合は1が返ってくるのが正しい流れで,この流れのどこかでエラーが生じて1が返らないために,手元のUSBメディアプレイヤーがremovableではないと判断されてしまっているようです。

さて,どこでトラブっているのだろうなぁ……,としばし悩みましたが,get_blockdev_attr()が実行されれば,3ヵ所のdebug文(262,270,274行目)のどこかで "get_blockdev_attr:" を行頭に持つデバッグメッセージが出力されるはずです。しかし,先に見たpmount -d /dev/sdb1のログではそのようなメッセージは出ていません。ということは,処理はget_blockdev_attr()まで来ていないので,device_removable_silent()が怪しそうです。

改めてこの関数を眺めると,先のデバッグメッセージには440行目のdevice_removable: could not find a sysfs device ...というデバッグ文が出力されているので,439行目のif ( !dev )のチェックで引っかかっていることがわかりました。このdevは438行目でfind_sysfs_device()の結果として帰ってくる値です。

それでは,find_sysfs_device()を調べてみました。この関数はリストを載せるには大きすぎるので詳細は示しませんが,デバッグメッセージに出力されていた"find_sysfs_device:"を手がかりに処理を追ってみたところ,/dev/sdb1に該当するsysfsのデータを調べるところまではうまく行っているものの,最後のリンクを辿るところがうまく行かずに,sysfsの情報を示す構造体のデータが取れていないようです。

著者プロフィール

こじまみつひろ

Plamo Linuxとりまとめ役。もともとは人類学的にハッカー文化を研究しようとしていたのが,いつの間にかミイラ取りがミイラになってOSSを仕事にするようになってしまいました。最近はスペシャリスト養成を目的とした専門職大学院で教壇に立ったりもしています。

URLhttp://www.linet.gr.jp/~kojima/Plamo/index.html