- Ubuntu Server 11.10に関する注意:このスクリプトは、廃止された
vol_id
コマンドが原因でUbuntu Server 11.10で失敗します。 vol_id
はに置き換えられましたblkid
。スクリプトを修正するには、スクリプトの「vol_id」を「blkid -o udev」に置き換えudev-auto-mount.sh
ます。
私はこれについてしばらく頭を動かしてきましたが、実用的な解決策を見つけたと思います。これはDebianベースのシステムで開発およびテストされているため、Ubuntuでも動作するはずです。他のシステムにも同様に適応できるように、この仮定を指摘します。
- プラグインにUSBドライブを自動的にマウントします。Firewireに適応するのにそれほど時間はかかりません。
- UDEVを使用しているため、HAL / DeviceKit / GNOME-Anythingを使用することはありません。
/media/LABEL
デバイスをマウントするディレクトリを自動的に作成します。
- ただし、他の自動マウンターと干渉する可能性があります。私はそれをテストすることはできません。Gnome-VFSがアクティブな場合、両方がマウントを試行する可能性があります... Gnome-VFSがマウントに失敗すると、デスクトップアイコンが構成されない可能性があります。Gnomeからのマウント解除は可能ですが、必要な
gksudo
場合もあれば同様の場合もあります。
システムの起動時にこれをテストしていませんが、システムがマウントの準備ができる前にUSBドライブをマウントしようとした場合に動作しない可能性があることがわかります。その場合は、おそらくマウントスクリプトをさらに微調整する必要があります。(私はServerFaultでアドバイスがあるかどうかを確認していますが、そこにはあまり興味がありません。)
それでは、
UDEV参照:
バックグラウンド(UDEV?Whuzzat?)
UDEVはカーネルのホットプラグシステムです。これ/dev/disk/by-label/<LABEL>
は、起動時とシステムの実行中に追加されたデバイスの両方で、適切なデバイスとデバイスシンボリックリンク(例:)を自動的に構成するものです。
D-BusとHALは、デスクトップ環境などのリスナーにハードウェアイベントを送信するために使用されます。したがって、GNOMEにログインしてCDを挿入するか、USBドライブに接続すると、そのイベントは次のチェーンに従います。
kernel -> udev -> dbus -> hal -> gnome-vfs/nautilus (mount)
そして、あなたのドライブはマウントされます。しかし、ヘッドレスシステムでは、自動マウントの利点を得るためにログインする必要はありません。
Udevルール
UDEVを使用すると、デバイスの挿入時にルールを作成してプログラムを実行できるため、これは理想的な選択です。Debian / Ubuntuの既存のルールを活用し、/dev/disk/by-label/<LABEL>
シンボリックリンクを設定してもらい、デバイスをマウントする別のルールを追加します。
UDEVのルールは/etc/udev/rules.d
(および/lib/udev/rules.d
Karmicで)保持され、数値順に処理されます。番号で始まらないファイルは、番号付きファイルの後に処理されます。私のシステムでは、HALルールはというファイルに格納されているため、HALに到達する前に90-hal.rules
ルール89-local.rules
が処理されるようにルールを設定します。主に、これらのルールがの後に発生することを確認する必要があります60-persistent-storage.rules
。 local.rules
十分かもしれません。
これを新しいルールファイルに追加します。
# /etc/udev/rules.d/local.rules
# /etc/udev/rules.d/89-local.rules
# ADD rule: if we have a valid ID_FS_LABEL_ENC, and it's USB, mkdir and mount
ENV{ID_FS_LABEL_ENC}=="?*", ACTION=="add", SUBSYSTEMS=="usb", \
RUN+="/usr/local/sbin/udev-automounter.sh %k"
の後にスペースがないことを確認してください(\
ちょうど)。newline
\n
Firewireサポートに変更SUBSYSTEMS=="usb"
しSUBSYSTEMS=="usb|ieee1394"
ます。
デバイスを常に特定のユーザーが所有する場合は、OWNER="username"
句を追加します。特定のユーザーが所有するファイルだけが必要な場合は、代わりにマウントスクリプトを調整してください。
ルールを読む
これにより、実行するプログラムのデバイスのリストに実行するプログラムが追加されます。によってUSBパーティションデバイスを識別し<LABEL>
、この情報をマウントを実行するスクリプトに渡します。具体的には、このルールは一致しています:
ENV{ID_FS_LABEL_ENC}=="?*"
-以前のシステムルールによって設定された環境変数。非ファイルシステムには存在しないため、チェックします。実際にID_FS_LABEL
マウントポイントに使用したいのですが、私はUDEVにそれをエスケープするように説得していないので、マウントスクリプトにそれを処理させます。
この環境変数およびその他の環境変数は、vol_id
コマンド(非推奨)を使用してudevによって取得されます。パーティションの素早い詳細を見るのに便利なツールです:
$ sudo vol_id /dev/sdc1
ID_FS_TYPE=ext2
ID_FS_UUID=a40d282a-4a24-4593-a0ab-6f2600f920dd
ID_FS_LABEL=Travel Dawgs
ID_FS_LABEL_ENC=Travel\x20Dawgs
ID_FS_LABEL_SAFE=Travel_Dawgs
ACTION=="add"
- add
イベントのみに一致...
SUBSYSTEMS=="usb"
-USBバス上にあるデバイスのみに一致します。SUBSYSTEMS
デバイスの親と一致するため、ここで使用します。対象のデバイスは、実際にはSUBSYSTEM == "scsi"になります。親USBデバイスと照合することにより、プログラムを内部ドライブに追加することを回避できます。
RUN+="..."
-一致ではなくアクション:このプログラムを実行するプログラムのリストに追加します。プログラムの引数で%k
、デバイス名に展開され(例:sdc1
not /dev/sdc1
)、$env{FOO}
環境変数FOOの内容を取得します。
ルールをテストする
最初の参照リンク(上記)は優れたUDEVチュートリアルですが、少し古くなっています。ルールをテストするために実行されるプログラム(udevtest
特に)は、catch-all udevadm
ユーティリティに置き換えられました。
ルールを追加したら、デバイスを接続します。数秒待ってから、どのデバイスに割り当てられているかを確認してください:
$ ls -l /dev/disk/by-label/*
lrwxrwxrwx 1 root root 10 2009-10-25 07:27 label_Foo -> ../../sda1
lrwxrwxrwx 1 root root 10 2009-10-25 07:27 label_Bar -> ../../sdb1
lrwxrwxrwx 1 root root 10 2009-10-25 07:27 label_Baz -> ../../sdc1
リムーバブルドライブにが含まれている場合label_Baz
、それはdeviceにありsdc1
ます。これを実行し、最後の方の出力を見てください:
$ sudo udevadm test /sys/block/sdc/sdc1
parse_file: reading (...) (many lines about files it reads)
import_uevent_var: import into environment: (...) (many lines about env variables)
(...) (many lines tracing rule matches & programs run)
update_link: found 1 devices with name 'disk/by-label/LABEL_BAZ'
update_link: found '/block/sdc/sdc1' for 'disk/by-label/LABEL_BAZ'
update_link: compare (our own) priority of '/block/sdc/sdc1' 0 >= 0
update_link: 'disk/by-label/LABEL_BAZ' with target 'sdc1' has the highest priority 0, create it
udevtest: run: '/usr/local/sbin/udev-automounter.sh sdc1 LABEL_BAZ'
udevtest: run: 'socket:/org/freedesktop/hal/udev_event'
udevtest: run: 'socket:@/org/kernel/udev/monitor'
RUN+=
最後の数行でルールからスクリプト名を探します(この例では下から3番目)。このデバイスに使用される引数を確認できます。このコマンドを実行して、引数が正しいことを確認できます。コマンドラインで動作する場合、デバイスが挿入されると自動的に動作するはずです。
UDEVイベントをリアルタイムで監視することもできます:実行sudo udevadm monitor
(man udevadm
スイッチの詳細については、をご覧ください)。次に、新しいデバイスを接続して、イベントがスクロールするのを見てください。(あなたが本当に低レベルの詳細に興味がない限り、おそらく過剰です...)
ルールのリロード
ルールが正しく読み取られていることを確認したら、新しいルールが有効になるように、ルールをリロードするようUDEVに指示する必要があります。これらの方法のいずれかを使用します(最初の方法が機能しない場合は、2番目の方法が必要ですが...最初の方法を試してください):
脚本!実際、2つのスクリプト...
これが最初のスクリプトです。 実行するプログラムは迅速に完了する必要があるため、2番目のスクリプトをバックグラウンドでスピンオフします。これを入れてください/usr/local/sbin/udev-automounter.sh
:
#!/bin/sh
#
# USAGE: usb-automounter.sh DEVICE
# DEVICE is the actual device node at /dev/DEVICE
/usr/local/sbin/udev-auto-mount.sh ${1} &
これが2番目のスクリプトです。 これにより、もう少し入力チェックが行われます。これを入れ/usr/local/sbin/udev-auto-mount.sh
ます。以下のマウントオプションを調整することをお勧めします。このスクリプトは、パーティションLABELを単独で検索するようになりました。UDEVはデバイス名のみを送信します。
起動時にドライブのマウントに問題がある場合sleep 60
は、このスクリプトに長い時間を設定して、スクリプトがドライブのマウントを試みる前にシステムが完全に起動するようにします。
チェック方法(ps
Webサーバーが実行されているかどうかを確認するための実行方法)についてはコメントで提案していますが、システムに合わせて調整することをお勧めします。nfsd、smbd、apacheなど、使用するネットワークサーバーのほとんどはこれで十分だと思います。もちろん、リスクは、サービスが実行されていない場合にマウントスクリプトが失敗することです。特定のファイルの存在がより良い解決策です。
#!/bin/sh
#
# USAGE: udev-auto-mount.sh DEVICE
# DEVICE is the actual device node at /dev/DEVICE
#
# This script takes a device name, looks up the partition label and
# type, creates /media/LABEL and mounts the partition. Mount options
# are hard-coded below.
DEVICE=$1
# check input
if [ -z "$DEVICE" ]; then
exit 1
fi
# test that this device isn't already mounted
device_is_mounted=`grep ${DEVICE} /etc/mtab`
if [ -n "$device_is_mounted" ]; then
echo "error: seems /dev/${DEVICE} is already mounted"
exit 1
fi
# If there's a problem at boot-time, this is where we'd put
# some test to check that we're booting, and then run
# sleep 60
# so the system is ready for the mount below.
#
# An example to experiment with:
# Assume the system is "booted enough" if the HTTPD server is running.
# If it isn't, sleep for half a minute before checking again.
#
# The risk: if the server fails for some reason, this mount script
# will just keep waiting for it to show up. A better solution would
# be to check for some file that exists after the boot process is complete.
#
# HTTPD_UP=`ps -ax | grep httpd | grep -v grep`
# while [ -z "$HTTPD_UP" ]; do
# sleep 30
# HTTPD_UP=`ps -ax | grep httpd | grep -v grep`
# done
# pull in useful variables from vol_id, quote everything Just In Case
eval `/sbin/vol_id /dev/${DEVICE} | sed 's/^/export /; s/=/="/; s/$/"/'`
if [ -z "$ID_FS_LABEL" ] || [ -z "$ID_FS_TYPE" ]; then
echo "error: ID_FS_LABEL is empty! did vol_id break? tried /dev/${DEVICE}"
exit 1
fi
# test mountpoint - it shouldn't exist
if [ ! -e "/media/${ID_FS_LABEL}" ]; then
# make the mountpoint
mkdir "/media/${ID_FS_LABEL}"
# mount the device
#
# If expecting thumbdrives, you probably want
# mount -t auto -o sync,noatime [...]
#
# If drive is VFAT/NFTS, this mounts the filesystem such that all files
# are owned by a std user instead of by root. Change to your user's UID
# (listed in /etc/passwd). You may also want "gid=1000" and/or "umask=022", eg:
# mount -t auto -o uid=1000,gid=1000 [...]
#
#
case "$ID_FS_TYPE" in
vfat) mount -t vfat -o sync,noatime,uid=1000 /dev/${DEVICE} "/media/${ID_FS_LABEL}"
;;
# I like the locale setting for ntfs
ntfs) mount -t auto -o sync,noatime,uid=1000,locale=en_US.UTF-8 /dev/${DEVICE} "/media/${ID_FS_LABEL}"
;;
# ext2/3/4 don't like uid option
ext*) mount -t auto -o sync,noatime /dev/${DEVICE} "/media/${ID_FS_LABEL}"
;;
esac
# all done here, return successful
exit 0
fi
exit 1
スーパーボーナスクリーンアップスクリプト!
もう1つのスクリプト。これは、デバイスをアンマウントし、マウントポイントディレクトリを削除するだけです。これを行う権限があると想定しているため、で実行する必要がありますsudo
。このスクリプトは、コマンドラインで完全なマウントポイントを取得します。例:
$ /usr/local/sbin/udev-unmounter.sh "/media/My Random Disk"
これを入れてください/usr/local/sbin/udev-unmounter.sh
:
#!/bin/sh
#
# USAGE: udev-unmounter.sh MOUNTPT
# MOUNTPT is a mountpoint we want to unmount and delete.
MOUNTPT="$1"
if [ -z "$MOUNTPT" ]; then
exit 1
fi
# test mountpoint - it should exist
if [ -e "${MOUNTPT}" ]; then
# very naive; just run and pray
umount -l "${MOUNTPT}" && rmdir "${MOUNTPT}" && exit 0
echo "error: ${MOUNTPT} failed to unmount."
exit 1
fi
echo "error: ${MOUNTPT} does not exist"
exit 1