* sysutils/libcdio で ATAPI CD/DVD ドライブを開くときの注意

root 権限でしか libcdio やそれに依存するアプリケーションが利用できないことがずっと謎でした。 libcdio バージョン 0.83 時点での回避策/解決策をメモします。
FreeBSDCD-DA を聴くには /usr/sbin/cdcontrol が断然便利なのですが、 ports に載っているアプリケーションはたいてい libcdio を利用するようです。 愛用の qmmp も CD 音源を再生しつつトラック情報を CDDB サーバーから取り寄せて表示してくれる機能のプラグインがあり libcdio に依存してます。
さて FreeBSD は CD/DVD ドライブのパーミッションの初期設定が 0600 なので、 一般ユーザーが利用するときは chmod 666 /dev/*cd0 するかあるいは /etc/devfs.conf に perm cd0 0666 や perm acd0 0666 の行を加えておく必要があります。 かつてはこれだけで充分だったのですが、 libcdio と FreeBSD の更新をしていくうちある日突然に CD-DA を読まなくなってしまいました。 そしてなぜか root 権限であればこれまで通り読めるのです。

FreeBSD 用ドライバーは SCSI 系 → ATAPI 系の順にデバイスを探る

この謎を解く鍵は libcdio のソースファイル lib/driver/FreeBSD/freebsd.c にあります。 cdio_get_default_device_freebsd() 関数が自動的にデバイスを判定するとき /dev/cd%c が先で /dev/acd%c が後 (%c は 0〜9 の数字) の順番に探っていました。
あまり詳しくは理解していないのですが、 最近の FreeBSD は ATAPI 系のデバイスでも /dev/acd0 でなく /dev/cd0 の名で登録してしまいます。 しかし libcdio は /dev/cd0 だと SCSI ドライバのように CAM 経由で扱います。 つまり /dev/pass0 を経由することになるので、 このデバイスも初期設定が 0600 なパーミッションを 0666 に解放してやる必要があったわけでした。
実際に /dev/pass0 を誰でも読めて操作できるよう権限を解放してやると、 cd-info コマンド (libcdio に付属) が一般ユーザーでも作動できるようになりました。

$ cd-info 
cd-info version 0.83 i386-portbld-freebsd9.1
Copyright (c) 2003, 2004, 2005, 2007, 2008, 2011 R. Bernstein
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
CD location   : /dev/cd0
CD driver name: FreeBSD
   access mode: CAM

さてこれはつまりかつての ATAPI のような扱いでデバイスを読めなくなってしまったということなのでしょうか。 そこで、 まず /dev/cd0 からシンボリックリンクを張って /dev/acd0 を作成し、 件のドライバソースをちょっと改造して、 ATAPI 系の /dev/acd%s を SCSI 系の /dev/cd%s よりも先に探すように変更してみました。

--- /usr/ports/sysutils/libcdio/work/libcdio-0.83/lib/driver/FreeBSD/freebsd.c.orig	2011-10-21 07:48:22.000000000 +0900
+++ /usr/ports/sysutils/libcdio/work/libcdio-0.83/lib/driver/FreeBSD/freebsd.c	2012-10-28 20:46:09.000000000 +0900
@@ -870,20 +870,20 @@
      Not always 100% reliable, so use the USE_MNTENT code above first.
   */
 
-  /* Scan SCSI and CAM devices */
+  /* Scan are ATAPI devices */
   for ( c='0'; exists && c <='9'; c++ ) {
-    sprintf(drive, "/dev/cd%c%s", c, DEVICE_POSTFIX);
+    sprintf(drive, "/dev/acd%c%s", c, DEVICE_POSTFIX);
     exists = cdio_is_cdrom(drive, NULL);
     if ( exists ) {
       return strdup(drive);
     }
   }
 
-  /* Scan are ATAPI devices */
+  /* Scan SCSI and CAM devices */
   exists = true;
   
   for ( c='0'; exists && c <='9'; c++ ) {
-    sprintf(drive, "/dev/acd%c%s", c, DEVICE_POSTFIX);
+    sprintf(drive, "/dev/cd%c%s", c, DEVICE_POSTFIX);
     exists = cdio_is_cdrom(drive, NULL);
     if ( exists ) {
       return strdup(drive);

この結果、 /dev/pass0 を解放しておかなくても一般ユーザーで使用できることが cd-info コマンドで確認できました。

$ cd-info 
cd-info version 0.83 i386-portbld-freebsd9.1
Copyright (c) 2003, 2004, 2005, 2007, 2008, 2011 R. Bernstein
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
CD location   : /dev/acd0
CD driver name: FreeBSD
   access mode: ioctl

/dev/acd0 を探知し、 ioctl を使うアクセス方法に替わりました。 /etc/devfs.conf に link cd0 acd0 という 1 行を追加しておきましょう。