linux etc hotplug,hotplug,automount与mdev的调试

首先看看/sbin/mdev的帮助

/sbin/mdev --help

BusyBox v1.16.1 (2011-08-29 15:29:53 HKT) multi-call binary.

Usage: mdev [-s]

-s      Scan /sys and populate /dev during system boot

It can be run by kernel as a hotplug helper. To activate it:

echo /sbin/mdev > /proc/sys/kernel/hotplug

It uses /etc/mdev.conf with lines

[-]DEVNAME UID:GID PERM [>|=PATH] [@|$|*PROG]

medv.conf中会定义需要检测的设备文件:

# Provide user, group, and mode information for devices.  If a regex matches

# the device name provided by sysfs, use the appropriate user:group and mode

# instead of the default 0:0 660.

#

# Syntax:

# [-]devicename_regex user:group mode [>|=path] [@|$|*cmd args...]

#

# =: move, >: move and create a symlink

# @|$|*: run $cmd on delete, @cmd on create, *cmd on both

null 0:0 0666

zero 0:0 0666

console 0:5 600

ttyS[0-9]* 0:0 0660

event[0-9]+  0:0 0640 =input/

mice         0:0 0640 =input/

mouse[0-9]+  0:0 0640 =input/

sd[a-z][0-9]* 0:0 0660 */etc/automount

[1-9]-[1-9]* 0:0 0660 */etc/automount

在这里我们关心U盘和wifi dongle的事件,wifi的dongle和其他usb设备一样都会在/dev下建立[1-9]-[1-9]* 的设备,当相关事件发生时,调用automount

在automount中通过getenv()我们去判断$MDEV和$ACTION两个环境变量.,当然也可以用对应设备在sysfs下的event文件中的其他变量去做某些识别比如DEVTYPE:

对于U盘我们可以看到uevent如下:

# cat /sys/block/sda/uevent

MAJOR=8

MINOR=0

DEVNAME=sda

DEVTYPE=disk

对于wifi我使用了一个笨办法,如果action是add,那么尝试读以下两个文件

/sys/bus/usb/devices/$MDEV/manufacturer

/sys/bus/usb/devices/$MDEV/product

如果能找到"Manufacturer Realtek","11n Adapter",那么说明确实是wifi dongle

对于拔除消息,由于wifi dongle不像普通优盘那样会有sd*的设备文件去除的消息,只有普通usb诸如[1-9]-[1-9]*的消息,所以我们在检测到插入的时候,把$MDEV变量存成一个文件,在有拔除消息的时候和当前的$MDEV比较,如果一样则说明是wifi dongle拔除。

在调试的时候由于automount不在当前shell执行,所以打印看不到,那么一个办法是将调试信息写入文件,然后tail -f filename 去实时打印文件最新内容.另外也可以在脚本中直接将打印输出到控制台,这样更为方便

sd[a-z]  0:0 660 */bin/echo “hello hotplug!” $MDEV $DEVTYPE $ACTION > /dev/console

如果automount里面有死机情况,那么可以使用strace来跟踪记录,将hotplug脚本替换如下,这会将mdev执行中所有变量存入/tmp/dbgMdev,同时strace会将运行时所有log存入log.txt

#!/bin/sh

set >/tmp/dbgMdev

echo "set ok==" >> /tmp/dbgMdev

echo >/tmp/dbgMdev">$@>>/tmp/dbgMdev

echo "prepare start mdev" >> /tmp/dbgMdev

#/bin/busybox mdev $*

#echo "end mdev" >> /tmp/dbgMdev

#set>>/tmp/MDEV

#echo >/tmp/MDEV">$@>>/tmp/MDEV

exec /sbin/strace -f -v -s 1024 -o /tmp/log.txt /bin/busybox mdev $*#

在2.6.15内核以后,系统也提供netlink接口通过socket消息来捕捉hotplug消息:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

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;

}

编译运行以后,拔插优盘:

但是对于冷拔插,还没有想到办法如何检测,初步想法是根据/dev下的设备文件([1-9]-[1-9]*)去查看/sys/bus/usb/devices/%s/manufacturer 和 product字段如果和"Manufacturer Realtek"  "11n Adapter"匹配则认为wifi存在

///depth is only used of indent level for print

int chech_wifi_dev(char * dir, int depth)

{

DIR *dp;

struct dirent *entry;

struct stat statbuf;

int ret = 0;

if((dp = opendir(dir)) == NULL) {

fprintf(stderr,"cannot open directory: %s\n", dir);

return ret;

}

chdir(dir);

while((entry = readdir(dp)) != NULL) {

lstat(entry->d_name,&statbuf);

if(S_ISDIR(statbuf.st_mode)) {

/**//* Found a directory, but ignore . and .. */

if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)

continue;

//printf("%*s%s/\n",depth,"",entry->d_name);

/**//* Recurse at a new indent level */

chech_wifi_dev(entry->d_name,depth+4);

}

else

{

//printf("%*s%s\n",depth,"",entry->d_name);

//find [1-9]-[1-9]*

if(((entry->d_name[0] <= 0x39)&&(entry->d_name[0] >= 0x31))&&(entry->d_name[1]=='-')&&((entry->d_name[2] <= 0x39)&&(entry->d_name[2] >= 0x31)))

{

//printf("find [1-9]-[1-9]*\n");

if(check_wifi(entry->d_name))

{

ret = 1;

break;

}

}

}

}

chdir("..");

closedir(dp);

return ret;

}

另外的方法是查看/sys/class/net/wlan0是否存在来判断

if(argc > 1 && strcmp(argv[1], "check-wifi") == 0)

{

if(access("/sys/class/net/wlan0/carrier", F_OK)==0)

{

iEvent = EVENT_WIRELESS_ADD;

setWirelessDev("");

goto send;

}

}

对于卷标的处理,由于不同文件系统获得卷标的命令不统一,十分麻烦,对于FAT和NTFS通过读FAT表的方式来获得:

static bool GetNTFSName(char *dev_name, char *volumename, int len, int *pActualLen)

{

int errNo;

// UINT32 fd;

FILE *fd;

unsigned short int BytePerSec;

unsigned char SecPerClus;

unsigned long long int mft, bak;

unsigned int record_size;

const unsigned int bsize = 8192;

unsigned char buffer[bsize], i;

// MFT_RECORD *mft_record;

unsigned char *attr_record;

unsigned int mft_offset;

unsigned int attr_offset;

unsigned int record_type, record_data_resident_value_length, record_data_resident_value_offset;

if (pActualLen == NULL)

return false;

// fd = open(dev_name, O_RDONLY);

fd = fopen(dev_name, "ro");

if (fd <= 0) {

*pActualLen = 0;

//strcpy(volumename,  "N\0T\0F\0S\0\0\0");

//*pActualLen = 4 * 2;

//  close(fd);

//  fclose(fd);

DebugPrint((fpDbg, "GetNTFSName fail 1!\n"));

return false;

}

// if (read(fd, buffer, bsize) != bsize) {

if (fread(buffer, 1, bsize, fd) != bsize) {

*pActualLen = 0;

//strcpy(volumename,  "N\0T\0F\0S\0\0\0");

//*pActualLen = 4 * 2;

//  close(fd);

//  fclose(fd);

DebugPrint((fpDbg, "GetNTFSName fail 2!\n"));

return false;

}

BytePerSec = (unsigned short int)((unsigned short int)buffer[0xb]&0xff) | ((unsigned short int)buffer[0x0c]<<8);

SecPerClus = buffer[0xd];

mft = ((unsigned long long int)buffer[0x30]&0xff) | (((unsigned long long int)buffer[0x31]<<8)&0xff00) | (((unsigned long long int)buffer[0x32]<<16)&0xff0000) | (((unsigned long long int)buffer[0x33]<<24)&0xff000000) | (((unsigned long long int)buffer[0x34]<<32)&0xff00000000) | (((unsigned long long int)buffer[0x35]<<40)&0xff0000000000) | (((unsigned long long int)buffer[0x36]<<48)&0xff000000000000) | (((unsigned long long int)buffer[0x37]<<56)&0xff00000000000000);

bak = (unsigned long long int)((unsigned long long int)buffer[0x38]&0xff) | ((unsigned long long int)buffer[0x39]<<8) | ((unsigned long long int)buffer[0x3A]<<16) | ((unsigned long long int)buffer[0x3B]<<24) | ((unsigned long long int)buffer[0x3C]<<32) | ((unsigned long long int)buffer[0x3D]<<40) | ((unsigned long long int)buffer[0x3E]<<48) | ((unsigned long long int)buffer[0x3F]<<56);

record_size = ((unsigned int)buffer[0x40]&0xff) | ((unsigned int)buffer[0x41]<<8) | ((unsigned int)buffer[0x42]<<16) | ((unsigned int)buffer[0x43]<<24);

DebugPrint((fpDbg, "GetNTFSName...BytePerSec: %d \n", BytePerSec));

DebugPrint((fpDbg, "GetNTFSName...SecPerClus: %d \n", SecPerClus));

DebugPrint((fpDbg, "GetNTFSName...MFT: %lld \n", mft));

DebugPrint((fpDbg, "GetNTFSName...BAK: %lld \n", bak));

DebugPrint((fpDbg, "GetNTFSName...record_size: %d \n", record_size));

// errNo = lseek(fd, (off_t)mft*BytePerSec*SecPerClus, SEEK_SET);

// errNo = fseeko(fd, (off_t)mft*BytePerSec*SecPerClus, SEEK_SET);

errNo = fseeko(fd, (long long int)mft*BytePerSec*SecPerClus, SEEK_SET); //DebugPrint((fpDbg, "GetNTFSName...(off_t)mft*BytePerSec*SecPerClus: %lld \n", (off_t)mft*BytePerSec*SecPerClus));

DebugPrint((fpDbg, "GetNTFSName...(long long int)mft*BytePerSec*SecPerClus: %lld \n", (long long int)mft*BytePerSec*SecPerClus));

if (errNo == -1) {

printf("Seek Error [%d]\n", errNo);

*pActualLen = 0;

//strcpy(volumename,  "N\0T\0F\0S\0\0\0");

//*pActualLen = 4 * 2;

//  close(fd);

fclose(fd);

DebugPrint((fpDbg, "GetNTFSName fail 3!\n"));

return false;

}

// if (read(fd, buffer, bsize) != bsize) {

if (fread(buffer, 1, bsize, fd) != bsize) {

*pActualLen = 0;

//strcpy(volumename,  "N\0T\0F\0S\0\0\0");

//*pActualLen = 4 * 2;

//  close(fd);

fclose(fd);

DebugPrint((fpDbg, "GetNTFSName fail 4!\n"));

return false;

}

// $MFT

mft_offset = 0;

// mft_record = (MFT_RECORD *)&buffer[mft_offset];

// attr_offset = mft_offset+mft_record->attrs_offset;

attr_offset = mft_offset + ((unsigned short int)buffer[mft_offset+20]&0xff) + ((unsigned short int)buffer[mft_offset+21]<<8);

// attr_record = (ATTR_RECORD *)&buffer[attr_offset];

attr_record = &buffer[attr_offset];

while (*(unsigned int *)attr_record != 0xffffffff) {

attr_offset += (attr_record[4]&0xff) + (attr_record[5]<<8) + (attr_record[6]<<16) + (attr_record[7]<<24);

attr_record = &buffer[attr_offset];

}

// $MFTMirr

mft_offset += (buffer[mft_offset+28]&0xff) + (buffer[mft_offset+29]<<8) + (buffer[mft_offset+30]<<16) + (buffer[mft_offset+31]<<24);

// mft_record = (MFT_RECORD *)&buffer[mft_offset];

// attr_offset = mft_offset+mft_record->attrs_offset;

attr_offset = mft_offset + ((unsigned short int)buffer[mft_offset+20]&0xff) + ((unsigned short int)buffer[mft_offset+21]<<8);

// attr_record = (ATTR_RECORD *)&buffer[attr_offset];

attr_record = &buffer[attr_offset];

while (*(unsigned int *)attr_record != 0xffffffff) {

attr_offset += (attr_record[4]&0xff) + (attr_record[5]<<8) + (attr_record[6]<<16) + (attr_record[7]<<24);

attr_record = &buffer[attr_offset];

}

// $LogFile

mft_offset += (buffer[mft_offset+28]&0xff) + (buffer[mft_offset+29]<<8) + (buffer[mft_offset+30]<<16) + (buffer[mft_offset+31]<<24);

// mft_record = (MFT_RECORD *)&buffer[mft_offset];

// attr_offset = mft_offset+mft_record->attrs_offset;

attr_offset = mft_offset + ((unsigned short int)buffer[mft_offset+20]&0xff) + ((unsigned short int)buffer[mft_offset+21]<<8);

// attr_record = (ATTR_RECORD *)&buffer[attr_offset];

attr_record = &buffer[attr_offset];

while (*(unsigned int *)attr_record != 0xffffffff) {

attr_offset += (attr_record[4]&0xff) + (attr_record[5]<<8) + (attr_record[6]<<16) + (attr_record[7]<<24);

attr_record = &buffer[attr_offset];

}

// $Volume

mft_offset += (buffer[mft_offset+28]&0xff) + (buffer[mft_offset+29]<<8) + (buffer[mft_offset+30]<<16) + (buffer[mft_offset+31]<<24);

// mft_record = (MFT_RECORD *)&buffer[mft_offset];

// attr_offset = mft_offset+mft_record->attrs_offset;

attr_offset = mft_offset + ((unsigned short int)buffer[mft_offset+20]&0xff) + ((unsigned short int)buffer[mft_offset+21]<<8);

// attr_record = (ATTR_RECORD *)&buffer[attr_offset];

attr_record = &buffer[attr_offset];

while (*(unsigned int *)attr_record != 0xffffffff) {

record_type = (attr_record[0]&0xff) + (attr_record[1]<<8) + (attr_record[2]<<16) + (attr_record[3]<<24);

if (record_type == 0x60) {

record_data_resident_value_length = (attr_record[16]&0xff) + (attr_record[17]<<8) + (attr_record[18]<<16) + (attr_record[19]<<24);

if (record_data_resident_value_length <= len)

len = record_data_resident_value_length;

record_data_resident_value_offset = (attr_record[20]&0xff) + (attr_record[21]<<8);

///for (i=0;i>1);i++)

///volumename[i] = buffer[attr_offset+record_data_resident_value_offset + i*2];

if (len != 0) {

memcpy(volumename, &buffer[attr_offset+record_data_resident_value_offset], len);//unicode16

*pActualLen = len;

} else {

*pActualLen = 0;

//strcpy(volumename, "N\0T\0F\0S\0\0\0");

//*pActualLen = 4 * 2;

}

break;

}

attr_offset += (attr_record[4]&0xff) + (attr_record[5]<<8) + (attr_record[6]<<16) + (attr_record[7]<<24);

attr_record = &buffer[attr_offset];

}

// close(fd);

fclose(fd);

return true;

}

fseeko总是出错,应该是因为int64的原因,暂时没解决。

static bool GetFATName(char *dev_name, char *volumename, int len)

{

// int   fd;

FILE   *fd;

short   f16_size;

const int  bsize = 8192;

char   buffer[bsize];

int   next_cluster = 0;

// fd = open(dev_name, O_RDONLY);

fd = fopen(dev_name, "ro");

if (fd <= 0) {

//strcpy(volumename, "FAT\0");

//  close(fd);

//  fclose(fd);

return false;

}

// if (read(fd, buffer, bsize) != bsize) {

if (fread(buffer, 1, bsize, fd) != bsize) {

//strcpy(volumename, "FAT\0");

//  close(fd);

//  fclose(fd);

return false;

}

// 0x16 & 0x17 is Sector per FAT

f16_size = (buffer[0x16]&0xff) + (buffer[0x17]<<8);

if (f16_size == 0) { // FAT32

short reserved, sec_size;

char clus, fats, attr;

int f32_size, root_cluster, i, j;

memcpy(volumename, buffer+0x47, len);

// Sectors Per FAT

f32_size = (buffer[0x24]&0xff) | (buffer[0x25]<<8) | (buffer[0x26]<<16) | (buffer[0x27]<<24);

// Reserved Sectors

reserved = (buffer[0xe]&0xff) | (buffer[0xf]<<8);

// Bytes Per Sector

sec_size = (buffer[0xb]&0xff) | (buffer[0xc]<<8);

// Root Cluster

root_cluster = (buffer[0x2c]&0xff) | (buffer[0x2d]<<8) | (buffer[0x2e]<<16) | (buffer[0x2f]<<24);

clus = buffer[0xd];   // Sectors Per Cluster

fats = buffer[0x10];  // No. of FATs

next_cluster = root_cluster;

// 0xFFFFFF7 is bad cluster, >= 0xFFFFFF8 is end Cluster, 0x0 if nod used cluster, Correct must 3 < x < 0xFFFFFF6

while ( (next_cluster <= 0xFFFFFF6) && (next_cluster >= root_cluster) )  {

//   lseek(fd, (reserved+((fats)*(f32_size)))*(sec_size)+(root_cluster-2)*(clus)*(sec_size), SEEK_SET);

fseeko(fd, (reserved+((fats)*(f32_size)))*(sec_size)+(next_cluster-2)*(clus)*(sec_size), SEEK_SET);

//   if (read(fd, buffer, bsize) != bsize) {

if (fread(buffer, 1, bsize, fd) != bsize) {

//strcpy(volumename, "FAT32\0");

return false;

}

for (i = 0, j = -1; i < 256; i++) {

attr = buffer[i*32+11]; // each entry 32 bytes, Byte 11 is Attribute

if ((attr & 0x8) && ((attr & 0xf) != 0xf) && ((attr & 0xf0) == 0)) {

char size;

size = buffer[i*32+31]; // 28~31 is size

if ( (size != 0) || ((int)*(buffer+i*32) == -27) )

continue;

j = i;

break;

}

}

if (j != -1)

break;

// Seek to FAT Table

fseeko(fd, reserved*sec_size, SEEK_SET);

if (fread(buffer, 1, bsize, fd) != bsize) {

//strcpy(volumename, "FAT32\0");

return false;

}

// Read FAT Table for root_cluster to search next Cluster

next_cluster = (buffer[4*next_cluster]&0xff) | (buffer[4*next_cluster+1]<<8) | (buffer[4*next_cluster+2]<<16) | (buffer[4*next_cluster+3]<<24);

}

// Get Real Volume Label

if ((j != -1) && ((int)*(buffer+j*32) != -27))

memcpy(volumename, buffer+j*32, len);

//else

//strcpy(volumename, "FAT32\0");

} else {    // FAT 16

short reserved, sec_size;

char fats, attr;

int i, j;

memcpy(volumename, buffer+0x2b, len);

// Reserved Sectors

reserved = (buffer[0xe]&0xff) | (buffer[0xf]<<8);

// Bytes Per Sector

sec_size = (buffer[0xb]&0xff) | (buffer[0xc]<<8);

// No. of FATs

fats = buffer[0x10];

//  lseek(fd, (reserved+((fats)*(f16_size)))*(sec_size), SEEK_SET);

fseeko(fd, (reserved+((fats)*(f16_size)))*(sec_size), SEEK_SET);

//  if (read(fd, buffer, bsize) != bsize) {

if (fread(buffer, 1, bsize, fd) != bsize) {

//strcpy(volumename, "FAT16\0");

return false;

}

for (i = 0, j = -1; i < 256; i++) {

attr = buffer[i*32+11];

if ((attr & 0x8) && ((attr & 0xf) != 0xf) && ((attr & 0xf0) == 0)) {

char size;

size = buffer[i*32+31];

if ( (size != 0) || ((int)*(buffer+i*32) == -27) )

continue;

j = i;

break;

}

}

if ((j != -1) && ((int)*(buffer+j*32) != -27))

memcpy(volumename, buffer+j*32, len);

//else

//strcpy(volumename, "FAT16\0");

}

// close(fd);

fclose(fd);

return true;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值