本連載は
今回紹介するのはpmountというコマンドをパッケージ化する際に遭遇したトラブルです。実のところトラブルの原因はこのソフトウェアとは違うところにあったのですが、
pmountとは?
伝統的なUNIXの考え方では、
UNIXのこの考え方は、
たとえば、
/dev/cdrom /cdrom iso9660 user,ro,noauto,exec,iocharset=euc-jp 0 0
CD-ROMやフロッピーディスクのように、
pmount
トラブル発生
pmountは現在も開発が続いており、
ところが手元にあったUSBメディアプレイヤーを挿してテストしてみると、
% ./work/usr/bin/pmount /dev/sda1 Error: device /dev/sda1 is not removable
直接mountコマンドを使えば問題なくマウントできます。
# mount /dev/sdb1 /media # df Filesystem 1K-ブロック 使用 使用可 使用% マウント位置 /dev/hda3 19236340 16601960 1657228 91% / none 1037060 168 1036892 1% /dev .... /dev/sdb1 942864 885448 57416 94% /media
しばらくドキュメントを調べたり、
pmountのヘルプメッセージを見ると、
% ./work/usr/bin/pmount -d /dev/sdb1 resolved /dev/sdb1 to device /dev/sdb1 Checking for device '/dev/sdb1' in '/etc/fstab' -> not foundmount point to be used: /media/sdb1 no iocharset given, current locale encoding is EUC-JP Cleaning lock directory /var/lock/pmount_dev_sdb1 Checking for device '/dev/sdb1' in '/etc/mtab' -> not foundChecking for device '/dev/sdb1' in '/proc/mounts' -> not founddevice_whitelist: checking /etc/pmount.allow... device_whitlisted(): nothing matched, returning 0 find_sysfs_device: looking for sysfs directory for device 8:17 find_sysfs_device: checking whether /dev/sdb1 is on /sys/block/ram0 (1:0) find_sysfs_device: checking whether /dev/sdb1 is on /sys/block/ram1 (1:1) ... find_sysfs_device: checking whether /dev/sdb1 is on /sys/block/sda (8:0) find_sysfs_device: major device numbers match find_sysfs_device: minor device numbers do not match, checking partitions... find_sysfs_device: checking whether device /dev/sdb1 matches partition 8:0 ... find_sysfs_device: checking whether device /dev/sdb1 matches partition 8:17 find_sysfs_device: -> partition matches, belongs to block device /sys/block/sdb device_removable: could not find a sysfs device for /dev/sdb1 Error: device /dev/sdb1 is not removable policy check failed
-dオプションを指定するとずいぶん詳細なデバッグメッセージを出してくれました。このメッセージを見る限り、
pmount がどうやってリムーバブルメディアか否かを判断しているかは、
問題の特定と追跡
まずはエラーメッセージを手がかりに、
% find src | xargs grep ' is not removable' src/policy.c: fprintf( stderr, _("Error: device %s is not removable\n"), device );
デバイスファイル名
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_
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 行目で、
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_
276行目まで進めば1が返るのでdevice_
これらの関数を眺めた限りではdevice_
さて、
改めてこの関数を眺めると、
それでは、
229 snprintf( devfilename, sizeof( devfilename ), "%s/device", devdirname );
230
231 /* read out the link */
232 if( !sysfs_get_link( devfilename, linkfilename, 1024 ) )
233 sysdev = sysfs_open_device_path( linkfilename );
234
このsysfs_
% nm /usr/lib/libsysfs.so.2.0.0 | grep sysfs_get_link 00001f70 T sysfs_get_link % nm /usr/lib/libsysfs.so.2.0.0 | grep sysfs_open_device_path 00005450 T sysfs_open_device_path
必要なライブラリが正しくリンクされていないのかな、
% ldd work/usr/bin/pmount linux-gate.so.1 => (0xffffe000) libsysfs.so.2 => /usr/lib/libsysfs.so.2 (0xb7f58000) libblkid.so.1 => /lib/libblkid.so.1 (0xb7f4f000) libc.so.6 => /lib/libc.so.6 (0xb7e21000) libuuid.so.1 => /lib/libuuid.so.1 (0xb7e1d000) /lib/ld-linux.so.2 (0xb7f89000)
ライブラリの呼び出し方でも変更されたのかなぁ、
ソースコードを調べるのも手詰りになったので、
このページによると、
こうなると、
いずれの方法もメリット、
% ./work/usr/bin/pmount /dev/sdb1 Error: device /dev/sdb1 is not removable % su パスワード: XXXXX # updatepkg sysfsutils-2.1.0_1-i586-P1.tgz removing sysfsutils-2.l.0 Removing package sysfsutils... Removing files: --> Deleting symlink usr/lib/libsysfs.so ... sysfsutils-2.1.0_1-i586-P1 のインストール中 PACKAGE DESCRIPTION: sysfsutils-2.1.0_1-i586-P1 のインストールスクリプトを実行中 # exit % ./work/usr/bin/pmount /dev/sdb1 % df Filesystem 1K-ブロック 使用 使用可 使用% マウント位置 /dev/hda3 19236340 16605608 1653580 91% / none 1037060 168 1036892 1% /dev /media 1037060 0 1037060 0% /media ... /dev/sdb1 942864 885448 57416 94% /media/sdb1
このデバイスはpumountで正しくアンマウントされ、
今回は比較的規模の小さいソフトウェアを例に、
Cで書かれたソースコードの場合、