hal, pmount, dbus 를 이용한 usb 디바이스 자동마운트하기

hokim의 이미지

최신의 배포판에서는 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을 다음과 같이 설치합니다

Quote:

$ apt-get install hal

lshal이라는 명령어로 hal의 의해 감지된 디바이스의 정보를 볼수 있는데 usbhd의 경우는 다음과 같습니다

Quote:

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의 경우입니다

Quote:

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

Quote:

$sudo apt-get install pmount

pmount-hal을 가지고 usbhd를 마운트하려면 'pmount-hal <udi>'를 해주면 다음과 같이 마운트 된것을 확인할 수 있습니다

Quote:

/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의 결과를 보면 속성들이 원하는대로 바꾸어져 있음을 확인할 수 있습니다

Quote:

/dev/sdc1 on /media/usbhd type ext3 (rw,noexec,nosuid,nodev)

이제 남은일은 usbhd가 연결되었을때 hal정보를 읽어들어서 pmount-hal을 동작하게 하는 것입니다. 그것을 다음의 python code와 daemon script으로 가능합니다

파이썬 모듈들을 위해서

Quote:

$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

Quote:

$ 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

Forums: 
랜덤여신의 이미지

hokim wrote:
참고로 저의 경우는 xfce 에 유용하게 사용하고 있습니다. gnome에서
사용한다면 gnome-volume-manager를 제거하고 사용해야 할것 같은데
의존성 때문에 제거 될 수 있을지 모르겠군요.

제거 안 해도 될 겁니다. 어차피 마운트는 한 번만 되는거고, gnome-volume-manager 도 다른 자동마운트 프로그램이 마운트한 항목들을 알아차리는 것 같더군요. :-)

저는 젠투에서 권장하는 ivman (Automounter) 을 씁니다.

emerge ivman
rc-update add ivman default

만 하면 자동 마운트 기능이 활성화됩니다.
hokim의 이미지

breezy에도 ivman 있군요. 소스코드에서 pmount를 쓰는거보니 제가 했던 것하고 똑같은 원리이군요. 아쉬운 점은 pmount 옵션에 exec가 없다는 점입니다:( gnome-volume-manager를 사용할때도 이것이 불만중에 하나였는거든요.

정태영의 이미지

http://gentoo-wiki.com/HOWTO_Auto_mount_filesystems_%28AUTOFS%29
http://gentoo-wiki.com/HOWTO_ivman

저런 문서들도 참고해보면 도움이 될 듯 싶군요 :)

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.