我日常用Ubuntu系统,当U盘插入的时候,Ubuntu总是帮我讲我的U盘挂载到/media目录下:
- manu@manu-hacks:/media$ ll
- total 12
- drwxr-xr-x 3 root root 4096 Dec 17 23:11 ./
- drwxr-xr-x 23 root root 4096 Nov 29 22:40 ../
- drwx------ 19 manu manu 4096 Jan 1 1970 Ubuntu 12.0/
- manu@manu-hacks:/media$ ps -ef|grep udevd
- root 378 1 0 19:31 ? 00:00:00 /sbin/udevd --daemon
- root 9310 378 0 23:11 ? 00:00:00 /sbin/udevd --daemon
- root 9311 378 0 23:11 ? 00:00:00 /sbin/udevd --daemon
- manu 9339 8894 0 23:13 pts/1 00:00:00 grep --color=auto udevd
在2007年李先静前辈在给出了一个sample程序,因为目前我对netlink的机制理解不够深入,我讲前辈的代码copy于此,学习了一番。还是那句话,没有恶意抄袭前辈的意思,光荣属于前辈:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <sys/un.h>
- #include <sys/ioctl.h>
- #include <sys/socket.h>
- #include <linux/types.h>
- #include <linux/netlink.h>
- #include <errno.h>
- static int init_hotplug_sock(void)
- {
- struct sockaddr_nl snl;
- const int buffersize = 16 * 1024 * 1024;
- int retval;
- memset(&snl, 0x00, sizeof(struct sockaddr_nl));
- snl.nl_family = AF_NETLINK;
- snl.nl_pid = getpid();
- snl.nl_groups = 1;
- int hotplug_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
- if (hotplug_sock == -1) {
- printf("error getting socket: %s", strerror(errno));
- return -1;
- }
- /* set receive buffersize */
- setsockopt(hotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
- retval = bind(hotplug_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));
- if (retval < 0) {
- printf("bind failed: %s", strerror(errno));
- close(hotplug_sock);
- hotplug_sock = -1;
- return -1;
- }
- return hotplug_sock;
- }
- #define UEVENT_BUFFER_SIZE 2048
- int main(int argc, char* argv[])
- {
- int hotplug_sock = init_hotplug_sock();
- while(1)
- {
- char buf[UEVENT_BUFFER_SIZE*2] = {0};
- recv(hotplug_sock, &buf, sizeof(buf), 0);
- printf("%s\n", buf);
- }
- return 0;
- }
当我拔出我的U盘的时候输出:
- remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host8/target8:0:0/8:0:0:0/bsg/8:0:0:0
- remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host8/target8:0:0/8:0:0:0/scsi_generic/sg2
- remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host8/target8:0:0/8:0:0:0/scsi_device/8:0:0:0
- remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host8/target8:0:0/8:0:0:0/scsi_disk/8:0:0:0
- remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host8/target8:0:0/8:0:0:0/block/sdb/sdb4
- remove@/devices/virtual/bdi/8:16
- remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host8/target8:0:0/8:0:0:0/block/sdb
- remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host8/target8:0:0/8:0:0:0
- remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host8/scsi_host/host8
- remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host8
- remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0
- remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2
- remove@/host8/target8:0:0
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host9
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host9/scsi_host/host9
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host9/target9:0:0
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host9/target9:0:0/9:0:0:0
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host9/target9:0:0/9:0:0:0/scsi_disk/9:0:0:0
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host9/target9:0:0/9:0:0:0/scsi_device/9:0:0:0
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host9/target9:0:0/9:0:0:0/scsi_generic/sg2
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host9/target9:0:0/9:0:0:0/bsg/9:0:0:0
- add@/devices/virtual/bdi/8:16
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host9/target9:0:0/9:0:0:0/block/sdb
- add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host9/target9:0:0/9:0:0:0/block/sdb/sdb4
- change@/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0003:00/power_supply/ADP1
- change@/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0003:00/power_supply/ADP1
- change@/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:0e/PNP0C09:00/PNP0C0A:00/power_supply/BAT1
udev同时提供了udevadmin,这个工具也非常实用。我们可以用udevadm来侦测内核事件。
- manu@manu-hacks:~/code/c/self/udev$ udevadm monitor
- custom logging function 0xb8670008 registered
- selinux=0
- runtime dir '/run/udev'
- calling: monitor
- monitor will print the received events for:
- UDEV - the event which udev sends out after rule processing
- KERNEL - the kernel uevent
- KERNEL[14475.004474] add /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2 (usb)
- KERNEL[14475.007146] add /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0 (usb)
- KERNEL[14475.007442] add /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11 (scsi)
- KERNEL[14475.007709] add /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11/scsi_host/host11 (scsi_host)
- UDEV [14475.016589] add /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2 (usb)
- UDEV [14475.017925] add /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0 (usb)
- UDEV [14475.019205] add /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11 (scsi)
- 。。。。。。
- manu@manu-hacks:~/code/c/self/udev$ udevadm info -a -n /dev/sdb
- custom logging function 0xb8950008 registered
- selinux=0
- runtime dir '/run/udev'
- calling: info
- device 0xb8950318 has devpath '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11/target11:0:0/11:0:0:0/block/sdb'
- Udevadm info starts with the device specified by the devpath and then
- walks up the chain of parent devices. It prints for every device
- found, all possible attributes in the udev rules key format.
- A rule to match, can be composed by the attributes of the device
- and the attributes from one single parent device.
- looking at device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11/target11:0:0/11:0:0:0/block/sdb':
- KERNEL=="sdb"
- SUBSYSTEM=="block"
- DRIVER==""
- ATTR{ro}=="0"
- device 0xb89507f0 has devpath '/devices/virtual/bdi/8:16'
- ATTR{size}=="15794176"
- ATTR{stat}==" 176 580 1365 204 0 0 0 0 0 204 204"
- ATTR{range}=="16"
- ATTR{discard_alignment}=="0"
- device 0xb89507f0 has devpath '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11/target11:0:0/11:0:0:0'
- ATTR{events}=="media_change"
- ATTR{ext_range}=="256"
- ATTR{events_poll_msecs}=="2000"
- ATTR{alignment_offset}=="0"
- ATTR{inflight}==" 0 0"
- ATTR{removable}=="1"
- ATTR{capability}=="51"
- ATTR{events_async}==""
- device 0xb8950b60 has devpath '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11/target11:0:0/11:0:0:0'
- looking at parent device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11/target11:0:0/11:0:0:0':
- KERNELS=="11:0:0:0"
- SUBSYSTEMS=="scsi"
- DRIVERS=="sd"
- ATTRS{rev}=="8.07"
- ATTRS{type}=="0"
- ATTRS{scsi_level}=="5"
- ATTRS{model}=="Flash Disk "
- ATTRS{state}=="running"
- ATTRS{queue_type}=="none"
- ATTRS{iodone_cnt}=="0x1a4"
- ATTRS{iorequest_cnt}=="0x1a4"
- ATTRS{timeout}=="30"
- ATTRS{evt_media_change}=="0"
- ATTRS{max_sectors}=="240"
- ATTRS{ioerr_cnt}=="0x2"
- device 0xb8951868 has devpath '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11/target11:0:0/11:0:0:0/scsi_generic/sg2'
- ATTRS{queue_depth}=="1"
- ATTRS{vendor}=="Generic "
- ATTRS{device_blocked}=="0"
- ATTRS{iocounterbits}=="32"
- device 0xb89519c8 has devpath '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11/target11:0:0'
- looking at parent device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11/target11:0:0':
- KERNELS=="target11:0:0"
- SUBSYSTEMS=="scsi"
- DRIVERS==""
- device 0xb8951e78 has devpath '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11'
- looking at parent device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0/host11':
- KERNELS=="host11"
- SUBSYSTEMS=="scsi"
- DRIVERS==""
- device 0xb8952220 has devpath '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0'
- looking at parent device '/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-1.2:1.0':
- KERNELS=="1-1.2:1.0"
- SUBSYSTEMS=="usb"
- DRIVERS=="usb-storage"
- ATTRS{bInterfaceClass}=="08"
- ATTRS{bInterfaceSubClass}=="06"
- ATTRS{bInterfaceProtocol}=="50"
- ATTRS{bNumEndpoints}=="02"
- ATTRS{supports_autosuspend}=="1"
- ATTRS{bAlternateSetting}==" 0"
- ATTRS{bInterfaceNumber}=="00"
- .......
- manu@manu-hacks:/etc/udev$ ll
- total 24
- drwxr-xr-x 3 root root 4096 Dec 15 23:56 ./
- drwxr-xr-x 147 root root 12288 Dec 17 23:32 ../
- drwxr-xr-x 2 root root 4096 Dec 17 23:11 rules.d/
- -rw-r--r-- 1 root root 219 Dec 15 23:56 udev.conf
如果我检查到有USB插入,我会判断U盘是否是特殊的那块U盘,如果是,我需要将U盘挂载到指定的路径下如/mnt/manu_usb,当有U盘拔出的时候,需要判断是否特殊的U盘,是的话umount掉。
- root@manu-hacks:/etc/udev/rules.d# cat 11-add-usb.rules
- ACTION!="add",GOTO="farsight"
- KERNEL=="sd[a-z][0-9]",SUBSYSTEMS=="usb",RUN+="/home/manu/code/shell/mount-special-usb.sh %k"
- label="farsight"
- root@manu-hacks:/etc/udev/rules.d# cat 11-remove-usb.rules
- ACTION !="remove",GOTO="farsight"
- SUBSYSTEM!="block",GOTO="farsight"
- KERNEL=="sd[a-z][0-9]", RUN+="/home/manu/code/shell/umount-special-usb.sh %k"
- LABEL="farsight"
- root@manu-hacks:/etc/udev/rules.d#
- udevadm control --reload-rules
插入我的U盘后:
- root@manu-hacks:/etc/udev/rules.d# mount
- /dev/sda1 on / type ext4 (rw,errors=remount-ro)
- proc on /proc type proc (rw,noexec,nosuid,nodev)
- sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
- none on /sys/fs/fuse/connections type fusectl (rw)
- none on /sys/kernel/debug type debugfs (rw)
- none on /sys/kernel/security type securityfs (rw)
- udev on /dev type devtmpfs (rw,mode=0755)
- devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
- tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
- none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
- none on /run/shm type tmpfs (rw,nosuid,nodev)
- gvfs-fuse-daemon on /home/manu/.gvfs type fuse.gvfs-fuse-daemon (rw,nosuid,nodev,user=manu)
- /dev/sdb4 on /mnt/manu_usb type vfat (rw)
- root@manu-hacks:/etc/udev/rules.d# mount
- /dev/sda1 on / type ext4 (rw,errors=remount-ro)
- proc on /proc type proc (rw,noexec,nosuid,nodev)
- sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
- none on /sys/fs/fuse/connections type fusectl (rw)
- none on /sys/kernel/debug type debugfs (rw)
- none on /sys/kernel/security type securityfs (rw)
- udev on /dev type devtmpfs (rw,mode=0755)
- devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
- tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
- none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
- none on /run/shm type tmpfs (rw,nosuid,nodev)
- gvfs-fuse-daemon on /home/manu/.gvfs type fuse.gvfs-fuse-daemon (rw,nosuid,nodev,user=manu)
参考文献:
1 Writing udev rules
2 udev的实现原理
3 How to reload udev rules without reboot?
4 Understand output of `udevadm info -a -n /dev/sdb`