- Примечание для Ubuntu Server 11.10: этот сценарий не выполняется на Ubuntu Server 11.10 из-за устаревшей
vol_id
команды. 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 используются для отправки аппаратных событий слушателям, таким как Desktop Environments. Поэтому, когда вы входите в GNOME и вставляете компакт-диск или подключаете USB-накопитель, это событие следует следующей цепочке:
kernel -> udev -> dbus -> hal -> gnome-vfs/nautilus (mount)
И до того, ваш диск будет установлен. Но в безголовой системе нам не нужно входить в систему, чтобы воспользоваться преимуществами автоматического монтирования.
Правила Удев
Поскольку UDEV позволяет нам писать правила и запускать программы при вставке устройства, это идеальный выбор. Мы собираемся воспользоваться существующими правилами Debian / Ubuntu, позволить им настроить /dev/disk/by-label/<LABEL>
символическую ссылку для нас и добавить другое правило, которое смонтирует устройство для нас.
Правила UDEV хранятся в /etc/udev/rules.d
(и /lib/udev/rules.d
в Кармическом) и обрабатываются в числовом порядке. Любой файл, не начинающийся с цифры, обрабатывается после нумерованных файлов. В моей системе правила HAL находятся в файле, который называется 90-hal.rules
, поэтому я помещаю свои правила 89-local.rules
так, чтобы они обрабатывались до того, как они попадут в HAL. Прежде всего, вы должны убедиться, что эти правила применяются после 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
).
Перейдите SUBSYSTEMS=="usb"
на SUBSYSTEMS=="usb|ieee1394"
поддержку Firewire.
Если вы хотите, чтобы устройство всегда принадлежало определенному пользователю, добавьте 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
, нет /dev/sdc1
) и $env{FOO}
получает содержимое переменной среды FOO.
Тестирование правила
Первая ссылочная ссылка (выше) - отличное руководство по UDEV, но оно немного устарело. Программы, которые он запускает для проверки ваших правил ( udevtest
в частности), были заменены 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
, это на устройстве 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+=
правила в последних нескольких строках (в этом примере третье снизу). Вы можете увидеть аргументы, которые будут использоваться для этого устройства. Вы можете запустить эту команду сейчас, чтобы проверить правильность аргументов; если он работает в командной строке, он должен работать автоматически при вставке устройства.
Вы также можете отслеживать события UDEV в режиме реального времени: run sudo udevadm monitor
(см. man udevadm
Подробности о коммутаторах). Затем просто подключите новое устройство и наблюдайте за прокруткой событий. (Вероятно, излишне, если вы не в мелочах ...)
Перезагрузка правил
После того, как вы убедились, что правило читается правильно, вам нужно сказать UDEV перезагрузить его правила, чтобы новое вступило в силу. Используйте любой из этих методов (если первый не работает, второй должен ... но попробуйте первый первый):
Сценарий! На самом деле, 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} &
Вот второй сценарий. Это немного больше проверяет ввод. Вставь это /usr/local/sbin/udev-auto-mount.sh
. Вы можете настроить параметры монтирования ниже. Этот скрипт теперь самостоятельно обрабатывает раздел LABEL; UDEV только отправляет имя УСТРОЙСТВА.
Если при загрузке возникает проблема с монтированием дисков , вы можете добавить sleep 60
в этот сценарий длинную строку, чтобы дать системе время полностью загрузиться , прежде чем скрипт попытается смонтировать диск.
Я дал предложение в комментариях о том, как проверить (запустите, ps
чтобы увидеть, работает ли веб-сервер), но вы захотите настроить его для своей системы. Я думаю, что для этой цели подойдет большинство любых сетевых серверов, которые вы могли бы использовать - 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
Супер бонус сценарий очистки!
Еще один скрипт. Все это делает размонтирование устройства и удаление каталогов точки монтирования. Предполагается, что для этого у него есть привилегии, поэтому вам нужно будет запустить его 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