- หมายเหตุสำหรับ Ubuntu Server 11.10:สคริปต์นี้ล้มเหลวบน Ubuntu Server 11.10 เนื่องจาก
vol_id
คำสั่ง ล้าสมัย ได้ถูกแทนที่โดยvol_id
blkid
ในการแก้ไขสคริปต์ให้แทนที่ "vol_id" โดย "blkid -o udev" ในudev-auto-mount.sh
สคริปต์
ฉันตีหัวของฉันรอบนี้มาระยะหนึ่งแล้วและฉันคิดว่าฉันได้พบวิธีแก้ปัญหาการทำงาน สิ่งนี้ได้รับการพัฒนาและทดสอบบนระบบที่ใช้เดเบียนดังนั้นมันจึงควรใช้กับ Ubuntu ฉันจะชี้ให้เห็นถึงสมมติฐานที่ทำให้มันสามารถปรับให้เข้ากับระบบอื่นเช่นกัน
- มันจะติดตั้งไดรฟ์ USB บนปลั๊กอินโดยอัตโนมัติและไม่ควรปรับใช้กับ Firewire มากนัก
- มันใช้ UDEV ดังนั้นอย่าลิงกับ HAL / DeviceKit / GNOME-Anything
- มันสร้าง
/media/LABEL
ไดเรกทอรีเพื่อติดตั้งอุปกรณ์โดยอัตโนมัติ
- อย่างไรก็ตามมันอาจรบกวนการเปิดประตูอัตโนมัติอื่น ๆ ฉันไม่สามารถทดสอบสิ่งนั้นได้ ฉันคาดหวังว่าด้วยการใช้งาน Gnome-VFS ทั้งคู่อาจลองเมานท์ ... หาก Gnome-VFS ไม่สามารถเมานต์ได้อาจไม่ได้กำหนดค่าไอคอนเดสก์ท็อป การถอนติดตั้งจาก Gnome ควรเป็นไปได้ แต่อาจต้องการ
gksudo
หรือคล้ายกัน
ฉันยังไม่ได้ทดสอบสิ่งนี้ในการบู๊ตระบบ แต่เหตุผลเดียวที่ฉันเห็นว่ามันอาจไม่ทำงานคือหากพยายามเชื่อมต่อไดรฟ์ USB ก่อนที่ระบบจะพร้อมสำหรับการเมานต์ หากเป็นกรณีนี้คุณอาจต้องปรับแต่งสคริปต์เพิ่มเติมอีกหนึ่งรายการ (ฉันกำลังตรวจสอบกับ ServerFaultเพื่อดูว่ามีคำแนะนำใดบ้าง แต่ไม่สนใจเรื่องนั้นมากนัก)
เมื่อไปแล้ว
การอ้างอิง UDEV:
พื้นหลัง (UDEV? Whuzzat?)
UDEV เป็นระบบ hotplug ของเคอร์เนล มันคือสิ่งที่กำหนดค่าอุปกรณ์และ symlink ของอุปกรณ์ (เช่น/dev/disk/by-label/<LABEL>
) โดยอัตโนมัติทั้งในเวลาบูตและสำหรับอุปกรณ์ที่เพิ่มในขณะที่ระบบกำลังทำงาน
D-Bus และ HAL ใช้สำหรับส่งกิจกรรมฮาร์ดแวร์ให้กับผู้ฟังเช่นสภาพแวดล้อมเดสก์ท็อป ดังนั้นเมื่อคุณเข้าสู่ GNOME และใส่แผ่นซีดีหรือเสียบในไดรฟ์ USB เหตุการณ์นั้นจะตามหลังสายโซ่นี้:
kernel -> udev -> dbus -> hal -> gnome-vfs/nautilus (mount)
และ presto, ไดรฟ์ของคุณได้รับการติดตั้ง แต่ในระบบไร้หัวเราไม่ต้องการเข้าสู่ระบบเพื่อรับประโยชน์จากการติดตั้งอัตโนมัติ
กฎ Udev
เนื่องจาก UDEV ช่วยให้เราสามารถเขียนกฎและเรียกใช้โปรแกรมในการแทรกอุปกรณ์ได้จึงเป็นตัวเลือกที่เหมาะสมที่สุด เราจะใช้ประโยชน์จากกฎที่มีอยู่ของ Debian / Ubuntu ปล่อยให้พวกเขาตั้งค่า/dev/disk/by-label/<LABEL>
symlink ให้กับเราและเพิ่มกฎอื่นที่จะติดตั้งอุปกรณ์ให้เรา
กฎของ UDEV ถูกเก็บรักษาไว้ใน/etc/udev/rules.d
(และ/lib/udev/rules.d
Karmic) และถูกประมวลผลตามลำดับตัวเลข ไฟล์ใด ๆ ที่ไม่ได้ขึ้นต้นด้วยตัวเลขจะถูกประมวลผลหลังจากไฟล์ที่มีหมายเลข ในระบบของฉันกฎ 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 ให้หลบหนีเพื่อฉัน
ตัวแปรสภาพแวดล้อมนี้และอื่น ๆ ได้รับโดย udev โดยใช้vol_id
คำสั่ง ( คัดค้าน ) มันเป็นเครื่องมือที่มีประโยชน์ในการดูรายละเอียดที่รวดเร็วของพาร์ติชัน:
$ 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
ที่นี่เพราะสิ่งนี้ตรงกับพ่อแม่ของอุปกรณ์ของเรา อุปกรณ์ที่เราสนใจจะเป็นระบบย่อย == "scsi" การจับคู่กับอุปกรณ์ USB หลักหลีกเลี่ยงการเพิ่มโปรแกรมของเราไปยังไดรฟ์ภายใน
RUN+="..."
- ไม่ใช่การจับคู่ แต่เป็นการกระทำ: เพิ่มโปรแกรมนี้ในรายการโปรแกรมที่จะเรียกใช้ ในอาร์กิวเมนต์ของโปรแกรม%k
รับขยายเป็นชื่ออุปกรณ์ (เช่นsdc1
ไม่ใช่/dev/sdc1
) และ$env{FOO}
รับเนื้อหาของตัวแปรสภาพแวดล้อม FOO
ทดสอบกฎ
ลิงค์อ้างอิงแรก (ด้านบน) คือบทช่วย UDEV ที่ยอดเยี่ยม แต่มันล้าสมัยเล็กน้อย โปรแกรมที่ใช้สำหรับทดสอบกฎของคุณ ( udevtest
โดยเฉพาะ) ได้ถูกแทนที่ด้วยudevadm
ยูทิลิตีcatch-all
หลังจากที่คุณเพิ่มกฎแล้วให้เสียบอุปกรณ์ของคุณ ให้เวลาสองสามวินาทีจากนั้นตรวจสอบเพื่อดูว่าอุปกรณ์ใดได้รับมอบหมายด้วย:
$ 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+=
กฎของเราในไม่กี่บรรทัดสุดท้าย (ที่ 3 จากด้านล่างในตัวอย่างนี้) คุณสามารถดูข้อโต้แย้งที่จะใช้สำหรับอุปกรณ์นี้ คุณสามารถเรียกใช้คำสั่งนั้นตอนนี้เพื่อตรวจสอบว่าข้อโต้แย้งนั้นเป็นเสียง ถ้ามันทำงานบน commandline ของคุณมันควรจะทำงานโดยอัตโนมัติเมื่อใส่อุปกรณ์
นอกจากนี้คุณยังสามารถตรวจสอบเหตุการณ์ UDEV แบบเรียลไทม์: เรียกใช้sudo udevadm monitor
(ดูman udevadm
รายละเอียดเกี่ยวกับสวิตช์) จากนั้นเพียงเสียบอุปกรณ์ใหม่แล้วดูการเลื่อนดูเหตุการณ์ (อาจ overkill เว้นแต่ว่าคุณจะลงรายละเอียดในระดับต่ำจริงๆ ... )
โหลดกฎใหม่
เมื่อคุณยืนยันว่ากฎกำลังอ่านอย่างถูกต้องคุณจะต้องบอก 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
สคริปต์การล้างข้อมูลโบนัสพิเศษ!
อีกหนึ่งสคริปต์ ทั้งหมดนี้ใช้เพื่อยกเลิกการต่อเชื่อมอุปกรณ์และลบไดเรกทอรีเมานต์ ก็ถือว่ามันมี privs sudo
การทำเช่นนี้เพื่อให้คุณจะต้องทำงานด้วย ตอนนี้สคริปต์นี้ใช้จุดเมานท์แบบเต็มบน commandline เช่น:
$ /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