一向的观点就是“别在内核上面处理字符串”!事实上,确实应当这么!
Linux内核的块设备驱动有能力读取c盘的序列号,这个数据储存在c盘的控制芯片ROM上面。内核应当以如何的方式将这个序列号呈现给调用者呢?我们ls一下这个目录:
/dev/disk/by-id
ll/dev/disk/by-id/
...
lrwxrwxrwx1rootroot910月1710:11scsi-SATA_ST3500413AS_Z2A2AGQA->../../sdb
可以看见,一个c盘可以用传统的/dev/sdX来索引,也可以by-YY来索引,其中by-id就是以序列号来索引,上述输出中,顿号前面的就是序列号。同样linux学习,我们可以用hdparm工具程序来读取,可以读到同样的结果。在hdparm的代码实现中,我们可以见到如下的代码段:
staticchar*strip(char*s)
{
char*e;
while(*s=='')++s;
if(*s)
for(e=s+strlen(s);*--e=='';*e='');
returns;
}
staticvoiddump_identity(__u16*idw)
{
inti;
charpmodes[64]={0,},dmodes[128]={0,},umodes[128]={0,};
char*model=strip(strndup((char*)&idw[27],40));
char*fwrev=strip(strndup((char*)&idw[23],8));
char*serno=strip(strndup((char*)&idw[10],20));
__u8tPIO;
printf("nModel=%.40s,FwRev=%.8s,SerialNo=%.20s",model,fwrev,serno);
...
}
很显著,在显示序列号时,strip除去了首尾的空格,由于空格显示下来是没有意义的。这非常正常。但是...
但是在2.6的老版本的内核例如2.6.8版本中linux 获取硬盘序列号,我们看见了do_identify中有下边的调用:
ide_fixstring(id->serial_no,sizeof(id->serial_no),bswap);
这么这个ide_fixstring是干哪些的呢?它的实现如下,详尽的注释早已给出了答案:
voidide_fixstring(u8*s,constintbytecount,constintbyteswap)
{
u8*p=s,*end=&s[bytecount&~1];/*bytecountmustbeeven*/
if(byteswap){
/*convertfrombig-endiantohostbyteorder*/
for(p=end;p!=s;){
unsignedshort*pp=(unsignedshort*)(p-=2);
*pp=ntohs(*pp);
}
}
/*stripleadingblanks*/
while(s!=end&&*s=='')
++s;
/*compressinternalblanksandstriptrailingblanks*/
while(s!=end&&*s){
if(*s++!=''||(s!=end&&*s&&*s!=''))
*p++=*(s-1);
}
/*wipeouttrailinggarbage*/
while(p!=end)
*p++='';
}
几乎是hdparm的strip愈发严格意义上的翻版!这有哪些问题呢?问题大了。这个内核没有办法给用户呈现一个原始的c盘序列号linux 获取硬盘序列号linux基础教程,也就是序列号本身。为什么不把处理留给应用程序呢?
Linux内核应当迅速返回最原始的二补码信息,将解析任务留给应用程序,不光是效率考虑,更多的是内核根本不晓得怎么去剖析这种信息!辛运的是,高版本的内核不再处理c盘序列号了,仅仅返回了原始信息,不幸的是,它带来了问题!
要不是工作中遇见了问题,我也不会闲到去折腾哪些块设备驱动。系统仅仅升级了内核,但是升级前后都须要读取c盘序列号和保存的序列号比对,老版本的内核和新版本内核对c盘序列号读取行为的不同造成出现了不同的结果,内核也就不再对应用程序透明了!那如何办?只得更改高版本内核驱动去讨好老版本的错误方法了!
LinuxKernel的详尽介绍:请点这儿
LinuxKernel的下载地址:请点这儿