Smiley face

我的征尘是星辰大海。。。

The dirt and dust from my pilgrimage forms oceans of stars...

-------当记忆的篇章变得零碎,当追忆的图片变得模糊,我们只能求助于数字存储的永恒的回忆

作者:黄教授

二〇一七


一月十八日 等待变化等待机会

长 久以来编译文件系统就是一个很麻烦的事情,之前尝试了一下其他的工具,现在看来linux from scratch有其独到之处,作为一个学习的途径肯定是好的,而且比较简单,对于自动化有需求的可以尝试一下他的alfs,我实验了一下,就是在编译内核 部分有些卡壳,有时候原来的lfs比如下载链接失效,如何修正源头而不是手动下载似乎还找不到办法.所以看到这个人的言论我有些赞同,就是宁可把所有的脚本放在一个文件里运行更好修改运行.

一月十九日 等待变化等待机会

使用LinuxFromScratch的下载清单发现80个文件有一个遗失,需要找出来那一个没有下载,因为下载直接使用wget --input-file=../wget-list没有报错:
while read file ; do if [ ! -e $(basename ${file}) ] ; then echo ${file} ;fi; done < ../wget-list

一月二十日 等待变化等待机会

使 用jhalfs也就是alfs的脚本,费了很大劲编译出错当然令人沮丧,想来development版本原本就不保证没有错,我没有选择stable是我 的错,看http://svn.linuxfromscratch.org/LFS/上没有什么branch可以选啊,都是6.x我想选最新的 stable都是在tags上,那么在menu上怎么表达呢?branch需要branch-的前缀,我一样话葫芦就用tag-结果看代码才发现直接选 tag名字就好了,怎么第一步没有想到呢?设定source-archive也是很有用的,否则很多package要反复下载,遇到之前zlib旧版没有 只有手动下载了.我基本放弃自己parsing原书的xml的想法,这套工具如果稳定何必呢?

一月二十日 等待变化等待机会


这里是很详细的步骤,怎样继续编译lfs,我在kernel部分失败了好几次,每次都是从头开始,不得已才读这里.

一月二十六日 等待变化等待机会

tcc 是一个神奇的东西,只有100多k做到了很多大型编译器的工作,我很久以前看到启动时候使用tcc编译内核然后启动的壮举为之惊叹不已.现在简单浏览发现 可以学习的很多,首先对于elf的parsing就值得研究一下, gcc里面曾看过一些小的东西,看看tcc怎么用.编译过程的库和include是怎么解决的呢?个
昨天看到关于sfs loader的部分,我的猜想是简单的mount替代puppy linux的某些目录,这样子就不会被重新remaster到livecd里.

二月四日 等待变化等待机会

这 几天在玩alfs,就是lfs的自动版.首先从lfs开始,配置看似简单采用人们熟悉的类似kernel的menuconfig的界面,一开始失败是因为 采用的book setting里的开发版,后来改成稳定版就行了,里面的小细节是版本号和branch,看脚本才明白直接使用7.0不加任何前缀.zlib的xz下载链 接已经失效了,只好手动下载gz版然后tar vxf zlib.x.x.gz | xz  > zlib.x.x.xz,然后把它存到$SOURCE_ARCHIVE目录下,这个很好的设置,否则要反复download.其次就是编译内核的时候总是 抱怨openssl的一些头文件找不到,因为lfs是使用自己编译的tool来编译,我不知道要怎样配置,最后只好在kenerl config里把module_signature之类的都去掉,总算能够编译了一个lfs,后来systemd也可以了.现在尝试clfs,这个使用的 是git,通过branch -a看到所有的branch,选择3.0.0-systemd.我现在不想太多,想直接做一个toolchain就好了,还是逐步来比较好,alfs虽然 好,但是实际上没有什么增长,仿佛开了一辈子车的人也不会明白发动机的原理.还是手动学习的多.
在和C的交流中发现如此的懊恼,因为需要的就是一个简单的内核Module但是我就是不知道要怎样才能给他,因为Module有signature我不知 道要怎么办,最后只能要求他编译整个内核,但是单单安装编译工具和下载内核代码就是一个大问题,的确在livecd的环境下内存的多少决定了你能够 mount的多少,不使用硬盘怎么编译得了那么大的文件呢?

二月五日 等待变化等待机会

这真是一个大笑话,你能够在x86-64架构下chroot编译mips64吗?我为什么有这么大的误区呢?应该是以前使用qemu的binary的一个机制让我有了这么大的模糊认识.这个看上去不错.

二月六日 等待变化等待机会

打算手动创建一遍,第一步创建一个空白的e2fs,使用gpart缩放一个硬盘分除了若干个分区准备实验几个不同的配置.卡在这里: 我即便重新编译mke2fs也会有个"ext_attr":   ext_attr dir_index filetype sparse_super large_file读manpage说是使用默认的配置在这里:/etc/mke2fs.conf,结果我就是用参数-O来传递各个feature,不 行,再读manpage原来可以用^禁用某个feature,所以,最后命令如下:sudo ./misc/mke2fs -O ^ext_attr,resize_inode,dir_index,filetype,sparse_super,large_file /dev/sdg2 原因是第一个ext_attr默认是有的,必须明确禁用!
我把lfs的sudo password timeout时间改成了无限,这个太危险了,还是改回来吧.Defaults:lfs timestamp_timeout=-1

二月十三日 等待变化等待机会

我 使用自动的clfs就是aclfs然后chroot不成功,然后拷贝qemu的static依然不成,让我感到很困惑,然后我决定手动创建一次clfs, 在检验是否chroot可以的时候迷惑而不敢轻易前行,因为照例说我没有拷贝qemu的static之前所有的mips的binary是无法执行的,可是 输出的结果又是可以的,至少libc.so.6在我tool目录下是可以正确执行的.这个很让我吃惊难道什么地方出错了?

二月十八日 等待变化等待机会

我 的记忆力非常的差,以至于忘记了我做过的很多事情,比如我想不起来这么一个简单的问题,就是如何能够在同一行输出,我记得这是一个非常幼稚的问题以至于缠 绕了我很久发现答案后我是如此的生气居然耻于写下答案因为太可笑了,然而当我再次遇到同样的问题我又不知所措了,这就是愚蠢,因为只有不想学习自己的无知 才叫愚蠢.首先,在console里换行是由你自己控制的,'\n',那么你同样的'\r'实际上回到行的开头,所以,每一个学习过编程都知道的'\n\ r'是两个符号,一个教你换行,一个教你到行的开头,难道你现在还不知道怎样保持在同一行吗?当然重复写在stdout的buffer里是要有格式的否则 就是自己覆盖自己的包含之前的如果没有覆盖的话.也许我始终不理解的原因在于在eclipse的console里这个是不行的,我猜想是为了调试程序清楚 eclipse把运行的\r自己加了\n或许是为了和windows统一?总之,我一直以为这个不成立就是因为在eclipse的debug运行无效的原 因.顺便说一下这个是c++11的语法,需要在编译的时候加上std=c++11,顺便再复习一下关于时间的问题,曾经有同事在工作中需要storage array提供localtime,这个被认为是一个无理的要求,系统只需要提供你utc时间,你作为使用者自己去转化为localtime才对,否则 array部署在什么地方还需要告诉你吗?现在都有可能是cloud的东西,今天是这个,明天说不定就是另一个系统在另一个datacenter了.


#include <iostream>
#include <vector>
#include <ctime>
#include <iomanip>
#include <cstdlib>
#include <unistd.h>
using namespace std;
int main()
{
    int i = 0;
    while ( i ++ < 1000)
    {
        std::time_t result = std::time(nullptr);
        struct tm * ptr = gmtime(&result);
        std::cout << '\r'
              << std::setw(2) << std::setfill('0') << ptr->tm_hour << ':'
              << std::setw(2) << ptr->tm_min << ':'
              << std::setw(2) << ptr->tm_sec << std::flush;
        sleep(1);
    }
    return 0;
}



二月二十日 等待变化等待机会

找了很久才发现从命令行启动handbrake的命令:dpkg-query -L handbrake-gtk  发现命令是ghb, 我下载了最新的代码然后重新编译结果老版的crash的问题就解决了.
HandBrakeCLI -i /dev/sr0 -o ~/diskStation/TheThinBlueLine/KidsToday.m4v  --preset-import-file /home/nick/diskStation/TheThinBlueLine/ThinBlueLine.json -s 1 --subtitle-burned 1 --subtitle-default 1 -t 6
我export了配置文件ThinBlueLine.json

二月二十五日 等待变化等待机会

找 了很久才明白其实这么简单,ipmi在redhat里的service叫做ipmi,在ubuntu里还原了本名叫做openipmi,大体的结构是这样 子的,首先,这个是内核的支持,需要内核模块ipmi_devintf,ipmi_si等等,这个可以称作是ipmi的驱动,他们需要和硬件的bmc等等 通讯.那么linux里的驱动典型的都是使用ioctl来的需要建立一个/dev/ipmi0的驱动文件来通讯,而作为工具的一部分ipmitool仅仅 是直接和驱动文件交流,所以为什么需要一个service是有一点令人费解,要看代码才明白,我估计是因为通讯的缓存吧,否则大量的信息需要一个监听者 吧.此外以前接触到的dmidecode的机制,这个似乎是一个硬件的信息库工具,能够读bios信息吗?以前读取的关于hdmi的支持信息,也有关于 bmc的信息.实验了一下证实是openipmi这个service呼叫驱动创建了/dev/ipmi0的驱动文件,看来这个服务也可以称之为用户方面的 驱动的一部分,内核的支持固然是必须的,用户级的辅助也是必须的否则无法使用工具ipmitool.另一个层面就是ipmi的机制是跨越操作系统的,本身 这些东西就是有相当一部分是原始的硬件的操控,比如远程安装操作系统或者远程控制硬件这些是不依赖于任何os的机制,所以这个是一个途径,另一个是利用主 板本身的bmc的网络和web service或者serial over lan等等的机制.

三月一日 等待变化等待机会

这些都是意外的意外,原本是看一些关于ipmi的东西,却发现了的确hitachi已经停用的服务器的确有安全的问题.这个是关于cypher0的问题,我按照文中所说的只要知道bmc的ip地址就一定能够登录.
1.先用cypher0去list user.Using cypher 0 to list all users without login. When prompt with Password, just press enter.
[root@rh63-58-110 ~]# ipmitool -I lanplus -H 172.17.58.120 -C0 user list
Password:
ID  Name             Callin  Link Auth  IPMI Msg   Channel Priv Limit
1                    false   false      true       ADMINISTRATOR
2   UserA            false   false      false      ADMINISTRATOR
3   UserB            false   false      false      ADMINISTRATOR
4   UserC            false   false      false      ADMINISTRATOR
5   UserD            false   false      false      ADMINISTRATOR
6   UserE            false   false      false      ADMINISTRATOR
7   UserF            false   false      false      ADMINISTRATOR
8   UserG            false   false      false      ADMINISTRATOR
9   UserH            false   false      false      ADMINISTRATOR
[root@rh63-58-110 ~]#
2.然后你可以任意修改一个用户的密码.同样的遇到密码提示就按回车
[root@rh63-58-110 ~]# ipmitool -I lanplus -H 172.17.58.120 -C0 user set password 9 Hitachi1
Password:
3.然后就可以使用新设定的密码登录了
[root@rh63-58-110 ~]# ipmitool -I lanplus -H 172.17.58.120 -U UserH -P Hitachi1 chassis status
System Power         : on
Power Overload       : false
Power Interlock      : inactive
Main Power Fault     : false
Power Control Fault  : false
Power Restore Policy : unknown
Last Power Event     : command
Chassis Intrusion    : inactive
Front-Panel Lockout  : inactive
Drive Fault          : false
Cooling/Fan Fault    : false
Front Panel Control  : none
[root@rh63-58-110 ~]#
当然这个应该是古老的问题了,quanta server就不行了,新型号的服务器应该早就杜绝了这些问题.早上搜索关于bios的信息,发现原来biosdecode就是dmidecode的一个 小工具,原理都是类似的就是从Linux的映射的内存中读取rom address的数据,这个在Linux里很容易因为内存通过/dev/mem的驱动文件读取,地址在0xe0000,问题是kernel一开始怎么映射 的呢?看了代码依然没有找到头绪,这个应该都是各种设备驱动的特有方式,然后就lost in language了,因为找bios的wiki,看到了coreboot,看到了libreboot,看到了uefi,看到了mbr...这一系列的 wiki粗粗的读一点就已经lost了,虽然几乎每个知道计算机的这名词的人几乎都听说过这些名字,但是我干保证没有几个人具体知道其中的实现细节.这个 途径也许是不可能的,昨天S的聊天知道他的目的是曾样从ipmi或者smbios等等获得bios的一些设置,显然的ipmi是没有这个方面的定义的,至 少ipmitool一看就发现这个是一个空白.那么作为服务器管理怎样让用户控制bios呢?我看到quanta,hitachi都是使用一个 remote console,这是一个.jnlp就是通过javaws启动的java程序,我昨天的猜想是这个是bmc通过所谓的sol实现的一个,其次我猜想这个是 bmc要在其中运行一个类似vnc server的服务,这样子这个remote console不过是一个java版本的vncviewer的实现,这个帮助用户设定bios,转念一下实际上实现了vncserver就不需要sol, 我原本是说在bios里激活console redirect to serial原理也是吧bios的输出转到serial,这样子利用bmc里的sol就可以输出到remote console可是后来想如果vnc都实现了还用的找sol吗?sol是在没有vnc的情况下才不得已啊.总之这个还是猜测,sol的运用需要支持的是什 么取决与你想吧什么放进去,比如kernel启动的部分,比如bios运行的部分,但是这些都需要他们主动的吧自己的输出转到serial然后才能利用 sol这个桥梁.

三月二日 等待变化等待机会

昨 天发现我的想法是错误的,实际上Ipmi的SOL渠道可以用来控制bios的设定,当然前提是bios支持redirect console to serial port的机制,这个原理和操作系统的启动设定是一样的道理,比如linux kernel要设定启动参数把console=ttyS0这样子。其次要在ipmitool里根据spec设定命令chassis bootdev bios强制进入bios设定画面,然后是启动就是chassis power reset之后进入sol状态sol activate结果看到了bios的启动画面,我一开始被蒙了以为是什么x display从bmc传回来的,后来和bmc自带的remote console比较才意识到这不过是serial console而已,作为bmc完全不费力气的直接把bios转到serial然后通过sol机制得以网络传输。因为sol是一个双向的协议所以可以进行 交互就是说用户的键盘相应可以传回bios,而这个不同于vnc/kvm机制是可以进行编程控制的,问题就在于在ipmitool里这个叫做 rawmode,就是使用termios的类似于dos窗口的图形模式,我还没有实验过,不过应该还是有区别吧应该是ascii而不是pixel,这一点 要确认。想到这里我突然意识到在rasperry/beagleboneblack之类的soc就没有一个对应的bios机制,因为没有主板的flash 存储?但是beagle是使用了一个内嵌的micro sd卡来存储,有异曲同工之效,总之,这个算是pc机的一个架构吧?

三月三日 等待变化等待机会

查看ipmi spec 2.0发 现有定义很多东西但是似乎ipmitool并没有实现?比如在boot flag部分有定义要求设定console redirection control,但是在ipmitool似乎没有这个参数。此外,很多open source project的document只有manpage,看起来不方便,于是你可以使用ps2pdf来转换为pdf文件,比如man -t ipmitool.1 | ps2pdf - ipmitool.pdf
这里有一个比较Ipmi library的表格很好的。本地一份

三月七日 等待变化等待机会

感冒了。在ipmi spec 2.0可以找到network function的codes,但是具体command的codes呢?我肯定是误解了什么后来下载spec1.5也没有找到。找了很久最后在最后一页也就是appendix G才找到command的codes.这里有一个惠普的例子使用raw command来通讯的,可以作为参考。

三月九日 等待变化等待机会

事 实上ipmi是一个很简单的通讯协议,我说简单是指的通讯协议本身,而标准覆盖各种各样的硬件以及不同的链接方式,因此是非常复杂的,有很多全都依赖于 oem厂商自己实现。我之前迷惑的在于没有找到在文件最后的附表里的command codes,appendix G,这个让我想到了Yes Prime Minister里那些官僚在提交公务员加薪报告里把最大涨幅的高官的列表也是放在报告最后的附件里而仅仅给首相审查会议预留五分钟审议还包括中间喝茶的 时间,所以这个能怪我吗?另一个重大的失误在于没有找到sub command的格式,以至于在看chassis的部分时候完全不知所以然,因为多到八九个的子命令明显的冲突,后来在使用raw模式的ipmitool 的例子里才意识到多么的简单,sub command直接加载command后面,所以是这样子的:network func+command+subcommand+data。这个是不是很简单阿!此外,在启动菜单里的这些所谓的mailbox模式都是非永久 persistent,也就是说取决于重启的时间和角色,可能完全被抹去。volatile是仅仅下一次而且必须60秒内重启才有用,但是semi volatile的存留时间我就不确定了。不过总之boot device order是不在协议的控制范围的,他们想要修改这个我觉得是不可能的,至少理论上通过sol模拟人操作修改boot bios菜单只是理论上可行,且不说解析菜单的byte来分析当前值,就算是盲打直接修改也有一大堆的特殊字符的夸平台处理,serial传输速率是否需 要等待相应?而且这个漫长的过程跟不不是一个同步api,作成异步岂不是违反了library的原则,成为service,所以,这个仅仅是理论上可行。
昨天分析了一下才意识到我以前需要的就是一个媒体流传输的部分,专业词叫做mux,这个ffmpeg有实现可以直接用,这就解决了本地显示的问题,只不过 我当初也没有这样在focus在一个想法完全的泛泛的探索。我想最容易的是使用udp,因为接收方可能不在,bbb不想有service来运行,也许 rtp也是可行的。又遇到编译ffmpeg没有ffplay的问题,google说sdl-dev没有部署,安装后才发现ffplay太老了不再兼容所以 不能编译了。
抓屏代码:ffmpeg -video_size 1024x768 -framerate 25 -f x11grab -i :0.0+100,200 output.mp4
ffmpeg -video_size 1920x1080 -framerate 30 -f x11grab -i :0.0 -c:v libx264 -qp 0 -preset ultrafast capture.mkv
折腾了很久才找到办法,发送rtp媒体流:ffmpeg -re -i TotalRecall-1.m4v  -vcodec copy -an -f rtp rtp://127.0.0.1:1238
但这个不是全部,在接受方ffplay需要一个所谓的sdp的文件才能播放,这个是拷贝以上的输出部分:
SDP:
v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat 57.58.101
m=video 1238 RTP/AVP 96
b=AS:900
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAHqzZQLQ9+X/wAgABtqDAIMgAAAMACAAV+QB4sWyw,aOvhMsiw; profile-level-id=64001E

Stream mapping:
  Stream #0:0 -> #0:0 (copy)

然后才使用ffplay如下:ffplay -i ~/.sdp  -protocol_whitelist file,udp,rtp


三月十日 等待变化等待机会

quanta 的server有一个web server可以使用gui来管理,我一开始以为S的代码是得自于QCT的官方,于是按照他的代码使用curl来操作达到gui的同样效果,后来 google没有任何线索以及代码的风格才意识到这个都是他硬从网络过滤得来的,大概就是使用wireshark之类一步一步分析出来的,这个的确很难 得,根据他的说法有些异步完成的操作非常的辛苦,这个让我十分的敬佩。我问他的同时也在问自己除了他发现的这些asp还有没有其他的可以利用的呢?我下载 了midnight commander就是大名鼎鼎的mc来查看qct的bmc的更新firmware,file命令说他是data file,显然的和我预期的cpio有差距,但是我从mc上怎么看都像是image,也许使用cpio还是需要一个文件系统来更新不适合最初的安装,因此 我想这个应该就是简单的disk的image吧?但是这个怎么更新就是一个悬念,也许有两个存储机制可以先mount起来?总之我找到了一个类似 /etc/passwd的文件,看到了smash里的唯一用户sysadmin,这个的默认passwd是superuser,但是smash是一个超级 简单的shell,也许qct这方面实现的很少吧?本身smash的部分还是很多的,它们使用一个ssh的login来实现的。可是我始终看不到root 在passwd文件的影子,我就去问V可能不可能一个系统把root用户清除掉了,他说当然可能因为很多系统压根就不想让用户有任何可以利用的地方,甚至 他们自己也没打算留后门,在production是全部拿掉的。然后我问有没有什么办法jailbreak一个customs shell,他提示passwd里说的那个shell难道不能改吗?我如梦初醒就去把/usr/local/bin/defshell改成了 /bin/sh期望能够成功,可是我还没找到bash之类的shell也许压根就都被删除光了。总之我想上载这个image来实验一下,但是gui上传过 不了验证,看来早有防范,image里有数字签名,同目录下有一个和image几乎一模一样的文件,后缀名多了enc,猜想这个是加密的,我相比较两个 binary文件,可是diff和cmp都不答应,google发现可以先使用xxd把文件转为hex来载使用vimdiff来比较。发现所谓的带enc 的就是在原本的image后面加了几十个byte,或者是反过来的,qct提供的都是加密的需要密钥解开,我已经拿到了机密过的?我有另一个猜想需要验 证,gui在上载前有一部叫做本地验证,不知道在干什么,难道是计算数字签名以便防止网络传输错误?会不会是这个仅仅是传输的校验码?我还有另一个途径可 以绕过验证,那就是直接使用破解的web api上传不呼叫bmc端的校验直接运行firmware。这个需要尝试。
这个是之前我尝试使用ipmi的raw command的时候发现的一个很好的范例网站。 其实我对照ipmi spec也是一步一步这么做的,只不过如果不想看spec直接用就省心了,我已经花时间看了就算是验证了。昨天顺便看了cpio的简单的说明,意识到其实 跟文件系统的描述很像,所以纠正了我一直的想法,在paypal的时候我看到部署使用cpio形式一直以为这个是一种binary的格式,现在才意识到这 个是一个文件系统已经就位后的部署,所以这个时候才明白操作系统级别的部署是不能用这个的,只有使用磁盘镜像,就是img之类的。那么有没有可能把磁盘镜 像mount起来再去修改那个运行的shell呢?
google了一个比较数字签名算法的论文,有时间去看看。

三月十二日 等待变化等待机会

没 有一条路走通了。首先,我不知道fw是什么类型的filesystem,所以mount不成功。也许故意的,也许是混合了什么。其次,我猜想bmc里是经 过什么处理后把镜像mount在一个设备之类上的。因此这个做法完全不需要fw是一个完整的磁盘镜像,也许仅仅是一部分的文件而已,这个也许就是为什么 fdisk/file命令不能识别的原因,因为一个系统不能自己把自己覆盖了,它还要作签名验证这部分程序是始终不会被覆盖的,它里面有预设的key来检 验签名的,包括mount之类的动作,这一点和hnas有些类似,仅仅更新一部分的文件系统。有一个接口允许上传key,但是我还没有尝试,也许这个也需 要现有的key的校验?不过也许也没有,因为如果之前的key丢失了呢?怎么recover呢?这个也许就是recover的窗口,那么问题是加密签名的 算法你不知道也不行,也许是通常的digital digest的算法,可是你要一个一个猜而且随便加一两把盐巴你就一辈子也猜不出来了。这个途径几乎不可能。再次,如果bmc系统真的把所有的shell 都拿掉了,仅仅留下一个customs的smash shell这个也不是不可能的。那么系统自身最基本的操作不使用脚本都是executable这个也许是更加的安全的?不过我始终表示怀疑,实现一个 web service使用asp脚本的做法令人感觉系统相当的简单都是拿来使用的,不至于彻底的改造文件系统。不过数字签名这一关过不去,这条路就是走不通的。 想了解一下fdisk的原理,阅读帮助。

这个是基于S的代码使用curl来操作的范例。

1.       Login and generate cookie:
[root@rh63-58-110 ~]# curl --insecure  -X POST https://172.17.21.13/rpc/WEBSES/create.asp -d 'WEBVAR_USERNAME=admin&WEBVAR_PASSWORD=admin'
……
//Dynamic Data Begin
WEBVAR_JSONVAR_WEB_SESSION =
{
WEBVAR_STRUCTNAME_WEB_SESSION :
[
{ 'SESSION_COOKIE' : '0vJAoSDt9NnZ91GD4TCZCv1kIdp7YE6L001','BMC_IP_ADDR' : '172.17.21.13' },  {} ],
HAPI_STATUS:0 };
//Dynamic data end

2.       Query to get firmware info:
[root@rh63-58-110 ~]# curl --insecure -H "Cookie: WebServer=Server: GoAhead-Webs; SessionCookie=0vJAoSDt9NnZ91GD4TCZCv1kIdp7YE6L001;Username=admin; PNO=4; test=1"  -X GET https://172.17.21.13/rpc/hoststatus.asp
……
//Dynamic Data Begin
WEBVAR_JSONVAR_HL_SYSTEM_STATE =
{
WEBVAR_STRUCTNAME_HL_SYSTEM_STATE :
[
{ 'JF_STATE' : 1 },  {} ],
HAPI_STATUS:0 };
//Dynamic data end


三月十五日 等待变化等待机会

在aliexpress看到大量的ipcamera很多是海信的soc,比如hi35xx,这里有一篇hack的文章,我觉得开发板上应该就是这样子的,原理就是那个在boot阶段的usart在production版本也许是disabled了?这里是soc的datasheet,值得参考。我不太理解的是是否内部就直接运行一个linux系统?
这个是使用vnc的步骤,但是全屏之后键盘无法使用。server: x11vnc -display :0 --usepw --forever --shared
client: vncview

三月十六日 等待变化等待机会

昨 天遇到了很多的问题,首先发现了QCT的那个更新CMC的FW的工具是使用了bridge的选项,参数-t在ipmitool里本来就是bridge采用 的,我使用wireshark跟踪了很久一直在疑惑似乎get deviceid被呼叫两次,后来发现ipmitool里有debug模式,就是-v可以反复使用以便打印更多详细的数据,基于此QCT的 bmc_tool的源代码估计95%以上都是ipmitool的,只是增加了一个send message,这个是ipmitool所没有的,于是我就用-v来让这个tool打印信息,结果send message的packet没有,因为这部分原本就不是ipmitool的代码是新加入的,所以,只能通过wireshark来还原。其次,在 wireshark里有些困惑到底是否是加密的,看起来如果使用ipmi2.0的lanplus是加密的,而1.5好像是没有的。其实想一下也明白作为一 个网络sniff的工具,如果你依靠截听网络packet能够解码那还要机密干什么?加密的本来目的不是就是防范wireshark的吗?晚上终于“发 现”我的主板是有bmc的,长久以来我一直不知道我的主板的两个ethernet card接口是做什么用的,现在知道了是bmc使用的,1.135还有一个web gui,基本的功能都有的ipmi2.0兼容。我非常的讨厌W这个人,满满的负能量就是指的这种人。

三月十七日 等待变化等待机会

昨 天终于明白了所谓的bridge的用法,在ipmitool里你可以直接指定bridge的地址,比如CMC的地址是0x68,然后你根本不需要指定 send message的命令,而依赖于ipmitool自动生成send message的命令,这个就是我之前的最大的迷惑之处,比如,最简单的就是查询CMC的信息,就是app的deviceid的命令,所以,你只需要给定 地址和network func,cmd,data就行了:ipmitool -t 0x68 raw 0x06 0x01,而这个是非常大的帮助,因为所谓的bridge的命令实际上是不同于普通的req/rsp的packet pair的,在wireshark里你会看到对应于一个req有两个response的,一个是bmc直接应答你的无任何数据的简单的 completion code,另一个才是真正的从CMC回来的response包含数据或者错误的。因此当ipmitool能够帮你处理这一切你应该很高兴才对。其次,我基 本找到了CMC上传FW的流程,其中有很多的oem的code只能照搬,但最主要的是文件每次通过send message分块上传的时候是有很多校验码的,尤其是开头的第一块数据前加了很多的前缀,也许是数字签名,这个如果猜不出来那么整个流程就算知道也没有 用,其次就是128byte的文件块的尾数也有一个checksum,这个应该容易,只不过在结尾有什么猫腻还没有看,这整个流程的错误处理也是一个恼人 的过程。我真的感到wireshark的强大,每用一次就要赞叹一次,感觉没有用过这个工具的人就不要说有进行过网络相关的编程了。其次反编译工具似乎很 难找到,我也不是很热心,讲老实话即便给你源代码去找bug都是一个头疼的事情,何况是类似于汇编的伪代码?另一个有趣的插曲是我一开始发现QCT提供的 所谓的bmc_tool是正式的ipmitool改造的,于是比较了输出结果发现ipmitool在bridge的之前总有一些unknown command,于是我就下结论说QCT之所以要改代码是因为sendmessage有问题,后来gdb+wireshark发现是ipmitool试图 猜测oem然后激活所谓的的一些功能,这个QCT理所当然的会屏蔽掉以提高效率。ipmitool的使用常识就是-v的灵活运用,多次叠加debug信息 更全面,同样的我也用bmc_tool来比较两者的输出以猜测流程。

三月十八日 等待变化等待机会

这里有一篇有趣的文章,harddrive的controller是不是一个linux系统呢? 我也这么好奇。读了一会儿我就感觉我还差的很远,比如从未真正的使用jtag来作这个层次的debug,之前在lenovo使用的时候都是别人帮你配置好 的,我也仅仅是debug代码,所以。。。载看此人的涉猎之广让我震惊不已,居然有这么多的硬件都有hack过的人还只是一个学生?自古英雄出少年,看来 没有在20岁成为国手基本此生无法成为真正的高手,Linus的工作也许很多都是在20几岁的时候完成的,读他的半自传just for fun,其中说porting都是没能力写代码的人干的工作,那么管理版本合并是否也是如此呢?我猜想他现在肯定也是过着一种比较固定的生活了。这么想应 该是对他的不尊敬,罪过啊。

三月二十一日 等待变化等待机会

昨 天终于明白了QCT CMC FW uploading的迷惑,那个文件的前面是boot program,后面才是fw。加了所谓enc的前面128byte是标示,总共(0x34+1)*2*128,然后从0x4000开始到结束是fw。我 之前被迷惑的一部分原因和mc有关是它的搜索有问题,3.x的hex search不working导致我迷惑。很难想像大名鼎鼎的midnight commander居然有这个问题,我无奈只好下载了bvi/bview,我只做简单的搜索,而mc的其他功能绝对是太棒了。

三月二十三日 等待变化等待机会

这里有一个很棒的关于bios/nvram的入门的文章。

三月二十四日 等待变化等待机会

这个是一个长久以来困扰的我的问题,就是对于任何一个开源项目编译的时候如何激活debug build,这个是一个通用的做法
./configure CFLAGS="-ggdb3 -O0" CXXFLAGS="-ggdb3 -O0" LDFLAGS="-ggdb3"
对于ipmiutil的编译来说有一个大问题就是无法定义openssl的路径,这个也只能用以上的办法来解决在CFLAGS里加上- I/your/openssl/header/path,在LDFLAGS里加上-L/your/openssl/lib/path,注意不能使用所谓的 useflags的选项,我把这两个export成环境变量结果无法configure,其中的一个修改是必须手动来把util/Makefile里的 CFLAGS_SAM之类的改造一下把-g -O2替换成@CFLAGS@,当然你可以在Makefile.in里作修改这样做你可以使用configure来生成正确的Makefile。我做这个 的原因是因为在使用ipmiutil的时候发现和ipmitool的区别在于activate_session没有被呼叫,然后导致oem的raw cmd出错,我的理解是QCT的这类oem扩展大都用于一些复杂的过程,比如上传FW文件,这样涉及大量的packet不愿意每次都验证,所以需要创建一 个session,以便后面的packet减少overhead。但是奇怪的是我在家里实验在wireshark上没有看到类似的问题,难道是编译的问 题?前天遇到另一个问题就是V要集成poco在其代码中这样子在一个系统里两个dll都有poco的代码,windows据他说默认dll是 private symbol如果static linking的话,但是linux默认是global的symbol,在运行期dll到底连接到哪一个版本呢?K后来说找到一个简单的解决办法就是 linking flag里可以屏蔽某些lib的symbol,我还没有来的即去看详细。前天开会QCT其实有一些不公开的bmc的ipmi扩展可以在bmc里mount 一个nfs的文件系统比如linux iso文件这样子就可以启动安装运行Linux,还没有来的即去仔细看。一直纠缠在ipmi的上传文件上。

三月二十五日 等待变化等待机会

这个github有很多redhat安装工具很酷的地方。这里有一篇关于server bios update保护的文档,很好的学习材料。这里是大名鼎鼎?的tianocore?我也是才听说的。flashrom是一个工具还没有看过,也不一定能看的懂。

三月二十六日 等待变化等待机会

ipmiutils 如果使用md5作为authType的话,似乎算法是这样子的,密码不再在网络传输,而是作为data的一部分来作md5的校验码,这其中也包含了之前的 challenge部分16bytes,总之实现部分有些奇怪,这也就是为什么当ipmiutil爆出buffer overflow错误的时候我有些疑惑,直接原因当然是在hash函数里的msgdata加上密码session,channel等等全部才有 80byte的buffer,自然地当我的数据有134bytes的时候自然就memcpy越界了。但是我对于authorizationtype的 md5怎么就需要连data也要包含进去我感到有些疑惑,后来即便我修正了buf size,可是我自己的逆向工程依然在文件传输的最后一部分出错,难道有什么玄机?无奈之下最后的机会就是使用ipmitool的Plugin来模拟,因 为qct的原生工具也是基于ipmitool的,难道真的是ipmiutil的某种很subtle的实现细节的问题?改造ipmitool的需要一点点的 努力,好在我只需要最简单的raw+lan部分,于是在intf这一层来做。当然以后移植的时候需要考虑intf的多线程问题,intf_loader实 际上是一个singleton,这个要改造也许需要更深入的了解session/channel才行,就如同gSoap的唯一context一样,也许需 要额外的努力。这里是一个最简单的样本希望上班能够实验成功,上帝啊。
./configure  --enable-internal-md5 --disable-intf-lanplus --disable-intf-imb --disable-intf-serial --disable-intf-open  --disable-solaris-opt --disable-ipmishell --prefix=/home/nick/ipmitool-install CFLAGS="-ggdb3 -O0" CXXFLAGS="-ggdb3 -O0" LDFLAGS="-ggdb3"

三月三十日 等待变化等待机会

从 图书馆借了一本书《Embedded Linux Primer》(2006)得益匪浅。也记不清这是第几次试图想冲击embedded领域了,每次都有这样或者那样的原因与结果,但是一次比一次更加的有 效与成熟,这就是学习的过程,比如当你对于基本的内核还没有概念的时候,或者当你对于linux文件系统也没有什么深刻认识的时候,又或者你对于驱动机制 一无所知的时候,还是你对于基本的硬件架构也不熟悉,干脆你连代码编译链接也不甚了了的时候。。。你空谈什么embedded这都是奇谈怪论,仿佛连百万 年前的穴居猿人立志征服宇宙一般。这其中的差距不是一般的大。但是我即便还处于刀耕火种的阶段也至少管中窥豹使得有些意识了,所以,一本好书首先是适合自 己的程度的书,不能太艰深一字一句的反复咀嚼,那是折磨自己,那是超过自己的能力,也不能太简单,每段文字都知道前因后果,这个是享受,也不叫学习。所以 恰如其分的把你当初没有连贯的知识点打通串联,把你当初模糊甚至想当然的阐述清晰,对于你知其然而不明所以然的深入刨析让你有峰回路转醍醐灌顶的感觉,让 你浮想联翩的守不住联想的骏马驰骋,只要有那么一些就算一本好书。书中对于Init家族的宏的刨析让人印象深刻,我以前只是在module里遇到 init_module之类的大约概念上明白这些是可以被弃置不用以便节约内存,但其中奥妙不明所以,作者从main.c的纯洁代码讲起来,怎样用不变的 generic代码来调用散布在各处的初始化函数还要传递参数呢?这个问题其实未必很多人明白这是一个问题,单单通过编译是很难做到的,是需要链接来做 的,作者说的把代码放在某个section的根本目的是可以之后完全释放掉,我好一阵子才回过神来,另一方面增样得知某个函数的symbol而又不用在代 码里书写呢?这个问题很多人都未必能理解,但是一旦提到dynamic loading即便不会编程的人也许都听过,可是同样的即便如此你也需要一个symbol的名字啊,在哪里传递?同时kernel有那么多的子系统,先后 顺序如此重要来不得半点错误,调用的顺序怎么保障?这一切都是把代码数据放在section的原因。其中还有一些没有提到,比如start_kernel 后来是把自己分配的内存释放掉啦,可是它自己还在运行中,且不说运行中实模切换到虚模,硬件软件的mmu都被调起来地址都转变了,怎么还能正常运行呢?这 一切想想就是惊人的复杂,难怪linus是神,因为即便这个世界目前不一定100%没有如他一般超强的大神,但是一定没有如他一般的有神的意志和胸襟,几 个缺一不可,如果他当初没打算开源,如果他打算开公司了,如果他功成名就退休了,如果他不再把持git闸门保证mainstream按照他的设想走下去, 如果。。。任何一点我们今天都不会看到今天。错误的道路有千千万万,人类的愚蠢有亿亿万,你随时随地都可以惊叹人类怎么能够把愚蠢演变的如此令人瞠目结舌 匪夷所思,但是绝顶的聪明睿智只有唯一的一条路可走,任何的偏差都是错误,这就是编程里函数返回0是正确的意义,因为宇宙的基点只有一个0,而错误有无 穷,所以,当linus自夸没有人第一次就能作对这件事,而他第一次就作对了这件事,全世界只有用沉默来表达无限的尊崇与敬畏!


四月一日 等待变化等待机会

需要用到Unix时间绰的转换:
Convert time to timestamp:
[root@C65-57-74 ~]# date -d "2017-03-28 08:07:19" "+%s"
1490713639
[root@C65-57-74 ~]# date -d  @1490713639
Tue Mar 28 08:07:19 PDT 2017

四月四日 等待变化等待机会

折磨了快两天原来又是被Little endian给骗了。md5auth的code里在bigendian才调换,真的不明白代码是怎么写的,结果就导致我误解了,把我们当前的littleendian当作了byte order, 这个真是很离谱,谁tmd的这么定义宏?看下面的代码我都快疯了。这说明什么?就是说bmc那边定义的,就是说数字一定按照littleendian来, 不要管什么order。结果我在wireshark看到的hex形式的littleendian的integer就按照byte order传参数了,白痴啊。

# define BSWAP_32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) |\
                     (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))

#if WORDS_BIGENDIAN
    temp = BSWAP_32(s->in_seq);
#else
    temp = s->in_seq;
#endif
    md5_append(&state, (const md5_byte_t *)&temp, 4);


四月五日 等待变化等待机会

终 于找到了问题,是我的Index计算错误,我把wireshark捕捉到的正确和我自己的capture文件的数据输出到两个文件,每个文件都是所谓的c array,有一千多个static const unsigned char pkt1[221]={...};static const unsigned char pkt2[221]={..};...然后我要写一个小程序来比较两个capture文件里的这些数据,这就牵扯到一个如何定义数组的数组的问题,确实有 些折磨头脑啊。当时为了赶时间就暴力的用简单的办法,真正正确的应该是这样子的。
typedef const unsigned char Array221[221];
in good.cpp:Array221* goodArray[]={&pkg1,&pkt2...,&pkt1115}; ...in bad.cpp:Array221* goodArray[]={&pkg1,&pkt2...,&pkt1115};
for (int i=0; i < 1115; i ++) const unsigned char*ptrGood = goodArray[i][0]; const unsigned char*ptrBad = badArray[i][0]; if (memcmp(ptrGood+110, ptrBad+110, 221-110)!=0)printf("packet %d differs\n", i);}
其中的教训是对于固定大小的数组最好是存储起指针而不是把数组作为元素,具体原因我不是很清楚总之编译的时候编译器对于类型的指针还是数据有些模糊,以上的最简单。对于wireshark采集的capture数据看样子只有自己写小程序来搜索了。

四月七日 等待变化等待机会

终 于找到了原因,ipmiutil和ipmitool的区别在于前者会主动升级使用ipmi2.0如果bmc支持的话,因此我必须强制选择,不过我想这也许 不是真的,也许是因为我使用后者的时候每次都明确指定使用lan driver而不是lanplus,因此在这一点上两者实际是一样的。但是前者有一个不小的bug就是在hash的时候没有考虑msgdata的size 可能很大,结果导致内存越界,这一点是authtype为md5的一个致命伤,只能改代码扩大buffer。好像还有什么选项可以使用大packet,这 肯定也不是前者的选项,因为它的代码hardcoded buffer size就是80。关于bootloader的代码很有必要研读一下,一方面是embbede linux primer的书正在阅读,另一方面项目中有用到使用QCT的BMCl来mount一个nfs export作为操作系统的功能,这个是一个异常强大的功能,不单单可以广泛作为data center的各种管理组合,实际很多公司要求的存储就是要使用nfs甚至是pci over ethernet之类的灵活部署操作系统,甚至可以解决很多的看似难以解决的问题,比如自由的load一个customized os自带各种检测安装工具,之前out of band不可能的任务都成为Inband的简单的实现。再次我自己的beagleboneblack启动总有些问题,怎么debug是一个头疼的事情, google来的一星半点不如自己去编译查看uboot的源码来的可靠。所以,这个是一个很好的主题,另外关于puppy linux的usb的安装启动有些不准确我下载的官方的半官方的image都失败,因该有些很细小的问题存在。

四月九日 等待变化等待机会

编 译是小孩子的游戏,但是我不说你也未必知道,至少我不知道。第一,你的toolchain装了吗?第二,u-boot和kernel很一致的。首先可以直 接使用默认的conf,比如make omap3_beagle_defconf,第三,cross compile的101,你要告诉编译器哪一个,比如,export ARCH=arm && export CROSS_COMPILE=arm-linux-gnueabihf-

四月二十日 等待变化等待机会

丢掉了几天的日记因为我重新安装了Ubuntu 14.04结果忘记设定cron job定期更新了.只记得今天学习怎样在gdb里输出程序输出,很简单使用文件.细节是进入gdb后使用set args myagument>outputfile,因为直接使用gdb –args myprogram myargument>outputfile不行.现在开始使用writer来记日记因为其他的kompozer/bluegriffon都不好用.前两天做的什么一点也想不起来了,唯一的记录是使用minicom的方法: sudo minicom -D /dev/ttyUSB0 -b 115200 -8    to exit, type ctrl+A+j, and fg will resume

四月二十一日 等待变化等待机会

长久以来实际上我始终有一个错误的观念,就是把静态库和动态库等量齐观,其实两者是风马牛不相及的东西,静态库完全应当被当作obj文件来一起链接,动态库却仅仅需要linker检视一下symbol就行了.玩玩libelf,结果还被虐了一下,因为需要先调用一下elf_version,而传入参数不能仅仅是0,需要比当前版本小一些的才行.

四月二十二日 等待变化等待机会

我居然糊涂到了printfformat都记不清了,实在是老了.libelf里偏移是一个long int,那么%l以前我记得似乎也可以,结果一怒之下怪罪g++4.8重新安装g++4.6甚至在-std=c99-std=c++98之间切换,最后还是google,似乎应该是%ld,偏移是signed,可以负数的.真是无知,似乎每天都发现自己的无知以至于天天都是战战兢兢的努力中.挺好的吧?在eclipse里直接创建makefileproject似乎比较适合我,因为直接改makefile比在设置里添加路径等等方便,比如静态库我要作为obj的一部分直接改就好了,在设置里我还真不知道怎么变,多半就链接到动态库了,而g++自带的有libelf的库,不是系统安装的,是编译器自带的,以至于我自己编译的debug版本始终无法用到,最后只能使用static的版本才能gdb找原因. 我现在意识到libelf是为了更复杂的工作而设定的工具,比如创建elf,而我只需要类似readelf里的一些功能而已.他们都在libelf-dev的开发包里,elfutils

四月二十四日 等待变化等待机会

又忘了ldd是一个脚本,而且什么都不干的脚本,意思是仅仅简单的呼唤ld-xx.so执行一下,把debug/verify的信息输出,我本来还以为要自己去读写elf文件结构呢,原来这么投机.不过这个是最准确的因为是ld的直接的runtime的结果.

四月二十六日 等待变化等待机会


ubuntu
server版和desktop版的启动是不同的,desktopcasperserver版有netboot.这里有一个非常好的介绍,但是有一个致命的问题就是desktop里的vmlinuz.efi而不是vmlinuz,我强行设定symlink结果启动就oopse了.

五月三日 等待变化等待机会

编译ipmitool的时候老是抱怨aclocal的版本missing.实际上是configure.achardcodeaclocal的版本为14,手动改为ubuntu当前版本15就好了.

五月四日 等待变化等待机会

遇到一个比较subtle的问题,我在开发一个api,实际上是按图索骥,QCT本身有完整的doc关于怎样使用他们的oemipmi命令来让bmc mount一个nfs serveriso image文件以便作为virtual cdrom来供server启动.本身很简单,但是这里我犯了一个小错误,比如我的/etc/exports里把我的/home export出来,也设定了no_root_squash保证root拥有者的文件可以正确的被nfs client mount.但是我把我的iso image file设定位一个symlink,比如我实际的文件是/home/actualImage.iso,而我开放给用户的是一个symlink: /home/Downloads/image.iso 它指向../actualImage.iso,正常思维是我在/etc/exports里给你的是/home,你就老老实实地mount -t nfs myIp:/home /yourmountpoint就好了,可是QCTapi为了简化要求你给它路径,结果我才意识到他是这么Mount: mount -t nfs myIp:/home/Downloads /yourmountpoint,结果这样一来那个image.iso就成了非法的symlink,因为../actualImage.iso没有被mount过来.这个问题实在是有些subtle.这个api实际上是比较简单的第一步实际上我们需要使用sol就是serial over lan来作为一个通讯渠道来boot一个自作的liveCDubuntuimage以便可以查询实际的blade的硬件信息,比如pci卡之类的.那么ipmi设定boot option的文档就是一个很费劲的文档,我花了很多时间才理解怎么阅读,比如data部分,第一个byte被作为api的序列号,每一个api的真正的数据是从第二个byte才开始的,于是在boot option里大概有七八种形式.关于boot option这个mountvirutalcdrom居然是被当作了removeable floppy/device,也就是第七种,而不是真正的cdrom第四种.这里是QCT的文档.而这里是QCToemipmi.

五月六日 等待变化等待机会

遇到qctmount nfs总是返回0x64的问题,之前遇到这个原因是等待,而现在却是无尽的等待.其实不是server在运行,而是因为mount的参数有问题,而bmc又没有很好的机制来捕捉错误.原因是nfspathfilename分别都有长度限制.前者63,后者31,估计是留一个给null凑够64/32这些程序员最喜欢的buffer size.有没有溢出?不知道?也许是snprintf之类的处理,所以是找不到mount的文件?现在轮到怎样和mountmini os透过sol通讯的问题了,输出没有问题,我就直接等待若干个idlecycle然后返回,但是输入似乎有些问题.难道sol需要像telnet或者是tty之类的有一个login session,答案肯定是的,问题是我使用remote console登录是否等同于使用ipmitoolsol是在同一个session呢?原理上是这样子,需要实验一下.

五月七日 等待变化等待机会

1. I have a mini.iso downloaded from ubuntu official website. So, I mount -o loop to see what is inside iso.

2. I create a clone directory and copy the contents to here. sudo mkisofs -o ../clone.iso -no-emul-boot -boot-load-size 4 -boot-info-table -b isolinux.bin -c boot.cat -R -J -v .

3. Does this new iso work? Yes, it works. I download qemu and test like this: qemu-system-x86_64 -cdrom ../clone.iso It works.

4. Then I dd this iso to my usb flash drive. sudo dd if=../clone.iso of=/dev/sdb bs=1M

5. Then I test it with qemu and it fails. sudo qemu-system-x86_64 -hda /dev/sdb

6. What is the difference between my iso and original mini.iso? Let's use fdisk to take a look:

nick@ubuntu-mini:~/Downloads/clone$ sudo fdisk -l ../mini.iso

Disk ../mini.iso: 57 MiB, 59768832 bytes, 116736 sectors

Units: sectors of 1 * 512 = 512 bytes

Sector size (logical/physical): 512 bytes / 512 bytes

I/O size (minimum/optimal): 512 bytes / 512 bytes

Disklabel type: dos

Disk identifier: 0x13012329

Device Boot Start End Sectors Size Id Type

../mini.iso1 * 0 104447 104448 51M 17 Hidden HPFS/NTFS

../mini.iso2 104448 116735 12288 6M 1 FAT12

nick@ubuntu-mini:~/Downloads/clone$

However, my clone.iso is nothing like this:

nick@ubuntu-mini:~/Downloads/clone$ sudo fdisk -l ../clone.iso

Disk ../clone.iso: 50.8 MiB, 53241856 bytes, 103988 sectors

Units: sectors of 1 * 512 = 512 bytes

Sector size (logical/physical): 512 bytes / 512 bytes

I/O size (minimum/optimal): 512 bytes / 512 bytes

nick@ubuntu-mini:~/Downloads/clone$

一切的一切开始于我需要制作一个mini live cd iso image.首先从官方网站我下载了mini.iso.而造成的误会源于这个iso制作巧妙可以同时作为cdrom/dvd和usb启动.而玄机是作为cdrom启动你使用mkisofs来制作是足够的,可是usb是截然不同的,我一开始没有意识到,一直怀疑我的mkisofs参数不对,其实使用qemu来检验iso是可以-cdrom启动的,问题是usb的启动需要作为harddrive来启动,需要使用分区.这就是为什么你需要使用fdisk来查看,你一看你使用mkisofs制作的压根就没有dos分区就应该明白仅仅使用mount -o loop得到的是不完整的,你漏掉了第二个分区,机关就在这里,通常我看到的gumstick/beaglebone/rasperypi这些做的image都是把dos分区放在第一个,这样子你是无法直接mount linux的第二个分区的,需要正确的offset,而这个iso的第一个是一个hidden hpfs,第二个分区才是dos,导致我可以直接mount以至于我没有意识到它有多个分区.难道是因为hidden?究竟要怎样把hidden hpfs(17)的分区做成使用第0个sector开始的呢?我使用fdisk始终没有办法,因为它或者sfdisk始终顽固的要求sector alignment,不让你使用从0开始的sector,后来我猜想也许它是直接从物理的设备上拷贝下来的而不是首先从一个img文件制作文件系统的?因为制作过程牵扯到chroot肯定是不简单还不如直接使用usb/cdrom直接制作然后再dd下来?另一个值得学习的是直接使用losetup而不是用mount -o loop,好处是我可以首先把img文件的某个片段映射到一个/dev/loopX的设备上,对于设备的读写要方便的多.一般的流程是这样子的:

1. create an image file: sudo dd if=/dev/zero of=1G.img count=1000 bs=1M

2.use fdisk to create multiple partition: sudo fdisk 1G.img

3. find out the offset so that you can mount to device in next step:

nick@nick-KGP-M-E-D16:/BigDisk$ sudo fdisk -l 1G.img

...

Device Boot Start End Blocks Id System

1G.img1 * 2048 2047000 1022476+ 83 Linux

1G.img2 2047001 2047999 499+ 7 HPFS/NTFS/exFAT

4.mount partition to a device: sudo losetup -o 1048576 /dev/loop1 1G.img

5.create filesystem by the device: mke2fs /dev/loop1


五月九日 等待变化等待机会

使用uck是最好的工具来remaster iso了,首先,它帮你copy iso,然后帮你mount squashfs,最棒的是帮你设置chroot的相关设备的mount,而最大的卖点是apt cache的配置,这个一直是我头疼的部分,然而,昨天发现chroot来编译驱动还是有个前提就是hostchroot的两者的内核版本一定要一样,否则很麻烦,而大部分driver的编译需要的是正确的内核的headersimage也许也需要吧?那么你有可能需要自己在/usr/src下设置linuxsymlink,我不明白这个也许是不同distribution的内核headersnaming不一致吧?


五月十三日 等待变化等待机会

我犯了一个先入为主的错误,因为直觉上认为如果Linux文件系统里没有创建这个用户,那么无论如何这个用户是不可能登录,而且即便登录,也没有任何文件权限,所以就不可能运行任何程序,听上去很自然,我猜想十有八九程序员都会认同.可是打脸的是错误的想法啊.年轻人啊.如果你允许systemd在创建serial的时候自动登录一个匿名用户,他是可以跳过所有安全通道成为超级用户,我不确定这是否是所有linux distribution的行为,还是kernel设计的救济措施,但是这个是我下载的remixubuntu mini的行为.自动登录后成为超级用户,即sudoer不需要passwd

实际的配置远远深刻,我非常的不熟悉systemd的运行与配置,在我的ubuntu14.04就不行,好像只有16.04才行,不过发现journalctl是一个很好的东西,其中记录了大量的信息,发现了很多启动的问题.编译ipmitool的时候,sol是需要lanplus的,于是你就不能再使用internalmd5了,因为configure会检查看有没有其他的hash function之类的,会失败然后拒绝编译lanplus

In order to build ipmitool for debugging with both lan and lanplus:

./configure --prefix=/home --enable-intf-lan --enable-intf-lanplus --disable-intf-serial --disable-intf-open --disable-intf-imb --disable-intf-bmc --disable-intf-usb --disable-intf-free --disable-ipmishell --enable-static --disable-shared --with-pic CFLAGS="-ggdb3 -O0" CXXFLAGS="-ggdb3 -O0" LDFLAGS="-ggdb3"

我遇到了一个奇怪的问题就是我的openssh-server似乎没有正常以至于我无法使用ssh从远程登录,排除了ip conflict和firewall的因素,似乎sshd没有再监听22端口.无奈之下就采用apt-get purge然后重新安装.总之,一般的debug办法是在server端改变/etc/ssh/sshd_config里的loglevel到最高级的debug3,然后tail -f /var/log/auth.log.在client端可以加-vvv来看client端的输出.不过这些都没有什么帮助,因为压根就没有到握手的阶段,所以,还是iptables之类的问题吧?


五月十六日 等待变化等待机会

我犯的另一个很傻的错误是设置环境变量,但是我是以sudo运行的,结果始终不对,这个实在是好笑,难道你想不到吗?sudo LD_LIBRARY_PATH=$PWD ./my_exe_here,很明显的这是因为它有一些动态库需要runtime链接.另一个错误是有些超过我的能力了.要使用serial over lan需要正确设置serial port,那么在kernel启动的参数要怎么设置呢?对于grubisolinux大体都是一样的,有两个原则,第一是正确的serial设备,不要说总是ttyS0,这个要看实际的设备,在Quanta服务器中使用的是ttyS1,结果我就始终没有sol的输出.第二是baudrate必须正确,在kernel的参数中必须写上,否则就按照默认的9660是肯定不行的.第三如果你想避免漏掉设备而写上两个设备结果只有第一个才行.console=ttyS1,115200n这个是直接传递给kernel的参数.另一个问题更加的超过我的常识,就是usb bootable是依赖于syslinuxbootloader而不是我之前认为的grub,这个也是有些意外,需要证实.不过至少通过qemu-system-x86_64 -hda /dev/sdb或者使用我自己制作的img file似乎证实了.步骤似乎是这样子的:

首先使用dd创建一个空文件,dd if=/dev/zero of=image.img bs=1M count=800然后使用mkfs.vfat创建文件系统,然后使用fdisk来创建分区,我把msdos/fat16之类的放在了后面,而前面的分区是ntfs,然后使用sudo syslinux -s image.img来安装bootloader,需要把isolinux改名为syslinux,同样的isolinux.cfg改为syslinux.cfg,然后就拷贝安装光盘iso的文件.但是问题是ntfs不支持symlink,而改为linux文件系统syslinux又不肯安装.似乎并不正确啊...

还有一个问题就是我制作的mini-isoboot后一直等待网卡起来运行,这个不行的,因为它根本没有ip分配,是纯粹利用bmcip通过sol来访问的,它自己不需要连接网络,于是需要禁止systemd等待,在/lib/systemd/system下有一个netwoking.service使用systemctl disable它.在chroot的情况下这个是唯一可以做的.


五月二十五日 等待变化等待机会

究竟动态库和静态库的链接有什么不同呢?静态库真的有"链接"这个动作吗?实际上在我看来静态库和obj的链接没有很大的区别,比如我烦透了ipmiutilbug,一怒之下转而使用ipmitool下的libintf.a结果发现和libipmiutil.a下有很多类似的代码函数名,结果两个静态库被抱怨有相同的函数名,这个在动态库是不会的吧,你找第一个就是了,可是静态库仿佛是obj一样的需要决定,而动态库仅仅需要解决就行了,反正是运行期才真正定位的.折腾了一晚上最后才找到这个开关--allow-multiple-definition,然后链接新的libintf.a又爆出了MD2的函数没定义,这个就是纯粹我们自己的小问题了,因为系统的openssl太老了,有很多安全隐患,我们自己bundle了最新版的openssl,但是编译的时候如果你不把它的路径指明,ipmitool的设置会找系统的发现md2是支持的,可是链接的时候发现我们的版本却没有定义.所以,对于一般的configure如果需要定义特殊的库通常是定义CFLAGS/CXXFLAGS/LDFLAGS

./configure CFLAGS="-I/root/devPath/HiStorAPI/external/openssl/oelx86_64/7.3/include" CXXFLAGS="-I/root/devPath/HiStorAPI/external/openssl/oelx86_64/7.3/include" LDFLAGS="-L/root/devPath/HiStorAPI/external/openssl/oelx86_64/7.3/lib" --prefix=/home --enable-intf-lan --enable-intf-lanplus --disable-intf-serial --disable-intf-open --disable-intf-imb --disable-intf-bmc --disable-intf-usb --disable-intf-free --disable-ipmishell --enable-static --disable-shared –with-pic

类似的需要编译debug版本通常是:CFLAGS="-ggdb3 -O0" CXXFLAGS="-ggdb3 -O0" LDFLAGS="-ggdb3"


五月二十六日 等待变化等待机会

事实上允许多个函数定义是一个错误,因为这就是为什么编译器报错的原因,即便是静态库这么做也是错误的,理论上静态库和obj没有什么区别.我昨天就一直遇到类似的illegal instruction的错误,utiltool两个都有相同的函数硬要把他们捆绑到一起是不行的,后来只好把tool的函数名都改掉,这里推荐eclipse里的一个强大的功能,altA+F然后replace,非常的好用,唯一的不足是应该我自己还没有学会使用regex来表达.


六月四日 等待变化等待机会

完全是血淋淋的教训啊!你以为我在这个日子里谈论的是某种历史的禁忌吗?不是,完全是我切身的经历,听我细细道来。首先是我的Ubuntu突然无法登陆,完全忘了前因后果,现在想来应该是我的.Xauthority之类的被corrupted,为什么?因为我始终保留一个硬盘作为/homemount在所有的操作系统导致我的Home directory总是以前的设置,好处是我想保持一直的习惯包括我的所有的下载记录等等,坏处是这真的可以吗?其实在unity无法显示登陆窗口的时候你可以ctl+alt+F1之类的登陆删除.Xauthority,可惜我知道的太晚了,因为我一筹莫展之下升级到了16.04,结果发现还是一样才怀疑到我的home里面的设置问题。其次是我的应用程序无法正常显示,比如我最爱的eclipse for c++虽然在安装openjdk-7,8,9之间反复选择可是依然无法正常launch,这个其实就应该告诉你是显示问题而并非是程序的问题,因为我为此反复安装ubuntu 14.04/16.04在完全纯净的安装之后不应该有任何显示的问题。最后发现甚至在不同的ubuntu desktop下也是类似的问题就应该告诉你这个是你的显示器相关的设置。在桌面上你可以发现应该是显示在第一个工作区导致你看不到,可是为什么应用要运行在你看不到的工作去呢?在setting/display里我注意到我有两个display,也许是我的显卡输出了dvi/hdmi/vga的多种输出,或者是我久违的主办上的显示芯片终于奇迹般的起作用,总之两个显示导致我应该使用mirrored。多么血淋淋的教训害得我折腾了一两天,反复安装,其中当然也实验了我的asus主板的remote console功能,的确很差劲,令人惊奇的是bios无法redirect serial over lan,仅仅在boot loader阶段有,调节video输出也无济于事,看来这个功能不简单。关于拼音输入法,始终很混乱,应该这么理解,首先是添加语言,其次是text input这个设置,你选择的input的语言以及连带的输入法,而在所有输入法之上是同意的快捷键来切换各种输入法以及自体排列方式等等。一层一层的独立。google的古老的拼音很奇怪的有bug,只好放弃不用。在不同的桌面之间的切换是在登陆窗口的ubuntu标志下选择的,这一点我一直疏漏了。同时在display里可以选择我钟爱的工作区以及显示桌面的快捷按钮,真不明白这么好的东西为什么被gnome拿掉了?还是说这个是unity的东西?我分不清两个桌面。


六月五日 等待变化等待机会

发现了一篇很好的文章,这个是当年得奖的,我觉得对于我这个device driver的门外汉是一个很好的启蒙教材。之所以对于usbip感兴趣说来话长,完全是一个工作上的挫折,如果能够尝试成功的话应该可以造福很多人的,不过这个肯定是痴人说梦。顺便说说我使用lshw的时候无法顺利从sol得到正确的输出是一个很有趣的问题,原因是应该不停地呼叫status导致buffer的问题吧,总之解决的办法是加-quiet的参数,否则你就只会看到输出一个USB字样的莫名其妙的东西。


六月六日 等待变化等待机会

时间久了记忆力就不行了。/usr/local/lib是在/etc/ld.conf.d/libc.conf里加上了,可是为什么新安装的executable抱怨他的dso找不到,而且明明就是在/usr/local/lib里的呢?注意了,这个是我自己编译安装的库才有这种问题,不是说/usr/local/lib不在搜索范围,而是ldconfig没有更新,这是一种相当于cache的机制大概是hash表吧,新安装的dso没有加入hash。这个问题需要解释吗?难道对于这个programming 101的内容我都忘记了。usbip需要一个userland的配合,可惜年久失修没有人维护结果当kernel module的名字从usbip改为usbip-host之后就break了,其实就是两三行代码的问题,我想测试一下提交给ubuntu(这里说了大话,其实module名字的改变是小儿科,重要的是似乎driver有了巨大的改变,我对于sysfs系统很不熟悉跟踪也是云里雾里,不过这里倒是训练多时的debug的功力有长进派上用场,基本上是杀鸡用牛刀的架势)

首先,debug sudo的程序要这样子,sudo gdb –args usbipd -d,基本上你不用到某些被系统禁用的如setuid之类的,这个就可以。其次,usbip要编译为debug版本,当然是在configure里设定CFLAGS/LDFLAGS来了,-g -O0就可以了,但是我看不懂libsysfs的函数在干什么就想也跟踪一些,就把sysfsconfigure设定为—enable-shared=false,当然同样要设定CFLAGS,然后回国同来在usbipconfigure里在LDFLAGS里面加上-L/PATH/TO/LIBSYSFS/STATICLIB -Bstatic -lsysfs -Bdynamic这样就使用我编译的版本可以直接debug了。当然这个改动太大把动态库改为静态库来debug,正确的是使用LD_LIBRARY_PATH来在gdb之前加上我的libsysfs.so的路径。总之,基本功有长进,但是驱动的原理依然模糊,连使用驱动都是一个问题,可以称之为在userlandlib的都不会使用。


六月九日 等待变化等待机会

长久以来我一直不是很清楚怎样使用find/exec,可笑吧?这个实在是令人难堪的。那么两个命令连续执行怎么办?一种是-exec ...\; -exec ... \;并列,但是你能够传参数吗?所以还是用shell脚本一类吧,比如sh -c 'my multiple shell cmd',那么参数如何传递?一个是所有的shell都应该通用的就是$()里面是首先evaluate的,那么怎样把find的参数传递呢?同样的shell script的原理是$0是第一个参数,只不过你要double quotesh去翻译,所以就成为如下的:

find redirector-master/ -name "*.class" -exec sh -c 'cd $(dirname "$0") && jad $(basename "$0") ' {} \;

下载了一个很不错的工程其中一部分是自动启用kvm,其中有很多的javaclass我想反编译看源代码,所以使用jad,但是它的命令输出不熟悉想要输出在.class文件相同的目录下,所以就成了这个样子。相似的,我想验证一下结果:

find redirector-master/ -name "*.jad" -exec sh -c 'cd $(dirname "$0") && ls -asl $(basename "$0") ' {} \;

同时我想了一天开始怀疑我的方向,因为usbip肯定不是一个万能的方法,首先,它的确很好,但是需要内核的支持,客户端和服务端都需要内核支持,其次,我后来才想明白tcp/ip部分还是在user space做的一个daemon所以效率也不见得很高吧?但是最主要的是它依赖于内核的驱动实现的usb的驱动来实现的。我需要的也许使用一个libusb就能实现,因为我需要的仅仅是生成usb的一个个URB,当然我需要一部分protocol的握手部分,所以。。。这个正是我下载java源代码来分析的原因,也许实际不复杂的,看了一下其实kvm依赖于三个针对linux/windows/macdso,我看了一下symbol,除了给java做借口的部分就是一个所谓的mediareader的类,应该是cdrom设备的读的实现,因为iso image根本不需要实现,然后就是一个100$的问题,怎样使用dl来呼叫一个c++的类的成员函数?首先创建类对象就是个问题,你没有header定义类的大小,你能够怎样生成对象?这里的问题有好几层:1.objdump -T -C看到的是所谓的demangle的函数签名是不行的,你只能用没有-C的原始symbol名字来dynamic load2constructor或者member function其实都是带一个类指针作为第一个参数的c函数,至少很多编译器是这么实现的,那么constructor是不返回类指针的你怎么得到类对象?你是传入指针的,比如class Foo; typedef void (*FooCtrFunc)(); google了一下想了一小会儿就明白你要冒个险,用一个超大buffer来模拟,比如char*buf[1024];/*让我们祈祷dso的类作者没有在类里存储超大数据,否则我们就内存overwrite*/

class Foo* foo = (Foo*) buffer;

FooCtrFunc ctr = dlsym(handle, “稀奇古怪的函数名字从objdump看到的“);

ctr(foo);

看懂了吗?你把类的指针做参数传递给constructor来获得对象实例,然后就可以呼叫member function了,不要忘记成员函数同样需要dlsym获得原始symbol name,呼叫的时候第一个参数是foo。但是这个做法太过危险了,我不明白的是objdump显示不出来函数的返回值,这个实在是头疼啊,因为函数返回值从来就不是函数签名的一部分,而我压根无法猜测怎么使用返回值,就是说你以后设计函数的时候如果心存恶念不想让如我这样的卑鄙小人依靠binary来猜测使用就尽管使用函数返回值来操作,那么真的很损阴德的。

所以,看到这里你才会真正明白一个道理,就是为什么需要factory模式,我写了三年的库真正体会到factory pattern的用途其实是在dynamic loading的时候体会到的,对于c++dso来说,如果你不提供factory简直就没法用了。很多的道理教科书上说的其实远没有实际体会来的深刻,我想至少factory模式的意义目的不经历实际使用是难以体会的。其次,c++dll对外声明成虚类使得类成为方法表导致函数的调用全部都是指针偏移,你完全不能依赖于symbol table,因为objdump看不到symbol,这样子最阴损,让你没有头文件就彻底死心了,这是最没有道德的做法。


六月十二日 等待变化等待机会

反编译javaclass是比较容易的事情了,我下载了jad不错,但是它对于新版的java有些不行,比如class版本50就不行了,后来下载了jd-gui很棒,而且他的gui做的也很棒好像和eclipseintelisense之类的一样,看代码像飞一样。不过安装eclipse插件有些问题,安装没问题,但是使用的时候即便把文件后缀联系改成了插件依旧无法显示,不过jd-gui本身就很好了,单独看javaproject很好了,而且我仅仅是在反编译才需要足够了。看java的代码的感觉就是c++程序员也许可以花几天时间学习java,但是反过来几年就难。ikvm的算法看懂了,也可以说完全没有看懂,因为核心protocol在动态库里,仿佛一个状态机,我所能看到的是图形相关和网络部分,不过公司的qct的版本似乎有实现虚拟机的部分也许有一些。。。不,应该没有,有的最多是cdrom的读写部分,至于说usb-scsi的协议部分应该还是在动态库里,不过第一步如果可以的话探索看看应该是标准的,一个bios公司单独实现一个协议可能性不大,也没有意义吧?


六月十九日 等待变化等待机会

动态库里面函数名字居然有类似alias的现象,比如他们的index相同但是实际的symbol名字不同,可是你去demangle后看到的名字相同,比如都是constructor/destructor,看assembly也仅仅是两行指令。实际发现其实调用那个没有区别,应该都是一样的,因为index相同就是相同的。所有的外围的都实验可以了就差最核心的execscsicommand来最后mount了。这个函数似乎也不是很复杂,看汇编也就是一两百行,这个让我有些诧异,scsi的实现这么简单吗?


六月二十日 等待变化等待机会

使用wireshark来破解ssl这个题目是误导的,首先加密的目的就是防止像wireshark这类网络截取工具窃听网络内容,包括篡改。如果加密这么容易就被破解了还要加密干什么?所以这里的原理不过是在特定情况下为了开发的目的而主动让wireshark破解加密包。前提是你主动提供加密的密钥给wireshark。这里有两个途径一个是你直接使用一个共享的密钥似的你的应用和wireshark都使用这个密钥,这个往往是你自己开发的应用才能做到。另一个是更普遍的问题就是用户是使用浏览器浏览某个加密网站,比如firefox,那么处于某种原因你想要窥探其中的奥妙,这里你需要浏览器主动交出密钥,这个是一个类似于debug的功能定义一个环境变量SSLKEYLOGFILE于是firefox就即时输出密钥到这里,同时你在wiresharkprotocol/ssl里把(pre)master key logpath只想你的文件。但是这个似乎是有版本的要求的,我在rhel6.5上的1.8版始终都是0bytes最后在ubuntu16.04上的更新版才成功。


六月二十二日 等待变化等待机会

写了这么多年的代码还犯这种错误实在是丢人,写下来以警后笑。你在一个头文件里用到了一个类型,而你又不想遵循头文件自己包含所要包含的头文件那么只能在需要的cpp文件里去自己添加include的头文件,那么这个时候顺序就显得很重要了,比如被引用的头文件里需要用到的另外的头文件自然就应该排在前面,这个是常识,如果不明白还写什么代码呢?只不过被是用到的boostproperty_tree比较的tricky,你需要引用的不是类的头文件,而是一个什么forward的头文件,boost的代码比stl难懂多了,我对于它的namespace也不熟悉,遇到为定义的错误第一个想到的就是namespace的问题,把问题想偏了。顺便说一下,boostptree的遍历是一个类似depth-first-search的算法,他的second不是可以直接使用的string,虽然first的确是一个string,结果遇到second.empty()对于有值的节点居然返回true我就知道这个second是一个结构了。


六月二十六日 等待变化等待机会

关于symboldemangle这个实际上是binutil的一部分,实现不是在c++ stl做的?至少我看到的是在binutil里的cxxfilt依赖于libiberty的部分。这部分代码相当的复杂,我决定使用gdb去跟踪来的更容易,通常configure里为了加快速度使用了config.cache来缓存,需要使用make distclean来清理,有时候只有手动删除他们了。


六月二十八日 等待变化等待机会

看来从demangle部分找答案是不行了,因为他们似乎就不认constructor的那些后缀名,比如

_ZN19CCDROMImgFileReaderD2Ev _ZN19CCDROMImgFileReaderD1Ev objdump眼里是一样的,所以,我想去找源头,应该是linker产生的,但实际上gcc/gdb等等一切的一切大家统一依赖于libbfd来处理object file,否则不一致就会产生无穷的问题,这是一个非常正确的选择。他们的源头就是libbfd从文档阅读开始。


六月三十日 等待变化等待机会

一个helloworldhttp://www.staroceans.com/practice/bfdTest.cppbfd遍历,主要是试探使用bfd


七月七日 等待变化等待机会

我乱搞防火墙结果自己也不知道为什么ssh被关闭了,于是笨办法就是重新安装openssh,可是在synaptica的图形界面里它误导我会卸载很多连带的包,我很害怕就不敢卸载openssh-client,后来看到错误信息好象是说有什么包阻断了,我卸载了另一个相关的包,似乎是替换了很多的包,总之,这个是愚蠢之极的做法,其实sudo ufw disable应该就能解决的,或者sudo ufw enable 22也行了。


七月八日 等待变化等待机会

一个如此简单的问题折腾了我一个上午。我的两台ubuntu系统各自都有设定自己的hostname,那么在局域网里我怎样使用hostname来呼叫彼此而不是使用ip,因为ip有可能改变,因为我使用routerdhcp server。这个问题是如此的普遍,而我却走了这么长的路。首先,我在是否我的ubuntu正确的把自己的hostname发送给了dhcp server上就纠缠了许久,这个问题简单吗?请看/etc/network/interfaces里你决定使用哪些接口,我手动改成了dhcp方式,然后查看dhclient的配置文件/etc/dhcp/dhclient.conf里找到了dhclient发送hostname的证据。send host-name = gethostname();这个是默认设置,其实你不需要手动hardcode,最好使用函数获取的,我曾经试图自己编造hostname替换为send host-name “mybogusname”;结果router当然老老实实展现了我的hostname,可是另一台ubuntu却是ping不到这个假的hostname。其次在lan你是否真的需要router来解析hostname吗?因为我发给router是假的hostname可是另一个ubuntu依然依照我的真实的hostnameping到我,这让我怀疑是否本地的dns解析在起作用。最后也是最重要的,hostname不是fqdn所以,不需要真的dns来解析的,因此区别于此,必须加上.local的后缀,就是ping myhostname.local,就是这么一个小小的关键耗费了我一个早上。另一个教训是我瞎搞ip addr flush eth0结果导致interface一直在broadcasting状态,flush到底是在干什么?我发现最可靠的重新刷新dhcp的配置是ifdown eth0 && ifup eth0

使用aptitude install要比apt-get install聪明多了,后者非常的糟糕,前者很智能的给出降级冲突包的方案,你只需要选择就好了。相比之下比synaptic要容易多了,因为图形界面似乎不真的支持gnome,而是kde的环境。


七月十日 等待变化等待机会

windows下编程的人会很熟悉visualstudio的预编译头文件的概念,可是在linux下似乎用的人不多,那么怎么实现呢?我的认识是这个需要编译器的支持,因为单单使用Makefile写规则是否能够达到预编译的效果呢?我不确定,这里有一段gcc文档里关于c++的头文件的预编译的例子,我摘录如下

How to construct a .gch file from one of these base header files.

First, find the include directory for the compiler. One way to do this is:

g++ -v hello.cc

#include <...> search starts here:

/mnt/share/bld/H-x86-gcc.20071201/include/c++/4.3.0

...

End of search list.

Then, create a precompiled header file with the same flags that will be used to compile other projects.

g++ -Winvalid-pch -x c++-header -g -O2 -o ./stdc++.h.gch /mnt/share/bld/H-x86-gcc.20071201/include/c++/4.3.0/x86_64-unknown-linux-gnu/bits/stdc++.h

The resulting file will be quite large: the current size is around thirty megabytes.

How to use the resulting file.

g++ -I. -include stdc++.h -H -g -O2 hello.cc

Verification that the PCH file is being used is easy:

g++ -Winvalid-pch -I. -include stdc++.h -H -g -O2 hello.cc -o test.exe

! ./stdc++.h.gch

. /mnt/share/bld/H-x86-gcc.20071201/include/c++/4.3.0/iostream

. /mnt/share/bld/H-x86-gcc.20071201include/c++/4.3.0/string

The exclamation point to the left of the stdc++.h.gch listing means that the generated PCH file was used这里是关于gccprecompiled header的文档,不像windows都为你做好了,linux下程序员要付出更多的努力去实现。


七月十八日 等待变化等待机会

我想知道gcc怎么产生汇编码的,看gcc代码一头雾水,就想着编译一个debug版本来用-S来跟踪,但是编译出错现实sys/cdefs.h找不到,一开始我还以为是target/host必须设定正确,反正是跟arch有关,后来去linux from scratchgcc编译部分才想起来是要disable multilib,其实google一开始就说这个是multilib的问题,可是我楞是不理解。所以,完整的configure是这样子的:./configure CFLAGS="-g -O0" CXXFLAGS="-g -O0" LDFLAGS="-g -O0" --disable-multilib –enable-languages=c,c++


七月二十四日 等待变化等待机会

这里的homm3研究真是到家了


七月二十五日 等待变化等待机会

对于debug使用wireshark来说常常遇到ssl的破解问题,事实上当然是不可能破解的否则就失去了使用ssl的意义,如果是浏览器的话我已经知道使用firefoxdebug的方式声明一个环境变量让他交出秘密,但是对于非浏览器的应用呢?另一个途径是在server一段,因为很多的server支持用户自定义private key,用户上传自己的key,所以这个就是我debug的一个方法。当然使用man in the middleproxy的办法是几乎战无不胜的,不过配置起来有些麻烦,需要应用的client端支持Proxy之类的。另一个途径比较的高难度,这里有详细的解释,我下载了源码但是还没有尝试,原理上不复杂,但是实际去做需要了解很多的细节,首先你要知道一个loader的环境变量就是preloading这个是所有的搞鬼的前提,我曾经想使用这个去篡改openssl的某些代码行为,其次就是linux下的dynamic loaderwindows强大的部分就是可以检查当前已经loaded的代码部分,你做一个类似hook的东西去呼叫原来的代码函数的前后干些偷鸡摸狗的勾当,这个和hacker的行为无异只不过是正道而已,有时候迫不得已,比如legacy binary的无奈,这里面的关节很多代码不长但是技巧不少。


八月一日 等待变化等待机会


jviewer
启动不正常的问题实际上很简单,是因为新版本的javaws试图去更新,与其更改javaws的代码,不如直接设立一个alias javaws='javaws -noupdate'

我试图理解为什么QCT提供的amivmcli不能支持旧版的问题,看它的初始化数据objump -s -j .rodata vmcli,的确看到定义的常量里的wget的参数是有加引号的,可是不知道为什么他会失败?我的实验是system()的确就像是shell command一样的,你必须使用引号屏蔽特殊字符。难道运行成daemon这个会有所不同吗?或者QCT不使用system()而是使用popen,我怀疑,因为从简单来看他们似乎就是一个速成的产品,很多都是把shell脚本直接搬过来。


八月二日 等待变化等待机会

我是怎么知道字符串是否加引号的呢?通过查看他的.rodata区: [root@rh63-58-110 Linux_x86_64]# objdump -s -j .rodata ./VMCLIEXE | less

其次我自己实验了一下system()的调用,虽然99%肯定,但是毕竟原因不明,因为在daemon情况下用ps看到的命令行参数就没有加引号了,这个也许是linux显示的问题?


八月十日 等待变化等待机会

需要搜集一个运行的daemon的个数:ps -C VMCLIEXE –no-header -o pid,args –cols 160


八月十八日 等待变化等待机会

遇到BMC更新BIOS后需要显示bios版本的问题,理论上BMC不专门提供是无法知道的,协议上也没有规定这个义务,只好在文件上动脑筋,通过搜索字符串来找: strings BIOS-binary-file | /bin/grep “ Ver: “

实验中遇到很多关于启动的疑惑,比如ESXi server boot是怎么发生的?注意到MallenoxIB好像有个一个什么flexboot的东西直接就启动了,好像类似与IntelNIC也有一个什么boot agent可以直接启动吧?还有就是在UEFI模式下启动有什么不同?同样是floppyremovable device,似乎bootloader不同?疑惑太多了。


八月二十日 等待变化等待机会

读 《习近平讲故事》是一种很好的享受,这实际上是把习近平讲话文稿中的典故进行阐述注解的一本小册子,读起来很有收益,很多的典故是人所熟识的,可是也有很 多是我第一次接触的,非常的又去生动。有些情节很有深意,比如掌故中关于康熙曾经对于西方从天文地理数学逻辑等等的广泛涉猎学习,可是中国当时中下阶层却 毫无影响与受益,传教士所绘制的中国地图被束之高阁完全不被社会所利用,整个中国完全没有机会接触西方的新科技成果,中国没有培育出任何一个有重要贡献的 近代科学家就是一个发人深省的故事。同时期彼得大帝也许和康熙一样的天纵英才,可是似乎前者把自己游历西方的学识带回了俄国并发扬传播给整个俄国,这个对 比实在是巨大。


八月二十三日 等待变化等待机会


UEFI
是一个非常大的topic,单单从启动部分就有很多的复杂的问题,首先这个是我阅读wiki得到的基本的常识,就是MBR就是一个512byte的在disk开头的sector,但是bootloader很难在几百个byte里写成,一定有一个second loader,所以,这里就牵出了另一个大的topicpartition scheme,究竟是传统的bios的还是较新的GPT,前者是总共就是1k*1k=1M的部分给你存放所有的partition tablebootloader的代码,而后者就不是这样子的。我昨天看的是这个wiki,结果看完了就更糊涂了,这些问题非常的复杂,而且一开始就提到sector size 5124K的异同让我更加的糊涂了。boot结构肯定是和磁盘结构紧密项链的。这真是废话,如果你什么也没有看懂就不要废话了。

LBA34是磁盘的第一个可用的地址,这个对于GPT来说就是34*512=17k必须分配给GPTheader/partition table entry等等,这里还包含了第一个所谓的protective MBR一个sector0所以才说总共就是16384=16k是分区的信息保存的大小:LBA0=MBR, LBA1=GPT header, LBA2-LBA33entry。所以16k=17k-sector0-sector1看图识字。我很感谢wiki于是今天就donate$3wiki。目前我一共捐过$8wiki


八月二十四日 等待变化等待机会

关于ssh login很慢的问题是很容易解决的:1.client-v可以看到原因是GSSAPI在交换key2.server端在/etc/ssh/sshd_config里加上LogLevel DEBUG3然后tail -f /var/log/secure也可以看到很多的端倪,当然需要重启/etc/init.d/sshd restart 3.所以在/etc/ssh/sshd_config里把GSSAPI注视掉或者设定为NO.

还有一个值得记录的是长久以来我一直认为boot option是一个一次性的设置,这个根据ipmi的协议的确是所谓的semivolatile,会被清除,但是是有条件的,而且我一直认为boot mode是不可通过ipmi来改变的,证明我是错的。这个是可以改变的不过ipmi的文档确实是有一些晦涩难懂,我读了好久才有些明白,还参照了一些例子,因为我的记忆力太差了,之前度过的有忘记了:

Boot with UEFI, persistent, 0xE0 (legacy: 0xC0)

Hdd 0x08

User password bypass+ console redirection 0x0A

Netfunc 0x00 cmd 0x08 subcmd 0x05

[root@rh63-58-110 Debug]# ipmitool -H 172.17.59.189 -U admin -P admin raw 0x00 0x08 0x05 0xE0 0x08 0x0A 0x00 0x00

查询使用这个:

[root@rh63-58-110 HiStorAPI-05_15_0]# ipmitool -H 172.17.59.189 -U admin -P admin chassis bootparam get 5

5指的是第五个函数,这个在ipmi文档里有交代,我曾经为此迷惑了许久,这个结果和以上的设定是不相关的,仅仅参考而已。注意同样的deviceuefilegacy模式下也许解释不同。

Boot parameter version: 1

Boot parameter 5 is valid/unlocked

Boot parameter data: c03c0a0000

Boot Flags :

- Boot Flag Valid

- Options apply to all future boots

- BIOS PC Compatible (legacy) boot

- Boot Device Selector : Force Boot from Floppy/primary removable media

- Console Redirection control : System Default

- User password bypass

- Lock Out Sleep Button

- BIOS verbosity : Request console redirection be enabled

- BIOS Mux Control Override : BIOS uses recommended setting of the mux at the end of POST


九月八日 等待变化等待机会

使用cmakeoption出乎我的意料居然和macro类似:

cmake -DENABLE_TOOLS=ON ..

boost 1.54版本似乎有些毛病,就是libboost_filesystem是depend on libboost_system的。结果就是很误导 我明明看到在编译的libwesnoth-core.a里的symbol出现在libboost_filesystem的DSO里,可是linker总是说找不到symbol的错误?后来只好手动修改cmakelists.txt添加了libboost_system

if(ENABLE_BOOST_FILESYSTEM AND NOT ENABLE_PANDORA)

set(common-external-libs

${common-external-libs}

${Boost_FILESYSTEM_LIBRARY}

${Boost_LOCALE_LIBRARY}

${Boost_SYSTEM_LIBRARY}

)


九月十日 等待变化等待机会

我自以为学了很多年的编程以为有些小成,可是每天都会感到自己依旧是那么的无知,也许我确实是学得太粗浅了。比如以前就遇到过的可是当时可能是没有理解或者现在忘记了,后一种说法可以挽回一些面子。实际上new这个operator是有多种的原型的,其中一个是一个结构,一般传入释放的方式或者什么的?为了特定的使用nothrow的方式,专门定义了一个常量型nothrow_t和他的常量nothrow,于是你传入这个特定常量就不会有歧义了,这个是我刚刚读Bjarne Struoustrup的巨著的解释结合stl的源码声明才明白了。这里的解释也很清楚,可惜以前看到过类似的工程里面直接用宏把普通的new变成new(nothrow),我其实并不理解,那个时候是在telepresence的时候吧?

其实我之所以遇到这个问题是查找以下的疑惑才无意中翻到的,以下是wesnoth代码的翻录,我不明所以然: 注释是照抄的,我放在一个小试验里来看结果,但是conversion为什么会调用呢?


#include 
using namespace std;

struct MyStruct
{
	static MyStruct invalid;
	struct safe_bool_impl { void nonnull() {} };
	/**
	* Used as the return type of the conversion operator for boolean contexts.
	* Needed, since the compiler would otherwise consider the following
	* conversion (C legacy): cfg["abc"] -> "abc"[bool(cfg)] -> 'b'
	*/
	typedef void (safe_bool_impl::*safe_bool)();
	operator safe_bool() const
	{ 
		return this != &invalid ? &safe_bool_impl::nonnull : NULL; 
	}
};
MyStruct MyStruct::invalid;
int main()
{
	MyStruct my = MyStruct::invalid;
	if (!my) //why??
	{
		cout << "not true" << endl;
	}
	return 0;
} 


试图在BS的巨作《The C++ Programming Languange》里寻找答案,可是每看一页就感觉脊梁冒冷汗,战战兢兢,只得掩卷长息为自己的无知与懒惰而气愤。

气愤之余也想明白了一些,因为!不一定是所谓的bool operator的调用,也可以是在把MyStruct转为指针时候,所以,虽然safe_bool是一个成员函数的函数指针,但是毕竟就是一个指针,所以理所当然的就被调用了。然后也是只有这个时候才明白wesnoth定义这个东西的用意,其实很简单,就是防止c程序员的习惯,比如经常我们会简单的说只要指针不是非法就可以调用: if (!ptr) ptr->do();可是现实生活中Invalid的结构比比皆是,c++11里面对于!的定义应该是比较严格的,所以,wesnoth严格定义了一个explicit operator bool() const这样子防止被滥用,当然这里不是指针了,而是if(!cfg)cfg是一个对象了。对于c++98wesnoth这么定义的原因是因为什么呢?为什么不能重载operator bool()const呢?

如果要编译wesnothdebug版本: cmake -DCMAKE_BUILD_TYPE=Debug ../


九月十四日 等待变化等待机会

工作中用到snmp++但是似乎它不能解析float/double,我是根据它的asn1.h的头文件的定义来推测的。因为linux的工具net_snmp里面是包含float/double的定义的。


九月十八日 等待变化等待机会


HOMM3
Linux 版本vmcl还是有些复杂的,主要是qt5widget的支持问题,而且为何要从这个复杂的入手呢?所以,我决定从最简单的wesnoth开始,至少这个代码容易懂一些。可是开始一看还是觉得复杂,因为他的ai也进化了好多了,于是我就从jit里翻出了它的1.0版本,这个很令人吃惊的运行的非常的好,我不禁从心底里佩服当初的开发者,在第一版就打下了如此坚实的基础。于是我就从改动启动参数学习看怎么能够先弄出一个运行的框架来吧。

编辑pdf使用的是xournal,然后使用pdftk来合并多个扫描的pdf


九月二十二日 等待变化等待机会

每天都有那么多的挑战,忙碌的像蜜蜂一样。

I think this boost/ssl issue of “short read” error (https://svn.boost.org/trac10/ticket/12528) will be a headache in many cases, especially during F/W, BIOS upgrading when procedure takes much long to finish and both network and Quanta server can cause this issue.

Currently it can be resolved by upgrading to boost1.58. (but upgrading will not only affect HiStor, but Puma also.)

In the change log of 1.58, search for “Fixed an ssl::stream<> bug that may result in spurious 'short read' errors.”

http://www.boost.org/users/history/version_1_58_0.html

Or alternately, we can issue a small patch to our boost code base by following as comparing 1.57/1.58 shows this is the fix. And comparing 1.57 with our current, the change are neglect able.

Comparing 1.57 with 1.58

[root@rh63-58-110 Downloads]# diff boost_1_57_0/boost/asio/ssl/detail/io.hpp boost_1_58_0/boost/asio/ssl/detail/io.hpp

5c5

< // Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)

---

> // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)

228c228,230

< if (bytes_transferred != ~std::size_t(0) && !ec_)

---

> if (bytes_transferred == ~std::size_t(0))

> bytes_transferred = 0; // Timer cancellation, no data transferred.

> else if (!ec_)

[root@rh63-58-110 Downloads]#


学习boost是我的另一个挑战,首先从bind开始,以前的stlbind1等等是类似的,可是boost做的很玄妙,c++的作者Struoustrup的书里面提到了很多类似的template的技巧吧?

quanta又埋了一个坑给我,我原本以为使用ipmi修改boot option可以解决boot order不能修改的难题,可是新安装的satadom作为一个新的启动分区确实不受bootoption控制的,这个是所谓的BBS就是bios boot specification的新标准,这个真的是头疼啊。最近还是做了不少的工作的,比如能够想的起来的就是ipmitool bootparam get 5这个不支持很多后来添加的比如remotely connected cd/rom,我是说它输出的时候说flag不正确,我按照ipmi标准修改代码添加了这些新的设备。再比如,对于os启动或者安装是否成功要怎么知道呢?一直以来有人主张使用bios POST code来查询,可是我从这个codebios公司的code,不属于ipmi能够控制的,而且作为bios一旦启动INT19把启动权交给osbootloader他就休息了,他怎么知道os的结果呢?我从server的界面上看到的POST CODE都是相关的硬件的checkpoint code,最后一个就是INT19启动os的。后来使用ipmi sdr查询到了有一个所谓的event onlysensoros,他能够记录os启动的event的。sdr是一个存储的方式,真正查询event的方法是sel命令,按照SK的说法,sdr存储的是thresholdsensor,比如温度,风扇,对于discrete的需要的是assertiveevent所以存储在sel,还可以被过滤使用pet,但是我在sel里只看到了rhel的启动事件,对于ubuntu就没有,看来这个是os需要主动回报给ipmi之类的硬件的吧?总之,每天的信息两太多了,大都忘记了。


九月二十六日 等待变化等待机会

ubuntu的使用上,我以前基本上没有使用vnc的需求,因为大部分都是命令行操作。但是如今我需要打中文字,调解图形界面等等就需要使用vnc了,但是网络上出于效率和安全的种种考虑采取的方式都不是我的需求,比如为了效率使用另一个desktop的界面如xfce等等,为了安全使用ssh等等,但是我因为在自己家里需要的是完全使用当前的x11session,所以,使用x11vnc是最好的。在serverx11vnc -display :0 而在client端: vncviewer server-ip:0

如果对于server端的vnc运行的instance有疑虑可以vncserver -kill :#其中的”#”display number.或者netstat -pant

对于ipmitool的安装需要ipmi_siipmi_devintf,前者如果没有bmc是不能成功安装的。但是如果指定port似乎也能modprobe,但是/dev/ipmi0是无法创建的。


十月三日 等待变化等待机会


libssh2
的使用有一个问题就是在libssh2_init(flag)有一个选项可以让你选择不初始化libcrypto的。这个是必要的因为 OpenSSL_add_all_algorithms不是一个线程安全的函数,而且也不应当被反复调用,这个是初始化被一次性的调用就可以的了。以下的程序说明它会crash.


#include 
#include 
#include 
#include 

void* thread_proc(void* param)
{
	int counter = 100000;
	while (counter > 0)
	{
		OpenSSL_add_all_algorithms();
		counter --;
	}
	return NULL;
}

int main(void)
{
	pthread_t pid[10];
	const size_t thread_size = sizeof(pid)/sizeof(pthread_t);
	for (size_t i = 0; i < thread_size; i ++)
	{
		pthread_create(&pid[i], NULL, thread_proc, NULL);
	}
	for (size_t i = 0; i < thread_size; i ++)
	{
		void* ptr = NULL;
		pthread_join(pid[i], &ptr);
	}
	return 0;
}


编译运行会crash:

[root@rh63-58-110 src]# gcc -g -O0 -std=c99 -lcrypto -lpthread ./openssl-test.c -o openssl-test.exe

[root@rh63-58-110 src]# ./openssl-test.exe

*** glibc detected *** ./openssl-test.exe: realloc(): invalid next size: 0x00007ff8f0000980 ***

*** glibc detected *** ./openssl-test.exe: realloc(): invalid next size: 0x00007ff8f0000980 ***

*** glibc detected *** ./openssl-test.exe: realloc(): invalid next size: 0x00007ff8f0000980 ***

*** glibc detected *** ./openssl-test.exe: realloc(): invalid next size: 0x00007ff8f0000980 ***

*** glibc detected *** ./openssl-test.exe: realloc(): invalid next size: 0x00007ff8f0000980 ***

Segmentation fault (core dumped)

但是这个问题是早就明白的( https://github.com/libssh2/libssh2/issues/61 ),对于libssh2的初始化如果使用libssh2_init(LIBSSH2_INIT_NO_CRYPTO);就可以避免这个问题了。


十月四日 等待变化等待机会

关于boost/asio的行为这个帖子说的非常的好,它的测试和我们的差不多都是使用一个route to sink的方式来模拟network breakdown,但是对于asynchrous callback返回的快慢却大不相同。总的来说,asynchrous write是最大的不同,居然需要15分钟以上才返回,原因是retransmission retry居然有15次。

但是我看到的system设定却不同。

[root@OEL72-59-177 ~]# sysctl net.ipv4.tcp_syn_retries

net.ipv4.tcp_syn_retries = 6

所以我也不明白在那一层设定的,至少 boost这一层我没有看到。


十月八日 等待变化等待机会

关于bootloader非常的费解,始终不太明白。以后再慢慢消化吧。关于razor-server这个东西,我还是吃不透它的原理,它的子系统microkernel的制作我大约是有一个概念,离自己亲手制作还差得很远,不过我有疑问的是为什么一定需要ipxe,我明白它支持很多高级的选择,比如san/iscsi/http等等的方式,可是如果不用这些的话还是pxe就足够了。razor究竟是怎样boot各种各样的os的呢?难道是为所支持的os及其相应的版本写下对应的kickstart script吗?


十月十一日 等待变化等待机会

看了一下mbr的代码,一开始很疑惑完全不明白为什么要处理event,后来才看到说明是说mbr的在模拟dos来实验是否mbr安装成功,实际的install-mbr是很简单的一个东西。

安装centos后想要进入gui,发现在/etc/inittab里说明要设定defaulttarget,就是systemctl set-default graphical.target

然后安装vncviewer实际上是安装tigervnc.x86_64


十月十二日 等待变化等待机会

centos7上安装完openssh-server并不能立刻工作,原因很简单因为/etc/ssh/sshd_config里压根没有设定sshdport。这个实在是有些让人意外,从这也看出了debian的系列安装更加傻瓜。在公司被自己搞笑了,因为我把别人做好的centos7安装iso通过nfs-mountbmc上,结果就忘记了这件事情,因为我的remote-console都不工作,最后发现只有在win8+chromium才可以,其他浏览器和os都不行,这个真的很讨厌,我用我的小程序发现jviewer说有一个127.0.0.1re-direction,现在想来应该就是这个nfs-mountbmc的结果,这个iso是含有kickstart的,因此,当我把启动设定为floppy/removalbe-device之后就开始自动安装centos,然后安装结束再自动重启,于是当我打开remote-console的时候就惊奇发现centos在安装的画面,还以为是别人在测试实在是闹笑话。

使用x11vnc确实的非常的棒,但是当我的client重启后发现server并没有自动退出,于是只能kill这个server.


十月十八日 等待变化等待机会

我可能丢失了一两天的日记,记忆力是如此的差以至于一两天前的事情都很难回忆清楚。我的关于mbr的记忆是这样子的。mbr-install本身应该是简单的不能再简单的工作,因为说到底只有512bytes的结构体,关键是manager的部分,似乎是一个有模拟运行并且更多功能的,这部分我不是非常清楚,但是我失去兴趣的原因是我的ubuntu压根儿就不用mbr,因为gnu的官方是grub2,所以,我转向看grub2了。顺带看到所有的文档是在这里,从文档入手是对于我比较合适的,因为我没耐心没毅力,前场辄止流于表面,看了motivation就停下来了。看grub2的文档自然需要了解multiboot的文档。我发现了一个如此微乎其微的东西,就是虽然grub-legacy不值得再去看,但是multiboot的文档却是存在于grub-legacy里的,这是一个可怜的发现,我只有这种能力了。

编译grub-legacy的时候遇到gcc -V的错误那个是因为老版本的gcc支持-V返回版本,新的用—version(也许这都是因为multilib引起的)但是遇到linker-lgcc_s找不到的问题我其实应该能够猜到是64/32bitlibrary的问题,我本来想要设置grub平台不是i386,但是不成功我自己的ubuntu64位,所以,sudo aptitude install gcc-multilib而我已经学乖了会使用aptitude而不是apt-get因为要降级很多package,这个是我唯一值得记忆的进步。关于objcopyconfigure错误也许是这个可以解决的,我还没有时间实验。(实验了的确行)

if { ac_try='${OBJCOPY-objcopy} --only-section=.text -O binary conftest.exec conftest'

然后编译了multiboot的文档


十月二十一日 等待变化等待机会

应该说fltk是一个相当不错的图形开发包,因为他的设计相当的紧凑,理念也是很多人的心声。一个小插曲是我为了测试把系统的fltkruntime卸载了,结果导致tigervnc也没有了,让我疑惑了好久因为这个vncviewer是基于fltk的实现的。


十月二十三日 等待变化等待机会

有多少人知道linux-vdso.so.1的故事?你随便找一个dso,然后使用ldd看看它所依赖的动态库,我敢打赌十有八九有这个,可是为什么?看看这个文档吧。我还没有耐心看完,就去下载centoskernel doc: kernel-doc.noarch,然后在这里看到两个很有意思的小测试程序parse_vdso.cvdso_test.c,怎么编译呢?注解里有这个:gcc -std=gnu99 -nostdlib -Os -fno-asynchronous-unwind-tables -flto vdso_test.c parse_vdso.c -o /tmp/vdso_test这个有什么神奇之处呢?如果你使用objdump -t /tmp/vdso_test来看的话就发现它没有任何的dependency。输出的结果就是这个date +%s.%6N

使用strace来看看究竟有没有syscall,这个程序输出时间,但是为什么没有关于时间的syscall呢?这里就是关键,为什么需要这种virtual DSO呢?原因是很多的criticalsyscall比如时间需要非常的有效率,而syscall需要int80进行context switch非常的昂贵,所以系统决定把这类syscall变成一个访问内存的快速实现。

strace /tmp/vdso_test

execve("/tmp/vdso_test", ["/tmp/vdso_test"], [/* 59 vars */]) = 0

write(1, "The time is 1508829416"..., 40The time is 1508829416.703105

) = 40

exit(0) = ?

+++ exited with 0 +++

[nick@localhost doc]$


十月二十七日 等待变化等待机会

关于boost/ptree有一个很讨厌的东西就是这个foreach对于空集合会跑出exception

BOOST_FOREACH(boost::property_tree::ptree::value_type &v,res.cJsonbody.get_child("LocalDrives."))

这里有一个关于如何防止的帖子: https://svn.boost.org/trac10/ticket/8465

但是还是比较别扭,最可靠的还是用find,因为我并不需要使用foreach的:

boost::property_tree::ptree::assoc_iterator ait = res.cJsonbody.find("LocalDrives");

if (ait != res.cJsonbody.not_found())

对于snmp我使用nmap来探寻,但是snmp默认使用UDP,所以要使用:

[root@rh63-58-110 ~]# nmap -sU 172.17.59.165

Starting Nmap 5.51 ( http://nmap.org ) at 2017-10-27 16:57 PDT

Nmap scan report for 59-165.sie.hds.com (172.17.59.165)

Host is up (0.00025s latency).

Not shown: 994 closed ports

PORT STATE SERVICE

69/udp open|filtered tftp

111/udp open rpcbind

123/udp open ntp

161/udp open snmp

514/udp open|filtered syslog

2049/udp open nfs


十月三十一日 等待变化等待机会

关于grub启动设置iso livecd来作为急救我以前就做过了,不过现在给一个更准确的设置。其中的ubuntu几乎都一样, 不过10.04和其他不一样的是不支持efi的启动吧?而且,你看到实际上linuxmintubuntu是如出一辙。至于linuxfromscratch的设置和使用isolinux是一样的。所以也没有很么特别的。不过我需要看看除了centos/rehat之外opensuselivecd boot的方法,也许我下载的iso不支持吧?其实我还没有亲自实验过。这些都是/etc/grub.d/40_custom


menuentry "Ubuntu Desktop amd64 10.04 ISO" {
	insmod ext2
	insmod loopback
	set isofile="/media/ubuntu-10.04.4-desktop-amd64.iso"
	search --no-floppy --fs-uuid --set aba502d4-8460-48fb-b9d3-201256d5c410
	loopback loop (hd0,5)$isofile
	linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=$isofile noprompt noeject
	initrd (loop)/casper/initrd.lz
}

menuentry "ubuntu 12.04 desktop amd64 ISO" {
	insmod ext2
	insmod loopback
	set isofile="/media/ubuntu-12.04.5-desktop-amd64.iso"
	search --no-floppy --fs-uuid --set aba502d4-8460-48fb-b9d3-201256d5c410
	loopback loop (hd0,5)$isofile
	linux (loop)/casper/vmlinuz.efi boot=casper iso-scan/filename=$isofile noprompt noeject
	initrd (loop)/casper/initrd.lz
}

menuentry "ubuntu 16.04 desktop amd64 ISO" {
	insmod ext2
	insmod loopback
	set isofile="/media/ubuntu-16.04.2-desktop-amd64.iso"
	search --no-floppy --fs-uuid --set aba502d4-8460-48fb-b9d3-201256d5c410
	loopback loop (hd0,5)$isofile
	linux (loop)/casper/vmlinuz.efi boot=casper iso-scan/filename=$isofile noprompt noeject
	initrd (loop)/casper/initrd.lz
}

menuentry "linuxmint 17.01 cinnamon amd64 ISO" {
	insmod ext2
	insmod loopback
	set isofile="/media/linuxmint-17.1-cinnamon-oem-64bit.iso"
	search --no-floppy --fs-uuid --set aba502d4-8460-48fb-b9d3-201256d5c410
	loopback loop (hd0,5)$isofile
	linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=$isofile noprompt noeject
	initrd (loop)/casper/initrd.lz
}

menuentry "lfs liveCD amd64 ISO" {
	insmod ext2
	insmod loopback
	insmod gzio
	set isofile="/media/lfslivecd-x86-6.3-r2145.iso"
	search --no-floppy --fs-uuid --set aba502d4-8460-48fb-b9d3-201256d5c410
	loopback loop (hd0,5)$isofile
	linux (loop)/boot/isolinux/linux boot=linux iso-scan/filename=$isofile noprompt noeject
	initrd (loop)/boot/isolinux/initramfs_data.cpio.gz
}



十一月二日 等待变化等待机会

关于grub菜单的背景图我以前就玩过一次,后来忘了。其实很简单。

首先在/etc/default/grub里设定GRUB_BACKGROUND="/background.jpg",然后运行update-grub就会自动生成grub.cfg,或者自己要手动添加的话,需要注意这么些:

terminal_output gfxterm

insmod part_msdos

insmod ext2

set root='hd0,msdos3'


search --no-floppy --fs-uuid --set=root 3e00216e-8aa8-4080-a622-3f98ae5921d0

insmod jpeg

background_image -m stretch /background.jpg

对于property tree的使用我伤了很多脑筋,最后这个做法是比较好的,比如,if (pt.get_child_option(path)) strValue=pt.get<string>(path);

参考了一点点代码做了一个简单的xml的示范如下:


#include 
#include 
#include 

using namespace std;
using namespace boost::property_tree;

void indent(int level)
{
	for (int i = 0; i < level; i ++)
	{
		cout << " ";
	}
}
void iterate_ptree(const ptree& pt, int level)
{
	for (ptree::const_iterator it = pt.begin(); it != pt.end(); it ++)
	{
		if (it->second.empty())
		{
			indent(level);
			cout << "<" <first << ">"<< it->second.get_value()<<"first << ">"<< endl;
		}
		else
		{
			indent(level);
			cout << "<" << it->first << ">"<< endl;
			iterate_ptree(it->second, level+1);
			indent(level);
			cout << "first << ">"<< endl;
		}
	}
}

int main()
{
	ptree pt;
	xml_parser::read_xml("/usr/share/X11/xkb/rules/evdev.xml", pt);
	iterate_ptree(pt, 0);
	return 0;
}


}


十一月三日 等待变化等待机会


grub
的代码比较的晦涩难懂,我stuck在那里一动不动。然后出现了一个新的曙光,模糊的我觉得一切的一切应该从qemu入手,这个是不可或缺的工具。这里有一个专题是关于内核的。至于这个简化版我遇到32/64位不兼容的问题,应该是linker编译脚本如何设定为32位的问题。


十一月五日 等待变化等待机会

对于点滴的实践我都需要记录是因为我的记忆力太差了,比如上文提到的编译32位的问题需要这样解决,首先是编译的flag需要-m32这样子gcc才能正确编译,当然前提是在x86_64位系统里有安装multilib,其次是链接的时候需要-m elf_i386,这个才能产生32位的目标。很小吗?可是不知道的话就卡在那里了,除非你想用32位的系统来编译?这个是修改后的Makefile。就在现在我又重新下载原作者的源代码包,发现其实也许是我自己的问题?

我非常急切的使用vnc链接到我的主机来加上这个链接在日记里,因为他看上去对我太有用了,我需要记录下来: http://www.osdever.net/tutorials/


十一月七日 等待变化等待机会

我的目标很简单,就是制作一个能够用qemu启动的磁盘文件,但是目前还没有找到正确的路径,记录一下我目前的点滴:

1.使用dd创建一个raw image,这个应该和qemu-img -f raw是一样的吧? dd if=/dev/null of=linux.img bs=512 count=2048

2。使用fdisk创建分区,这是简单的不能再简单的,可是我的记忆太差了,写下来吧:

a) fdisk linux.img

b) 先创建一个分区,默认是linux,随后在使用t命令修改。n===>p

c)也许应该再创建一个分区,因为bios只认MBRgrub是安装在所谓的boot-sect,就是第一个sector,注意sector0是所谓的MBR,我后来遇到的错误都是抱怨grub-install不能embedding

3. 需要创建文件系统,这个可以直接使用mkfs.ext2 linux.img,但是因为我没有有多个分区,所以,首先我们需要使用devmapper来做(我个人认为直接使用mount -o loop,offset=也可以达到同样的效果,但是计算offset太麻烦了)

4.先用kpartx来创建devmapper,这个部分是我今天完全陌生的部分,但是现在总算明白了一些,就是kpartx -l linux.img是告诉你它打算怎样mapping,大体就是/dev/mapper/loop0p1 /dev/mapper/loop0p2分别mount 我们linux.img里的两个分区。使用-d来删除这样的mount,使用-a 添加。

5. 那么如果你只想把一个分区mount成一个设备而不是directory,应当使用losetup /dev/loop0,不使用任何flag是显示当前的状态,使用-ddetach,所以,当我们把分区mount到了/dev/mapper/loop0p1之后就可以使用grub-install来安装了,不过我在这里失败了。如果我只有一个分区会报错grub不能embedding,如果我有多个分区,我必须先把/dev/loop0 mount 到一个目录,grub-install –root-directory=./mnt/boot –no-floppy /dev/loop0


十一月八日 等待变化等待机会

我依然没有找到真正的解决方案,但是找到了一个办法:自己安装os到qemu的image

先使用qemu-img create -f qcow2 linux.img 1G

然后直接用一个linux的iso来安装: qemu-system-i386 -m 1024 -hda linux.img -cdrom ubuntu-1404_amd64.iso -boot d

内存256M似乎不行,我安装server版直接挂掉了。

下载了一本电子书,看目录相当的不错,不过心里很愧疚没有买正版的,不过有点贵,才两百多页而且大部分是所谓的代码页,所以,还是先看看再说:Learning_Linux_Binary_Analysis.


十一月九日 等待变化等待机会

实际上qemu是一个非常强大的模拟器,至少对于我来说是很好的替代virtualbox/vmware的选择,因为我需要的是简单的测试启动,并不是真正的运行。试图安装ubuntu14qemu的模拟磁盘上,但是确实是很慢。而且磁盘3G都不够。匆匆浏览fdisk的帮助文档,我觉得所谓的mbr部分是很简单的部分。我找到一个非常好的关于链接的文档

我有时候觉得我很无理,我为什么要费那么大麻烦要用x11vnc链接到服务器去打开writer来编辑这个日记,而我可以很简单的nfs mount文件到本地来编辑?这个难道我之前没有想到吗?一个小技巧是关于选取第一列who am i|tr -s ' ' | cut -d' ' -f1

安装qemu的磁盘的确非常的慢。我找到了这篇文章似乎是比较可信的,因为和我目前收集的流程相似,不过使用parted比fdisk来说脚本更容易一些。

parted --script mink.img mklabel msdos mkpart p ext2 1 20 set 1 boot on

这个很容易从manpage里找到,不确定的是size 1-20是lba吗?就是第一个sector到第二十个sector?

记住了dd是不能从/dev/null读的,这个只能写,需要从/dev/zero来读!

当我远程登陆后有时候执行命令会遇到类似这样子的: fdisk 是在/sbin而你的路径没有包含等等,而我本地启动的shell则没有这个问题,很明显的是non-login的shell的环境不对,查看$PATH果然不全。原因在这里, 怎么解决呢?不是很清楚,我查看了etc/environment发现路径则这里定义了,但是/etc/bash.profile因为查看是否为login-shell---

# If not running interactively, don't do anything

[ -z "$PS1" ] && return

所以,我就在这之前加上了source /etc/environment,我觉得这个改动比较安全,因为environment里仅仅定义了一个PATH没有太大的风险。


十一月十一日 等待变化等待机会

对于kpartx -d img出错说device busy的时候,使用这个办法找到访问的进程号:

sudo dmsetup ls 找到比如lurks_process_xxx(252:1) 然后使用lsof | grep 252,1

现在完整的流程是这样创建一个qemu可以启动的linux镜像文件。最简单的是只可以linux启动的单partition既没有msdos在第一个分区,这个是最简单的,如果需要windows也能启动的只不过是创建第一个msdos分区。

1.创建磁盘文件。可以使用qemu-img create也可以直接使用dd if=/dev/zero of=output.img bs=1M count=1K

2.创建分区。可以使用parted也可以使用传统的fdisk。比如parted --script mklabel ubuntu mkpart p ext4 1 100 set 1 boot on

使用fdisk可以直接创建一个默认的0x83linux分区:n,p,1,return,t,0x83,w

3.mount分区并创建设备文件为安装bootloader作准备。可以使用kpartx,也可以直接使用losetup -o,offset=,但是使用kpartx是很方便的不需要自己计算偏移。kpartx -av img,结果是为每一个分区创建了类似/dev/mapper/loop0p1的设备。

4.创建文件系统。使用mkfs.ext4等等工具对于Mount的设备就可以了。mkfs.ext2 /dev/mapper/loop0p1

5.安装grub。这里有两重工作,一方面grub-install需要访问磁盘设备安装自己的bootsector,另一方面需要访问磁盘启动分区的文件系统拷贝内核文件及其启动配置文件等等。所以,一方面你要有Mounted设备/dev/loop0(注意不是分区设备,是磁盘设备,比如/dev/mapper/loop1p2实际上代表了磁盘/dev/loop1的第二个分区,所以作为grub-install需要的参数是/dev/loop1),同时要mount相应的分区来拷贝。因此,创建mount point: mkdir mnt && mount /dev/mapper/loop1p2 mnt

我不确定grub-install是否会自己创建目录,所以我索性自己创建(注意root-directory的路径必须是绝对路径,相对路径会被加上/就大错特错了):

mkdir -p mnt/boot/grub/i386-pc

然后安装grub-install -v –no-floppy –root-directory=$PWD/mnt /dev/loop1

注意grub-install很不友善报错不及时,所以-v很有用。

6.你需要一个linux的distribution,通常我们使用debootstrap,在ubuntu下下载stage1就可以了。

debootstrap trusty build

至于stage2我觉得我只需要chroot去修改密码就行了,配置网卡等等我还没有实验过。

7.需要kernel,我投机取巧直接debootstrap了我当前的ubuntu的版本所以使用我自己本地的kernel就可以了。比如cp /boot/vmlinuz_xxx mnt/boot && cp /boot/initrd_xx mnt/boot

8.获得partition的uuid。blkid可以获得,目的是免除device.map的繁琐,因为设备加载的scsi设备顺序不是保证的,在下一步中有用。

9.创建grub.cfg。这个是我的一个简化到几乎最简单的模板:(其实还可以简化,也许我根本不需要msdos模块,为了加载一幅范冰冰的照片作为启动背景我们加载了jpeg,所以,要拷贝jpg文件到mnt/是最简单的做法。不过现在背景不工作还要修改)


insmod part_msdos
insmod ext2
insmod jpeg
background_image -m stretch /background.jpg
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-50e4cd30-c12d-4308-b51b-7333f6c7e1d5' {
	insmod gzio
	insmod part_msdos
	insmod ext2
	#set root='hd0,msdos2'
	#search --no-floppy --fs-uuid --set=root 50e4cd30-c12d-4308-b51b-7333f6c7e1d5
	linux /boot/vmlinuz root=UUID=50e4cd30-c12d-4308-b51b-7333f6c7e1d5 ro
	initrd /boot/initrd
	boot
} 


现在实验结果已经出来了,这个几乎是最精简的了:

首先使用blkid找出qemu的image的partition的uuid,其次拷贝你想要的background.jpg文件到mnt/boot下。然后以下就是我的grub.cfg:


search --no-floppy --fs-uuid --set=root 50e4cd30-c12d-4308-b51b-7333f6c7e1d5
insmod ext2
insmod jpeg
insmod video_cirrus
insmod gfxterm
terminal_output gfxterm
background_image -m stretch /boot/background.jpg
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-50e4cd30-c12d-4308-b51b-7333f6c7e1d5' {
	insmod gzio
	linux /boot/vmlinuz root=UUID=50e4cd30-c12d-4308-b51b-7333f6c7e1d5 ro
	initrd /boot/initrd
}


我现在唯一不确定的是video_cirrus是否因为我的笔记本的显卡相关,还是jpeg相关?

然后接下来的就是chroot到你的image在mount的目录下去设定root的passwd。

目前我还没有明白怎样设定网卡。


十一月十二日 等待变化等待机会

同样的你可以按照以上步骤制作usb的启动盘。

1.使用fdisk创建多个partition,我创建了msdos和两个linux partition,但是设定linux的为启动盘符。

2.同样使用kpartx来创建多个盘符,这里我犯了一个错误,因为usb工厂设置是一个msdos的分区,所以,在linux上被自动加载为/dev/sdb1,但是作为整个设备需要使用的是/dev/sdb,所以kpartx -av /dev/sdb而不应该添加1在末尾,可是kpartx很聪明照样正确的map/dev/mapper/sdb1,2,3

3.同样使用mkfs.xxx来创建各个文件系统mkfs.ext4 /dev/sdb2

4.同样的要把分区mount以便拷贝grub启动文件,同样的grub-install来安装。

5.同样的拷贝linux的文件系统。设置正确的grub.cfg

所以,这个就是以前我看到别人怎么制作的linux


十一月十三日 等待变化等待机会

现在终于成功设定了qemuimage的网卡。

sudo qemu-system-x86_64 -m 2048 -device e1000,netdev=eth,mac="52:54:00:00:00:01" -netdev user,id=eth,net=192.168.1.0/24,dhcpstart=192.168.1.9 -hda /dev/sdb

启动后,我在dmesg里看到了e1000的设备创建,然后我在/etc/network/interfaces里设定如下:


auto lo
iface lo inet loopback
# The primary network interface
auto eth0
iface eth0 inet dhcp
address 192.168.1.9
netmask 255.255.255.0
network 192.168.1.0
broadcast 192.168.1.255
gateway 192.168.1.1

这里的解释说明了为什么host不能访问guest qemu. 实际上qemu有一个内置的dhcpserver,所以这就是为什么我的网络并无法看到qemu内的os。使用nmap -Pn 192.168.1.9可以看到系统是up,但是所有的packet都被丢弃了。


十一月十五日 等待变化等待机会

上个星期在工作中亲眼看到了计算机里的所谓的thrashing的现象。如果一台服务器对于一个请求能够在5秒内处理完毕返回,并发二十个请求结果所有的结果都延迟十倍,最后几乎是同时在60秒内返回,总体上快了,但是用户是不能接受的。


十一月十六日 等待变化等待机会

ipmitool能否使用g++编译呢?这么作的原因是我要实现一个fru的查询函数,而不是简单的打印,现在就明白为什么原来没有实现查询而是打印,因为那个数据结构太复杂了,没有map,vector,string的时代是多么痛苦,我被迫去实现一个linklist来模仿vector,当然后来和吸血鬼聊天才意识到dynamic array的实现更容易,尤其是你不需要插入,排序的话。所以,在我实现了一半我的链表后我实在是受不了了,因为strdup,strcat都要反复的free,否则内存就泄露了。所以,在configure里设定CC=g++,但是-std=gnu99只能在configure里hardcode为-std=gnu++98。然后我遇到这个错误:error: 'INT32_MAX' was not declared in this scope,这个是因为必须在#include <stdint.h>前定义这个宏:#define __STDC_LIMIT_MACROS而且必须在这个include之前。类似的关于这个错误:error: expected ``)' before 'PRIu64'这个必须定义这个宏#define __STDC_FORMAT_MACROS

在#include <inttypes.h>

关于使用ipxe远程启动需要设定dhcp,/etc/dhcp/dhcpd.conf

allow booting;

allow bootp;

subnet 192.168.1.0 netmask 255.255.255.0 {

range 192.168.1.226 192.168.1.226;

option broadcast-address 192.168.1.255;

option routers 192.168.1.1;

option domain-name-servers 192.168.1.1;

}

INTERFACES="eth0"; ## 这个防止错误没有interface设定

next-server 192.168.1.115; ## 这个是tftp server的ip

if exists user-class and option user-class = "iPXE" {

filename "nfsboot.sh";

} else {

filename "ipxe.pxe"; ### 编译的时候在general.h设定nfs。

}


option space ipxe;

option ipxe-encap-opts code 175 = encapsulate ipxe;

option ipxe.priority code 1 = signed integer 8;

option ipxe.keep-san code 8 = unsigned integer 8;

option ipxe.skip-san-boot code 9 = unsigned integer 8;

option ipxe.syslogs code 85 = string;

option ipxe.cert code 91 = string;

option ipxe.privkey code 92 = string;

option ipxe.crosscert code 93 = string;

option ipxe.no-pxedhcp code 176 = unsigned integer 8;

option ipxe.bus-id code 177 = string;

option ipxe.san-filename code 188 = string;

option ipxe.bios-drive code 189 = unsigned integer 8;

option ipxe.username code 190 = string;

option ipxe.password code 191 = string;

option ipxe.reverse-username code 192 = string;

option ipxe.reverse-password code 193 = string;

option ipxe.version code 235 = string;

option iscsi-initiator-iqn code 203 = string;

# Feature indicators

option ipxe.pxeext code 16 = unsigned integer 8;

option ipxe.iscsi code 17 = unsigned integer 8;

option ipxe.aoe code 18 = unsigned integer 8;

option ipxe.http code 19 = unsigned integer 8;

option ipxe.https code 20 = unsigned integer 8;

option ipxe.tftp code 21 = unsigned integer 8;

option ipxe.ftp code 22 = unsigned integer 8;

option ipxe.dns code 23 = unsigned integer 8;

option ipxe.bzimage code 24 = unsigned integer 8;

option ipxe.multiboot code 25 = unsigned integer 8;

option ipxe.slam code 26 = unsigned integer 8;

option ipxe.srp code 27 = unsigned integer 8;

option ipxe.nbi code 32 = unsigned integer 8;

option ipxe.pxe code 33 = unsigned integer 8;

option ipxe.elf code 34 = unsigned integer 8;

option ipxe.comboot code 35 = unsigned integer 8;

option ipxe.efi code 36 = unsigned integer 8;

option ipxe.fcoe code 37 = unsigned integer 8;

option ipxe.vlan code 38 = unsigned integer 8;

option ipxe.menu code 39 = unsigned integer 8;

option ipxe.sdi code 40 = unsigned integer 8;

option ipxe.nfs code 41 = unsigned integer 8;

option ipxe.no-pxedhcp 1;

我在tftp serverde 路径设定了我的启动脚本:/var/lib/tftpboot/nfsboot.sh

这种菜单是我发现最可靠简单的。

#!ipxe

set boot-url http://192.168.1.115

set iso-file current.iso

set ubuntu-nfs /BigDisk/ubuntu-14.04

:menu

echo 1 kernel_http ubuntu (Memdisk) [1]

echo 2 kernel_tftp ubuntu (Memdisk) [2]

echo 3 initrd_chain ubuntu (Memdisk) [3]

echo 4 sanboot_one_line ubuntu (SANBOOT) [4]

echo 5 imgargs_memdisk ubuntu (Memdisk) [5]

echo 6 kernel_nfs ubuntu (nfs) [6]

read choice

goto menu_${choice} || goto menu

:menu_1

kernel memdisk

initrd ${boot-url}/${iso-file}

imgargs memdisk iso raw

boot || shell

:menu_2

kernel ${boot-url}/memdisk iso raw

initrd ${boot-url}/${iso-file}

boot || shell

:menu_3

kernel memdisk iso raw

initrd ${boot-url}/${iso-file}

boot || shell

:menu_4

initrd ${boot-url}/${iso-file}

chain memdisk iso raw || shell

:menu_5

sanboot --no-describe ${boot-url}/${iso-file} || shell

boot || shell

:menu_6

kernel nfs://192.168.1.115${ubuntu-nfs}/casper/vmlinuz.efi || shell

initrd nfs://192.168.1.115${ubuntu-nfs}/casper/initrd.lz || shell

imgargs vmlinuz.efi initrd=initrd.lz root=/dev/nfs boot=casper netboot=nfs nfsroot=192.168.1.115:${ubuntu-nfs} ip=dhcp splash -- || shell

boot || goto menu


sanboot可以直接boot iso,但是livecd看样子需要更多的支持,所以,你要把pxelinux的memdisk拷贝到tftp,或者你设定一个http server,放在那里,http比tftp快的多。

关于initramfs 和initrd的解说真好,看来关于linux的解析最适合我的是lfs,因为从实做开始,有代码有真相!主要是看代码最准确。


十一月十八日 等待变化等待机会

在编译ipmitool的时候经常遇到一个错误就是抱怨jump to label之类的,大多是case语句,看起来没有什么错误,后来注意到在case里声明临时变量这个在c99/gnu99里是合法的,可是c++98/gnu++98是非法的,必须加上一对{}。另一个头疼的地方是gnu99的extension就是结构的初始化允许指定成员的初始化,比如:struct MyStruct my={.version=”first”,.data=0};这个在c++里不行,我也想不出来什么好办法。还有一个小细节是bit-operator |=之类的,当lhs是一个enum,rhs是int的时候简单的把lfs cast为enum似乎不行,应该是operator的特点吧?首先|=是一个纯粹的int的操作,但是赋值的时候又需要cast,所以我只好把这个enumValue|=intValue拆解成enumValue=(enum EnumValue)(enumValue|intValue);

关于chroot,switch_root,pivot_root的异同比较难以理解,而且这个东西也有相当大的危险性需要明白清楚才行。目前的说法是initrd使用pivot_root,而initramfs使用switch_root因为前者是真正的文件系统,后者不是。我听说前者是有确定的blocksize,不能再扩展,后者则更灵活。


十一月十九日 等待变化等待机会

关于initrdinitramfs的异同有多个层面的讨论。

1.编译内核的过程的讨论,这个是纯粹实际操作者的探索与观察。从Kernel config的角度看,两者要么都被enable,要么都不行。他们的形态在早期是纯粹的文件系统的映像,但现在都是cpio的格式,这个实际上也说明需要依赖于某个基本的文件系统的支持,通常ext2。另一个有趣的观察是initramfs实际上可以成为内核的一部分,就是直接编译进内核,而不需要单独的initrd,这个也解释了有些distribution可以不携带initrd,因为他们直接就编译在一个内核文件了,作者展示了默认的initramfs的代码,就是创建一个/dev/console的设备和一个/root目录,这个是最最简单的文件系统?这里也侧面说明了initramfs是一个和initrd不太一样的地方,因为前者是内核的一部分。

2那么从功能的角度来解释为什么有了initrd又创造了initramfs,这个帖子的问题首先说明了历史的原因,就是initrd的实现是依赖于ramddisk,(而近期我在实验ipxeboot的时候反复听到有人提到memdisk比较的耗费内存,这个也得到了解释)而这个设备是模拟block,但是在linux里的cache机制导致复制了一份内容,所以,浪费内存的由来在这里。帖子的问题提出引述了当年Linus的一个天才设计,把cache mount成为一个文件系统,这个就是initramfs的后面的tmpfs的由来。所以这个设计是非常的精巧的,在没有触动原来cache系统代码的情况下把cache自己作为一个文件系统,省去了复制的部分。而且回答者还指出这个机制也是实现共享内存的方式。这里的第一篇回答着重从文件系统组成来解释:VFS作为所有文件系统的抽象层始终都是最高一层,下面是具体的文件系统的实现层,最下面是实现文件系统的具体设备驱动层。VFS主要就是三个接口,inode是文件和目录的数据结构,dentry是目录里包含文件子目录的结构,file是真正的文件的打开读写关闭的接口。这里面有三种不同的objectcacheinode/dentry/page,最后一个是文件内容的cache,作者着重介绍了page cache,那么tmpfs是怎么实现的呢?我还没有看懂,否则这个天才的设计也不会是在linux一开始就有的,还是需要再学习的。总之它是文件系统应该做的最最简单的东西。

3.另一个回答者着重从linux kernel boot的过程来回答两者的异同,initrd是文件系统的镜像因此需要文件系统的驱动模块才行,而initramfs的驱动是kernel必须自带的,是tmpfs,是内核的一部分,所以两者的mount的方式是不同的。前者仿佛是创建了一个ramdisk的设备,然后使用dd直接写到设备,这个无疑就是任何block device的做法,可以明白为什么既慢又有缓存的重复。而后者不然,是类似于这样mount -t tmpfs nodev /root然后可以直接的解压缩cpioarchive,所以这里不需要明显的设备文件。

几个作者从不同的角度阐述initrd和initramfs的异同揭示了很多内核和操作系统的深层次的机制,并且给人对于早期启动过程一些深层次的演示让人有耳目一新的感受。(我是不是写的像小学生的中心思想和读书心得?)

我现在学习的方式基本上就是看文档,因为内核代码对我来说还是有些超前,阅读内核文档有一个高层面的认识还是没那么困难的。


十一月二十一日 等待变化等待机会

搜到了一个非常全面的关于elf的资料不敢私藏贡献给大家。写的非常的棒,我看了汗颜。工作上的记录是同事写的,我需要验证一些细节。


十一月二十二日 等待变化等待机会

其实我的打印机很容易配置,他们现在都自己提供一个dhcp服务器,并且在配置时候发出一个固定的ssid,这个dhcp server ip是固定的192.168.223.1,所以,我如果连入这个网络就可以登陆配置wifi密码。我以前做过就忘了。


十一月二十四日 等待变化等待机会

学 习的过程看代码是终极的解决方法但是也是最困难的选择,所以对于能力不够的时候还是从文档开始,但是我们也常常听说当能力绰绰有余的时候也选择从文档开 始,我的猜测是程序员写的文档有时候是非常的干货,很多精微奥妙的部分用文字来解说精微奥妙的代码部分,所以节省了看代码的时间,因为代码往往比文档多很 多,当然也有反例。不过对于我来说,我是看不懂内核的代码,只能看文档来理解,在文档里给了一个入门的在线书。我以为我的想法应该是可以的,就是传统的initramfs是一个临时的在内存中的临时文件系统帮助启动,但是并没有什么能够阻止你能够让他成为一个真正的文件系统,当然用途是一个非常的值得讨论的问题,也许这个在企业用户使用专业存储的情况因为操作系统部分完全不需要频繁的变更,比较适合这个情况。但是当我简单的使用cpio把操作系统制作成initramfs启动失败了。需要再学习。这个文档给你很多经典的资料

我很多时候感觉就是在一个无边无际的荒野上游荡,因为linux的世界是一个如此浩大的天地,任何一个小小的领域都是一片海洋,我偶尔拾起沙滩上的贝壳就欣喜不已了。


十一月二十六日 等待变化等待机会

找到一篇论文是关于linux boot的前世今生,原文在这里,我为了方便改成了pdf


十二月三日 等待变化等待机会

回到了中国,第一天转机时差睡不着,搜到了一个关于u-boot的博客,以后看看去。

重新编译fltk发现它依赖libxi-dev这个是x11extension


十二月四日 等待变化等待机会

关于Linux bootloader的前世今生写的真好啊。此论文虽然是2000年写成,但是今天很多依然是如此的深刻与准确。让我摘要如下也算是学习心得吧。首先一个问题就是bootloader是否是filesystem-awareness,这个是我以前从没有想过的问题,而此文娓娓道来不但说明了历史,还说明一些必然的道路。这一切都来自于linux kernel的历史,当Linus1.0版内核写成的时候,它只能使用Minix文件系统,而很自然的shoelace就成为默认的bootloader,可是shoelace只能启动Minix文件系统,但是问题是难道Linux将来就只能使用在Minix文件系统吗?Minix本身有一些缺陷比如文件名最长只有14个字节?但是当时的有力的竞争者还有ext2文件系统和其他,究竟谁是赢家当时并不清楚,于是Lilo就是一个合适的人选,因为Lilo本身并不了解文件系统,它需要依赖与Linux kernel的帮助来把一些文件作一个映射,这个一开始在我看来filesystem-unawarenessbootloader是一个不足,没想到这里反而是他的优势,因为在未来的linux使用的文件系统不确认的情况下Linux Kernel使用Lilo是一个明智的选择,因为它的很多代码不会因为后来采用EXT2文件系统而过时。我一开始有一个错误的认知觉得一个bootloader不了解文件系统而依赖于kernelload kernel岂不是鸡蛋和鸡的悖论吗?后来才意识到我们讨论的文件系统的依赖都不是在第一次安装发生的,首先操作系统是要安装好了才安装bootloader,它完全可以使用kernel的文件系统的驱动把它需要的文件比如kernel/initrd等等映射成一系列的readlist,这些都是为了再次启动的时候boot才需要的。因此这个在我看来并不是什么很不方便的,当然一旦更新内核文件或者其他配置需要重新运行Lilo的所谓的mapper重新运行配置了。这个虽然是其他如grub之类的filesystem-awarebootloader的长处但是这个绝对是有代价的,因为这些bootloader更像一个小型的OS,所以,这里你就深刻认识到所谓的grub启动的命令行ls显示文件系统的能力啦。另一个明显的议题就是i386的局限性与特殊性,这个非常的自然因为第一版的linux kernel只能支持i386,而这其中的各种各样的令人怒不可遏的东西真的不少,首先很多的限制都来源于历史,早期intelcpu是比i386还早的i286,那个时代是所谓的16位的寄存器“实模”时代,就是在i386保护模式以前的模式,intel因为为了兼容早期的程序因此cpu一上电首先是进入16位模式,也就是说内存地址最多只有4+16=20bits也就是1M,这个是cpu导致的并无法可以依赖于bios来配置,而这一点我一开始也不太理解想着既然Intel允许你改变寄存器进入保护模式不就是几行汇编就可以的为什么成为限制呢?后来才意识到这所谓的汇编不就是你bios最先load进内存的那些bootloader自己吗?如果cpu要兼容i286模式bios也是要兼容的,它也只能按照cpu的模式只能把bootloader本身load1M内存以内才行吧?否则cpu/bios两个如果不是手拉手要怎么运行正确?这里引出了古老的linux内核的两个形式zImagebzImage,前者现在在嵌入式系统还是广泛使用的,他的特点就是大小才不到512K,因为1M内存并不是全都给你kernel的,0-512K给了mbr和一些video mode等等,应该还包括bootloader本身,那么zImage是可以自解压并且进入保护模式使用超过1M内存限制的,它把自己解压缩到1M以上才跳转到那里开始运行。它的优点我的理解就是小而快且兼容早期的bios,对于内存宝贵的嵌入式是受欢迎的,可是512k实在是太小了,而且就算内核自己小你也限制了initrd的大小啊,而且cpu导致的1M内存限制并不是全部还包括bios因为兼容i286实模的限制,对于bzImage来说它是把自己load到了1M以上才开始解压缩,我的理解是需要或者改变cpu进入保护模式或者使用特殊的bios的内存拷贝函数,而限制就是在这里因为这些特殊函数兼容i286实模导致bios能够使用的最大内存是16M,所以意味着内核和initrd不能超过这个限制,内核也许够了可是initrd要多大是个很大的问题。不过bzImage是远远比zImage512K限制好太多了所以几乎都是这个形式了。这里才让我明白了内核编译目标里的zImagebzImage的前世今生。这里作者介绍了一个著名的关于i386架构下的惊心动魄的操作,而这一切的目的就是为了增加512K内存的使用,bzImage首先被load1m内存上去作解压缩,有意识的读者一定会说那么bzImage自身所占用的内存岂不是被浪费了吗?可惜这个读者我不是因为我压根儿想不到这一层,而内核开发者想到的是更多,首先,bootloaderlinuxsetup sector装载到0x90000地址,并且把bzImage装载到1m地址,(这里是如何做到的呢?是改变为保护模式还是使用bios的特殊拷贝函数呢?)我的理解是linuxboot sector自身有能力去改变保护模式或者调用bios函数把内存拷贝到1M以上,这个就是bzImage被装载到1M内存的原因,然后在bzImage里有一小部分未压缩的extractor代码,功能就是自解压缩,但是惊险的在于为了增加512K内存,这个解压缩是从512K地址开始到1M,然后再接着从bzImage结尾地址继续,这样子就增加了512k内存,当然分段的内存是不能正确执行的,于是解压缩结束的时候还需要把内容连接成连续内存。应该是把一小段mover函数放到了4k内存处然后把512K-1M的那部分移到1M内存处,在把bzImage后面的解压缩的内容拼接过来,最后在跳转到1M内核起始处来开始执行内核。这个惊险吧?为了减少512K内存的使用耗费了多少心血啊?

那么历史上是谁吵吵着引入initrd这个怪兽的?为什么需要这个庞然大物呢?这是因为早期的硬件驱动的困难之处,很多时候内核吃不准硬件是什么,只能探索着往一些寄存器写东西看看有啥反应,但是很多时候也许就把硬件搞乱了,而也许有时候确实需要把硬件reset再 启动来看更可靠,这些在硬件驱动领域的困难历程让人们很多时候编译大量的不同的内核每个也许只有很少量的驱动,因为很多时候不同的设备驱动彼此冲突,而一 个明显的解决方案是所谓的内核模块,这个道理很简单,你不能因为突然发现某个设备不能正常加载驱动就去重新编译整个内核,这个很多时候既危险也很困难,因 为编译内核的环境相当的复杂,而且相当的慢,最致命的是一旦失败有可能系统crash,而单独的可加载模块就算失败也不至于让整个内核失效。可是如何携带这么多的动态可加载的模块呢?这个当然就是Initrd的由来原因。它本身就是一快连续内存数据,memdisk能够把它创建为一个block设备在内核看起来是一个在内存中存在的磁盘设备,因此内核就可以运行在这样一个临时小OS里作更复杂的事情了,甚至于这个临时的系统也可以成为正式的系统如果你想要通通运行在内存中,这个是不是livecd的做法呢?当然了在作者写作的年代2000时候还没有initramfs出现,这个是后话。当然更直接的原因还是作者说的好,这个是一个鸡蛋和鸡的悖论,因为使用模块是需要文件系统的,因为很明显的每个模块都是一个文件,他们如何被调入内存如何运行是文件系统的责任,可是创建initrd的一个重要原因就是在文件系统建立之前帮助创建它,那么谁走先呢?细节就是创建一个/dev/initrd的磁盘设备把那一片连续内存当作一个磁盘文件系统的镜像。

引入initrd就引入了另一个高难度的杂技,作者形象的比喻为怎样站在地毯上来换地毯,注意这个不是飞毯啊。为什么呢?因为initrd的 使命就是在完成了各种复杂任务后建立真正的文件系统并且从当前的临时文件系统无缝的转移到新的文件系统,这个难道不是更换地毯的比喻吗?为什么这么难呢? 首先,每个可执行程序包括它依赖的库都是从当前文件系统的文件映射到内存的,如果更换当前文件系统,皮之不存毛之焉附?其次,基本输入输出和错误是不可或 缺的三大文件,被console广泛使用的这三个stdout/in/error怎么办?还有mount point和被service or daemon使用到的current directory怎 么办?这些问题看来都不是普通程序员所需要考虑的。不容易的工作啊。关于换地毯有两种方式一个是跳在空中然后把旧地毯抽走再同时把新地毯塞在脚下,褶皱的 部分随后再磨平。另一个相对难度小的做法是大多数家庭妇女都采用的就是把新地毯和旧地毯并排卷起来,一个收一个放,收多少放多少,还能回滚,还可以反复 来,这个方法好吧?事实上change_rootpivot_root就是这两个的活写真。前者粗暴的把旧的文件系统umount然后mount新的,但是如果遇到旧的正忙失败很有可能就让整个系统失败了。而后者可以逐步转移,同时新旧系统都还在还可以回滚或者多次反复调用。


十二月五日 等待变化等待机会

病了一场,最后一部分没有写完。不过也没有很多可以写的了。其中linux boot linux比较的新奇,就是说在一个linux系统里再去启动另一个linux,具体的应用是什么呢?作者的意思是有很多的情况是非常复杂的,也许一次boot并不能完成而需要多次。

也许有人说这些陈芝麻烂谷子有什么意义呢?看看这里关于android的启动文件就知道了。这对于你理解不是很有帮助吗?

这个文档很好是关于boot


十二月七日 等待变化等待机会

玩一个流行的小游戏2048产生了好奇,想自己动手做一个,因为看起来实在是再简单不过的了。最容易的是使用fltk,可是再怎么样也是一个图形库,也许比sdl简单可也是一大堆的东西,即便我以前有半吊子的图形基础还是遇到了一堆的问题,尤其fltk的特点是把widget都装在父window的一个所谓的group里,我在一个循环里放了两层的控件,结果互相遮挡,这个对于我来说是相当的意外的,只好分成两个循环。然后滑动块让我彻底失去了耐心,就放弃了。术业有专攻,图形界面是计算机界的外门武功,我大部分时间练内功,对于这方面是生疏的很,等再老一点才研究吧。


十二月八日 等待变化等待机会

我一直想好好学一下汇编,不是为了装逼,至少不是纯粹而是经常debug遇到障碍开始怀疑代码的时候想看看gdb里的汇编码,不过始终没有耐心,知道个皮毛就丢掷脑后,这一次是因为看mbrx86的汇编,非常的短却还是看的不太明白,主要是一些directive不甚了了,比如.(dot)directive,现在明白大体上就是.org,这里有一个非常好的初级入门,很体贴的解释几乎一切,不把你当作内行来看待的粗鲁的解释的那种。而我其实最需要的就是gas,也就是gnu as,这个对于帮助读懂inline assembly很有帮助,这个也是我的另一个主要动机,这里似乎是gnu as的文档,可是为什么使用的是at&tsyntax?作者自己也说gnu使用的是nasm,这里我是没有读懂他的意思。现在似乎明白了一些,因为所谓的gnu as or GAS实际上是一个家族的汇编器,就是说有很多的平台的汇编器集合在一起,当然他们都要遵守一些共通的原则,所以,应该才有不同的语法吧?再读才发现作者解释的很清楚我的英文似乎经常开溜,明明说了gas接受多个语法,只不过inline assembly使用的是at&t的语法。这里有关于attintel汇编的异同

以前改古老的c的代码文件时候经常被编译器抱怨说文件结尾没有换行符,虽然是warning可是总是觉得有些莫名,这里解释的很清楚了,这个部分的文档活脱脱就是汇编器实现部分的语法定义:文件头是可以作为statement的分割,但是文件尾是不行的,必须要有换行:newline

其实我花了一早上看汇编仅仅就是为了理解mbr的这个小小的汇编码,也就是mbr的定义而已,但是也是他的一个核心内容。

1.table.S86这个x86的汇编描述了一个512bytembr结构吧.

2. .org 0这个说的是起始须从0

3. dw 0 这个我一直感到有些不踏实,虽然一眼就明白是pad 0,但是找定义没有找到。原因是倒过来的,因为下面一句.space实际上可以填0,当然这样做保险。

4. .space 0x1be-2这个就是著名的partition table的起始位置。

注释里给出了partition table的结构

! 00 byte Boot indicator

! 01 byte start head

! 02 byte start sector

! 03 byte start cylinder

! 04 byte type

! 05 byte end head

! 06 byte end sector

! 07 byte end cylinder

! 08 dw sectors before partition

! 0c dw sectors in partition

看上去很简单,但是以下是我在mc里实际看到的来对比一下:

000001B0 00 02 90 C7 │ 12 00 80 00 │ 00 00 00 00 │ A8 01 80 21

000001C0 03 00 83 6B │ EE FD 00 08 │ 00 00 00 D8 │ 77 00 00 00

000001D0 00 00 00 00 │ 00 00 00 00 │ 00 00 00 00 │ 00 00 00 00

000001E0 00 00 00 00 │ 00 00 00 00 │ 00 00 00 00 │ 00 00 00 00

000001F0 00 00 00 00 │ 00 00 00 00 │ 00 00 00 00 │ 00 00 55 AA

这里还有一个小技巧,在ubuntu下使用midnight commander(mc)如何copy呢?我首先把terminal最大化,然后在菜单里的edit/select all之后copy再粘帖到gedit里面很棒的,可惜我再次copy到html编辑器就走样了。

注意以上地址是1be-2也就是高亮部分01就是说boot enabled,这个就是你使用fdisk设定的?(我怎么觉得这个partition table和mbr是毫无关系的?我肯定是胡说吧,需要作实验才知道。)然后是head(80)sector(21)cylinder(03),

我的fdisk的输出如下:

Device Boot Start End Blocks Id System

/dev/sdb1 * 2048 7856127 3927040 83 Linux

所以我需要知道chs的计算方法,究竟2048byte是怎么转换成chs的?这个是一个非常简单的问题,可是我忘了。

我无法解释观察到的问题,究竟这个partition table的偏移是怎么算出来的呢?而且我开始怀疑1be-2的位置,因为type83对应的是linux这个似乎多了一个byte的偏移?2048=32*64说明head应该是32=0x21但是sector应该为0而不是0x03所以怎么也对不上。也许我需要一个正确安装了的mbr来实验。

事实证明我是瞎折腾,我把我的usb的512byte清零,然后重新install-mbr结果partition完全是空的。

事实上看install-mbr的代码它也根本没有能力去读取partition table,你倒是可以提供一个参数文件知名partition table的情况。那么是谁写了partition table呢?当然是fdisk了,我使用fdisk之后结果就是以上。所以,我需要看fdisk的代码,顺便说以下,这个包是util-linux


十二月九日 等待变化等待机会

害的我花了一整天的东西就是我又做了一回我自己的所谓的”English Programmer“的毛病,我以前一个老同事我那时候年轻气盛就老是讥讽他看不懂代码唯一能读懂的是代码里的注释,我就给了他这么一个标签,没想到今天我自己栽在自己挖的坑里了。mbr的代码压根不懂的partition table,至少在它写mbr的这个sector的时候,(当然mbr的那个loader的汇编码应该要懂得怎么解读的,所以,要回去看它的loader的汇编。)(现在回过头来看mbr的注解有什么错?第一个就是boot indicator,是我自己看花眼了还怪别人!)install-mbr的代码压根就不触碰partition table的,而且我仅仅依据作者的注释就去瞎琢磨,结果怎么都对不上,因为少了一个paritition的状态参数,通常0x80ACTIVE,我现在去读真正写paritiontablefdisk的代码才看到真正的定义如下:

struct partition {

unsigned char boot_ind; /* 0x80 - active */

unsigned char head; /* starting head */

unsigned char sector; /* starting sector */

unsigned char cyl; /* starting cylinder */

unsigned char sys_ind; /* What partition type */

unsigned char end_head; /* end head */

unsigned char end_sector; /* end sector */

unsigned char end_cyl; /* end cylinder */

unsigned char start4[4]; /* starting sector counting from 0 */

unsigned char size4[4]; /* nr of sectors in partition */

} PACKED;

所以,这个partition的起始head=0x21,sector=0x03,cylinder=0x00,结尾head=0x6b,sector=0xee,cylinder=0xfd,starting logical sector=0x0800,size of sector=0x77d800 类型当然是linux=0x83

让我现在来验算一下:0x0800=2048这个是和fdisk输出一致的,但是head=0x21=33按照63sector/head来算已经是33*63=2079了唯一能对的上的是32*64=2048,但是sector=0x03怎么解释呢?难道说所谓的起始sector之前还有所谓的sector?那么size对吗?

Starting sector=0x0800+number of sectors=0x77d800 = end sector number=0x77e000=7856128这个和fdisk报告的7856127似乎是符合的(从0开始减一??)但是所谓的ending cylinder=0xfd,ending head=0x6b,ending sector=0xee要怎么算呢? cylinder=0Xfd=253, head=0x6b=107,sector=0xee=238,按照255heads/cylinder63sector/head计算253*255*63+107*63+238根本不沾边?所以只能再去看fdisk的代码,还是老祖师的那句话:RTFC!!!

十二月十日 当前只有等待等待编译util-linuxdebug模式然后跟踪,当然之前也读代码好几遍,只是确认一下,其实是读代码有时候会跟丢了,fdisk的代码不难懂,可是毕竟全部都是使用全局变量比较的让人不乐见。list模式没有问题,当然是从之前的mbr读出来的,size是结合了blkdev得到的partitionsize,否则如果未定义使用blkdev就使用最原始的探索,反复用lseek/read来看device是否可读,使用的算法是binary search之类,每次加倍,最后失败在使用binary search找到成功的大小,使用blkdev其实也很简单,就是/proc/partition读出的数据,这个是blocksize,我这里有些迷惑的是,ext2blocksize默认是1k吗?似乎是,不过我记得很多大磁盘使用的是4k,总之转换为sector默认512就加倍了,这个是需要注意的。接下来才是真正的问题,就是怎么addnewpartition的计算chs的。

十二月十一日 当前只有等待等待说起来就是一肚子气,如此简单的问题我却折腾了一天多,可能脑子就是不开窍,所谓的传统就是如此,我不知道从什么时候被灌输了LBA的概念以为所有的磁盘系统都是使用标准的chs的计算方式,肯定是我误解了。也就是说你需要先知道你的head/sector才能知道具体的starting head/starting sector,可是这个是古老的年代当磁盘没有控制芯片你需要告诉机械臂我要把磁盘转到哪个扇区需要这些参数,所谓的LBA就是说这个工作磁盘控制器帮你做了,你只要说出sector,控制器自己去控制转到对应的head,我却还以为大家统一了head=63,sector=255才做到LBA,这个就是理解的误区,并不是制造商统一了磁盘参数而是控制器做到了自动,让你不用关心这个参数。想想看古老年代为什么要有很多的alignment的限制,肯定就是OS直接发令给机械磁盘转动到某个位置有可能效率不高啊,比如你不能同时读取所有sector,所以让你有限制地创建partition的开始。所以,回到问题的开始,之所以我看到的starting sector/head很奇怪实际上是因为我的磁盘的head=62,sector=62,cylinder=1021,所以,现在看起来一点不奇怪,fdisk按照古老的起始2048sector的老办法,那么起始的head就是32因为每个head62sector,所以,最后余下3sector33*62+3=2049,至于说20482049我懒的追究了,fdisk里面充斥了类似的偏移这里加一那里减一的,或者就是我从零数数都不懂,总之,你需要知道的是这个{heads = 124 '|', sectors = 62 '>', cylinders = 1021, start = 0}的来源是linux kernel,调用这个函数ioctl(fd, HDIO_GETGEO, &geometry)其中define HDIO_GETGEO 0x0301

struct hd_geometry {

unsigned char heads;

unsigned char sectors;

unsigned short cylinders; /* truncated */

unsigned long start;

};

我对于fdisk诉说cylinder被truncated而弃置不用有些将信将疑,如果查看/proc/partitions得到的block总数是3928064,换算为sector是加倍7856128,那么从kernel的HD geometry函数得到的1021*124*62=7849448我的理解是这个cylinder是准确的,因为结尾的确还有ending head/ending sector没有加上,很可能fdisk说的是老版本的kenerl了。所以,我觉得fdisk完全不需要费力的去计算cylinder直接采用kernel的值1021就行了。至此关于starting sector/head/cylinder的谜团揭开了,那么ending head/sector/cylinder就应该是从总的sector数反推的,我懒的再看代码了,有这个时间还不如看看gnu disk的实现,fdisk我觉得很多人都有诟病吧毕竟太老了。(这个年头真的有人关心磁盘分区的问题吗?)

总结一下就是mbr的磁盘分区内容就是1be偏移开始的地方,mbr的启动小汇编代码倒是可以看看怎样在两三百个byte里去load这个磁盘分区地址指示的boot sector的。这个才是核心,应该有一个地方指示了第几个分区是启动区,并且在512-2,512-1有mbr的magic number:0x55aa。当然每个partition有标注自己的类型,比如dox/linux等等,以及是否为activated:0x80或者是extended,同时在偏移0x1B8=440处写的dos label,通常就是id的hex形式。顺便说一下,在fdisk的高级模式下查看partition table,让我验算一下:

ending head=107,sector=46,cylinder=1021,start sector=2048,total sector=7854080: 7854080+2048=7856128这个是/proc/partitions得到的。1021*124*62+107*62+46=7856128所以,这个证实了ending sector/head/cylinder是用总数倒推出来的,代码也是如此,我也懒得找了,fdisk里面很多宏没有什么解释移位来来去去很难理解。

Disk /dev/sdb: 124 heads, 62 sectors, 1021 cylinders

Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID

1 80 33 3 0 107 46 1021 2048 7854080 83

你回过头来再看fdisk有些显示真实把你气死非常的误导:

nick@ubuntu-14:~/travel/util-linux-2.20.1/fdisk$ sudo fdisk -l /dev/sdb

Disk /dev/sdb: 4022 MB, 4022337536 bytes

108 heads, 46 sectors/track, 1581 cylinders, total 7856128 sectors

Units = sectors of 1 * 512 = 512 bytes

Sector size (logical/physical): 512 bytes / 512 bytes

I/O size (minimum/optimal): 512 bytes / 512 bytes

Disk identifier: 0x84300bd9

Device Boot Start End Blocks Id System

/dev/sdb1 * 2048 7856127 3927040 83 Linux

这里108heads46sectors1581cylinder在讲天书啊?说的是结尾的位置,哪里蹦出来一个1581cylinder


十二月十二日 等待变化等待机会

fdisk的探索告一段落又重新回到mbr的研读,现在只能看汇编码了,因为抛开所谓的mbr-manager的部分我关心的指示install-mbr,而这个程序说来极其的简单,总共编译就是这么几步:

gcc -E -xc mbr.S86 -o mbr.s86.tmp && mv mbr.s86.tmp mbr.s86

as86 -0 -b mbr.b.tmp -s mbr.sym -l mbr.lst mbr.s86 && mv mbr.b.tmp mbr.b

ld -r -b binary -o mbr.o mbr.b

gcc -DY2KBUG -E -xc mbr.S86 -o y2k.s86.tmp && mv y2k.s86.tmp y2k.s86

as86 -0 -b y2k.b.tmp -s y2k.sym -l y2k.lst y2k.s86 && mv y2k.b.tmp y2k.b

ld -r -b binary -o y2k.o y2k.b

gcc -Wall -Wstrict-prototypes -Wmissing-prototypes -g -O0 -g -O0 -o install-mbr install-mbr.o mbr.o y2k.o

gcc -DTESTDISK -E -xc mbr.S86 -o testdisk.s86.tmp && mv testdisk.s86.tmp testdisk.s86

as86 -0 -b testdisk.b.tmp -s testdisk.sym -l testdisk.lst testdisk.s86 && mv testdisk.b.tmp testdisk.b

rm mbr.s86

因为install-mbr是c代码没有多少干货就是传参数拷贝,因为核心部分是那个真正的loader就是mbr.S86,这个是因为bios是初始化使用i286运行的16位,当然我可以使用as86来汇编,所以要安装bin86包,它带有as86汇编器。至于说你要使用objdump查看汇编因为我是x86_64系统objdump理所当然的有很多汇编指令不认识,bing看到这个参数:objdump -D -mi386 -Maddr16,data16 mbr

它不但要求使用i386汇编器指令还需要16位的内存寻址才行。这样子的结果和mbr.S86的汇编源代码是一致的,当然这个是毫无意义的,难道你怀疑汇编器有问题吗?只不过是验证而已。mbr.S86有不少的注释,首先,bios是把mbr这个boot sector加载到内存0x7c00处,可是我们的这个所谓的loader的目的是要把真正的bootloader加载到这个地址,所以,它把自己拷贝到0x600的地址。(这一点要再确认)(需要吗?不需要。以下是汇编码证明。)

b: be 00 7c mov $0x7c00,%si

e: bf 00 06 mov $0x600,%di

11: b9 00 01 mov $0x100,%cx

14: f3 a5 rep movsw %ds:(%si),%es:(%di)

首先设置起始地址也就是我们目前被bios加载的地址0x7c00到si寄存器,然后设定目标地址0x600到di寄存器,然后拷贝0x100个word长度也就是512bytes,所以整个mbr被挪到了0x600位置。


十二月二十日 等待变化等待机会

旅行中我的笔记本总是启动很慢,一开始以为是我设定的nfs mount的问题,就设定softmount option,可是没有效果,事实上注解了/etc/fstab里的nfs mount也没有用,的确是plymount-update-bridge的讯息configure networking总是不成功。我看到/etc/init/plymouth.confkill timeout 60需要等待60秒才杀死networkingconfguration,改为0依旧没有效果。最后看/etc/network/interface里我强制要求static ip,但是即便手动加载wlan依然不行,后来干脆这个地方什么也要写,结果成了。实际上我那个时候困的睡着了,真正的原因需要看plymouth,这个是manpage。我以前约略的看过一点代码,不过那个时候关心的是它怎么显示,实际上它仿佛一个小小的操作系统,这个应证了我最近学习的那样,一个secondary boot loader有很多时候就是一个mini os。


十二月二十一日 等待变化等待机会

的确plymouth是一个辅助的系统,说他是bootloader也许不是很准确吧,因为它实际上是运行于initrd或者说initramfs内,就是说它的作用是一个帮助mount真正的rootfs,当然这里帮助的意思并不是它本身在作这些,因为在ubuntuinitramfs里的init实际上调用的是udev,至少这是我看到的init-top/bottom脚本里的,目前我还不确定是否udev内部在借助plymouth,因为用strings看到udevbinary里用到一个plymouth的路径名,所以在看udev代码前我只能猜测,我的理解plymouth就是一个用户splash/progress的辅助图形模块,本身不做很多的具体工作,这个也是我当初希望看plymouth能否作为一个不依赖过多资源的图形系统的原因,现在看来似乎是一个简化的x-window系统,因为也有一个daemon在运行,很想x系统。


十二月二十二日 等待变化等待机会

有同行反映类似的vmcli的问题,我翻我的工作笔记才发现这些细节,但是这个是否是最后结论我的记忆力完全不能保障。

In shell command, if you have special character like “&”, you need to quote it. Clearly it is

[root@rh63-58-110 Linux_x86_64]# objdump -s -j .rodata ./VMCLIEXE | less

41ae80: 6d 62 65 72 0a 00 00 00 20 2d 2d 64 69 72 65 63 mber.... --direc

41ae90: 74 6f 72 79 2d 70 72 65 66 69 78 3d 25 73 20 20 tory-prefix=%s

41aea0: 2d 2d 70 72 65 66 65 72 2d 66 61 6d 69 6c 79 3d --prefer-family=

41aeb0: 49 50 76 36 20 20 2d 2d 63 6f 6e 6e 65 63 74 2d IPv6 --connect-

41aec0: 74 69 6d 65 6f 75 74 3d 31 20 2d 2d 72 65 61 64 timeout=1 --read

41aed0: 2d 74 69 6d 65 6f 75 74 3d 31 32 30 20 20 2d 2d -timeout=120 --

41aee0: 74 72 69 65 73 3d 32 20 2d 2d 6b 65 65 70 2d 73 tries=2 --keep-s

41aef0: 65 73 73 69 6f 6e 2d 63 6f 6f 6b 69 65 73 20 2d ession-cookies -

41af00: 2d 6e 6f 2d 76 65 72 62 6f 73 65 20 2d 71 20 2d -no-verbose -q -

41af10: 2d 75 73 65 72 2d 61 67 65 6e 74 3d 56 4d 43 4c -user-agent=VMCL

41af20: 49 20 2d 2d 73 61 76 65 2d 63 6f 6f 6b 69 65 73 I --save-cookies

41af30: 20 25 73 20 20 2d 2d 6e 6f 2d 63 68 65 63 6b 2d %s --no-check-

41af40: 63 65 72 74 69 66 69 63 61 74 65 20 20 2d 2d 70 certificate --p

41af50: 6f 73 74 2d 64 61 74 61 3d 22 57 45 42 56 41 52 ost-data="WEBVAR

41af60: 5f 55 53 45 52 4e 41 4d 45 3d 25 73 26 57 45 42 _USERNAME=%s&WEB

41af70: 56 41 52 5f 50 41 53 53 57 4f 52 44 3d 25 73 22 VAR_PASSWORD=%s"

41af80: 20 68 74 74 70 73 3a 2f 2f 25 73 3a 25 64 2f 72 https://%s:%d/r

41af90: 70 63 2f 57 45 42 53 45 53 2f 63 72 65 61 74 65 pc/WEBSES/create

41afa0: 2e 61 73 70 00 63 72 65 61 74 65 2e 61 73 70 00 .asp.create.asp.

41afb0: 25 73 25 73 00 67 65 74 73 65 73 73 69 6f 6e 74 %s%s.getsessiont

41afc0: 6f 6b 65 6e 2e 61 73 70 00 67 65 74 72 6f 6c 65 oken.asp.getrole


我做了一个简单的验证,但是我现在回过头来看不知道为什么我的结论是vmcli的这个常量字符串有问题?明明是有quote的,为什么我当时在笔记里说不行?也许我头脑想反了?难不成我认为c代码里的这个常量字符串需要escape character,我头脑比较混乱。

而且我当时看到的错误似乎完全不相关:

The command is:
[root@rh63-58-110 Linux_x86_64]# ./VMCLIEXE -r 172.17.59.189:443 -u admin -p admin -c /home/Downloads/fifth.iso

The log shows:
Mon Jul 31 15:39:42 2017 Warning (6): Check if Wget is installed on Client machine
Mon Jul 31 15:39:42 2017 Error (1): Unable to connect to the server: 172.17.59.189 : Check HTTPS port : Check HTTPS Port

这个是我的简单的测试程序似乎再证明vmcli没有问题?



#include <stdio.h>
#include <stdlib.h>

const char* param = "wget --directory-prefix=%s --prefer-family=IPv6 --connect-timeout=1 --read-timeout=120 --tries=2 --keep-session-cookies --no-verbose -q --user-agent=VMCLI --save-cookies %s --no-check-certificate --post-data=\"WEBVAR_USERNAME=%s\&WEBVAR_PASSWORD=%s\" https://%s:%d/rpc/WEBSES/create.asp";

int main(int argc, char**argv)
{
	char buffer[2048];
	char* sDirPrefix = "123456789";
	char* sCookieFile = "123456789/cookie.txt";
	char* sUser = "admin";
	char* sPassword = "admin";
	char* sIp = "172.17.59.189";
	int nPort = 443;
	sprintf(buffer, param, sDirPrefix, sCookieFile, sUser, sPassword, sIp, nPort);
	int ret = system(buffer);
	printf("return value: %d and its status %d of command: %s\n", ret, WEXITSTATUS(ret), buffer);
	return 0;
}


我是否记录过这个问题呢?就是ubuntu的apt的proxy的设置

it needs a apt.conf to tell how to acquire proxy:

Acquire::http::proxy "http://<yourproxyserver>:<Port>";

Acquire::https::proxy "http://<yourproxyserver>:<Port>";

Acquire::ftp::proxy "http://<yourproxyserver>:<Port>";

Acquire::http::proxy "http://<domain\user>:<password>@<yourproxyserver>:<Port>";

Acquire::https::proxy "http://<domain\user>:<password>@<yourproxyserver>:<Port>";

Acquire::ftp::proxy "http://<domain\user>:<password>@<yourproxyserver>:<Port>";

我翻阅我的工作笔记看到以下莫名其妙的文字,这究竟在说些什么?

Certificates on their own are only public pieces of information. What links a public key certificate to the name it contains is the fact that whoever has legitimate control over that name (e.g. your name or your server's name) also has the private key for it.

Certificates are used to prove the identity of the remote party by challenging the remote party to perform an operation that can only be done with the corresponding private key: signing something (which can be verified with the public key) or deciphering something that was encrypted with the public key. (Both can happen in the SSL/TLS handshake, depending on the cipher suite.)

During the SSL/TLS handshake, the server sends its certificate (in clear) and proves to the client that it has the corresponding private key using an authenticated key exchange.

In your case, you also want to use client-certificate authentication. It's not enough to send the client certificate during the handshake: the client must also prove it has the private key. Otherwise, anyone who receives that certificate could clone it. The point of using certificates is to prevent any cloning, in such a way that you never have to show your own secret (the private key).

More specifically, the client has to sign the handshake messages in the Certificate Verify message of the TLS handshake so that the server can verify it against the public key sent in the client certificate. Without this step, no client-certificate authentication would be taking place.

the client certificate was given to me by the third party, but it does not contain any private key

Giving you your certificate without its private key seems a bit pointless, unless you're expected to have generated a certificate request on your side beforehand (in which case you would have the private key).

Indeed, rather than being given a certificate and its private key, it's better practice for you to generate your key-pair, create a certificate request (CSR), and have your CA issue a certificate from that CSR (but without them ever knowing your private key). In this case, you would be expected to have kept your private key, and you would be able to use it with the cert you would have received.

我大约记得以上部分是我从stackoverflowgoogle来的,解释的是关于certificate的问题,我现在理解是说:所谓public/private key pair是互为加密解密的钥匙,就是说你用你的privatekey来加密的部分成为你的certificate,当然其中包含了public key作为certificate的一部分,任何人都可以使用这个明文的public key来解密这个certificate来验证这个证书的确是你使用你的privatekey加密的,原因是没有人能够根据publickey来猜出你的privatekey,这个理由就是分解两个质数的乘积没有捷径。

我以前记得提过这个,是否有详情?

I compare some headers of snmpget with our libsnmp++ and see that snmpget(a part of http://www.net-snmp.org/download.html ) has some float/double type defines like in asn1.h

#define ASN_APP_FLOAT (ASN_APPLICATION | 8)

...

#define ASN_OPAQUE_FLOAT (ASN_OPAQUE_TAG2 + ASN_APP_FLOAT)

And my gdb snmpget shows it knows the return pdu has type of float.

And in libsnmp++ asn1.h, there is no ype of float or double defined.

So, I guess libsnmp++ is lack of native support of float or double when encoded with octlet tag...


十二月二十三日 等待变化等待机会

有些Project已经省略了autogen.sh,你需要重新运行autoconfgenerate这个脚本,我需要先把cache下的部分删除。


十二月二十四日 等待变化等待机会

无意中安装了一个所谓的binfmtc的东西,看了半天才明白类似一个所谓的just in time之类的把c代码编译运行好像脚本一样。不过要在c代码开头加上所谓的magic

他的代码有一个有意思的地方,虽然是很小的东西一点就破,可是我不说你还真不知道为什么。比如原理是如此的简单,查看magic然后在临时目录下编译源代码然后fork然后根据返回的pid,如果是0就是child Process,通常我们是去执行exec,可是它不时地,反而child processwhile(kill(getppid(),0)>=0)sleep(1);而如果pid>0也就是parent process,它反而去execvp.这是为什么呢?难道代码逻辑有误?当然不是,其实有谁规定了一定要parent process必须是原来的,一定要childprocess去执行?本身这个使用fork只是保障exec之后有人保障unlink那个临时文件,所以,这个工作无论是parent还是child都可以做到,使用parent processexecvp按照作者注释的解释:The reason the compiled program is execed as the parent program is to allow use of same PID for the compiled program, so that it is possible to use "strace" "kill -HUP" and other conventional methods of debugging.


十二月二十五日 等待变化等待机会

killmanpage说的很清楚可惜我都没有读懂。其中说了每个shell都可能有它自己的kill,所以我必须使用/bin/kill -L

nick@ubuntu-14:~$ /bin/kill -L

1 HUP 2 INT 3 QUIT 4 ILL 5 TRAP 6 ABRT 7 BUS

8 FPE 9 KILL 10 USR1 11 SEGV 12 USR2 13 PIPE 14 ALRM

15 TERM 16 STKFLT 17 CHLD 18 CONT 19 STOP 20 TSTP 21 TTIN

22 TTOU 23 URG 24 XCPU 25 XFSZ 26 VTALRM 27 PROF 28 WINCH

29 POLL 30 PWR 31 SYS

在man 7 signal里有详细的解说关于每一个signal。(Where three values are given, the first one is usually valid for alpha and sparc, the middle one for x86, arm, and most other architectures, and the last one for mips)

Signal Value Action Comment

─────────────────────────────────────────────────────────

SIGHUP 1 Term Hangup detected on controlling terminal or death of controlling process

SIGINT 2 Term Interrupt from keyboard

SIGQUIT 3 Core Quit from keyboard

SIGILL 4 Core Illegal Instruction

SIGABRT 6 Core Abort signal from abort(3)

SIGFPE 8 Core Floating point exception

SIGKILL 9 Term Kill signal

SIGSEGV 11 Core Invalid memory reference

SIGPIPE 13 Term Broken pipe: write to pipe with no readers

SIGALRM 14 Term Timer signal from alarm(2)

SIGTERM 15 Term Termination signal

SIGUSR1 30,10,16 Term User-defined signal 1

SIGUSR2 31,12,17 Term User-defined signal 2

SIGCHLD 20,17,18 Ign Child stopped or terminated

SIGCONT 19,18,25 Cont Continue if stopped

SIGSTOP 17,19,23 Stop Stop process

SIGTSTP 18,20,24 Stop Stop typed at terminal

SIGTTIN 21,21,26 Stop Terminal input for background process

SIGTTOU 22,22,27 Stop Terminal output for background process


Next the signals not in the POSIX.1-1990 standard but described in

SUSv2 and POSIX.1-2001.

Signal Value Action Comment

─────────────────────────────────────────────────────

SIGBUS 10,7,10 Core Bus error (bad memory access)

SIGPOLL Term Pollable event (Sys V).

Synonym for SIGIO

SIGPROF 27,27,29 Term Profiling timer expired

SIGSYS 12,31,12 Core Bad argument to routine (SVr4)

SIGTRAP 5 Core Trace/breakpoint trap

SIGURG 16,23,21 Ign Urgent condition on socket (4.2BSD)

SIGVTALRM 26,26,28 Term Virtual alarm clock (4.2BSD)

SIGXCPU 24,24,30 Core CPU time limit exceeded (4.2BSD)

SIGXFSZ 25,25,31 Core File size limit exceeded (4.2BSD)



Next various other signals.

Signal Value Action Comment

─────────────────────────────────────────────────────

SIGIOT 6 Core IOT trap. A synonym for SIGABRT

SIGEMT 7,-,7 Term

SIGSTKFLT -,16,- Term Stack fault on coprocessor (unused)

SIGIO 23,29,22 Term I/O now possible (4.2BSD)

SIGCLD -,-,18 Ign A synonym for SIGCHLD

SIGPWR 29,30,19 Term Power failure (System V)

SIGINFO 29,-,- A synonym for SIGPWR

SIGLOST -,-,- Term File lock lost (unused)

SIGWINCH 28,28,20 Ign Window resize signal (4.3BSD, Sun)

SIGUNUSED -,31,- Core Synonymous with SIGSYS


其实以上照抄manpage似乎毫无意义,大多数的signal我一辈子都不一定会用到,我只不过从来没有听说过HUP这个,确实是孤陋寡闻,假如binfmt-interpreter创建的childprocess去按照习惯execvp执行编译好的可执行程序,而parentprocess使用waitpid等待那么对于debug确实是比较罗嗦因为你gdb到fork以后你要根据返回的pid再去远程gdb这个pid。而以下的代码确实很经典值得借鉴。首先,fork返回0的是childprocess,那么先把自己至于后台也就是daemon(0,0),根据manpage如果两个参数都是0的话,首先chdir到”/”,其次把stdout/in/err都转向到/dev/null。这样子我们的子进程就不会干扰真正执行的程序了,而这一步也正是父进程所期待的waitpid需要得到的。我觉得waitpid所说的childprocess的state change不是指的daemonize这一步而是sleep。daemonize只是把前台让给父进程,或者原来前台就是父进程的,子进程不想干扰而已。那么作为子进程监听父进程就只能使用getppid得到的parent_pid来持续假装kill使用一个特殊signal “0”来检验父进程是否存在,根据kill的manpage,这个0照样需要错误处理只不过没有发出任何的实质的signal而已。这个是一个很实用的技巧,因为作为父进程简单的waitpid就可以监控子进程,可是作为子进程就只有这个办法了。

而以下代码中的父进程则需要先等待子进程进入到休眠状态后才去execvp。不要忘记execvp之后一行代码打印错误,你正常执行execvp是不会返回到这里的,嫁出去的女儿是不会回娘家的,回来的都是被休掉的,所以要打印错误,这个是基本常识,只不过我觉得我会遗漏。当然毫无疑问的这个编译后的可执行程序被删除的工作只有子进程才能做到了,为什么呢?理由同上了,正常的execvp是不会返回的,同样的函数的最后的返回也是预备给这个情况的。以下的代码可以保证我们使用gdb一直跟踪执行到原本的C代码文件里,这也就是binfmtC的目的让你似乎以为c代码可以被直接当作脚本执行。


int exec_prog(const char * filename, int argc, char**argv)
{
  int pid;
  int parent_pid;

  switch(pid=fork())
    {
    case -1:
      /* fork failed */
      fprintf(stderr, 
	      "binfmtc: Failed to fork \n");
      return EXIT_FAILURE;
      break;
    case 0:
      /* when I am the child process, unlink the file after the parent
	 process has exited.
       */
      parent_pid=getppid();
      if (daemon(0,0) < 0)
	{
	  exit (-1);
	}
      while ((parent_pid!=-1)
	     && (kill(parent_pid,0) >= 0))
	{
	  sleep(1);
	}
      unlink(filename);
      exit(0);
    default:
      /* I am the parent process, exec into the built program */
      waitpid(pid,NULL,0);
      execvp(filename, argv);
      fprintf(stderr, 
	      "binfmtc: failed execvp of %s \n", filename);
      break;
    }
  return EXIT_FAILURE;
}

查看linux kernel的binfmt唯一能看懂的就是这个是实现在文件系统之上?成为内核的一部分,当然也是linux支持的可执行格式的实现?总之我已经忘了为什么看到这里,原本是systemd的问题?

关于plymouth的图形问题找到了这个,首先下载相应的plymouth的theme,然后使用update-alternatives –config default.plymouth选择下载的theme.然后update-initramfs -u这个参数仅仅修改initramfs,这个很好用的命令。实验以下。


十二月二十五日 等待变化等待机会

学习上遇到了困境,就把很久以前读到的好书再来读一遍吧。我保留一份A Heavily-commented Linux Kernel Source Code.以及作者的另一篇饶有趣味的文章,我称之为linux kernel的掌故与历史。这里是linux kernel的早期代码,很宝贵的。


十二月二十六日 等待变化等待机会

究竟是否应该去了解biosfunction呢?这里下载了一份bios手册。读了开头才明白bios也有不同家的,所谓的embedded bios是哪一家的呢?说是embeddedpc的很相似,那么这个phoenixbios手册更加的适合。我又一次的陷入迷途完全忘记了究竟我要做什么,实际上bios的中断向量表对于我有什么价值?我的疑惑是对于操作系统来说是否可以完全抛开?嵌入式的rasperryPI/BeagleBone他们是没有bios的,对吗?你只需要一个存储的flash,我的理解是u-boot可以把一些设置存在那里,这样子u-boot在某种程度上代替了bios的功能,说到底bios是一个小程序而且不是免费的,之所以存在的原因我还是不太理解,是否只有bios能够初始化内存速度,cpu设置?


十二月二十七日 等待变化等待机会

其实这个是相当的深奥的问题,而我却从来都没有意识到它的存在。cpu在刚启动的那一刻是怎么运行的,因为那一刻内存是空的没有可执行的代码,那么最先的那些指令是怎么加载到内存的,是谁?是所谓的bios的代码,可是它自己也需要加载,封诺依曼的架构要求所有的代码必须先加载到内存中才能执行,那么cpu仿 佛一台汽车引擎虽然油箱里有油但是油必须通过输油管送到燃烧室引擎才能做工运转,只有它运转以后才能输出动力把油从油箱输送到燃烧室自我维持运转,因此它 需要一个“第一推动”,这个就是点火器的作用要第一次给一个启动的动力让至少一点点的油送到燃烧室里燃烧产生哪怕一点点的动力足够把后续的油汲取到燃烧室 供后续运转,这个是所有的飞机汽车引擎启动那一刻的难题,你需要一个特殊的外在动力在引擎能够自主维持运转之前点火启动,而bootloader/bootstrap,甚至于在它之前还有一个更加的原始的推动力在扮演着这个点火器的角色,这个是我一开始没有意识到的,普通人都是泛泛的认为这个是bios的作用,可是bios自己难道不需要加载吗?他自己难道不是一个需要加载到内存才能运行的程序吗?存在rom里的代码同样是不能运行的,不是吗?我觉得我吃过早饭后再好好读一下这里补齐我的常识。然后这位大侠指出上面的作者生活在石器时代是老古董了,我想的确的cpu应该不再是一开始就运行在000f:fff0了吧?大侠说:CPUs haven't started with the CS:IP combination FFFF:0000 since the 8086. The 80286 changed this to F000:FFF0. But the 80286 world itself is the highly out of date world of the late 1980s that folk wisdom still circulates.然后大侠给出了另一个较好的资料,我读了一个开头觉得似乎是比之前的更可信。我感觉我之前读的那篇linux kernel里引用的古老的2000年的论文其中某些细节也许有些过时的,这毫不奇怪而且丝毫不损伤原论文的意义,因为作者是在2000年的时候探讨linux boot的历史现状和未来,在当时应该是正确的,只不过我对于80386cpu在启动之初是怎样支持80286的寻址方式并不理解,似乎也没有什么实际意义了,在以上的大侠的细节里他也提到在resetcs:ip寄存器的默认的地址我觉得似乎这个就是intel支持16位寻址的细节吧。另一个我的理解就是rom里的代码是可以执行的?但是我不确定的一点也是疑惑,是否这是依靠所谓的shadow来实现的,就是说rom被自动的“映射”到ram里形成所谓的shadow,就是说依靠总线或者什么其他硬件导致某些内存地址天然的由内存控制器自动的把rom加载到特定地址,从而达到运行rom里的bios的代码的能力?因为我还是倾向于认为冯诺依曼的代码一定要在内存中才能执行的原则不变,也就是说rom里的代码实际上是被自动加载到ram里的,当然代价就是这里有一小块内存不可再作其他用途了,看来内存控制器是相当的复杂和紧密贴近架构的依赖,也许主板厂商需要和内存厂商作配合的吧?


十二月二十九日 等待变化等待机会

感觉学习还是有一个小目标比较好,所以,我开始结合单板机来比对,rasperryPI的文档不如TI的详细,是否是说它的硬件是不公开的?总之这个文档似乎以前也下载过可是几乎一行也看不懂,现在多少能够读懂一点了。内存地址通通被映射的各式各样的硬件设备,包括rom也是在特定地址的,而且还有两个rom,一个是所谓的安全的好像要检查image的数字签名之类的,另一块则是普通的,我的理解是这是一个多级的bootloader,首先是TI的这个所谓的rom充当bios一样的启动,甚至作一些安全检查,然后根据其他资料解释取决于启动pin的状态可以搜索多个启动device,或者外设启动包括networkboot,uart,usb等等,这里的usb实际上使用了rndis也就是remote network的驱动让usb设备模拟网络设备以便达到networkboot,弟子里还是bootp/tftp,至于本地设备则支持emmc/mmcsd等。关于microsd卡的制作这里有人给出了这个instruction,我一直也没有实验过,不过现在看来倒是比较简单的,学习的基本的chs的概念只不过是如何使用fdisk制作文件系统的问题,难道TIbootloader不去读mbr自己计算chs?转念一想,实际上grub2是依赖于linux kernelblkid来获取设备的chs的信息的,让bootloader探索分区的磁盘信息这个似乎是没有办法的,所以只有是用最“理想”的63sector/255head来计算cylinder才是唯一可行的。TITRM我现在阅读initialization部分也就是boot相关的部分。还是比较highlevel的功能性的讲解,目前我也就是这个层级。现在只能说部分的理解了我昨天的困惑,rom里的代码是可以执行的,但是远非这么简单,beaglebone分两种:1.如果是non-XIP的方式,也就是说代码不是“本地运行”(XIP)那么原理上是使用shadowing,应该就是内存映射把rom映射到ram里,所以,本质上还是透过某种硬件设备比如内存控制器的配合把rom的代码loadram像普通程序一样去执行。2.如果是XIP,据说主要是NOR-flash类型,那么代码是比较特殊的所谓“本地运行”,有若干要求,比如地址独立PIC,不能写只能读,数据和代码必须没有链接的部分,只能在当前“段”内,我的理解就是类似于“实模”里的本地地址,甚至比这个要求更高,也许连段都没有?我对于XIP的理解不是很清楚,总之是很简单的代码。或者地址都是写死的?总之不管怎样我觉得有一点是共同的,那就是cpu在上电以后,或者说reset之后在得到power信号开始运行的初始都是固定去固定地址执行的,所以这也就是rom地址映射的原因。这一点在随后的阅读里可以留心看看。

这里是我的猜想,有两个rom,一个是安全机制,一个是正常机制,但是即便是没有安全同样的两个rom并不会少只不过是被disable了安全机制而已,那么对于non-XIPcode要求一个header指名size和目标地址就很容易理解了,很可能是上电后直接执行安全rom的地址,这里如果是xip很简单没有问题,但是如果是所谓mmc的话,目标地址也是写死了,等到这个逻辑在内存里站住脚了再去执行另一块rom的代码,这里就需要所谓的GP header要写明size和目标地址了。


十二月三十日 等待变化等待机会

经过讨论以后实际上是比较清楚了,instruction cycleload next instruction的地址的寄存器与当前的已经loaded instruction是两个寄存器,那么开机的时候很明显的前者的地址也许就被cpu制造商reset到一个固定的大的地址,这个就是rom的映射的地址,这个是必须的,这也就是为什么所有的计算机都必须有一个rom的原因,在pc里这里也许就是bios,在嵌入式的架构是制造商自己的第一级的bootloader。在pc里使用bios应该是一个历史问题,同时为了更广泛的兼容性的目的。

我发现还是结合阅读linux kernel的文档是一个很好的学习的方式,因为那里的文档不但言简意赅,更重要的有很多延伸阅读给你很多的线索,比如我觉得我应该要去好好理解dts/dtb的设计,因为我几乎是一无所知根本看不懂,唯一知道的是device tree的设计最早是Linus不满大量的代码被用来描述设备。文档里的开头就把我引导了启动部分,而arm/booting的这段文字我需要深刻的理解:

Essentially, the boot loader should provide (as a minimum) the

following:


1. Setup and initialise the RAM.

2. Initialise one serial port.

3. Detect the machine type.

4. Setup the kernel tagged list.

5. Load initramfs.

6. Call the kernel image.


十二月三十一日 等待变化等待机会

Smiley face