Gih's Blog

只言片语

FreeBSD系统通过devd/devfs自动挂载USB存储

2011-06-21 by gihnius, tagged as freebsd

因为自己不用KDE/GNOME等桌面系统,也不喜欢Hald提供的挂载方式, 所以写了一个脚本, 实现FreeBSD系统使用devd/devfs自动挂载U盘. 想了解 devd/devfs 就参考man文档吧! 设计脚本的功能大致如下:

插入usb disk后, 创建挂载目录, 检测文件系统类型, 然后使用适当的命令挂载, 把挂载信息记录到syslog里. 支持多个U盘,多分区,多文件系统类型挂载. 默认使用当前桌面用户id进行挂载.脚本的缺点:不能提示用户已经挂载, 不能通过图形界面卸载. 如果你觉得这个脚本有用,就给些建议帮忙改进吧!配置:设置系统运行普通用户挂载设备:在/etc/sysctl.conf加入:

vfs.usermount=1

设定SCSI 设备的默认权限:/etc/devfs.conf

perm    pass0   0660
perm    devstat     0444 

/etc/devfs.rules

add path 'da[0-9]*' mode 0660 group operator
add path 'msdosfs/*' mode 0660 group operator
add path 'usb/*' mode 0660 group operato 

把用户加入到设备权限组里:/etc/group

operator:*:5:root, gihnius

重要的是这个:增加一个/etc/devd/umass.conf 文件, 内容如下:

attach 100 {
        device-name "umass[0-9]+";
        action "/bin/sleep 2; /etc/automount.sh attach $device-name";
};

detach 100 {
        device-name "umass[0-9]+";
        action "/etc/automount.sh detach $device-name";
}; 

其它:/boot/loader.conf for mount_msdosfs by user

libiconv_load="YES"
msdosfs_iconv_load="YES" 

/etc/rc.conf for ntfs-3g

fusefs_enable="YES"

我把脚本放到 /etc/automount.sh 下.

#!/bin/sh

#
## Author: gihnius@gmail.com
#

## auto mount usb disk by devd control
## version 0.1

## restore 'C' locale
unset LANG

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:$HOME/bin

## get desktop user name
XUSER=$(/usr/bin/last | awk '/still logged in/ && /:0.0/ {user=$1}END{print user}')
test -z $XUSER && XUSER="root" ## else mount for root
## get uid gid
uid=$(awk -F: -v user=$XUSER '{if($1 == user) {print $3}}' /etc/passwd)
gid=$(awk -F: -v user=$XUSER '{if($1 == user) {print $4}}' /etc/passwd)

mount_ntfs () {
    ## ntfs-3g must run by root
    ntfs-3g -o uid=$uid,gid=$gid,umask=022,fmask=133,locale=zh_CN.UTF-8 $1 $2
    logger "mount ntfs $1 to $2. "
}
mount_ufs2 () {
    su -m $XUSER -c "mount $1 $2"
    logger "mount ufs2 $1 to $2. "
}
mount_vfat () {
    su -m $XUSER -c "mount_msdosfs -L zh_CN.UTF-8 $1 $2"
    logger "mount msdosfs $1 to $2. "
}

action=$1
umass=$2

## do

case $action in
    attach)
        umass_id=$(echo $umass | sed 's/umass//')
        ## mount under /mnt/usb0 .. usb1 .. usb2 ..
        mount_dir="/mnt/usb${umass_id}"
        test -d $mount_dir || mkdir -p $mount_dir
        chown -R ${uid}:${gid} $mount_dir

        ## get da0 or da1 da2 ...
        main_device="da$umass_id"
        ## get da0s1 da0s2 ... or da0s1a da0s1d ...
        slice=$(cd /dev ; ls ${main_device}s* 2>/dev/null)
        has_slice=$(echo $slice | wc -w)
            ## only a main device (mount it to $mount_dir
        if [ $has_slice -eq 0 ] ; then
            fstype=$(fstyp /dev/$main_device)
            [ "x$fstype" = "xntfs" ] && mount_ntfs /dev/$main_device $mount_dir
            [ "x$fstype" = "xufs2" ] && mount_ufs2 /dev/$main_device $mount_dir
            [ "x$fstype" = "xvfat" ] && mount_vfat /dev/$main_device $mount_dir
        elif [ $has_slice -ge 1 ] ; then 
            for s in $slice
            do
                cd /dev
                ls ${s}? >/dev/null 2>&1
                if [ $? -eq 0 ] ; then
                    continue
                fi
                test -d $mount_dir/$s || mkdir -p $mount_dir/$s
                chown -R ${uid}:${gid} $mount_dir/$s
                fstype=$(fstyp /dev/$s)
                [ "x$fstype" = "xntfs" ] && mount_ntfs /dev/$s $mount_dir/$s
                [ "x$fstype" = "xufs2" ] && mount_ufs2 /dev/$s $mount_dir/$s
                [ "x$fstype" = "xvfat" ] && mount_vfat /dev/$s $mount_dir/$s
            done
        fi
        ;;
    detach)
        umass_id=$(echo $umass | sed 's/umass//')
        mount_dir="/mnt/usb${umass_id}"
        for d in `ls $mount_dir/`
        do
            test -d $mount_dir/$d && rmdir $mount_dir/$d 2>/dev/null
        done
        ;;
    *) exit 1
esac 

根据上面脚本的流程,简单解释一下:

  • XUSER是 local DISPLAY 的用户, 如果没有,就使用root.
  • mount_xxxx各种文件系统的 mount 方法, 这个有待完善, 目前太局限了. 你可能需要修改才能用!
  • 接受devd传递来的参数attach, dettach, umassID , 根据umass ID建立挂载目录, 并修改目录权限.
  • 检测文件系统类型, 这里要安装 fstyp 工具, 在/usr/ports/sysutils/fstyp可以找到.
  • 确认是一个slice还是多个slices 及文件系统类型之后再挂载.

更新了脚本,之前好多bug!