- Lưu ý cho Ubuntu Server 11.10: Tập lệnh này không thành công trên Ubuntu Server 11.10 do
vol_id
lệnh lỗi thời . vol_id
đã được thay thế bởi blkid
. Để sửa tập lệnh, thay thế "vol_id" bằng "blkid -o udev" trong udev-auto-mount.sh
tập lệnh.
Tôi đã đập đầu mình một lúc rồi và tôi nghĩ mình đã tìm được giải pháp hiệu quả. Điều này được phát triển và thử nghiệm trên một hệ thống dựa trên Debian, vì vậy nó sẽ hoạt động trên Ubuntu. Tôi sẽ chỉ ra các giả định mà nó đưa ra để nó cũng có thể thích nghi với các hệ thống khác.
- Nó sẽ tự động gắn ổ USB vào plugin và không cần nhiều thời gian để thích ứng với Firewire.
- Nó sử dụng UDEV, do đó, không có trò đùa với HAL / DeviceKit / Gnome-Anything.
- Nó tự động tạo một
/media/LABEL
thư mục để gắn thiết bị.
- Tuy nhiên, nó có thể can thiệp vào các thiết bị tự động khác; Tôi không thể kiểm tra điều đó. Tôi hy vọng rằng, với Gnome-VFS hoạt động, cả hai có thể thử thực hiện việc gắn kết ... nếu Gnome-VFS không thực hiện được việc gắn kết, nó có thể không định cấu hình biểu tượng máy tính để bàn. Có thể ngắt kết nối từ Gnome, nhưng có thể yêu cầu
gksudo
hoặc tương tự.
Tôi chưa thử nghiệm điều này khi khởi động hệ thống, nhưng lý do duy nhất tôi có thể thấy rằng nó có thể không hoạt động là nếu nó cố gắn ổ USB trước khi hệ thống sẵn sàng để gắn kết. Nếu đó là trường hợp, có lẽ bạn sẽ cần một điều chỉnh bổ sung cho tập lệnh gắn kết. (Tôi đang kiểm tra với ServerFault để xem có lời khuyên nào không, nhưng không quan tâm nhiều đến nó ở đó.)
Sau đó, sau đó.
Tài liệu tham khảo UDEV:
Bối cảnh (UDEV? Whuzzat?)
UDEV là hệ thống cắm nóng của kernel. Đó là những gì tự động cấu hình các thiết bị và liên kết tượng trưng thiết bị phù hợp (ví dụ /dev/disk/by-label/<LABEL>
), cả lúc khởi động và cho các thiết bị được thêm trong khi hệ thống đang chạy.
D-Bus và HAL được sử dụng để gửi các sự kiện phần cứng tới người nghe như Môi trường máy tính để bàn. Vì vậy, khi bạn đăng nhập vào Gnome và cắm CD hoặc cắm vào ổ USB, sự kiện đó diễn ra theo chuỗi này:
kernel -> udev -> dbus -> hal -> gnome-vfs/nautilus (mount)
Và thế là, ổ đĩa của bạn được gắn kết. Nhưng trong một hệ thống không đầu, chúng tôi không muốn phải đăng nhập để nhận được lợi ích của việc tự động hóa.
Quy tắc Udev
Vì UDEV cho phép chúng tôi viết các quy tắc và chạy các chương trình khi chèn thiết bị, đây là một lựa chọn lý tưởng. Chúng tôi sẽ tận dụng các quy tắc hiện có của Debian / Ubuntu, để họ thiết lập /dev/disk/by-label/<LABEL>
liên kết tượng trưng cho chúng tôi và thêm một quy tắc khác sẽ gắn kết thiết bị cho chúng tôi.
Các quy tắc của UDEV được giữ trong /etc/udev/rules.d
(và /lib/udev/rules.d
trên Karmic) và được xử lý theo thứ tự số. Bất kỳ tệp nào không bắt đầu bằng số được xử lý sau các tệp được đánh số. Trên hệ thống của tôi, các quy tắc HAL nằm trong một tệp được gọi 90-hal.rules
, vì vậy tôi đặt các quy tắc của mình vào 89-local.rules
để chúng được xử lý trước khi chúng đến HAL. Chủ yếu, bạn cần chắc chắn rằng các quy tắc này xảy ra sau 60-persistent-storage.rules
. local.rules
có thể đủ tốt
Đặt điều này trong tệp quy tắc mới của bạn:
# /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"
Hãy chắc chắn rằng không có khoảng trắng nào sau \
, chỉ là một newline
( \n
).
Thay đổi SUBSYSTEMS=="usb"
để được SUBSYSTEMS=="usb|ieee1394"
hỗ trợ Firewire.
Nếu bạn muốn thiết bị luôn được sở hữu bởi một người dùng cụ thể, hãy thêm một OWNER="username"
mệnh đề. Nếu bạn chỉ cần các tệp thuộc sở hữu của một người dùng cụ thể, hãy điều chỉnh tập lệnh mount thay thế.
Đọc quy tắc
Điều này thêm một chương trình để chạy vào danh sách các chương trình sẽ chạy. Nó xác định các thiết bị phân vùng USB bằng cách <LABEL>
, sau đó chuyển thông tin này đến một tập lệnh thực hiện việc gắn kết. Cụ thể, quy tắc này phù hợp:
ENV{ID_FS_LABEL_ENC}=="?*"
- một biến môi trường được thiết lập bởi một quy tắc hệ thống trước đó. Không tồn tại cho các hệ thống không phải tệp, vì vậy đó là lý do tại sao chúng tôi kiểm tra nó. Chúng tôi thực sự muốn sử dụng ID_FS_LABEL
cho điểm gắn kết, nhưng tôi đã không thuyết phục được UDEV thoát nó cho tôi, vì vậy chúng tôi sẽ để kịch bản gắn kết xử lý điều đó.
Biến này và các biến môi trường khác được udev thu được bằng cách sử dụng vol_id
lệnh ( không dùng nữa ). Đây là một công cụ tiện dụng để xem chi tiết nhanh chóng trên phân vùng:
$ 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"
- chỉ phù hợp với add
sự kiện ...
SUBSYSTEMS=="usb"
- chỉ phù hợp với các thiết bị trên bus USB. Chúng tôi sử dụng SUBSYSTEMS
ở đây vì điều này phù hợp với cha mẹ của thiết bị của chúng tôi; thiết bị chúng tôi quan tâm thực sự sẽ là SUBSYSTEM == "scsi". Việc kết hợp với thiết bị USB gốc sẽ tránh thêm chương trình của chúng tôi vào các ổ đĩa trong.
RUN+="..."
- không phải là một trận đấu, mà là một hành động: thêm chương trình này vào danh sách các chương trình sẽ chạy. Trong các đối số của chương trình, %k
được mở rộng thành tên thiết bị (ví dụ: sdc1
không /dev/sdc1
) và $env{FOO}
lấy nội dung của biến môi trường FOO.
Kiểm tra quy tắc
Liên kết tham chiếu đầu tiên (ở trên) là một hướng dẫn tuyệt vời về UDEV, nhưng nó hơi lỗi thời. Các chương trình mà nó chạy để kiểm tra các quy tắc của bạn ( udevtest
đặc biệt) đã được thay thế bằng udevadm
tiện ích Catch-all .
Sau khi bạn đã thêm quy tắc, hãy cắm thiết bị của bạn. Đợi vài giây, sau đó kiểm tra xem thiết bị được gán cho thiết bị nào:
$ 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
Nếu ổ đĩa có thể tháo rời của bạn chứa label_Baz
, nó nằm trên thiết bị sdc1
. Chạy cái này và nhìn vào đầu ra về cuối:
$ 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'
Tìm tên tập lệnh từ RUN+=
quy tắc của chúng tôi trong một vài dòng cuối cùng (thứ 3 từ dưới cùng trong ví dụ này). Bạn có thể thấy các đối số sẽ được sử dụng cho thiết bị này. Bạn có thể chạy lệnh đó ngay bây giờ để kiểm tra xem các đối số có âm thanh không; nếu nó hoạt động trên dòng lệnh của bạn, nó sẽ tự động hoạt động khi thiết bị được chèn.
Bạn cũng có thể theo dõi các sự kiện UDEV trong thời gian thực: chạy sudo udevadm monitor
(xem man udevadm
chi tiết về các công tắc). Sau đó, chỉ cần cắm vào một thiết bị mới và xem các sự kiện cuộn qua. (Có thể là quá mức trừ khi bạn vào các chi tiết thực sự cấp thấp ...)
Tải lại các quy tắc
Khi bạn đã xác minh quy tắc đang được đọc đúng cách, bạn cần yêu cầu UDEV tải lại quy tắc để quy tắc mới có hiệu lực. Sử dụng bất kỳ phương pháp nào trong số này (nếu cách thứ nhất không hoạt động, cách thứ hai nên ... nhưng hãy thử cách đầu tiên):
Kịch bản! Trên thực tế, 2 tập lệnh ...
Đây là kịch bản đầu tiên. Vì chương trình chúng tôi chạy cần hoàn thành nhanh chóng, điều này chỉ làm cho tập lệnh thứ hai tắt trong nền. Đặt cái này vào /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} &
Đây là kịch bản thứ hai. Điều này không kiểm tra đầu vào nhiều hơn một chút. Đặt điều này trong /usr/local/sbin/udev-auto-mount.sh
. Bạn có thể muốn điều chỉnh các tùy chọn gắn kết bên dưới. Kịch bản lệnh này hiện tự xử lý việc tìm phân vùng LABEL; UDEV chỉ gửi tên THIẾT BỊ.
Nếu có vấn đề về việc gắn ổ đĩa vào thời gian khởi động , bạn có thể đặt một đoạn mã dài sleep 60
trong tập lệnh này, để cho hệ thống có thời gian hoàn thành trước khi tập lệnh cố gắng gắn ổ đĩa.
Tôi đã đưa ra một gợi ý trong các nhận xét về cách kiểm tra (chạy ps
để xem máy chủ web có đang chạy không), nhưng bạn sẽ muốn điều chỉnh điều đó cho hệ thống của mình. Tôi nghĩ rằng hầu hết các máy chủ mạng mà bạn có thể đang sử dụng đều đủ cho mục đích này - nfsd, smbd, apache, v.v ... Rủi ro, tất nhiên, là tập lệnh mount sẽ thất bại nếu dịch vụ không chạy, vì vậy có thể thử nghiệm sự tồn tại của tập tin cụ thể sẽ là một giải pháp tốt hơn.
#!/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
Tập lệnh dọn dẹp siêu thưởng!
Thêm một kịch bản. Tất cả điều này là ngắt kết nối thiết bị và loại bỏ các thư mục mountpoint. Nó giả định rằng nó có quyền riêng tư để làm điều này, vì vậy bạn sẽ cần phải chạy nó với sudo
. Tập lệnh này hiện lấy điểm gắn kết đầy đủ trên dòng lệnh, ví dụ:
$ /usr/local/sbin/udev-unmounter.sh "/media/My Random Disk"
Đặt cái này vào /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