2010年04月29日

    前几日有幸受央视垂青,Dian团队一干人马进京录制了《小崔说事》的一期节目,名曰“点亮未来”。节目已于上周日播出,回想录制节目的前后,却是对小崔说事节目组深深的敬佩,作为国家级电视台的节目制作组,无处不彰显其特质。
    1、敬业。点亮未来这一期的选题大约是在Dian团队8周年团庆晚会期间(4月4日)由央视采风的记者上报的。不到一周的时间,4月10日,小崔说事的记者张老师和摄像吴老师即再次来到团队为节目录制素材。那是一个多云转大雨的周末,在周六一早到达武汉时,他们就立刻投入了工作。周六上午录制出站队员姚磊的视频,与刘玉老师沟通策划内容,中午调取了团队多年来的文字、图片、视频资料,并在下午仔细研习,寻找亮点。次日,首先赴行政楼录制了李校长的谈话镜头,接着不顾大雨在校门口拍摄了校门近景,甚至在关山一路马路中央双黄线上支起三脚架拍摄校门全景。两位央视老师全然不管雨水打湿自己的衣衫,也要用雨伞护着摄像器材,犹如战场上的士兵视自己的武器为生命。
    2、专业。节目组在上周二晚上通知团队派人进京录制节目,上周五晚7点~9点间录制完毕,时长共计1.5小时。而节目播出时间是上周日下午2点,间隔40小时左右。在这40小时的时间里,小崔说事节目组需要完成剪辑(从1.5小时剪辑到45分钟)、字幕(1万字左右,输入并校对)等后期工作,还得留出时间给央视领导审核。可以想象,这工作量会有多大,事实上节目组几乎也是通宵达旦的在忙碌。在上周日临晨5点多,我们一行人尚在返程列车上时,节目组的张老师还给团队刘玉老师打电话核对节目过程当中谈论到的名词术语。那一刻,我感觉到小崔说事节目组的专业精神一点不逊于咱们团队熬夜奋斗的同学,相反,小崔说事后期制作团队的专业精神给我们立了一个新的标杆、学习的榜样。
    3、职业。我并非第一次进入演播厅录节目,上一次是十年前在湖北台作为旁观观众录制一期娱乐节目。因此,在踏入演播室之前早就作好了充分的思想准备——肯定有镜头是需要重录的,说不定还得专门录一些特需镜头——例如鼓掌一类的。央视不愧是央视,小崔说事不愧也是名嘴主持,从崔永元开口的第一句话开始,整个场面就无时无刻不在其掌控之中。气氛的调动,活泼的话语,找茬的艺术,90分钟的录制时间不知不觉就这样从手指缝间溜走。直到崔永元说到“干一行,体验这一行的责任和荣誉。谢谢刘老师,谢谢大家”,我们才意识到节目录制结束,而大家谈性还正浓。之后的撤场也是迅速而有序,30分钟不到,所有布景、道具包括电视上看到的座椅板凳统统收拾得干干净净。
    敬业、专业和职业,是小崔说事此行给我最大的感受,相信这一点也是崔永元和整个小崔说事节目组引以为傲的地方,也是我和整个Dian团队都应当向他们学习的方面,这还真的应验了小崔的那句“干一行,体验这一行的责任和荣誉”,还可以补上一句“让别人敬佩你的敬业、专业与职业”。

2009年08月24日

 by quickmouse <quickmouse@263.net>
2009年8月24日

    上月,喻信星空BBS出现了一次重大的故障,管理员在改变某版面属性操作后,term界面挂起,之后账号信息等数据丢失。分析良久,均未找到具体原因。而此站在08年底迁移到新主机上时,并未更改过程序,其二进制代码甚至都没有重新编译就可以直接使用,而此次使用的功能以往也表现正常,此番故障匪夷所思。
    在喻信测试站上,我重复了一遍管理员的操作,证实故障可重现,于是通过gdb编译定位了故障代码,结论却令我惊讶。故障点位于fileio.c这一BBS底层自封装库当中,函数rm_dir用于递归删除某一目录及其下所有的文件,部分代码如下:
static int rm_dir(char *fpath)
{
        DIR    *dirp;
        struct dirent *de;
        char    buf[256], *fname;
        if (!(dirp = opendir(fpath)))
                return -1;

        readdir(dirp);
        readdir(dirp);

        while (de = readdir(dirp)) {
                fpath = de->d_name;
                ……
        }
        ……
}
    此函数通过使用系统库函数opendir和readdir打开目录并读取目录下的每一项,若该项是目录,则递归调用rm_dir,若是文件,使用unlink删除文件内容。具体实现上,在使用opendir之后,连续调用两次readdir以避开"."和".."两个目录项,接着处理之后的每一项。此次故障调试时却发现,这个处理策略并未避开"."和".."两个目录项,导致删除时越过了本级回到上一级目录去删除了。可以前函数的表现应该是正常的呀,不管是在Linux环境还是Solaris环境都是如此,01年我在调试此函数时还顺带解决过在ucb库里的错位问题,所以印象深刻。可为什么此番会出现重大的误删除问题呢?
    对比喻信星空BBS在换机器前后的环境,之前用glibc-2.3.2,更换之后采取glibc-2.5,莫非底层库函数出了问题?于是写了一个简单的测试程序,用于输出readdir顺序读出的结果。测试结果显示,在glibc-2.3.5的环境下,一个目录的头两个readdir输出是"."和"..",Solaris 9下也为此。而glibc-2.5、glibc-2.6以及我刚刚升级到的glibc-2.10.1均为乱序输出,"."和".."并不一定都是在头两个输出。之前的代码,估计是顾及到执行效率,兼考虑到libc在实现时将"."和".."放在头两个输出,为减少strcmp的调用,opendir之后直接放过两个readdir,接着“放心大胆”的进行处理。然而,一旦libc底层库的实现发生改变,输出并非"."和".."打头时,这段代码就越界闯出大祸。修正的部分不得不重新加上"."和".."的strcmp判别。
    虽然这部分的代码并不是我所写,但对此部分检视时虽有顾虑却并没有放在心上。在此不由得感慨以前总听着说“编程技巧不要依赖于编译器、库函数的内部实现,否则容易出问题”,并没有深刻体会,这次活生生的碰到一个例子,也赔上几天的数据恢复工作代价。

ps: 白云黄鹤BBS的代码当中也有这个问题,目前的系统工作正常,但若更新系统,一定要注意先修复这个bug。

by quickmouse <quickmouse@263.net>

    上个月的一篇博文《glibc-2.10.1头文件string.h带来的问题》提到在更新了glibc之后,不少地方编译都会出现问题。这一现象在我以前升级glibc-2.3.5的时候也遇见不少。再次碰到以后思忖良久,觉得还是应该再次编译gcc尝试一把。我的系统是首先在glibc-2.3.5环境下升级到gcc-4.4.0的,之后在gcc-4.4.0和glibc-2.3.5的环境下编译了glibc-2.10.1,并成功升级,但并未再次编译gcc-4.4.0。于是再次在gcc-4.4.0和glibc-2.10.1环境下重新编译gcc-4.4.0,update之后换回原版的string.h,再未出现类似的编译问题。
    感觉glibc和gcc两者就像一个连环套,真是奇妙啊。
    ps:gcc-4.4.0在支持C/C++的编译需求下需要1.2G的空间才能完成编译工作,比kernel还要大,并且编译时间长达两小时。

2009年08月02日

    事件的起因:湖北老河口市经适房摇号出现14连号,各大门户网站的标题如是说的。经历了前段时间武汉经适房的6连号丑闻,这个标题无疑引爆了一个更大的……气球。不能说炸弹,这回只是气球而已。
    一时间群情激愤,新闻当中华中科技大学王湘君教授估算出现此状况的概率是1.4%左右,这下真变成炸弹了!6连号的丑闻当时话说是千万亿分之一的概率,到了14连号居然成了1.4%的概率,于是各大门户网站上一片批判之声。
    相比之下,各高校的BBS迅即将此演化成了数学问题,毕竟对于概率统计这一块工科的同学们还是熟悉的。6连号的条件是5141户当中选出124户,而这124户当中有6个号码相连。从概率上说124之于5141很小了,还得6连号,确实是极低的概率。而14连号的情况却是1138户当中选514户,几乎是2户当中选出1户,其中有14个号码是相连的,概率确实不会太低。于是学生们冷静得用各种方法去验证这1.4%。
    水木清华和白云黄鹤的BBS上均有人用排列组合的方法、用计算机编程模拟的方法大致得到这样的结论:14连号及以上(15连号甚至更多)的概率和是1.4%左右,单纯的14连号概率应该是0.8%左右。
    应该说王教授的估算学术上不能说很准确,但还不是离谱的,可惜能理解他这个结论的网民太少,各大门户网站上的评论贴主流言论还是在批判这1.4%,只有少数的人在坚持着进行概率科普,无奈网络暴民者众,在经历了6连号之后对公权力的不信任导致了14连号合理解释的无视。
    对于14连号当中有13人来自同一单位,另一人来自下属单位的说法,我倾向于相信本来各个单位上报的名单就是号码相连的。既然能出现14连号,就注定了这连号的14人里分布是集中的,要么是甲单位有14人中了,要么是乙单位有14人中了,如果正好号码范围跨了单位,就是这挨着的邻接区域框进了14人。
    当然,我并非为这个事件当中其他不合理之处开脱:例如据报道中签者当中有一17岁的申报者。但是,仅就1138选514个号码,其中有14个号码相连,并非有什么不可能的极小概率。记者同志选择如此的标题,确有误导之嫌,使得王湘君教授成了被误伤的标靶。

2009年07月22日

by quickmouse quickmouse@263.net

2009年7月22日 星期三

    今日在新系统当中编译bison时提示有编译错误:
/usr/include/string.h:546: error: expected declaration specifiers or ‘…’ before ‘__locale_t’
/usr/include/string.h:547: error: nonnull argument with out-of-range operand number (argument 1, operand 3)
/usr/include/string.h:550: error: expected declaration specifiers or ‘…’ before ‘__locale_t’
/usr/include/string.h:551: error: nonnull argument with out-of-range operand number (argument 1, operand 4)

    由于新系统刚刚使用了glibc-2.10.1,其中的头文件也是glibc编译以后替换的,于是怀疑glibc库的头文件出现了问题。当然为了排除gcc的错误,在当前环境下重新编译gcc,同样无法通过。遂构造一个简单的.c文件进行编译:
#include <stdio.h>
#include <string.h>

int main(void)
{
        printf("hello\n");
        return 0;
}

    用gcc test.c编译正常,回头查找string.h当中提示错误的地方,发现如果define了__USE_GNU,则编译出错。而bison的源码当中用了define _GNU_SOURCE,同样造成了__USE_GNU的定义。于是用gcc -D_GNU_SOURCE test.c,错误重现。
    查找string.h的错误部分:
extern int strcasecmp_l (__const char *__s1, __const char *__s2,
                        __locale_t __loc)
     __THROW __attribute_pure__ __nonnull ((1, 2, 3));

extern int strncasecmp_l (__const char *__s1, __const char *__s2,
                          size_t __n, __locale_t __loc)
     __THROW __attribute_pure__ __nonnull ((1, 2, 4));

    属性的设置并无问题,怀疑__locale_t没有定义。在/usr/include下查找__locale_t的定义,出现在xlocale.h当中,同时发现在stdlib.h当中已有相关的include。于是尝试将test.c改为:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
        printf("hello\n");
        return 0;
}
    编译无错。于是对比另外一个系统的string.h与当前的string.h的区别,发现在以上两个函数的声明前有一句#include <xlocale.h>,而glibc-2.10.1的string.h头文件内并无这一句。于是加上,测试以后一切ok。
   不知道这个地方是怎么遗漏了。google查到的很多页面都没有具体的解决方案,哪位朋友遇到这样的问题参考一下上面的办法吧。

2009年05月27日

    这段时间,5.19全国DNS大规模故障的原因在网络上吵得沸沸扬扬,暴风影音一开始还装成受害者的样子,把DNSpod推到了前台,说是那家伙的DNS服务器不够strong,最后挂掉了。结果后来才澄清DNSpod挂掉以后导致大量DNS请求导向给了电信、网通等主干网络上的DNS服务器,最终导致全国范围内的DNS故障。好不容易发了一个公告说了一下要改进,今天又看到拉虎皮说自己被有组织的陷害,我晕。
    我自己是不用暴风影音的,以前曾经是它的用户,不过后来发现那个该死的stormliv后台服务程序以后,就索然无味了。虽然我知道可以在服务当中禁用掉它,但是每次打开程序的时候服务设置又被恢复,索性就直接卸载,换了Klite+Mplayer。曾经有段时间在团队的网关上监控DNS的请求,大约是60~70台内网机器的样子,平均每秒钟大约就有2~3个www.baofeng.com的DNS请求在监控端上看到,要知道团队里是不许看视频的,这些请求基本都是那个后台服务程序的杰作。这还是在一个玩家比较高级的网络里,团队里还是有不少人抛弃暴风的,所以想想如果是普通的大众百姓,安装暴风的比例可想而知,而那个极烂的后台程序每几秒出一个DNS请求,在骨干网上就是一个不小的流量。于是网络上的评论大约都是一个播放器居然在不用的时候也有一堆的后台请求,实在流氓。
    从技术的角度讲,写这么一个后台服务程序,能用这么高的频度去查网络,也算是水平太烂,看样子连CSMA/CD相关技术都没有学过,在连接失败的时候退让算法也有很大问题。不过最重要的是,这种设计模式完全是一个实验室模型的实现,丝毫不考虑后台服务程序规模上量之后带来的冲击尤其是失败后的冲击。
    最后,还是那句话,技术并不是最重要的。写程序孰能无错?暴风错就错在明明是自己程序机制的问题助纣为虐,偏偏要摆出一个受害者的样子,贼喊捉贼。这种姿态只能让人觉得没有责任感,靠不住。

2009年04月19日

IPC信号量当中的UNDO问题
by quickmouse <quickmouse@263.net>

    以往使用信号量的情形通常都是用于进程间互斥,锁定临界区。以前在维护bbs的代码过程当中,学会了用文件锁flock,后来拜读APUE学会了信号量,信号量还是比文件锁有优势的,效率不是高那么一点,起码不用打开文件关闭文件这些耗时间的工作。但是信号量最大的一个问题就是一旦锁定,若在解锁之前出现程序崩溃等segment fault问题,将直接导致锁定的信号量无法恢复,形成永久占用。文件锁则没有这个问题,进程的退出将导致文件描述符关闭,在该描述符上进行的锁定操作就自行解除了。
    好在设计信号量的前辈们考虑到了这个因素,在加锁的时候会有一个UNDO的设置,也就是在调用semop的时候指定操作结构体当中可以放置一个UNDO参数,我通常都是这样去调用的:
semop(iSemID, &stLocksem, 1);
    其中stLocksem就是定义的一个操作结构体,一般定义为:
static struct sembuf stLocksem={0, -1, SEM_UNDO}, stUnlocksem={0, 1, SEM_UNDO};
    这样的UNDO选项会让内核记录一个与调用进程相关的UNDO记录,如果该进程崩溃,则根据这个进程的UNDO记录自动恢复相应信号量的计数值。详细的可以参考man pages。

    今天想要记录的内容不是来谈这个锁定的。前面也提到了,信号量通常用于锁定临界区,但还有一个重要的工作,也是信号量常干的活——同步进程(线程)。以往我自己写的程序,比较少涉及这方面的工作,最近演了这么一出,在这个信号量锁定上就“老革命碰到新问题了”。
    程序刚开始运行时,挺好。若干次同步后,程序报锁定失败,semop返回-1,errno返回值ERANGE(34),就是number out of range。在每次锁定解锁之前都用semctl检查信号量的值,始终保持0/1的范围,很正常。百思不得其解之间,把眼光盯向了SEM_UNDO,琢磨良久,才估计可能是由于UNDO造成的,试着把前述结构体当中的SEM_UNDO去掉,一切又都ok了。

    原来对于SEM_UNDO来说,内核记录的信息是跟进程相关的。一个进程在lock的时候设置一个UNDO,那么对应该进程的UNDO计数就多一个,unlock的时候设置一个UNDO,那么计数就减一个。对于临界区互斥的应用而言,lock和unlock都是在一个进程当中完成,于是UNDO可以切实发挥作用。然而,用在同步进程(线程)里,由于是生产者-消费者模型,一边不停的lock,另一边不停的unlock,那么使用UNDO就不起作用了,而且由于都是单边操作,导致UNDO计数对单一进程而言,只朝一个方向发展,最后必定是超过内核限制值,当然出现了ERANGE的错误。
    接着,为了验证这个问题,单独写了一对小程序加解锁并显示锁定次数值。果然在次数达到32768时候,出现ERANGE错误,证实此事。

2009年03月25日

    今日旁听07级数字电路课程。课间黄老师声言作业是一道课本上没有出现的题目,下课后放在投影上让大家抄下。待到下课铃响,我饶有兴致的看着投影上的题目,却发现为数不少的同学并未打开自己的作业本抄下题目——大家用了更简洁明快的方式——掏出手机将题目拍下,然后背起书包离开了教室。这一招确实是出乎我的意料,原来手机上的摄像头还有这个功用,看样子我是out了。
    技术的进步在课堂上的体现越来越明显,现在不再是十年前的黑板、粉笔和挂图,多媒体+ppt的方式成为绝大部分课堂的讲授方式,不过对于学生们的影响也不知道到底是正面还是负面。也越来越多的同学们不再抄笔记,习惯于在课后找老师索要课件。我一向是不愿意给课件给学生的,一来这属于个人版权的材料,另一方面课件copy给学生之后,绝大部分他们都是不会再去看的——因为他们心里有“底”,觉得课件在手心中无忧,反而会导致课堂上课注意力不集中。再则,我认为课件只是老师的总结和提纲,要想把一门课学好,更重要的是同学们需要把老师讲述的知识结构转变为自己的知识结构,要整理出自己的提纲。自从多媒体课件推广以来,以前那种上课笔记、划书的场景见得少了,也可能是ppt翻得太快同学们来不及抄,但更多的原因恐怕还是同学们的心态变了,认为copy比自己手抄容易多了。岂不知一分耕耘一分收获,难道抄笔记的时候,那些文字符号一点都没有落在你的心里么?
    再举一个例子,前次团队周日例会的时候,正好是电源组的同学们作技术专题——开关电源。作为电信系的同学,电源是一个不应该被回避的问题。记得在我们大学那个年代,学英语基本清一色的单放机+磁带。单放用电池不是很划算,虽然也用充电电池,但一般只作为熄灯以后的手段,大部分情况下只要可以用外接电源,都是外接电源来对付。有过带外接电源听单放经历的同学一定听过那种变压器供电的嗡嗡声——劣质的外接电源通常只有简单的变压器抽头分压和小电容滤波手段,工频的信号总是通过供电串到耳机里,甚至盖过磁带的声音。于是改造外接电源成了电信系同学课外几乎必修的一课,如何准确稳压,在狭小的外接电源内部用不太大的电容达到大电容滤波的效果,成了大家琢磨的话题,电路设计和分析的功底基本在这个时候就有成形了,而且效果令人雀跃——外接电源供电的嗡嗡声变成了和电池供电一样的安静,改造生活的信心霎时大增。不过,现在的同学们,条件好多了,清一色的MP3听英语,基本都内置锂电,连更换电池的步骤都省下了,当然连同那些学习电源原理、改造电路、分析设计的机会也一并省掉了。到底是好事还是不好呢?
    一分耕耘一分收获,技术进步造福了我们的学习、生活,但我们不应躺在技术进步的方便上懒洋洋的享受,那只会牺牲本应属于我们的知识和机会。

2008年11月26日

    上周五,因为想到自己招行卡上面没钱了,遂从工行的ATM机器上取了4000转身到旁边的招行ATM机上存进去。结果不想自助存款机哗啦哗啦把咱的银子一点,屏幕上弹出:故障,若钱未退回,请联系工作人员等字样。用卡十年,终于碰上一回机器故障把咱的钱给黑了。看着机器吐出一张回单,再巴巴的望一下似乎根本没打算再打开的钱箱,我只好问旁边的招行工作人员怎样处理。彬彬有礼的招行小姐如是说:下周二我们会清机器,最晚下周三把钱上到你账上。就这么就完了?今天才周五呐,俺还真是不放弃的多问了一句:“那这段时间的利息怎么算?”
    “我们不算利息”招行的小姐还真说得出口……
    一听这个话,就觉得有话讲了,咱接着说:“这不对吧,我今天把钱存你们招行的机器上,你们的机器自己出了故障,给我造成的麻烦和损失不说,解决问题期间的利息你们还不算,钱不是这么借的啊,要这样的话你们招行干脆把所有的ATM机都这么搞一下,然后免息的借个千八百万的去玩三五天,再还给储户,天下可没这个道理。”
    正巧旁边有个储户路过,劝了咱一句“别跟这个小姐说,她这句解释都被熟了,每次都是这些话,没用”。
    小姐只答道我们的规定是这样,我无能为力。接着她填了一个事件记录单,记清楚日期、时间、事发金额等等,再拿到我面前请我签字确认,当然口中还是说着抱歉。咱自然也不客气的在签名处先写上“对此事的解释非常不满意”,再把大名一签。小姐看到我写的这个评语马上就说“我再跟分行联系一下”,于是电话里吧啦吧啦的一通说,接着把电话递给我说分行的人跟我解释,自然还是之前的那些说辞。
    我先将了那边的人一军“你千万不要跟我说我今天存钱的机器不是你们招行的”,自然对方绝对不敢说不是,嘿嘿,接着:“既然是你们招行的,我的钱已经在里面了,那么先不谈我这几天不能用这笔钱给我带来的不便和损失,我应当所得的利息,我的收益你不能少我的。”
    对方开始说机器需要维护,需要时间等等。我继续道:“你维护机器以及因此所投入的成本不是我储户关心的,你的机器故障给我带来的麻烦,至少不能造成我在利息上的损失,你什么时候上账是你们的事情,我今天把钱交给招行,利息就要从今天开始算。机器故障造成的赔偿应该计入你们自己的机器运营维护成本当中,跟我储户有啥关系?”
    以下省略若干重复的理由和解释,最后结论是他们立刻派人清机器。
    本以为这出戏可以落下帷幕了……
    二十分钟以后,两个工作人员过来,拿了我的卡、身份证就跑到后头咔咔的捣腾机器去了。又过了近十分钟,拿出咱的4000元和我的证件、卡递给我道:“你怎么能在钱里面夹橡皮筋呢?这样能不卡机器么?”说得我楞了一下。“把钱拿了,签字,然后再存进去就行了”,接着把处理单递给我签字。
    接过单子,正准备签字的时候突然想了一下——不对啊,于是把笔往桌子上一拍,怒目道:“不对啊,你凭什么说是我放进去的橡皮筋?”
    “我们清机器的时候看到后面你的钱里夹着的”对方察觉气氛不对,解释道。
    “我的钱刚刚从工行的ATM机器上取的,动都没动就转到你们这里来了,难道人家的机器能吐出橡皮筋,你们的机器处理不了?再说了,你怎么知道没可能是前面的客户不小心掉进去的,当时没卡,到我存的时候卡住了。而且你有什么证据证明是我放进去的?”我进一步反驳道。
    对方语塞到,另一个工作人员赶紧打圆场说:“我们只是说钱里面夹了橡皮筋”
    “刚才可是他对我说:你怎么把皮筋放进去的啊,话不是这样说的”我继续不退让,不过看对方不再坚持也就此打住,签字再存,一切ok。
    出门,心想莫非中国的储户太好忽悠了?

2008年11月25日

by quickmouse <quickmouse@263.net>  2008年11月25日

    最近团队里面新增了一个ADSL出口,于是拖来一台旧电脑作网关出去。因为想直接用已经很成熟的RAM Disk小系统,但是又要考虑网关配置经常改动的情况,于是在小系统当中添加了一个脚本,可以处理grub引导时传给内核的参数,使得我能够在grub参数当中指定一个额外的cpio包,这个包当中的内容可以替换小系统当中一些“陈旧”的设置,以便我不需要更新小系统的img镜像文件即可更新实际运行的环境。脚本的名字取名为/etc/update_initrd_fs,然后在/etc/rc3.d/当中增加一个S01update的符号链接指向/etc/update_initrd_fs以便能第一时间更新RAM Disk的文件系统。update_initrd_fs的内容如下:

#!/bin/bash
cmdline=`cat /proc/cmdline`
if [ x"$cmdline" != x ]; then
        tmpvar=${cmdline/*localupdate=/}
        if [ "$tmpvar" = "$cmdline" ]; then
                # no localupdate specification
                echo "no localupdate= string"
                exit
        fi
        tmpvar=${tmpvar/ */}
        if [ "$tmpvar" = "${tmpvar/"@"/}" ]; then
                # no @ in string
                echo "no @ in string"
                exit
        fi
        file=${tmpvar/"\@*"/}
        device=${tmpvar/"*\@"/}
        if [ x"$device" = x ]; then
                # no device
                echo no device
                exit
        fi

        if [ x"$file" = x ]; then
                echo no file
                exit
        fi

        echo update file $file on device $device
        mkdir -p /mnt
        if mount $device /mnt > /dev/null 2>&1; then
                # mount success
                if [ -f /mnt/$file ]; then
                        cd /
                        zcat /mnt/$file | cpio -i -u
                fi
                umount /mnt
        fi
fi

    在grub的配置当中,只需要传给kernel的参数加上localupdate=filename@device这样的格式,例如localupdate=/grub/update.tgz@/dev/sda1即可由这个脚本自动挂载设备并更新数据包。当然,这个脚本也是有一些限制的:
1、更新的数据包需要是cpio的压缩格式,不过你也可以修改倒数第5行的解压命令使之适应其他的格式
2、更新后的文件不一定会生效,例如对/etc/inittab的更新。/etc/inittab的解析是/sbin/init干活的第一步,所以在整个启动过程接近尾声的更新如果涉及到/etc/inittab或者其他的关键驱动更新不一定能够取得效果(例如改变sysinit的级别就无效)。当然,如果是对于/etc/inittab的更新,可以在更新包当中替换/etc/rc.local,在其中执行init q来完成改动。
    总之,这个脚本提供了一种途径,可以使得我们不需要重新对整个initrd.img进行打包就能够获得更新其中部分文件的能力。