hal, pmount, dbus 를 이용한 usb 디바이스 자동마운트하기
최신의 배포판에서는 gnome 데스크탑의 gnome-volume-manager가 usb 장치를 연결하면 자동마운트를 해주고 있습니다. 여기서 소개하려는 팁은 gnome-volume-manager를 사용할 수 없거나 gnome-voume-manager가 제어할 수 없는 마운트옵션을 사용하고자 할 경우를 위한 것입니다
hal(Hardware Abstraction Layer)을 가지고 있는 리눅스 시스템은 그것을 통해서 디바이스의 상태변화를 모니터링할 수 있습니다. gnome-volume-manager도 이놈으로부터 usb나 cdrom의 연결및 분리를 감지해내서 마운트/언마운트를 하는 걸로 알고 있습니다. pmount는 일반유저가 장치를 마운트/언마운트를 할 수 있게 해주는 동시에 이패키지의 pmount-hal이라는 명령어는 hal로부터의 정보로부터 마운트디바이스/포인트/옵션등을 넘겨받아 마운트 해줄 수 있습니다. 그리고 마지막으로 dbus는 hal정보를 얻기위한 프로그래밍 인터페이스로서 사용하였습니다.
이 팁은 우분투 breezy를 기준으로 해서 만들어졌기 때문에 다른 배포판에서는 작동하지 않을 수도 있습니다
제가 80G 외장형 usbhd와 mpio mp3를 가지고 있는데 이것을 가지고 설명을 하겠습니다. 일단 hal을 다음과 같이 설치합니다
$ apt-get install hal
lshal이라는 명령어로 hal의 의해 감지된 디바이스의 정보를 볼수 있는데 usbhd의 경우는 다음과 같습니다
udi = '/org/freedesktop/Hal/devices/volume_uuid_d69f9cf1_e376_407a_a203_cb97192aa7ea'
volume.policy.desired_mount_point = 'usbdisk' (string)
volume.policy.mount_filesystem = 'ext3' (string)
volume.policy.should_mount = true (bool)
info.udi = '/org/freedesktop/Hal/devices/volume_uuid_d69f9cf1_e376_407a_a203_cb97192aa7ea' (string)
info.product = 'Volume (ext3)' (string)
volume.size = 80023716864 (0x12a1c90400) (uint64)
volume.num_blocks = 156296322 (0x950e482) (int)
volume.block_size = 512 (0x200) (int)
volume.partition.number = 1 (0x1) (int)
info.capabilities = {'volume', 'block'} (string list)
info.category = 'volume' (string)
volume.is_partition = true (bool)
volume.is_disc = false (bool)
volume.is_mounted = false (bool)
volume.mount_point = '' (string)
volume.label = '' (string)
volume.uuid = 'd69f9cf1-e376-407a-a203-cb97192aa7ea' (string)
volume.fsversion = '' (string)
volume.fsusage = 'filesystem' (string)
volume.fstype = 'ext3' (string)
block.storage_device = '/org/freedesktop/Hal/devices/storage_model_MK8025GAS'
(string)
block.is_volume = true (bool)
block.minor = 17 (0x11) (int)
block.major = 8 (0x8) (int)
block.device = '/dev/sdb1' (string)
linux.hotplug_type = 3 (0x3) (int)
info.parent = '/org/freedesktop/Hal/devices/storage_model_MK8025GAS' (string)
linux.sysfs_path_device = '/sys/block/sdb/sdb1' (string)
linux.sysfs_path = '/sys/block/sdb/sdb1' (string)
다음은 mpio의 경우입니다
udi = '/org/freedesktop/Hal/devices/volume_uuid_8C78_DAD7'
volume.policy.desired_mount_point = 'MPIO FL300' (string)
volume.policy.mount_filesystem = 'vfat' (string)
volume.policy.should_mount = true (bool)
info.udi = '/org/freedesktop/Hal/devices/volume_uuid_8C78_DAD7' (string)
info.product = 'MPIO FL300' (string)
volume.size = 523763712 (0x1f380000) (uint64)
volume.num_blocks = 1022976 (0xf9c00) (int)
volume.block_size = 512 (0x200) (int)
info.capabilities = {'volume', 'block'} (string list)
info.category = 'volume' (string)
volume.is_partition = true (bool)
volume.is_disc = false (bool)
volume.is_mounted = false (bool)
volume.mount_point = '' (string)
volume.label = 'MPIO FL300' (string)
volume.uuid = '8C78-DAD7' (string)
volume.fsversion = 'FAT16' (string)
volume.fsusage = 'filesystem' (string)
volume.fstype = 'vfat' (string)
block.storage_device = '/org/freedesktop/Hal/devices/storage_model_FL300' (string)
block.is_volume = true (bool)
block.minor = 32 (0x20) (int)
block.major = 8 (0x8) (int)
block.device = '/dev/sdc' (string)
linux.hotplug_type = 3 (0x3) (int)
info.parent = '/org/freedesktop/Hal/devices/storage_model_FL300' (string)
linux.sysfs_path_device = '/sys/block/sdc/fakevolume' (string)
linux.sysfs_path = '/sys/block/sdc/fakevolume' (string)
여기서 주목해야 할 속성들은 다음과 같습니다
udi : hal데이터베이스의 고유한 id
block.is_volume : 마운트할 수 있는 block 디바이스인지 판단
volume.is_mounted : 마운트되어 있는지 판단
volume.policy.should_mount : 마운트되어야 할지 판단
volume.policy.desired_mount_point : /media아래의 마운트 포인터(디렉토리) pmont-hal마운트시 자동생성되고 언마운트시 자동삭제됨
volume.uuid : 마운트할 파일시스템의 고유한 id
$sudo apt-get install pmount
pmount-hal을 가지고 usbhd를 마운트하려면 'pmount-hal <udi>'를 해주면 다음과 같이 마운트 된것을 확인할 수 있습니다
/dev/sdb1 on /media/usbdisk type ext3 (rw,noexec,nosuid,nodev)
여기서 여러개의 usbhd를 가지고 있고 각각마다 고유한 마운트포인트를 갖게 만들고 싶으면 각각의 usbhd가 가지고 있는 volume.uuid에 대응하는 마운트 포인터를 아래처럼 변경해주면 됩니다. 또 마운트할때 noexec옵션을 제거하고 싶으면(이것때문에 마운트된 usbhd에 있는 실행파일들을 실행할수 없습니다) 'volume.policy.mount_option.exec'이라는 옵션을 임의로 만들어주어서 아래처럼 추가해 줍니다
my_storage.fdi:
<?xml version="1.0" encoding="ISO-8859-1"?> <!-- -*- SGML -*- -->
<deviceinfo version="0.2">
<!-- Example: Match a volume from an USB Storage Based mp3 player
by the file system UUID and assign a mount point.
NB: When reformatting the volume a new UUID will be
used and this rule will have to be altered -->
<device>
<match key="block.is_volume" bool="true">
<match key="volume.fsusage" string="filesystem">
<match key="volume.uuid" string="d69f9cf1-e376-407a-a203-cb97192aa7ea">
<merge key="volume.policy.mount_option.exec" type="bool">true</merge>
<merge key="volume.policy.desired_mount_point" type="string">usbhd</merge>
</match>
</match>
</match>
<match key="block.is_volume" bool="true">
<match key="volume.fsusage" string="filesystem">
<merge key="volume.policy.mount_option.exec" type="bool">true</merge>
</match>
</match>
</device>
</deviceinfo>
이 파일을 /etc/hal/fdi/policy 아래에 옮기고 나서 usb장치들을 분리했다가 다시 연결해서 lshal 와 pmount-hal의 결과를 보면 속성들이 원하는대로 바꾸어져 있음을 확인할 수 있습니다
/dev/sdc1 on /media/usbhd type ext3 (rw,noexec,nosuid,nodev)
이제 남은일은 usbhd가 연결되었을때 hal정보를 읽어들어서 pmount-hal을 동작하게 하는 것입니다. 그것을 다음의 python code와 daemon script으로 가능합니다
파이썬 모듈들을 위해서
$sudo apt-get install hal-device-manager
아래파이썬 코드는 hal-device-manager패키지에 있는 코드를 참조하여 만들었습니다
/home/hokim/bin/hal-monitor.py
#!/usr/bin/python
import gobject
import dbus
import os
import sys
if getattr(dbus, "version", (0,0,0)) >= (0,41,0):
import dbus.glib
def gdl_changed(signal_name, device_udi, *args):
if signal_name=="DeviceAdded":
device_udi_obj = bus.get_object("org.freedesktop.Hal",
device_udi)
properties = device_udi_obj.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device")
if properties.get("block.is_volume") and not properties.get("volume.is_mounted") \
and properties.get("volume.policy.should_mount") :
pmount_hal = "/usr/bin/pmount-hal %s" % (device_udi)
if properties.get("volume.policy.mount_option.exec") :
pmount_hal = pmount_hal + " --exec"
os.system(pmount_hal)
elif signal_name=="DeviceRemoved":
pass
else:
pass
class Dummy:
def write(self, s): pass
if os.fork():
os._exit(0)
os.setpgrp()
os.umask(0)
sys.stdin.close()
sys.stdout = Dummy()
sys.stderr = Dummy()
bus = dbus.SystemBus()
hal_manager_obj = bus.get_object("org.freedesktop.Hal",
"/org/freedesktop/Hal/Manager")
hal_manager = dbus.Interface(hal_manager_obj,
"org.freedesktop.Hal.Manager")
hal_manager.connect_to_signal("DeviceAdded",
lambda *args: gdl_changed("DeviceAdded", *args))
hal_manager.connect_to_signal("DeviceRemoved",
lambda *args: gdl_changed("DeviceRemoved", *args))
device_names = hal_manager.GetAllDevices()
for name in device_names:
gdl_changed("DeviceAdded", name)
main_loop = gobject.MainLoop()
main_loop.run()
/etc/dbus-1/event.d/40hal-mon
#! /bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/home/hokim/bin/hal-monitor.py
PIDDIR=/var/run/hal-mon
PIDFILE=$PIDDIR/hal-mon.pid
NAME=hal-mon
DAEMONUSER=hokim
DESC="Hardware abstraction layer monitor"
. /lib/lsb/init-functions
test -x $DAEMON || exit 0
# Include hal defaults if available
if [ -f /etc/default/hal ] ; then
. /etc/default/hal
fi
set -e
do_start() {
if [ ! -d $PIDDIR ]; then
mkdir -p $PIDDIR
chown $DAEMONUSER:$DAEMONUSER $PIDDIR
fi
log_begin_msg "Starting $DESC: "
if [ -n $(pidof -x $DAEMON) ]; then
su - $DAEMONUSER $DAEMON
echo $(pidof -x $DAEMON) > $PIDFILE
fi
log_end_msg $?
}
do_stop() {
log_begin_msg "Stopping $DESC: "
# if hald does not want to die, apply some more force
if [ -e $PIDFILE ]; then
kill -9 $(< $PIDFILE) || true
rm -f $PIDFILE
fi
log_end_msg $?
}
case "$1" in
start)
do_start
;;
stop)
do_stop
;;
#reload)
#
# If the daemon can reload its config files on the fly
# for example by sending it SIGHUP, do it here.
#
# If the daemon responds to changes in its config file
# directly anyway, make this a do-nothing entry.
#
# echo "Reloading $DESC configuration files."
# start-stop-daemon --stop --signal 1 --quiet --pidfile \
# /var/run/$NAME.pid --exec $DAEMON
#;;
restart|force-reload)
#
# If the "reload" option is implemented, move the "force-reload"
# option to the "reload" entry above. If not, "force-reload" is
# just the same as "restart".
#
do_stop
sleep 5
do_start
;;
*)
N=/etc/init.d/$NAME
# echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
log_success_msg "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0
$ sudo mkdir /var/run/hal-mon
$ sudo chown hokim:hokim /var/run/hal-mon
$ sudo /etc/dbus-1/event.d/40hal-mon start
이제 장치를 분리했다 연결했다해보시고 테스트 해보면 특정 usbhd가
특정 디렉토리로 항상 mount 됨을 알 수 있습니다. 또한 부팅하기전에 연결해 놓고 부팅을 해도 자동마운트가 됩니다.
참고로 저의 경우는 xfce 에 유용하게 사용하고 있습니다. gnome에서
사용한다면 gnome-volume-manager를 제거하고 사용해야 할것 같은데
의존성 때문에 제거 될 수 있을지 모르겠군요.
참고자료
http://gnome.or.kr/wiki/HAL
http://dbus.freedesktop.org/doc/dbus-tutorial.html
apt-get install hal-doc


Re: hal, pmount, dbus 를 이용한 usb 디바이스 자동마운트하기
제거 안 해도 될 겁니다. 어차피 마운트는 한 번만 되는거고, gnome-volume-manager 도 다른 자동마운트 프로그램이 마운트한 항목들을 알아차리는 것 같더군요. :-)
저는 젠투에서 권장하는 ivman (Automounter) 을 씁니다.
만 하면 자동 마운트 기능이 활성화됩니다.
----
블로그 / 위키 / 리눅스 스크린샷 갤러리
breezy에도 ivman 있군요. 소스코드에서 pmount를 쓰는거보니
breezy에도 ivman 있군요. 소스코드에서 pmount를 쓰는거보니 제가 했던 것하고 똑같은 원리이군요. 아쉬운 점은 pmount 옵션에 exec가 없다는 점입니다:( gnome-volume-manager를 사용할때도 이것이 불만중에 하나였는거든요.
http://gentoo-wiki.com/HOWTO_Auto_mount_
http://gentoo-wiki.com/HOWTO_Auto_mount_filesystems_%28AUTOFS%29
http://gentoo-wiki.com/HOWTO_ivman
저런 문서들도 참고해보면 도움이 될 듯 싶군요 :)
오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...
http://mytears.org ~(~_~)~
나 한줄기 바람처럼..
댓글 달기