Resovling AM_ICONV undefined error when building osxfuse

I got this issue when building osxfuse code:

 
wum@osxfuse$ ./build.sh -t lib
OSXFUSEBuildTool()            : supported platforms: 10.7 10.8
OSXFUSEBuildTool(lib)         : initiating Universal build for 10.7
OSXFUSEBuildTool(lib)         : configuring library source
Running libtoolize…
Running autoreconf…
configure.in:82: warning: macro `AM_ICONV' not found in library
glibtoolize: putting auxiliary files in `.'.
glibtoolize: copying file `./ltmain.sh'
glibtoolize: Consider adding `AC_CONFIG_MACRO_DIR([m4])' to configure.in and
glibtoolize: rerunning glibtoolize, to keep the correct libtool macros in-tree.
glibtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am.
configure.in:82: warning: macro `AM_ICONV' not found in library
configure.in:82: error: possibly undefined macro: AM_ICONV
      If this token and others are legitimate, please use m4_pattern_allow.
      See the Autoconf documentation.
autoreconf: /usr/bin/autoconf failed with exit status: 1
Linking kernel header file…
To compile run './configure', and then 'make'.
configure: error: cannot find install-sh or install.sh in "." "./.." "./../.."
OSXFUSEBuildTool(lib) failed: cannot configure OSXFUSE library source for compilation.
 
I soon googled and find that I was short of the get text library. However installing the library with homebrew didn't help. I try other workarounds but they didn't appear to work.
 
The major problem is that AM_ICONV (used in some automate script) is defined in iconv.m4
 
Soon I realized if there's an issue in the include path. autoconf/glibtoolize is searching the m4 file in /usr/share/aclocal, but gettext's m4 file was installed to /opt/local/share/aclocal/ by my homebrew. I copied all the m4 files from /opt/local/share/aclocal/ to /usr/share/aclocal, and everything was resolved…
 

wheel 用户组

UNIX系统里有个wheel用户组,大概相当于root组的权限,比如sudoer。这个名字的由来可见下面这个帖子——来源于big wheel这个俚语,指的是有权势权力的人。另外也有一种说法是当初在搞这个功能的哥们,一边弄一边在听"Wheel in the Sky"这首歌,然后就把用户组命名为wheel

参考资料:
http://unix.stackexchange.com/questions/1262/where-did-the-wheel-group-get-its-name

Mac OSX Tips (1)——彩色化ls输出

Mac OSX终端彩色化ls输出似乎和linux不一样。

 
最简单的就是ls -G,然后在.bash_profile里用alias把ls 定义成ls -G: (上面是简单的ls,下面是ls -G)
 

 
或者在.bash_proflie里
export CLICOLOR=1
export LSCOLORS=GxFxCxDxBxegedabagaced
 
 

MBR,GPT与Boot Camp

MBR

作为BIOS时代的分区管理格式,MBR (Master Boot Record)已经走过了31个年头。1982年,MBR被引入IBM PC DOS 2.0,用来支持10MB大小的硬盘。

MBR的结构非常简单。前面446字节是引导代码,接着4条16字节的主分区信息,最后是两个字节的签名(魔数):

Start Size Description
0 446 Boot code
446 16 Primary partition entry 1
462 16 Primary partition entry 2
478 16 Primary partition entry 3
494 16 Primary partition entry 3
510 2 Signature (0xaa55)

这么看每个磁盘的分区数被限死在了4个,不过后来又引入了扩展分区技术(EBR)解决(或者说是绕过)了这个问题。简单来说,EBR就是把最后一个主分区特别对待,这个分区(又称扩展分区)的第一个扇区看成是一个MBR,又叫EBR,不过不同的是EBR只用了前两个分区项(同样从446字节处开始),第一项指明了新的普通分区,而第二项除了可以指新的普通分区外,还可能用来指向新的扩展分区。这样通过链表的形式把非主分区(又称逻辑分区)给串起来。下面这两张张图(来自MSDN)基本说明了是怎么回事:

 

上图前三个主分区项都指向了普通分区,最后一项指向了扩展分区。下图则演示了扩展分区的细节:

 

EBR

扩展分区里只用了两项分区项,第一项指向普通分区,第二项指向下一个扩展分区。前一级扩展分区总是涵盖了后面的所有分区,形成了嵌套的链接关系。

这样的做法缺点很明显,链表当中要是断了,后面的可就都丢掉了。另外要让一些主流操作系统从分主分区启动也要花一些功夫。

下面简单说说分区项的具体内容:

Start Size Descripton
0 1 Status (0x80 = boot flag)
1 3 CHS start (deprecated, use 0xfeffff)
4 1 Partition type
5 3 CHS end (deprecated, 0xfeffff)
8 4 LBA start (in sectors)
12 4 LBA size (in sectors)

可以看到一个明显的限制是磁盘的大小。LBA的宽度只有4个字节,这样只能用来描述最大2TB的磁盘,再大就不够了(有别的hack,不过至少肯定不能用来当启动盘)。另外分区类型最多256种,不够描述当今所有的文件系统类型(包括操作系统)。MBR格式(以及其背后的BIOS)过于古老,严重阻碍了新技术的推广。但是PC市场这么大,想要改也没那么容易,涉及到硬件软件以及大量第三方公司和整个产业链。

EFI

Intel和HP在90年代一起研发Itanium的时候,就打算趁引入新架构的机会也把老掉牙的BIOS踢到一边去。98年搞了一个项目叫Intel Boot Initiative,后来更名为EFI,2005年又更名为现在的名字UEFI。Itanium算是没做起来,UEFI这些年的势头开始起来了,除了Intel架构的Mac以外,Windows 8的加入无疑将大大加速UEFI的推广(虽然Secure Boot备受争议)。

EFI的一个组成部分是规定了新的磁盘分区格式GPT(GUID Partition Table)。首先GPT支持最高达8ZB(4PB*2M)的磁盘容量(在可见的未来足够了),以及最多128项磁盘分区。另外出于保护数据的目的,分区表在磁盘上存放了两份,分别放在磁盘的开头和结尾,以防以外丢失。

保护MBR(Protective MBR)

由于市场上大量非EFI机器的存在,GPT通过保护MBR来达成与MBR的兼容,或者说是保护GPT分区不被非EFI机器破坏。方法很简单,结合上面MBR的描述就可以明白:

  1. 占领MBR的第一项分区项;
  2. 分区类别设定为特殊类型;
  3. 起始地址为扇区1;
  4. 分区大小为磁盘大小-1。

这样非EFI机器读MBR的时候,就会发现整个磁盘已经被别的分区全部占满了,而用户也不会轻易的重新分区。这就是所谓的“保护性”。

GPT头和分区项

GPT头描述了磁盘和分区表的基本信息,如磁盘的GUID和分区表的大小。分区项最多有128项,一般4项为一个单位。分区项每项占128字节:

Start Size Descrption
0 16 Partition type GUID
16 16 Unique Partion GUID
32 8 Start LBA
40 8 Last LBA
48 8 Flags
56 72 Partition name

(令人意外的是,分区类型虽然是GUID,不过已经有冲突了)

GPT和MBR这两种磁盘分区格式可以说是天差地别,融合起来可不是很容易。不过好在GPT给MBR让出了扇区0作为保护MBR,在一个磁盘上支持两种分区格式也成为可能。典型的做法是Boot Camp的实现。

Boot Camp

苹果在2005年宣布使用Intel作为Mac平台以后,由于控制了硬件软件平台,使得它应用EFI没有什么问题。不过大部分Windows并不支持GPT而只能从MBR磁盘启动,苹果也提供了Boot Camp方便使用者在Mac上安装双系统。

Boot Camp的原理是混合MBR (Hybrid MBR)。利用MBR里的空余主分区项,使得一个分区在两个分区表里都有份。

前面说过了保护性MBR的做法是把整个磁盘写成一个大分区,这时候这个大分区被Mac OSX占据了。如果我们把Mac OSX分区缩小(比如一半),那后面一半分区就可以腾出来给Windows用了。要做到这一步很简单,只需要把保护性MBR里那条特殊的分区项的分区大小改小就可以了,另外需要往MBR里再加一条分区项(并设置成启动),描述后面半个磁盘上的Windows分区。

操作系统按道理可以安装启动了,不过下一步我们还需要在两个操作系统里分别都能看到对方操作系统的分区,至少方便拷贝数据(假定都有相应文件系统的驱动)。对于Windows来说,由于MBR里已经有两条分区项充分描述了这两个分区,所以Windows里能够看到两个分区;但是对于Mac OSX来说,它只认识GPT的分区,所以还看不到Windows的分区。当然这也很简单,只要往GPT分区表里加一条描述Windows分区的分区项就可以了。

具体来说Boot Camp做了三件事:

  • 把Mac OSX分区缩小(Shrink HFS+)
  • 改动GPT和MBR的分区表;
  • 在启动菜单里加上其他操作系统的选项,另外给其他操作系统提供驱动。

下面是我启用了Boot Camp的MBR导出结果:

00fe ffff eefe ffff 0100 0000 2740 0600   <<<< EFI partition (200M ESP)
00fe ffff affe ffff 2840 0600 0047 0740   <<<< Mac main partition, size 0x40074700 (512G)
00fe ffff abfe ffff 2887 0d40 205f 1300   <<<< Mac recovery partition
80fe ffff 07fe ffff 00e8 2040 0078 3317   <<<< Windows partition, size 0x1733008 (185G), boot bit             
                                               (first bit) is set

或者是用fdisk导出结果

wum@dev$ sudo fdisk -d /dev/rdisk0

1,409639,0xEE,-,1023,254,63,1023,254,63
409640,1074218752,0xAF,-,1023,254,63,1023,254,63
1074628392,1269536,0xAB,-,1023,254,63,1023,254,63
1075898368,389249024,0×07,*,1023,254,63,1023,254,63

参考文献

Hybrid MBRs

What's a GPT?

Apple support of GPT

更换Mac OSX启动内核(XNU)

前面的文章讲述了编译Mac OSX内核的基本步骤,下面的步骤就是更换内核重启了。对于Macbook的同学来说,除了如何把内核启动起来,最关心的恐怕就是如果内核crash的话,怎么样换回来原来的内核文件,至少别把自己的Mac给玩挂了。
网上搜了很多资料,最靠谱的就是这封邮件列表里的邮件了。邮件的标题是“choosing kernel on Intel”,我想很大一部分原因是之前众多的资料是关于PowerPC平台的Open Firmware(连苹果官网里的文章还停留在那个年代)。而现在鸟枪换炮用上了EFI这个新鲜玩意儿,方法自然是大不同了。(而苹果却又没把EFI shell这些东西给提供出来,也给开发者造成了一些麻烦。不过从苹果角度出发的确也没必要给普通用户提供SHELL)。
下面是这些方法:

EFI Shell

装个EFI Shell,比如rEFIt。rEFIt提供了在Macbook上一些方便的安装方法,比如光盘启动、U盘启动或者直接放硬盘上。其中硬盘上的安装一步到位,兼容BootCamp,开机以后看到的就是rEFIt的界面,几个菜单项,如下图,另外每个菜单项还可以有简单的定制,以带入不同的启动选项。左下角就是EFI Shell。

相比于古老的BOIS,EFIShell提供了强大的功能和运行环境,具体的用法可以看Intel的这个手册,或者中文版。常用的命令有:
(EFI Shell进入后分辨率偏低,可以通过mode命令调整。打一个命令往往会超出屏幕的显示范围,这个时候需要在每个命令后加一个“-b“的选项,达到more命令那样的效果。)

  • help/?: 用法很简单,help <command>,类似man
  • fs1:     切换文件系统,类似于DOS下的盘符切换。具体有什么fs可以切换参见map命令
  • map:显示当前映射表,也可以把当前的块设备加上盘符;
  • 简单的文件系统命令,比如cd/rm/mkdir等等,还可以通过edit, hexedit来编辑文件(这个很有用,可以用来改下面步骤里的东西)

而如果需要启动内核的话(就像grub里敲initrd,boot),只需要找到你Mac OSX的挂载盘(我的是fs1)
fs1:/> \System\Library\CoreServices\boot.efi Kernel=mach_kernel.test
我相信应该还可以带一些别的参数,比如调试位,不过目前还没有尝试过。

编辑启动文件

这应该是最简单的办法,也是邮件里最推荐的办法。
打开/Library/Preferences/SystemConfiguration/com.apple.Boot.plist,往里面增加一项

<key>Kernel</key>
<string>mach_kernel.test</string>

如果你自己编译的内核挂了,建议的办法是用rEFIt引导,然后修改配置文件。建议无论如何都要在文件系统里保留一份mach_kernel的备份。

NVRAM变量

修改NVRAM里的boot-args变量,使用以下命令:

$sudo nvram boot-args=”debug=0x144 -v Kernel=mach_kernel.test”

如果玩坏了,办法是在启动时按住“Cmd-Opt-P-R”把NVRAM清空(并载入默认选项)。当然如果你把mach_kernel搞坏了这招估计行不通。

EFI启动选项

$sudo bless –mount / -setBoot –options “Kernel=mach_kernel.test”

这是传给EFI启动的引导选项(显然可以用rEFIt引导来跳过),如果你想暂时用原来的kernel启动,则在启动时按住Opt,进入启动菜单,并选择Mac OSX进行启动。这样会覆盖bless的选项,从而直接启动mach_kernel。同样用上面的办法清空NVRAM也可以达到同样的目的(只不过下次启动就是默认了)。

在Mac OSX 10.7(Lion)上编译XNU内核

Apple虽然备受封闭系统的指责,但事实上只要访问http://www.opensource.apple.com,你就能看到苹果对开源软件的贡献。其中最值得一提的就是OSX内核——XNU。
根据我的理解,XNU是Mac OSX的内核,是一种融合了Mach、BSD和IOKit的混合型内核。其中Mach提供核心的基本操作(IPC、同步、VM、进程管理),BSD负责POSIX API,网络,文件系统(以及很多其他),另外IOKit则包含了驱动模型。
虽然网上有不少关于如何编译XNU的文章(包括项目),但在我的试验中,最后能够成功编译的只有这篇文章(因为正好符合各项条件,另外10.8的文章链接在此,都需翻墙),苹果官网上的文档甚至还停留在PowerPC的时代,告诉你如何通过Open Firmware进入调试模式,而Macbook早已在5年前转换到Intel平台,使用EFI作为bootloader。(另外一个明显问题是gcc4.3可以编译最新XNU,无需倒退到3.3)
具体的步骤我不逐句搬过来,概括来说就是:

  1. 下载dtrace(调试追踪工具)和bootstrap_cmds(用来生成Mach IPC服务端代码,又称Mach Interface Generator,这个是服务器版叫migcom);
  2. 分别编译并安装;
  3. 进入xnu代码目录编译;
  4. 在BUILD/obj/RELEASE_<arch> 目录里的mach_kernel就是最终文件。

有几点需要注意:

  • CC和C++一定要换成GCC前端而不是clang,CC是一个符号链接,C++我改了符号链接似乎还不行,最后指定了CXX的环境变量。
  • dtrace和bootstrap_cmds可以在http://www.opensource.apple.com/tarballs/下载打包好的tarball;
  • Xcode的Command Line Tools需要升到最新,这个不会跟着Xcode一起升级,否则在安装bootstrap_cmds时install_name_tool会报告“malformed object (unknown load command XX)”,具体看这个问答

编译完成之后当然就是更换内核重新启动了。具体步骤请看这里
另外编个内核好歹留点纪念吧,如果需要在uname信息留下你的印记的话,编辑config/version.c (我的OS是中文的,居然uname还给出中文了)

[email protected]$ uname -a
Darwin Marshalls-MacBook-Pro.local 11.4.2 DarwinMarshall’s Kernel Version 11.4.2: 2013年 2月24日 星期日 20时20分00秒 CST; wum:xnu-1699.32.7/BUILD/obj//RELEASE_X86_64 x86_64

最后附上原文里的一些步骤,防止原来的链接丢失。

  1. Build dtrace

    $ cd dtrace-90
    $ mkdir -p obj sym dst
    $ xcodebuild install -target ctfconvert -target ctfdump -target ctfmerge ARCHS="i386 x86_64" SRCROOT=$PWD OBJROOT=$PWD/obj SYMROOT=$PWD/sym DSTROOT=$PWD/dst
    ...
    $ sudo ditto $PWD/dst/usr/local /usr/local
    Password:
    $ cd ..
  2. Build bootstrap_cmds

    $ cd bootstrap_cmds-79
    $ mkdir -p obj sym dst
    $ make install RC_ARCHS="i386" SRCROOT=$PWD OBJROOT=$PWD/obj SYMROOT=$PWD/sym DSTROOT=$PWD/dst
    ...
    $ sudo ditto $PWD/dst/usr/local /usr/local
    Password:
    $ cd ..
  3. Build xnu

    $ cd xnu-1699.22.73
    $ make ARCH_CONFIGS="I386 X86_64" KERNEL_CONFIGS="RELEASE"
    ...
    $ file BUILD/obj/RELEASE_*/mach_kernel
    BUILD/obj/RELEASE_I386/mach_kernel: Mach-O executable i386
    BUILD/obj/RELEASE_X86_64/mach_kernel: Mach-O 64-bit executable x86_64

解密IPSW固件文件

最近看“Mac OSX and iOS Internals”,顺便小动手了一把,把IPSW(iOS固件包)里的文件拆开来看了看。操作平台为Mac OSX Lion。(另外似乎只适用于6.0以前的固件)
工具:
vfdecrypt (http://theiphonewiki.com/wiki/VFDecrypt
xpwntool (http://code.google.com/p/ios-jailbreaking-stuff/source/browse/trunk/tools_bin/xpwntool?r=5)点击下载raw file
lzssdec(Google第一个结果是源代码,下下来直接用g++编译)
固件下载:
http://www.ipswdownloader.com/download-iphone-ipsw-files.php
步骤:
1. ipsw直接当成zip文件解压;
2. 得到一个文件夹和几个文件,其中最大的那个以dmg结尾的就是文件系统ramdisk,另外一个dmg是restore ramdisk(大概将近20M)。不过由于文件被加密,不能直接mount;
3. 在 http://theiphonewiki.com/wiki/VFDecrypt_Keys 找到对应的版本,并得到文件系统的key;
4. 通过“./vfdecrypt -i<dmg location> -k<key> -o<out location>.dmg” 命令解密后的文件系统镜像;
5. Mount 解密后的镜像,可以看到一个类Unix的文件系统结构,其实这就是iOS的文件系统的layout;
6. 在ipsw解压的文件里找到kernelcache文件,基本上这可以算是iOS的内核文件(加上了一些静态链接好的扩展)
7. 通过xpwntool先把kernelcache给解密出来
./xpwntool <infile> <outfile>  [-k <key>] [-iv <key>] [-decrypt]
8. 用lzssdec把kernelcache从解密的文件里提取出来(其实就是找到相应的offset然后用lzss算法解压缩出来),注意“<“和“>”都要打
./lzssdec -o 448 < input_file > out_file
9. 用file确定解压文件的属性“Mach-O executable arm”