敏님의 프로필南京.旧事사진블로그리스트 도구 도움말
사진(1/11)

南京.旧事

______一切都会成为历史_______
5월 29일

09年的端午

     09年的端午,三天假期,而现在是第2天的下午.上午结束了<潜伏>,中午小睡了一觉,而现在儿子在睡觉,老婆去美容,老妈在小屋打毛衣.
     周围挺安静的,也挺噪热,葡萄树上挂的几串葡萄,如同我一般无精打采.三十岁,感觉这两年心态变化挺大,更多的是茫然.工作一天后,感觉很疲倦,也对目前生活的意义产生极大的怀疑,但是又无力抗争,无更多的时间去思考.
     <潜伏>告诉我,人的信仰是最重要的.没有了精神寄托是最危险的.而我,似乎逐渐空虚起来.
5월 10일

旧文-小屋四章

小屋四章
1:
我在小屋里踱来踱去,寻找什么
寻找什么?寻找什么?
逝去的琴声,失落的笑语,抑或残缺的诗稿?
可是什么也没有,除了灰尘
掩盖了一切:悲与欢,喜与乐
蜘蛛肆意结网,灰鼠占洞为王
它们自由自在地生活,繁衍后代
只有我好像与这里一切无关
我将要失望且庆幸地离去,不再遗憾
可是我却失手打翻一个箱子
陈年往事洒落一地
古典的愁绪绕膝而上
沧桑了我并不光洁的脸庞
今秋最后一抹斜阳轻抚小屋
二十年的时光就在桔红色中弥漫
我突然觉得小屋拥挤不堪
2:
时光如酒杯里的啤酒
久远的沉寂杯底
新鲜的如杯口泡沫,爆个不停
江河东逝,岁月滔滔
沧海也会成桑田
有谁如我 记得最初的约定
山雀子衔走的春光一去不返
收获的土地上谁会想起第一道犁铧
小屋门上的衰草在风中响个不停
诉说的故事除了我有谁会懂?
3:
小屋,你好吗?
当我轻推门扉
我听见了一声惊喜的欢呼
你是怎么认出我的?-----
从我调皮的眼神,嘴角的笑容
还是一种遥远的感应?
当我第一次走出你的怀抱
我还是单薄的身材,依稀的黄发
如今我满头的长发,
需要低头进入你的门檐
只是心如故乡天空的颜色 永远湛蓝
小屋,你还记得吗?
我的第一声啼哭,第一次摔倒的声音
第一次轻抚琴弦
第一次在你斑驳的墙上舞文弄墨,涂鸦作诗
就在那页窗户下面
我看过梅开梅落,云卷云舒
我数过满天忧伤的眼睛
听过南来北往雁鸣燕语
往事如水底的沼气一同浮出水面
4:
小屋,伸出你的双手
让我再次感受你的体温
我终要离你而去,消失在茫茫人海
小屋,你孤单否?
在我想你的时候,我会放出
千万只思念的流萤
盘旋于你的窗前门下

旧文-舞蹈

       舞蹈
 
学校举行大型文艺晚会
舞台上有我的同学 用她的舞姿
演绎着一个伤感而美丽的故事
她有蝴蝶般斑斓的舞服
和藕白的手臂
灯光闪烁 阴影与光明共存
我的同学就在黑与白之间
舞成一只骄傲的蝴蝶
左三步,右三步,前进一步,后退一步
 
台下有我一千多校友 还有老五
被我从阅览室拉来看舞蹈
一张张相同颜色的眸子
在看我同学的舞姿 化院无双
左三步,右三步,前进一步,后退一步
舞是美丽 踌躇的美
所有有一千多校友 穿过长长的甬道
静静的站在台下,沉溺其中
直到谢幕鼓掌
把心从上个世纪的某个地方
重新放回胸膛
 
我的同学也匆匆脱下舞服
如同脱下一个世纪的时光,微笑地和我们一起涌出大门
而我在匆忙间
拾到了一个朴素的哲理
生活不是舞蹈 不能
左三步右三步地徘徊
更不能有太多的退步
生活也没有灯光的映衬
和漂亮的舞服
即使遇上了一个春天
却总伴有 风雨泥泞

人生的转变

    干了4年多的开发,今年有了改变,开始进行技术管理.虽然是基层管理,但渐渐发现,不同的岗位,你的角色在变,你的思想必须转变.昨天部长特意找了一个茶馆,鼓楼OCC,进行了一次科长和开发经理的学习会,感觉还是很有激励的.特别是对个人的定位,一定要准确到位.否则很可能付出很多,但结果却不是你想要的.
    知识型的企业,重要的不是告诉员工怎么做,而是要引导员工知道做什么,为什么要做.在某个领域,开发人员的知识结构比一般开发经理或科长掌握更加全面,因此我们不需要去外行知道内行,指导他们怎么做;而是在合适的时间,告诉他们做什么,并且让他们知道做这件事情的目的.基层管理者并不一定就是保姆,陪伴在开发人员左右,更重要的是准确接收上级的指令,转化成开发语言,制定实施计划,引导开发人员去实现,并在实施过程中进行过程控制,风险控制,从而按期达成目标.
    人的管理和管理仓库性质完全不同.特别是高科技企业,每个员工都比较有个性,工作的内容有很难量化,因此无法按照传统的记件式进行管理.因此管理弹性非常大,难度也比较大.沟通就显得尤为重要了,所谓的领导就是包含沟通引导的含义,从我个人来说,口头沟通是我的弱相,而书面表达是我的强项,需要补弱增强,全面沟通.
    有人说管理是很虚的东西,其实是他们没掌握管理的精髓.在不同的环境下,不同的阶段,管理方法和重点是不同的,不可以把书本上的理论直接搬到现实中.因此对所在环境要经常思考,我们处在一个什么样的水平,我们当前最重要的事情是什么.搞不清这些内容,只能是四处碰壁.
2월 21일

重新打理BLOG,打理人生

快一年了,BLOG荒芜一片,感觉自己的人生也荒芜了.
男人到了三十,是不是对人生麻木了?
 
要振作起来,坚持锻炼,坚持信念!
4월 20일

我家牛牛降生了!

我家牛牛于2008年4月14日早晨6点降生到这个世界了!性别:男,大名:高许一。
恍惚一瞬间,我都有自己的小孩了。不过都来不及感慨,我们都围着他忙碌着。
老人们都非常高兴,我和胖妞到是没那么兴奋,只是觉得身上担子在加重。人生的轮回谁都无法抗拒,
我们只能随着他,按照他安排的轨迹不停的走,直到生命停止。
 
这两天南京一直下雨,院子里的花草都越发翠绿,葡萄挂满了小小的果实,在我重新搭建的架子上快乐地生长着。
一切都是真实的,又似乎隔着层面纱。在这个小雨淅淅沥沥的春天的下午 ,胖妞和牛牛安静的睡在床上,
屋里除了我们的呼吸,很安静。我似乎回到了17,8岁的青春岁月,在无忧无虑的时光里撒野。
一切都是那么美好,一切又是那么的珍贵和遥远。
 
 
 
 
9월 22일

关于目标

转眼要到十月了,胖妞回了大连,一个人突然觉得寂寞起来.也清闲起来.
 
自从工作后就忙碌不止,很少时间去思考工作以外的事情,更不要说对自己生活的反省了.
我记得我以前是一个很能反省的人,无论是成功还是失败,我做总结,然后设定新的目标.
 
曾经都有那些目标呢?
 
比如小时候喜欢打四角子,目标就是拥有很多的弹簧炮(四角子的高档货,比较费纸,但威力大).所以那时到处和别人去赌.
而且觉得个人力量太薄弱,就和高胜飞,还有张瓦的束五林合作,把各自的四角子,还有火柴皮放在一起,然后共同去赌.
但那次合作是不愉快的,可以说对我造成了伤害.他们都比我年纪大,老是占我便宜.
比如有次我从外婆处获得了一大批火柴皮,回来后三个人平分了;
但他们并不把他们的东西分给我.我记得我当时十分气愤,和高胜飞打了一架.在他家里,两个人抱在一起,打到了他家床底下,
直到他妈回家才被拉开,终止了战斗.
 
呵呵.一说扯远了.不过说回来我还真是个好斗的人,但本身体格并不好,因此常常不是别人的对手.但好象固执的很.
和高胜飞打架是最多的,一直打到我初中毕业左右.最后一次是腊月里,在我家厨房外面打,呵呵,是最后一次.
后来我就上高中了,他则出去赚钱,见面少了架自然没有了.
最出名的两次打架是在小时候,一次和高雪飞,,我们村庄里有名的哥们.他比我大多了,有次不知道怎么惹毛我了,我一整天跟在他后面,我奶奶知道我被打了,也赶来帮忙.呵呵.我奶奶可是个厉害人物.最终把他制服了.还有就是张瓦的小流氓张小立,同样的招数,我根本打不过他,但是我就是在后面追他,让他不得安生.
 
小学四年级的时候,才突然想要学习.开始把心收了回来.从那时开始吧,学习成了我的重点.考初中,考高中,考大学是我的目标了.
这些目标也一个个的实现了,虽然大学考的不如意,但总算也是大学.其间还有其他的梦想,比如写作,这个梦想持续了多年,但工作后就放弃了.
 
工作后似乎没有目标了.应该说还是有一个的,还是很久以前确立的.就是在三十岁赚到一百万.那时年轻,没觉得目标远大,但现在看看,有些难度.不过我还是没有放弃.
因为它毕竟是一个目标,如果人没有了目标,该怎么生活?
 
那么,三十岁后,这个目标实现了,或者未能实现,我该确定另一个什么样的目标? 
7월 21일

21日无题

今天21号.周六
早上去公司加班,打开电脑看到老五的留言,说要我看他千金照片.心里有些不是滋味.我原本知道五嫂最近会添喜,但我也没打电话.或者短信去问候下他们.有时很想去骚扰一下老朋友,但终究把念头放下.
杨兵立胜也很久没打电话了.我们是从小的兄弟了,我想能和他们再象从前一样,可以在安徽老家闲聊,或者去小城里找个小饭店吃饭.那时候大家都在上学,很穷.吃顿饭十几块,大家还AA.我清楚记得前两年我毕业了,工作了.在大连过年.他们两正月里去城关茶馆喝茶.发消息给我说要我请他们喝茶.可惜我一直都没有这个机会.如今相隔三地,北京,南京,杭州,真的是人越大,距离越远了.
 
最近一个人在狭小的生活圈地徘徊着,家,公司;公司,家.偶尔和胖妞出去走走.即使是南京的老朋友,也联系的很少.想把自己封闭起来.
妹妹说我脾气大了.我也承认,每次她打电话给我,我都不很耐烦.
但我知道,我是不会倒下的!现在的我,最大的愿望是老岳父能好起来,能给他周围的亲人带来希望和快乐.我在沉默地工作,只是在等这天的到来.或许等待命运对他的宣判.
 
所以,朋友兄弟们,原谅你这个伙伴.他是想:时间总可以磨灭一切伤痛.
 
 
7월 14일

我爱它们 ---转自胖妞BLOG

我家它们

葡萄
葡萄是前年在路边的花贩子手中买的,25块钱不包送,于是我用一辆快散架的破自行车一路驼到家中,又摇摇晃晃搬到11楼,煞费周折!刚买回时是冬天,葡萄杆子光秃秃的没一点生气,埋在地下半天没动静,也不知道能不能活.没想到春天来了,它竟然悄悄的发出许多叶子,让我们很是欣喜!后来又经历了几次灾害折磨,它却依然健壮!现在它已经是我家花园里长势最好的一棵植物了.老公给它搭了个架子,它就顺着架子爬满,绿油油一片很是养眼.今年竟然结了5串了!每天早晚我们都要去看看它,去见证葡萄粒的一天天长大成熟.前几天,一串葡萄上终于红了一个粒!正当我们兴奋的为这一粒的分配问题争论辩解时,却被一只鸟抢了先,晚上再去见它,已经没了踪影,只剩下一只光光的蒂!看来对它虎视耽耽的人何止我们两个啊!心急之下,摘了个青的来尝,原本以为必定酸涩难咽,没想到竟然很爽口!酸中带着甘甜,还有一股淡淡的香!真的很好吃!于是再有朋友来,我们都会为他摘上一粒未来得及成熟的葡萄品尝,以作为我们家最奢侈的水果!产果虽然不丰盛,但这棵葡萄在我们的朋友圈内已是"名声大震"!要预约品尝的人络绎不绝!今年我们的办法是,让每个有此念头的人自己买几串葡萄带来,我们负责帮他绑在葡萄架上,然后他就可以摘果品尝了!明年,期待这个愿望能真正实现!
樱桃
我们家有两棵樱桃,都是去年从大连坐飞机带回来的.说起这两棵樱桃的"来历",还真是蛮久远的.在我六七岁的时候,记不得是爸爸还是爷爷,让我到隔壁邻居家要两棵樱桃苗子,说认真浇水它就会长大结果.于是我就要了两棵小苗回来,栽在院子后面,每天都很认真的浇水,几年下来,它们竟然真的长大结果了!而且结的很多!再后来就搬家了,没有照顾过,难得回去看一眼,却发现樱桃依然长的很好!而且很大!几乎把后面的小院子都撑满了!春天树上开满了花,洁白清新如樱花般美丽!秋天又会结满果实,红通通的压弯了枝头!每年掉落的樱桃核会自己发出小苗,许多年下来,院子周围长满的小樱桃.去年回家,到老房子转转,又看到了这两棵樱桃树,于是带了两棵小苗回来,栽在花园里.开始几天可能是水土不服,两棵小苗蔫下去了,眼看就要死了!老公就每天给它们浇水,一如我儿时般执着,几天下来,它们终于缓过来了!几场春雨过后,樱桃长势逼人,现在一棵已经半人高了!再过几年,我家的樱桃也会长大结果,院子里或许也会长满小樱桃.儿时教我种樱桃的人已经慢慢老去,而这些小樱桃或许能留给我那些珍贵的回忆.
海棠
海棠花是去年我们在安德门花卉市场买回来的.之前我对海棠没什么概念,模糊中觉得象是一种叶子很大、花很丑的植物。去年去花卉市场添置花草时,看到一棵枝干挺拔、花很小巧精致的植物,顿时对它很有好感觉,用老公的话形容就是:觉得它很有气质!向店主一打听,原来它就是海棠!与我想象中的差距千里!在高性价比的前提下,我们很快将它搬回了家!海棠似乎很适应我家环境,回来后一直生长良好,没有经历其他植物那样的“适应期”。海棠花期与花园里其他植物不同,在别的植物都落花养息时,它静静的盛开了。淡红色的小巧花朵疏密有秩的排布在树干上,不张扬又恰倒好处,好似精心绘制的图画般完美。今年五一,因为爸爸生病的缘故,我们去了大连很久,家里的花没人照顾。回来时发现好多花都枯萎了,包括海棠。我们伤心极了,拼命浇水以期它能“复活”。没想到奇迹真的发生了,在呵护了几天后,海棠枯萎的主干上竟然又发起了小嫩牙!再过几天,主干竟然慢慢恢复了元气!只是旁边有的小枝干已经彻底枯萎断掉了!原来,海棠在遭遇缺水的灾难时,毅然选择“自断小枝”来“保全主干”,让有限的水分供应到最重要的部位!现在,经过多日养息,主干又慢慢发出许多小枝,甚至比从前更健壮!海棠的坚强、海棠的淡定、海棠的果断、海棠有舍有得,这一切让我沉思许久。
红叶树
这棵小树是我和老公在月牙湖公园偷偷挖回来的!不知道叫什么名字,只因刚挖回来时满叶红色,所以叫它“红叶树”。红叶树其实现在早已“面目全非”了,叶子全部变成了绿色不说,个头和精致程度也与初见时相去甚远了!还记得刚见到它时的情景:远远的看见一棵棵小树上开满红花,衬托着修长的枝干,艳丽而不俗气!我和老公一下子就喜欢上了!走近一看,这些所谓的“红花”原来就是树叶,我们于是惊叹怎么会有这么精致脱俗的树叶!于是在旁边偷偷的挖了一棵带回来,看到它成活了窃喜半天!没曾想现在已经完全没有了当时的模样!是该感叹“物是树非”呢还是该感慨“得不到的总是最美的”?明年春天,当它叶落重生时,期待它能让我们再次迷恋。
柳树
所谓“有心栽花花不开,无意插柳柳成荫”,现在我终于深刻理解了。我家花园里这棵挺拔的柳树在两年前是被我们当作棍子使用的.当时家里移来一些爬墙虎,碍于它们太小,找不到攀附物不容易爬上去,老公就找来一根"棍子"插在爬墙虎旁边,谁曾想爬墙虎没有顺杆爬上,反而是"棍子"发了牙,越长越高!没多久工夫,这根不起眼的"棍子"竟然长成了两米多高的柳树! 纤细的柳枝迎风飘扬,竟然成了我家花园里很独特的风景!而且,倾斜的柳枝伸出了露台外,从楼下很远的地方就能看得到!每次朋友找不到我家时,看到顶楼有翠绿柳枝的地方就可以知道!每次我们外出回家时,从楼下也都能看到它在对我们招手!老公常常沾沾自喜:这棵柳树全是他的功劳!是他精心栽培的!我做呕吐状,心里却对他的无意之功充满着感激.
栀子花
栀子花并不名贵,我却对它情有独衷.或许是因为诗词中对它的浪漫描绘,或许是因为它盛开时那份纯洁的白,也或许,只为它花瓣中散发出的独特香气!栀子花在北方并不多见,在南方却是比较普及.记得儿时难得摘到一朵栀子花插在瓶中,小小的花朵就会带来满屋香气!花快枯萎时,摘下几瓣夹在书里,也会留香许久!那种机会却并不常有,所以,栀子花在我心中一直如女神般神秘高贵.后来到了南京,见到满大街5毛钱一把的栀子花时,我是如此震惊诧异!甚至还夹杂着一丝淡淡的痛!物以稀为贵是亘古不变的道理,多了,即使再好,也不显得珍贵了.然而,这并没有改变我对栀子花的感情,在花市见到它,我还是情不自禁的买一盆回来,栽在园中.可是,它并没有如期望中那样成长开花,而是慢慢的枯萎了.不死心,又买了一盆,结果还是同样的命运!后来才总结出,可能是因为移栽的时间不恰当,5、6月份天气已经开始炎热,土壤水分挥发快,而栀子花叶子茂盛吸水很多,这时候换土移栽很容易导致它吸水不足而死亡。于是将它们枯萎的枝干剪掉,以减少水分需求量,再勤浇水,一些日子过去,两棵栀子花果然都缓过来了,还发出了许多嫩牙。只是,开花的季节已经错过了。要想感受到那份迷人的香,只能期待明年了。
夜来香
在上星期朋友来我家之前,我们并不知道园子里那棵奇怪的植物叫“夜来香”。我们曾为它的名字争执不休,我说叫“一串红”,老公怎么也不同意,但他没有想出更好的名字,再说也确实不认识这个奇怪的家伙,无奈之下只好听从了我。它是怎么来到我们家的不得而知,可能是花土中夹带的种子,也可能是我们去安徽时随手带回来的,后者可能性似乎更大些。在它刚长出来时,我们兴奋了半天!因为它看起来不象草,又不同于园子里任何的已有植物!我们猜想,它会是个艳丽无比的“美人花”!然而,对它的宠爱没持续几天,就渐渐冷却了。因为它长势惊人,没多久就长的几寸高了!而且还横向发展!甚至直接影响到花园的整体美观和其他植物的生存空间!于是再看到它时总觉得碍眼,总想把它除掉!老公坚决反对,我才作罢。去大连呆了一个月,回来时吓一跳!它已经长的半人高了!胖胖的身躯占据了花园很大一角,粗壮的叶子更增添了它的丑陋!我简直觉得无法容忍了!不过,这时它已经结出很多花蕾,看在它快要开花的份上,我再次压制了除掉它的念头。没过几天,花开了!与丑陋枝干不同的是,它的花朵竟然如此精致美丽!紫红色的花瓣艳丽而高雅,粉色的花蕊更衬托出它的独特气质!我甚至无法将花与枝干联系到一起!朋友来玩,说这叫夜来香!说它只在夜里开花,而且很香!我们一下子又来了兴致!仔细观察,发现果然如朋友所说!白天它基本不开花,偶尔开几朵也是没有味道的,到了晚上,它会满树盛开,而且香气扑鼻!真是一侏奇特的植物啊!自从有了个“洋名”,老公又对它刮目相看、疼爱有嘉,仿佛母鸡瞬间变成金凤凰。哎!人需要包装,这植物又何尝不是呢?
花园里还生长着傲气的腊梅、异域风情的芦荟、大难不死的桂花、散发橘香的金橘树、顽强的金银花、无缘长大的石榴树、小巧的月季、自娱自乐的常青树、恼人的小竹草……它们互相映衬、茁壮成长。而那些虎皮兰、散尾葵、杜鹃、仙人掌、西红柿……却只陪伴我们一段时间就黯然离开了。人与人之间是讲究缘分的,人与植物之间又何尝不是呢?你珍惜它、呵护它,它是可以感觉的到的。你每天灌溉它一滴水,它就会回报你整园子的快乐!
5월 14일

It Had To Be You

Why do I do just as you say?
Why must I just give you your way?
Why do I sigh, why don't I try to forget?
It must have been that something lovers call fate
Kept on saying I had to wait
I saw them all, just couldn't fall till we met

It had to be you
It had to be you
I wandered around,
And finally found
The somebody who
Could make me be true
Could make me be blue
And even be glad,
Just to be sad,
Thinking of you

Some others I've seen,
Might never be mean,
Might never be cross
Or try to be boss,
But they wouldn't do,
For nobody else
Gave me a thrill,
With all your faults
I love you still,
It had to be you,
Wonderful you,
It had to be you.
 
一直很喜欢罗嘉良演绎的电视剧,比如<创世纪>,比如<卫斯里>.
<卫斯里>这个名字我很早听说了,开始是小说,由于早期我并不喜欢科幻小说,所以没有看过它.
最近胖妞借来了电视剧,我一见是罗主演的,就很有兴趣的看了.上面英文是剧中的一个插曲的歌词,被那个短小的老男人弹着钢琴演绎出来,颇为感人!
 
11월 16일

一年,再一年

去年的今日,到中兴上班的第一天.
也就是,来到中兴一年了.踩一脚,留个脚印.虽然这个脚印太肤浅,无法天长地久.
我是一个喜欢总结的人,读书时代每一个阶段我都会自我总结.哪些地方比较满意,哪些需要改进.
毕业后,慢慢忘记总结,忘记抽空思考自己的生活.每天是忙碌的,也是虚无的,偶尔牢骚一下,偶尔郁闷一回,
却没有了曾经的心痛感觉---眼无泪,心流泪的感觉.
 
不过我确定:这绝对不是我的生活,更不是我生活的永久状态.
我确定我能过另一种生活,等待的是一个合适的切入点.也许明天,也许写完某行代码或者打过某次卡之后.
11월 6일

爱涛天城 水世界


昨天正是秋高气爽的日子,小刘,他老婆程宇,我还有胖妞四人去江宁的爱涛天城去游泳。爱涛天城这个名字在电视上是常常听说,不过我
一直以为是个房地产,惭愧呀。去了才知道是类似于太阳宫的戏水场所,不过比太阳宫豪华,设施也多。
水世界里面的设施基本被我们玩遍了,印象深刻是药浴区,里面的水是温的,旁边或者底座的水流冲击身体的穴位,起到很好的按摩作用。特别是一种功率很强的水柱撞击脊背的,就想冰雹一样,打的后背象负伤了。再有的是各式浴房,有的狂热,温度超过60度,有的却象冰窖,冷的直打颤。快哉。
再有就是游泳了,其实俺是一个标准的见水沉,什么蝶泳,狗刨,全部不会。不过昨天在胖妞同学的热情帮助下,终于学会了仰泳。当然所谓的会就是基本能浮起来不至于象石头一样只冲水底。里面的顾客很多是全家一起来,或者是情侣,当然也有商务人士。我想周末全家来消遣下还真是好的选择。玩累了还可以去休息室休息,每人一台LCD电视,哎,看来俺也堕落了,享受起来也没有愧疚感。
感谢小刘师弟和程宇,和他们在一起玩,随心所谓,没有顾虑。可惜很多的朋友,都远在他方,难得聚首。
10월 25일

越狱 (摘自ZTE BBS)

<越狱2>放到第7集,我实在无语了。我知道编剧开始抓狂,为了剧情的曲折他们挺而走险,现在剧中人没一个值钱的,谁都会像Joey演的医生一样随随便便的死掉。而且还是死得特不值的那种。
  《越狱1》的精彩在于它存在于一个封闭的容器,所有的外部条件都准备好了,就等着放一堆各色的人进去,让他们产生化学反应。Foxriver其实就是个副本。智商极高的法师Michael因为有幸拿到了内测帐号,对副本内部十分熟悉。他哥LB是个傻大个战士,因为卖点卡骗G给弟弟买马,导致全服通辑,最后被关押进高级副本Foxriver。MS(魔鬼按:这里的MS是指Michael名字的简写,而不是牧师职业,下同,大家不要看迷惑,因为我第一次看就迷惑了)为了救哥哥,只身单刷Foxriver.凭着他对路线的熟悉和游戏规则的了解,策划了一个完美的营救计划。
  但Foxriver不是一个好玩的地方。Bos***elik皮厚,心狠,长得又丑,还是有两把刷子的。不过大Boss Warden这个老胖子心慈手软,私底下居然有求于MS.让MS在FR副本里的气焰顿时嚣张起来。
  要成功越狱,单刷是不智的,所以MS通过各种手段组织了一个小团队。主要的成员除了LB,还有Abu,t-bag,Sucre,C-note,Hiphop小偷等等。
  大个子Abu虽然形象伟岸,实际是个外强中干的家伙。而且后来还假模假式的信仰圣光,由此可见,此人是个标准的圣骑士。这厮在团队中的价值一开始比较大,因为他是劳改工人的头头,有权有势,后来显示出控制技能不足的问题,出副本后连承诺的飞机都没能提供,直接导致了第2季垃圾公路逃亡篇的产生。所以后来没有利用价值了,所以后来就死了。此人是圣骑士的最大佐证是,曾经与盗贼t-bag决斗。t-bag隐身,割裂,照他脖子就来个放血。眼看贼胜利在望,结果小强来个无敌+炉石,直接就去了医院,过了几天居然活蹦鲜跳的回来了,嘛事没有嘴里还嚷嚷着:以圣光的名义!……NND,真趟不牢!
  盗贼T-bag绝对是一个压倒性成功的形象!地球上很少有一个反派角色如此受到观众的追捧的。相比t-bag,MS简直就是唐僧,除了小白脸毫无可取之处。我真不知道所谓MS勾人的眼神是怎么发掘出来的,虽然我也曾断背过,但MS对我真的没有产生化学!而t-bag凌厉的眼神,变态的走路姿式,杀人不眨眼的本性,感染力可以打十分!t-bag比起Abu最大优势在于智商(乱伦胎,嗯……)他总是先走一步。别人吃到果子时,他已经在吐核了。作为一个人人讨厌的人,他可以轻易的在团队占据一席之地,其对利益制衡的把握,是里面最强的之一。
  说到不速之客,c-note也是一个。谁都知道猎人副本组队难,MS组队的时候根本没把c-note放进去。生存猎人c-note是硬生生把把自己送入团队的。这也是我觉得c-note比MS更适合当 Leader的原因。此人是个背景良好的军士,含冤入狱,逼上梁山。在整个FR上百上千囚犯中,c-note是唯一一个不知情并靠敏锐的观察力发现MS们在策划越狱的。人才啊,考虑到猎人的野外生存能力,c-note比MS更适合在第2季当RL.事实上,MS在第2季明显技穷了,他双手抱头的招牌动作越来越少,说明他已经无计可施。法师在野外就是活动荣誉。加油啊,小C,向着夕阳奔跑吧!希望你在第2季发挥更大的作用。事实上,第7集里的挖出来美元就是c -note开出来的,红酥手哇!由引可见,PB编剧们也对c-note充满了期望……唯一的缺憾是他是个黑人……嗯……在LB这个除了长得像坎通纳一无是处不用嘲讽不会破甲的小白战士牛比起来之前,我还是力挺c-note的……
  Sucre,一个辅助角色。他最大的功用就是在MS晚上挖洞的时候给他拉旗子挡视线(岗哨图腾),所以,我打赌Sucre是萨满。这个多情小黑男本来一直安份守己。但是计穷的编剧们在第7集里貌似要拿他开刀了。结尾时他背叛了团队,接下来他要干什么?很多人从善意的角度看待他的举动,但是我觉得,这人离死不远了!
  Hiphop小偷 Tweener一开始似乎是个若有若无的小角色,虽然被Belik精神控制了一把,但因为实力有限,没有给PB团队造成什么大麻烦。但是MS因为小偷帮他偷过表,觉得欠他人情就硬生生把他拉上贼船。这一点我觉得MS不厚道。人家不过是小小的偷窃罪,你倒让他跟你越狱,惹上一身骚。可能MS还是看中 Hiphop是德鲁伊这个稀有职业。到了第2季,小德果然辉煌了一把,先是在村庄时使用战复技能,帮团队恢复了补给。后来第2次想战复时因为CD时间未到,再加上仇恨大,被敌对bug术士Mahone擒拿。整个PB里面就Hiphop死得最值,彻底扭转其无脑小青年的形象,整个一美国王二小,不但为敌人做了错误的导向,还在临死前向心爱的Motel girl精彩道别。生亦何哀,死亦何苦,这样死真的不错咧。
  还有副本里的外援女牧师 Sara.这个角色,理论上的第一女主角,本人非常的不喜欢。编剧对这个角色的定位也是煞费苦心,铁着心让她与MS玩速配。她是当地州长的女儿,为了让她形象更立体,编剧非让这个女医生有一段吸毒史。可怜Sara的演技太差,演吸毒那段像在演贵妃醉酒。再加上其外形比较死板,和美国小唐僧MS倒也确实配对,但可惜了东欧妓女Nika.Nika只是个小角色,充其量只是个魅魔。但她为MS出生入死,数次的冒险相救都没有打动MS.而MS更是无情地当着Nika的面给Sara 打电话,还动情哭诉。太伤Nika的心鸟~所以Nika后来举枪威胁MS带她走,居然被小白防战LB来了个缴械。编剧们明显是力挺Sara的。由此可见, PB完全是一部主旋律电视剧。主旋律哇主旋律,一百遍啊一百遍……
  DB Cooper,副本里的传奇NPC.这个头上带感叹号的老家伙有着埋着一个巨大的秘密。护送任务最后没有完成。死在副本口的DB临死前说出五百万的下落。第2季的最大推动力。当之无愧的PB最具挖掘性老男人。终身成就奖。
  除了副本里的团队,副本外的go-vern-ment荣誉收割队一直在追杀着三个人:JB的儿子,命歹男Nick以及克夫女Veronica.唯一值得一提的就是V了,这女人简直是地球上最不受欢迎的正派女角了。人笨,钻牛角尖,长得又欠抽,老一副苦大仇深的表情,更要命的是感情过于丰沛,先是LB的女朋友,后来又想跟MS好(明显脑子缺根弦),后来又有了个未婚夫,最后又差不多和Nick产生感情。这倒也没什么,问题在于,这几个男人前2个饱受监狱及追杀之苦,后2个直接就被她克死了!我真想打开她的命盘看看她婚神星与冥王星的相位。由于她太不受欢迎了,所以第2季一开始就挂了。我怀疑这确实是观众们施加的压力所致。因为她死得确实十分仓促+不值,显示了她的低智商。
  最后提一提第2季请来的大牌FBI探员Mahone,这人是第2 季开拍前才签约的。所以他选择了bug职——术士。不低于MS的智商,但更为阴险。一开始还觉得此人办案归办案,人品应该不像前几个血滴子那样有问题。结果到第7集无语了。秒杀Hiphop一幕让人彻底对其不抱希望。只是不知道他究竟有什么精神病要不停吃药。更不知这种病会给剧情带来什么影响。
  最后祝福伟大的凡高渡海成功!
9월 17일

9月17日及孙狡猾同学结婚及其他

9月17日,就是今天,周日。天气很好,很典型的秋天天气。
晚上八点半胖妞坐火车去北京出差,一个忽然觉得很安静,还有点落寞的感觉,似乎回到当初一个人的日子:简单,还有点无聊。记得结婚之前我还认真的思考过,一个人的生活一下子变成两个人,会不会有些不适应。呵呵,的确,自由少了不少,不能无所谓那里吃饭那里游荡了,心里总惦记点什么。好处当然更多了,至少有人陪着。
我想孙狡猾同学最近肯定也会思考和经历这个过程吧,因为她在10号和他过期的男朋友(因为现在升级成“夫君”了)走入了围城。真是值得庆贺呀,一下子解决了两个老大难,你们不觉得可喜可贺吗?哈哈。
介绍一下两位:孙狡猾原名孙娇华,不对不对,她就叫孙娇华,只是我 觉得孙狡猾更顺口一些。大学里我还给她起名孙中华,是不是我起的我有些不准了,抢了哪位的风头还请站出来,我一巴掌拍地下去。孙中华也很好听呀,有点象孙中山的妹妹或者亲戚吧?呵呵。
大学时光一晃而过,但发生的事情却象雨中撑开的伞,轻轻一转便洒落一地。进入沈阳之前,大家谁也不认识,而离开沈阳之时,就象被撕开的一块匹萨,粘在一起不忍分离。记得大学刚毕业时,感慨最多的就是大学,追忆最多就是乱七八遭的往事,偶然 遇到一个同学,
绝对要坐在一起诉说历史,曾经的辉煌,还有曾经的狗屁。
时间绝对是优秀的清理工,不象格式化那样立即彻底清除历史,也不会任由历史堆积。时间慢慢把我们的记忆淡化,扩散。等突然有一天过去的某个东西冲在你面前,你或许还有些慌张。
似乎废话说的太多了点,呵呵。孙狡猾的老公我是见过的,2004年秋北京的一个招聘会上见到的,还一起吃的饭,请客的当然要提下是李艳丽同学,绝对的好同学。提到李同学多说几句,新郎旁边凉快下先。李同学在大家心目中,我想是所有的9732
班同学心目中,最热心的一位同学,对谁都没有偏见,这是很难得的,我觉得我自己做不到。
现在两位新人应该在大连了,此时应该还在应酬亲朋好友吧。人生就是一个过程,终点不是唯一,享受其中的每个细节才是最重要的。
祝福两位新人幸福!
顺祝胖妞北京一路顺风,我一定帮你保持好商茂新园第一卫生家庭的称号的。呵呵
 
8월 22일

悼念小鱼之死

    小鱼是2个月之前和胖妞去紫霞湖捞回来的,当时一共两条,可惜一条小的不适应环境,回到俺家后不吃东西,一周后死掉了.剩下一条大点的却异常活跃,游走于乱石和螺钉之间,悠然自得.而且对我们喂的食物颇为满意,每次都吃的很干净.这食物其实是以前喂养金鱼留下的,每想到湖里的鱼也喜欢.
    小鱼呆了一段时间后,逐渐熟悉新的环境,以及在他身边走动,偶尔喂他食物的两个主人--我和胖妞.可能是我喂的较多,每但我走到鱼缸边,他就忽的一下冲出水面,冲我吐泡,不知道是想吃的还是欢迎我.呵呵,鱼非草木,对他的主人还是存感激之情的.
     本以为他可以陪我们走很久,可惜周日犯了一个错误.我们又去紫霞湖捉回了几条小鱼,个头都比他小,而且还抓了三个虾,两个蚌回来.本以为他们可以和谐相处.可惜昨天下班回家,发现他们全死了!
     他们是怎么死的,不得而知.
8월 5일

高山流水,相忘江湖

抚琴而坐,心中一片茫然
已不知是第几度秋了
六弦无声 仿佛已沉入昨夜
听风叩响门扉 四下无人
只有月色冷冷
突然瞥见自己的影子
犹如一道暗黑的伤痕  
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
不记得入梦已是几更
醒来的一切 恍惚如昨
所有的话 都已印入霜痕
说不出的萧瑟 滞留在指间
再也没有人了 只有自己
独坐于山巅 众声寂寂
仿佛霜降之后 万物都已白头
触目都是乱石 盘亘心中
磊落不平
可惜一生都已辜负
多少年 一曲未竟
众花纷纷摇落 而另一只耳朵
依旧 在千山之外
已经等了多久,只为一生知己
弹奏一曲 然后
把琴抛入火焰
都说流水无情 却已经忘了
误过多少落花 只有一地猩红
宛如那人的泪痕
所有的梦都遥远了 包括春天
那一夜 月光下的拈花一笑
淡若轻烟 逝入无痕
以及夜半的私语
听到的只有风声 马蹄遥遥
一袭衣袂犹如翻涌的阴云
最熟悉的脸 是模糊的
犹如千年之夜 一次月蚀
此后 已不知是第几度轮回
抬眼看见流星 顿时泪落如雨
仿佛去年的花瓣
而天上 所有的鸟
一定缩紧了羽毛
 
耳畔是一片泠泠之声
被石头割痛 伤过一次
就再也不知道疼了 只有一场雪
才能彻底地覆盖一切
没有尽头 所有的话都无从说
只有低咽是无声的
被人听到
也已过了无数的沧桑
 
 
7월 7일

7月7日下班前

还有20分钟就下班了,明天又是周末.
渴望一次常常的假期,暑假是最好,回到我的老家发呆.安徽的乡下真是发呆的好地方,中午大家都午休了,村庄安静的听得见风划过的声音;我喜欢在厢房屋里,看陈旧的杂志.当然这些都是过去的学生时代的事情.整个暑假其实大都时间都是寂寞的,偶尔和父母出去干活,偶而老陈,扬宾会来玩,但大部分时间都是我一个人.
于是看书.家里书很少,而且很老,大都是高中和大学留下的,比如<平凡的世界>,<贾平凹选集>,还有一些很旧的电影杂志.当然少不了<读者>.书现在都发黄了
6월 15일

再临博客

有个故事:很久很久以前,有人在写博客...
呵呵,对于我,实在是很久没来这里了.天热了,一切缓慢起来.把工作干完,就想一动不动地呆着,看着圆中花草疯长.
小圆中真是一幅欣欣向荣的景象:西红柿花开得正盛,有一个已经结了小柿子了;金银花的脑袋四处游荡,渴望寻找一个着落点;葡萄似乎势头慢了一些,果子没结,叶子也慢慢成熟起来.其他,比如高贵的紫花(无名),已经落幕,结出了许多种子,我想明天一定是紫花的天下!
 
5월 11일

使用 /proc 文件系统来访问 Linux 内核的内容(1)

 /proc 文件系统是一个虚拟文件系统,通过它可以使用一种新的方法在 Linux® 内核空间和用户空间之间进行通信。在 /proc 文件系统中,我们可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段,但是与普通文件不同的是,这些虚拟文件的内容都是动态创建的。本文对 /proc 虚拟文件系统进行了介绍,并展示了它的用法。

    最初开发 /proc 文件系统是为了提供有关系统中进程的信息。但是由于这个文件系统非常有用,因此内核中的很多元素也开始使用它来报告信息,或启用动态运行时配置。

/proc 文件系统包含了一些目录(用作组织信息的方式)和虚拟文件。虚拟文件可以向用户呈现内核中的一些信息,也可以用作一种从用户空间向内核发送信息的手段。实际上我们并不会同时需要实现这两点,但是本文将向您展示如何配置这个文件系统进行输入和输出。

尽管像本文这样短小的一篇文章无法详细介绍 /proc 的所有用法,但是它依然对这两种用法进行了展示,从而可以让我们体会一下 /proc 是多么强大。清单 1 是对 /proc 中部分元素进行一次交互查询的结果。它显示的是 /proc 文件系统的根目录中的内容。注意,在左边是一系列数字编号的文件。每个实际上都是一个目录,表示系统中的一个进程。由于在 GNU/Linux 中创建的第一个进程是 init 进程,因此它的 process-id 1。然后对这个目录执行一个 ls 命令,这会显示很多文件。每个文件都提供了有关这个特殊进程的详细信息。例如,要查看 init command-line 项的内容,只需对 cmdline 文件执行 cat 命令。

/proc 中另外一些有趣的文件有:cpuinfo,它标识了处理器的类型和速度;pci,显示在 PCI 总线上找到的设备;modules,标识了当前加载到内核中的模块。

清单 1. /proc 的交互过程

[root@plato]# ls /proc

1     2040  2347  2874  474          fb           mdstat      sys

104   2061  2356  2930  9            filesystems  meminfo     sysrq-trigger

113   2073  2375  2933  acpi         fs           misc        sysvipc

1375  21    2409  2934  buddyinfo    ide          modules     tty

1395  2189  2445  2935  bus          interrupts   mounts      uptime

1706  2201  2514  2938  cmdline      iomem        mtrr        version

179   2211  2515  2947  cpuinfo      ioports      net         vmstat

180   2223  2607  3     crypto       irq          partitions

181   2278  2608  3004  devices      kallsyms     pci

182   2291  2609  3008  diskstats    kcore        self

2     2301  263   3056  dma          kmsg         slabinfo

2015  2311  2805  394   driver       loadavg      stat

2019  2337  2821  4     execdomains  locks        swaps

[root@plato 1]# ls /proc/1

auxv     cwd      exe  loginuid  mem     oom_adj    root  statm   task

cmdline  environ  fd   maps      mounts  oom_score  stat  status  wchan

[root@plato]# cat /proc/1/cmdline

init [5]

[root@plato]#

 

清单 2 展示了对 /proc 中的一个虚拟文件进行读写的过程。这个例子首先检查内核的 TCP/IP 栈中的 IP 转发的目前设置,然后再启用这种功能。


清单 2. /proc 进行读写(配置内核)

 

[root@plato]# cat /proc/sys/net/ipv4/ip_forward

0

[root@plato]# echo "1" > /proc/sys/net/ipv4/ip_forward

[root@plato]# cat /proc/sys/net/ipv4/ip_forward

1

[root@plato]#

 

另外,我们还可以使用 sysctl 来配置这些内核条目。有关这个问题的更多信息,请参阅 参考资料 一节的内容。

顺便说一下,/proc 文件系统并不是 GNU/Linux 系统中的惟一一个虚拟文件系统。在这种系统上,sysfs 是一个与 /proc 类似的文件系统,但是它的组织更好(从 /proc 中学习了很多教训)。不过 /proc 已经确立了自己的地位,因此即使 sysfs /proc 相比有一些优点,/proc 也依然会存在。还有一个 debugfs 文件系统,不过(顾名思义)它提供的更多是调试接口。debugfs 的一个优点是它将一个值导出给用户空间非常简单(实际上这不过是一个调用而已)。

使用 /proc 文件系统来访问 Linux 内核的内容(2)

内核模块简介

可加载内核模块(LKM)是用来展示 /proc 文件系统的一种简单方法,这是因为这是一种用来动态地向 Linux 内核添加或删除代码的新方法。LKM 也是 Linux 内核中为设备驱动程序和文件系统使用的一种

流行机制。

如果您曾经重新编译过 Linux 内核,就可能会发现在内核的配置过程中,有很多设备驱动程序和其他内核元素都被编译成了模块。如果一个驱动程序被直接编译到了内核中,那么即使这个驱动程序没有运行,它的代码和静态数据也会占据一部分空间。但是如果这个驱动程序被编译成一个模块,就只有在需要内存并将其加载到内核时才会真正占用内存空间。有趣的是,对于 LKM 来说,我们不会注意到有什么性能方面的差异,因此这对于创建一个适应于自己环境的内核来说是一种功能强大的手段,这样可以根据可用硬件和连接的设备来加载对应的模块。

下面是一个简单的 LKM,可以帮助您理解它与在 Linux 内核中看到的标准(非动态可加载的)代码之间的区别。清单 3 给出了一个最简单的 LKM。(可以从本文的 下载 一节中下载这个代码)。

清单 3 包括了必须的模块头(它定义了模块的 API、类型和宏)。然后使用 MODULE_LICENSE 定义了这个模块使用的许可证。此处,我们定义的是 GPL,从而防止会污染到内核。

清单 3 然后又定义了这个模块的 init cleanup 函数。my_module_init 函数是在加载这个模块时被调用的,它用来进行一些初始化方面的工作。my_module_cleanup 函数是在卸载这个模块时被调用的,它用来释放内存并清除这个模块的踪迹。注意此处 printk 的用法:这是内核的 printf 函数。KERN_INFO 符号是一个字符串,可以用来对进入内核回环缓冲区的信息进行过滤(非常类似于 syslog)。

最后,清单 3 使用 module_init module_exit 宏声明了入口函数和出口函数。这样我们就可以按照自己的意愿来对这个模块的 init cleanup 函数进行命名了,不过我们最终要告诉内核维护函数就是这些函数。


清单 3. 一个简单的但可以正常工作的 LKMsimple-lkm.c

 

#include <linux/module.h>

 

/* Defines the license for this LKM */

MODULE_LICENSE("GPL");

 

/* Init function called on module entry */

int my_module_init( void )

{

  printk(KERN_INFO "my_module_init called.  Module is now loaded.\n");

 

  return 0;

}

 

/* Cleanup function called on module exit */

void my_module_cleanup( void )

{

  printk(KERN_INFO "my_module_cleanup called.  Module is now unloaded.\n");

 

  return;

}

 

/* Declare entry and exit functions */

module_init( my_module_init );

module_exit( my_module_cleanup );

 

清单 3 尽管非常简单,但它却是一个真正的 LKM。现在让我们对其进行编译并在一个 2.6 版本的内核上进行测试。2.6 版本的内核为内核模块的编译引入了一种新方法,我发现这种方法比原来的方法简单了很多。对于文件 simple-lkm.c,我们可以创建一个 makefile,其惟一内容如下:

 

obj-m += simple-lkm.o

 

要编译 LKM,请使用 make 命令,如清单 4 所示。


清单 4. 编译 LKM

 

[root@plato]# make -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules

make: Entering directory `/usr/src/linux-2.6.11'

  CC [M]  /root/projects/misc/module2.6/simple/simple-lkm.o

  Building modules, stage 2.

  MODPOST

  CC      /root/projects/misc/module2.6/simple/simple-lkm.mod.o

  LD [M]  /root/projects/misc/module2.6/simple/simple-lkm.ko

make: Leaving directory `/usr/src/linux-2.6.11'

[root@plato]#

 

结果会生成一个 simple-lkm.ko 文件。这个新的命名约定可以帮助将这些内核对象(LKM)与标准对象区分开来。现在可以加载或卸载这个模块了,然后可以查看它的输出。要加载这个模块,请使用 insmod 命令;反之,要卸载这个模块,请使用 rmmod 命令。lsmod 可以显示当前加载的 LKM(参见清单 5)。


清单 5. 插入、检查和删除 LKM

 

[root@plato]# insmod simple-lkm.ko

[root@plato]# lsmod

Module                  Size  Used by

simple_lkm              1536  0

autofs4                26244  0

video                  13956  0

button                  5264  0

battery                 7684  0

ac                      3716  0

yenta_socket           18952  3

rsrc_nonstatic          9472  1 yenta_socket

uhci_hcd               32144  0

i2c_piix4               7824  0

dm_mod                 56468  3

[root@plato]# rmmod simple-lkm

[root@plato]#

注意,内核的输出进到了内核回环缓冲区中,而不是打印到 stdout 上,这是因为 stdout 是进程特有的环境。要查看内核回环缓冲区中的消息,可以使用 dmesg 工具(或者通过 /proc 本身使用 cat /proc/kmsg 命令)。清单 6 给出了 dmesg 显示的最后几条消息。


清单 6. 查看来自 LKM 的内核输出

 

[root@plato]# dmesg | tail -5

cs: IO port probe 0xa00-0xaff: clean.

eth0: Link is down

eth0: Link is up, running at 100Mbit half-duplex

my_module_init called.  Module is now loaded.

my_module_cleanup called.  Module is now unloaded.

[root@plato]#

 

可以在内核输出中看到这个模块的消息。现在让我们暂时离开这个简单的例子,来看几个可以用来开发有用 LKM 的内核 API

 

使用 /proc 文件系统来访问 Linux 内核的内容(3)

集成到 /proc 文件系统中

内核程序员可以使用的标准 APILKM 程序员也可以使用。LKM 甚至可以导出内核使用的新变量和函数。有关 API 的完整介绍已经超出了本文的范围,因此我们在这里只是简单地介绍后面在展示一个更有用的 LKM 时所使用的几个元素。

创建并删除 /proc

要在 /proc 文件系统中创建一个虚拟文件,请使用 create_proc_entry 函数。这个函数可以接收一个文件名、一组权限和这个文件在 /proc 文件系统中出现的位置。create_proc_entry 的返回值是一个 proc_dir_entry 指针(或者为 NULL,说明在 create 时发生了错误)。然后就可以使用这个返回的指针来配置这个虚拟文件的其他参数,例如在对该文件执行读操作时应该调用的函数。create_proc_entry 的原型和 proc_dir_entry 结构中的一部分如清单 7 所示。

 

清单 7. 用来管理 /proc 文件系统项的元素

 

struct proc_dir_entry *create_proc_entry( const char *name, mode_t mode,

                                             struct proc_dir_entry *parent );

 

struct proc_dir_entry {

      const char *name;              // virtual file name

      mode_t mode;                   // mode permissions

      uid_t uid;                     // File's user id

      gid_t gid;                     // File's group id

      struct inode_operations *proc_iops;  // Inode operations functions

      struct file_operations *proc_fops;   // File operations functions

      struct proc_dir_entry *parent;       // Parent directory

      ...

      read_proc_t *read_proc;              // /proc read function

      write_proc_t *write_proc;            // /proc write function

      void *data;                    // Pointer to private data

      atomic_t count;                      // use count

      ...

};

 

void remove_proc_entry( const char *name, struct proc_dir_entry *parent );

 

稍后我们就可以看到如何使用 read_proc write_proc 命令来插入对这个虚拟文件进行读写的函数。

要从 /proc 中删除一个文件,可以使用 remove_proc_entry 函数。要使用这个函数,我们需要提供文件名字符串,以及这个文件在 /proc 文件系统中的位置(parent)。这个函数原型如清单 7 所示。

parent 参数可以为 NULL(表示 /proc 根目录),也可以是很多其他值,这取决于我们希望将这个文件放到什么地方。表 1 列出了可以使用的其他一些父 proc_dir_entry,以及它们在这个文件系统中的位置。

 

1. proc_dir_entry 快捷变量

proc_dir_entry

在文件系统中的位置

proc_root_fs

/proc

proc_net

/proc/net

proc_bus

/proc/bus

proc_root_driver

/proc/driver

 

回调函数

我们可以使用 write_proc 函数向 /proc 中写入一项。这个函数的原型如下:

 

int mod_write( struct file *filp, const char __user *buff,

               unsigned long len, void *data );

 

filp 参数实际上是一个打开文件结构(我们可以忽略这个参数)。buff 参数是传递给您的字符串数据。缓冲区地址实际上是一个用户空间的缓冲区,因此我们不能直接读取它。len 参数定义了在 buff 中有多少数据要被写入。data 参数是一个指向私有数据的指针(参见 清单 7)。在这个模块中,我们声明了一个这种类型的函数来处理到达的数据。

Linux 提供了一组 API 来在用户空间和内核空间之间移动数据。对于 write_proc 的情况来说,我们使用了 copy_from_user 函数来维护用户空间的数据。

读回调函数

我们可以使用 read_proc 函数从一个 /proc 项中读取数据(从内核空间到用户空间)。这个函数的原型如下:

 

int mod_read( char *page, char **start, off_t off,

              int count, int *eof, void *data );

 

page 参数是这些数据写入到的位置,其中 count 定义了可以写入的最大字符数。在返回多页数据(通常一页是 4KB)时,我们需要使用 start off 参数。当所有数据全部写入之后,就需要设置 eof(文件结束参数)。与 write 类似,data 表示的也是私有数据。此处提供的 page 缓冲区在内核空间中。因此,我们可以直接写入,而不用调用 copy_to_user

其他有用的函数

我们还可以使用 proc_mkdirsymlinks 以及 proc_symlink /proc 文件系统中创建目录。对于只需要一个 read 函数的简单 /proc 项来说,可以使用 create_proc_read_entry,这会创建一个 /proc 项,并在一个调用中对 read_proc 函数进行初始化。这些函数的原型如清单 8 所示。


清单 8. 其他有用的 /proc 函数

 

/* Create a directory in the proc filesystem */

struct proc_dir_entry *proc_mkdir( const char *name,

                                     struct proc_dir_entry *parent );

 

/* Create a symlink in the proc filesystem */

struct proc_dir_entry *proc_symlink( const char *name,

                                       struct proc_dir_entry *parent,

                                       const char *dest );

 

/* Create a proc_dir_entry with a read_proc_t in one call */

struct proc_dir_entry *create_proc_read_entry( const char *name,

                                                  mode_t mode,

                                                  struct proc_dir_entry *base,

                                                  read_proc_t *read_proc,

                                                  void *data );

 

/* Copy buffer to user-space from kernel-space */

unsigned long copy_to_user( void __user *to,

                              const void *from,

                              unsigned long n );

 

/* Copy buffer to kernel-space from user-space */

unsigned long copy_from_user( void *to,

                                const void __user *from,

                                unsigned long n );

 

/* Allocate a 'virtually' contiguous block of memory */

void *vmalloc( unsigned long size );

 

/* Free a vmalloc'd block of memory */

void vfree( void *addr );

 

/* Export a symbol to the kernel (make it visible to the kernel) */

EXPORT_SYMBOL( symbol );

 

/* Export all symbols in a file to the kernel (declare before module.h) */

EXPORT_SYMTAB

使用 /proc 文件系统来访问 Linux 内核的内容(4)

   

通过 /proc 文件系统实现财富分发

下面是一个可以支持读写的 LKM。这个简单的程序提供了一个财富甜点分发。在加载这个模块之后,用户就可以使用 echo 命令向其中导入文本财富,然后再使用 cat 命令逐一读出。

清单 9 给出了基本的模块函数和变量。init 函数(init_fortune_module)负责使用 vmalloc 来为这个点心罐分配空间,然后使用 memset 将其全部清零。使用所分配并已经清空的 cookie_pot 内存,我们在 /proc 中创建了一个 proc_dir_entry 项,并将其称为 fortune。当 proc_entry 成功创建之后,对自己的本地变量和 proc_entry 结构进行了初始化。我们加载了 /proc read write 函数(如清单 9 和清单 10 所示),并确定这个模块的所有者。cleanup 函数简单地从 /proc 文件系统中删除这一项,然后释放 cookie_pot 所占据的内存。

cookie_pot 是一个固定大小(4KB)的页,它使用两个索引进行管理。第一个是 cookie_index,标识了要将下一个 cookie 写到哪里去。变量 next_fortune 标识了下一个 cookie 应该从哪里读取以便进行输出。在所有的 fortune 项都读取之后,我们简单地回到了 next_fortune


清单 9. 模块的 init/cleanup 和变量

 

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/proc_fs.h>

#include <linux/string.h>

#include <linux/vmalloc.h>

#include <asm/uaccess.h>

 

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION("Fortune Cookie Kernel Module");

MODULE_AUTHOR("M. Tim Jones");

 

#define MAX_COOKIE_LENGTH       PAGE_SIZE

static struct proc_dir_entry *proc_entry;

 

static char *cookie_pot;  // Space for fortune strings

static int cookie_index;  // Index to write next fortune

static int next_fortune;  // Index to read next fortune

 

 

int init_fortune_module( void )

{

  int ret = 0;

 

  cookie_pot = (char *)vmalloc( MAX_COOKIE_LENGTH );

 

  if (!cookie_pot) {

    ret = -ENOMEM;

  } else {

 

    memset( cookie_pot, 0, MAX_COOKIE_LENGTH );

 

    proc_entry = create_proc_entry( "fortune", 0644, NULL );

 

    if (proc_entry == NULL) {

 

      ret = -ENOMEM;

      vfree(cookie_pot);

      printk(KERN_INFO "fortune: Couldn't create proc entry\n");

 

    } else {

 

      cookie_index = 0;

      next_fortune = 0;

 

      proc_entry->read_proc = fortune_read;

      proc_entry->write_proc = fortune_write;

      proc_entry->owner = THIS_MODULE;

      printk(KERN_INFO "fortune: Module loaded.\n");

 

    }

 

  }

 

  return ret;

}

void cleanup_fortune_module( void )

{

  remove_proc_entry("fortune", &proc_root);

  vfree(cookie_pot);

  printk(KERN_INFO "fortune: Module unloaded.\n");

}

module_init( init_fortune_module );

module_exit( cleanup_fortune_module );

 

向这个罐中新写入一个 cookie 非常简单(如清单 10 所示)。使用这个写入 cookie 的长度,我们可以检查是否有这么多空间可用。如果没有,就返回 -ENOSPC,它会返回给用户空间。否则,就说明空间存在,我们使用 copy_from_user 将用户缓冲区中的数据直接拷贝到 cookie_pot 中。然后增大 cookie_index(基于用户缓冲区的长度)并使用 NULL 来结束这个字符串。最后,返回实际写入 cookie_pot 的字符的个数,它会返回到用户进程。

使用 /proc 文件系统来访问 Linux 内核的内容(5)

 


清单 10. fortune 进行写入操作所使用的函数

 

ssize_t fortune_write( struct file *filp, const char __user *buff,

                        unsigned long len, void *data )

{

  int space_available = (MAX_COOKIE_LENGTH-cookie_index)+1;

 

  if (len > space_available) {

 

    printk(KERN_INFO "fortune: cookie pot is full!\n");

    return -ENOSPC;

  }

 

  if (copy_from_user( &cookie_pot[cookie_index], buff, len )) {

    return -EFAULT;

  }

 

  cookie_index += len;

  cookie_pot[cookie_index-1] = 0;

 

  return len;

}

 

fortune 进行读取也非常简单,如清单 11 所示。由于我们刚才写入数据的缓冲区(page)已经在内核空间中了,因此可以直接对其进行操作,并使用 sprintf 来写入下一个 fortune。如果 next_fortune 索引大于 cookie_index(要写入的下一个位置),那么我们就将 next_fortune 返回为 0,这是第一个 fortune 的索引。在将这个 fortune 写入用户缓冲区之后,在 next_fortune 索引上增加刚才写入的 fortune 的长度。这样就变成了下一个可用 fortune 的索引。这个 fortune 的长度会被返回并传递给用户.

清单 11. fortune 进行读取操作所使用的函数

 

int fortune_read( char *page, char **start, off_t off,

                   int count, int *eof, void *data )

{

  int len;

 

  if (off > 0) {

    *eof = 1;

    return 0;

  }

 

  /* Wrap-around */

  if (next_fortune >= cookie_index) next_fortune = 0;

 

  len = sprintf(page, "%s\n", &cookie_pot[next_fortune]);

 

  next_fortune += len;

 

  return len;

}

 

从这个简单的例子中,我们可以看出通过 /proc 文件系统与内核进行通信实际上是件非常简单的事情。现在让我们来看一下这个 fortune 模块的用法(参见清单 12)。


清单 12. 展示 fortune cookie LKM 的用法

 

[root@plato]# insmod fortune.ko

[root@plato]# echo "Success is an individual proposition.  Thomas Watson" > /proc/fortune

[root@plato]# echo "If a man does his best, what else is there?  Gen. Patton" > /proc/fortune

[root@plato]# echo "Cats: All your base are belong to us.  Zero Wing" > /proc/fortune

[root@plato]# cat /proc/fortune

Success is an individual proposition.  Thomas Watson

[root@plato]# cat /proc/fortune

If a man does his best, what else is there?  General Patton

[root@plato]#

 

/proc 虚拟文件系统可以广泛地用来报告内核的信息,也可以用来进行动态配置。我们会发现它对于驱动程序和模块编程来说都是非常完整的。在下面的 参考资料 中,我们可以学习到更多相关知识。

 

4월 27일

跟我一起写 Makefile(一)

 

跟我一起写 Makefile


 陈皓

概述
——

什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。

因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。

现在讲述如何写makefile的文章比较少,这是我想写这篇文章的原因。当然,不同产商的make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述,我的环境是RedHat Linux 8.0,make的版本是3.80。必竟,这个make是应用最为广泛的,也是用得最多的。而且其还是最遵循于IEEE 1003.2-1992 标准的(POSIX.2)。

在这篇文档中,将以C/C++的源码作为我们基础,所以必然涉及一些关于C/C++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是UNIX下的GCC和CC。

 

关于程序的编译和链接
——————————

在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。

编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。

链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。

总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的Object File.

好,言归正传,GNU的make有许多的内容,闲言少叙,还是让我们开始吧。

 

Makefile 介绍
———————

make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。

首先,我们用一个示例来说明Makefile的书写规则。以便给大家一个感兴认识。这个示例来源于GNU的make使用手册,在这个示例中,我们的工程有8个C文件,和3个头文件,我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:
    1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
    2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
    3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。

只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。


一、Makefile的规则

在讲述这个Makefile之前,还是让我们先来粗略地看一看Makefile的规则。

    target ... : prerequisites ...
            command
            ...
            ...

    target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。

    prerequisites就是,要生成那个target所需要的文件或是目标。

    command也就是make需要执行的命令。(任意的Shell命令)

这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。

说到底,Makefile的东西就是这样一点,好像我的这篇文档也该结束了。呵呵。还不尽然,这是Makefile的主线和核心,但要写好一个Makefile还不够,我会以后面一点一点地结合我的工作经验给你慢慢到来。内容还多着呢。:)


二、一个示例

正如前面所说的,如果一个工程有3个头文件,和8个C文件,我们为了完成前面所述的那三个规则,我们的Makefile应该是下面的这个样子的。

    edit : main.o kbd.o command.o display.o \
           insert.o search.o files.o utils.o
            cc -o edit main.o kbd.o command.o display.o \
                       insert.o search.o files.o utils.o

    main.o : main.c defs.h
            cc -c main.c
    kbd.o : kbd.c defs.h command.h
            cc -c kbd.c
    command.o : command.c defs.h command.h
            cc -c command.c
    display.o : display.c defs.h buffer.h
            cc -c display.c
    insert.o : insert.c defs.h buffer.h
            cc -c insert.c
    search.o : search.c defs.h buffer.h
            cc -c search.c
    files.o : files.c defs.h buffer.h command.h
            cc -c files.c
    utils.o : utils.c defs.h
            cc -c utils.c
    clean :
            rm edit main.o kbd.o command.o display.o \
               insert.o search.o files.o utils.o

反斜杠(\)是换行符的意思。这样比较便于Makefile的易读。我们可以把这个内容保存在文件为“Makefile”或“makefile”的文件中,然后在该目录下直接输入命令“make”就可以生成执行文件edit。如果要删除执行文件和所有的中间目标文件,那么,只要简单地执行一下“make clean”就可以了。

在这个makefile中,目标文件(target)包含:执行文件edit和中间目标文件(*.o),依赖文件(prerequisites)就是冒号后面的那些 .c 文件和 .h文件。每一个 .o 文件都有一组依赖文件,而这些 .o 文件又是执行文件 edit 的依赖文件。依赖关系的实质上就是说明了目标文件是由哪些文件生成的,换言之,目标文件是哪些文件更新的。

在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab键作为开头。记住,make并不管命令是怎么工作的,他只管执行所定义的命令。make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的话,那么,make就会执行后续定义的命令。

这里要说明一点的是,clean不是一个文件,它只不过是一个动作名字,有点像C语言中的lable一样,其冒号后什么也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令,就要在make命令后明显得指出这个lable的名字。这样的方法非常有用,我们可以在一个makefile中定义不用的编译或是和编译无关的命令,比如程序的打包,程序的备份,等等。