Random Tech Thoughts

The title above is not random

FreeBSD 安装升级笔记

前些天装 Solaris 时因为它不认 Linux 下 fdisk 建立的分区表,要用我的整个硬盘而放弃了。再次开始尝试 FreeBSD。Linux 用着也很好,但就是想尝试更 Unix 的系统,在一年之后再次看 BSD vs Linux 这篇文章时终于感觉看明白了,理解 BSD 系统为什么要采取集中式的开发以及它那样做的好处。Linux 各个发行版更多的是在组装了一个可用的系统,各个发行版可以用不同的组件来组装出这个系统,有差异那是当然的。而 FreeBSD 则本身就是一个可用的系统,所以这个基本系统中的各个组件都能确保良好的合作。下面这句话也是很有意思的:

BSD is what you get when a bunch of Unix hackers sit down to try to port a Unix system to the PC. Linux is what you get when a bunch of PC hackers sit down and try to write a Unix system for the PC.

总之是又想尝鲜了,正好刚考完试,可以先折腾一段时间了。下面记录安装时候的笔记。都是从网上能找到的东西,主要是方便自己以后查看。

安装
这个不想多说什么了,装过那么多 Linux 以后感觉 FreeBSD 的安装也是很方便的。Arch 的安装程序倒是和 FreeBSD 的很像。(二进制包的打包方式还有启动脚本 rc.conf 之类的都很像。)要注意的是 FreeBSD 下的分区概念和我平时接触的不一样。FreeBSD 必须要安装在我们平时所说的主分区上,在这一个分区上 FreeBSD 又会建立多个 slice,系统的根目录,swap 等是挂载到 slice 上,而不是直接挂载到分区上的。
ADSL 上网
网上找到的,原文在这里,不知道为什么以前在自己家的时候总是失败,现在在学校是没有问题。文件为 /etc/ppp/ppp.conf,注意default 和 adsl 之前没有空格,其他行首为空格。
# $FreeBSD: src/etc/ppp/ppp.conf,v 1.2.2.5 2001/07/13 10:55:23 brian Exp $
default:
 set log Phase Chat LCP IPCP CCP tun command
 ident user-ppp VERSION (built COMPILATIONDATE)
 set device PPPoE:bge0 # 我的是 BroadCom 的网卡
 set speed sync
 set mru 1492
 set mtu 1492
 set ctsrts off
 set timeout 30 # 3 minute idle timer (the default)
 disable lqr
 deny lqr
 add default HISADDR
 enable dns # request DNS info (for resolv.conf)
adsl: # 注意:这里的hz163是你的ISP名,要比下面的set语句多出一点(一个空格).
 set authname user(把这里的user换成你的ADSL用户名)
 set authkey password (把这里的password换成你的ADSL密码)
 set dial
 set login
 set ifaddr 10.0.0.1/0 10.0.0.2/0
 nat enable yes
执行 ppp -ddial adsl 后就可以上网了。
升级
因为我只有 6.0 的光盘,但是现在都已经到 6.2 了,所以决定先升级。
  1. 安装 cvsup-without-gui。6.2 里面可以使用 csup,怕 6.0 直接装 csup 会有问题,所以还是先用 cvsup。我是用 pkg_add 来安装的。可能因为版本较老,直接用 pkg_add -r cvsup-without-gui 找不到文件,所以到 ftp://ftp.freebsd.org.cn 手工下载以后安装。
  2. 更新内核源代码。找到文件 /usr/share/examples/cvsup/standard-supfile,拷贝一份,然后把里面的 *default=xxxxx 改成 cvsup2.FreeBSDChina.org,国内的更新笔记快。然后执行 cvsup -g -L 1 ,-g 表示不要图形界面,-L 控制输出内容,可以是 0 - 3。
    注意要升级到 6.2 的话把文件里面的 *default release=cvs tag=RELENG_6 改成 RELENG_6_2(这个表示取出修订标签为 6.2 的版本,如果要升级到 CURRENT,改成 tag=.),这样才能更新到 6.2 的源代码。
  3. 更新 ports。找到文件 /usr/share/examples/cvsup/ports-supfile,解下来的步骤同上,不过对 ports collection,tag 只能是 “.”。执行完 cvsup 之后 ports 就也更新完了。
  4. 修改 /etc/make.conf。可以拿了 /usr/share/examples/etc/make.conf 来修改。我现在的配置是:
    CPUTYPE=pentium-m
    CFLAGS=-O2 -pipe
    COPTFLAGS=-O2 -pipe
    NO_ATM=true
    NO_BLUETOOTH=true
    NO_INET6=true
    NO_OBJC=true
    NO_BIND=true
    ENABLE_WPA_SUPPLICANT_EAPOL=true
    
    看到 Gentoo 的影子了。编辑完以后拷贝回原来的地方或者建个链接。最好先备份一下原来的配置。
  5. 接下来就到 /usr/src 目录下 make buildworld 了。这个要耐心等了,又想起 Gentoo 了。
  6. 趁着编译的时间来配置内核。拷贝一份 /usr/src/sys/i386/conf/GENERIC 出来,然后打开编辑器修改了。配置文件很简单,都是名称–值这样的对(其实是选项–参数),而且都有注释,配置起来还是很方便的。
  7. 等 make buildworld 结束,就 make buildkernel 了。
  8. 接下来先 make installkernel。重启进入单用户模式,依次运行 mergemaster -p,make installworld,mergemaster。mergemaster 是为了合并有变化的配置文件而运行的,在第二次执行 mergemaster 时会显示有差异文件的 diff 输出,然后让你选择是保留原来的、安装新的还是合并。(又看到 Gentoo 的影子了。)最后重启,如果一切顺利的话就大功告成了。

很不错的一篇文章

昨天在 reddit 上看到的,Working for The Man。对学计算机的人来说有许多不错的建议。


从学计算机开始到一直没有怎么研究过微软平台的东西,原来有些担心,但是看了这篇文章以后放心了。另外一点令我高兴的是我虽然是学软件,但是一直对底层的东西保持兴趣。


以后要找机会参与一个开源项目来锻炼自己了。


另外很喜欢那句话,Be realistic. Demand the impossible.

面向对象和 C

在寒假那次作业中渐渐意识到应该把面向对象作为一种思想来使用,而不要受所使用的语言限制。而产生这样的想法也是因为在 C 中要使用面向对象的思想必须要自己来使用一些技巧。

比如对 C 里面定义的某个 struct 类型,当定义操作这个类型的函数时,让函数都接受这个 struct 类型的指针为参数,函数作用在指针所指向的对象上。在 C++ 中形如 object.function() 的函数调用在背地里就传了指向 object 对象的指针给 function,当然在类中定义这个方法的时候你可以看到这个指针,也就是 this 了。

而在 C 里面要使用继承的思想的话也不是不可以。对于父类的成员要在子类里面也能够访问的话直接在子类的 struct 里面包含一个父类的 stuct 就可以了,当然这样做的话要访问父类的成员会需要写成 descendants->parent->somemember 而不能直接写 descendants->somemember,而且访问控制也没有办法由编译器来控制。

对于多态通过函数指针也是可以实现的(Rob Pike 在 Notes On Programming in C 中说到 “I argue that clear use of function pointers is the heart of object­oriented programming.”)。这时要把函数指针作为类的成员,父类和子类需要手工设置不同的函数指针。对函数指针在 struct 定义中出现的位置可能也会有限制,目前我还没有做太多的考虑,也没有试过。关于使用 C 来进行面向对象编程有人写了一本书 Object-Oriented Programming wich ANSI C,有时间的话打算看看了。

当然,直接使用 C 来做面向对象的编程肯定会有许多不便,要不然也不需要所谓的面向对象语言的出现。但是面向对象的语言只是从语言层面上让我们更容易地表达面向对象的思想。语言本身不是核心,语言是我们表达思想的媒介,思想才是核心。当然好的语言能让我们更好、更方便地思考和表达思想,所以在进行面向对象编程的时候选择一种面向对象的语言还是有必要的。

关于使用语言来表达面向对象思想的问题还可以看看 Common Lisp 作为函数式语言是如何做到的。Common Lisp 在面向对象成为主流之前就已经出现,它实现面向对象的机制不是通过像 C++,Java 采用的 message passing,而是通过将函数特化于对象的方式。虽然我还没有在实际的程序中使用过 Common Lisp,但是感觉 Common Lisp 的对象机制比 C++,Java 灵活许多(不知道实际使用会不会更复杂),而且也有 AOP 的影子在其中。更令人惊叹的是这个对象机制的实现使用了大量的 macro(我不知道是不是只是使用了 macro),从使用 macro 来是语言具有面向对象的能力也可以证明面向对象只是思想,而不是语言本身。

最后一点是虽然面向对象的思想很好,但是它也不是万能的。有些程序不用面向对象的思想反而能得到更简单的解决办法。总觉得在用设计模式的时候很容易把设计搞的很大,可能还是我能力不够的原因吧。

写文本编辑器的收获

好久没有写东西了,因为这次开学以后实在是有太多的事情要做,到今天为止几乎每天都要写程序。没有想到一年三个学期会这么累,但是每天都有明确的事情要做总比漫无目的自己瞎找事情做要好一些。

寒假写终端下的文本编辑器用的是 C,在 20 号的时候终于提交了。虽然最后还是有一个比较重要的功能没有实现,但是这次用 C 写程序的经历倒是终于让我对 C 比较熟悉了。收获不少,主要的有两个,一个是了解 Unicode 了,也知道怎样让自己的程序支持 Unicode 从而支持中文的处理;另外一个就是对 C 的指针使用更熟练了。另外因为是写文本编辑器,所以对字符串的处理是少不了的,加上 C 里面字符串都是通过字符指针来处理,所以不光是指针,对 C 的字符串处理现在也是很习惯了。(反倒是有点不习惯 C++ 的 string 了。)

在开始写的时候从来没有想到过文本编辑器的缓冲区内容和屏幕光标位置的维护工作有那么麻烦,主要的问题都出在边界上,每一种特殊情况都要处理。而 Vi 在不同模式下光标的移动、删除操作等实际上都有一些小的区别的,我模仿 Vi 来写所以这些模式之间的差别也增加了我写编辑器时的负担。有时间的话倒是想看看 Vim 是如何维护缓冲区和光标的位置的,也想看看它是怎样解析命令的。

这次还用到一个很不错的技巧:用 struct 数组来初始化 hash table。比如用一个 struct command,成员是命令名字和对应的操作的函数指针,然后定义一个 struct command 的数组,里面把所有的命令和函数指针放进去,这样就可以很容易的在程序初始化的时候把把数组里面的内容全部放入 hash table。而且以后要添加命令的话也只需要在 struct command 的数组里面添加一项就可以了。

最后一点值得说的就是用函数指针实现了一个类似 state 模式的东西。我用一个整数表示编辑器的状态,另外有一个函数指针数组。程序处理用户输入的主循环中,利用状态作为下标从函数指针数组中得到状态对应的函数指针,然后调用这个函数。函数指针真的是好东西!终于喜欢上指针了 :–)

Linux Programming by Example

Linux Programming By Example 这本书断断续续地终于差不多全看完了,真是惭愧,买了一年了才看完……(不过中间还是看了不少其他的书的,SICP 就是其中之一)

总的来说这本书很不错,用来入门是非常好的。我感觉最出色的地方在于书里面用 production code 来讲解系统 API 的使用,由此可以看到健壮的代码是什么样的,而且可以学到不少编程技巧,同时还可以锻炼一下读代码的能力。(以前想看 Code Reading,不过感觉比较吃力,现在也许会好些了) 书里面的 production code 有来自 V7 Unix, GLIBC, GNU coreutils, GNU make, gawk (作者 Arnold Robbins 是 gawk 的维护者)。虽然书名是 Linux Programming,不过实际上不是专门针对 Linux 的,也覆盖了其他的 UNIX 系统,包括 BSD, Solaris 等,对 API 都标注上是 ISO C, POSIX, XSI, 具体某个特定的 UNIX 还是 GLIBC 提供的,而且提供了不少编写 portable code 的建议。大多数的章节都写的不错,只是觉得讲 Signal 的那章太罗嗦了。这个话题本来是比较复杂,作者用了三个 episode 一步一步从最古老容易产生 race condition 的 signal handling API 讲到最新最 powerful 最安全的 API,虽然内容全了,但是我头也大了。

可惜书看的时间太长了,也没有把精彩的地方记下来,遗憾啊。就写下现在记得的一些吧。

第三章中的从 CNU make 3.8 中抽出的 readline 函数代码,这个其实很实用,GLIBC 中有现成的函数可以使用,getline。看一下 readline 的实现,在没有 GLIBC 的系统上需要时自己实现一个好了。

第四章中 V7 cat 的源代码。这个 cat 检查了输入文件和输出文件为同一个文件的情况 (重定向带来的),这个如果我自己写 cat 时不会想到的。

第五章讲 UNIX 文件系统的一些概念讲的很不错。这一章最后有的习题要自己实现 getcwd 的功能,这个问题我是做错的,在处理根目录的时候。问题在于 /home 这样的目录我是用单独的分区挂载到根目录的,直接利用 .. 不停的向上一级目录走到最后是没有办法得到 /home 这个目录名的。看了第八章以后再做这个问题可能会比较好。coreutils 中的 pwc 其实就自己实现了一个 getcwd,看看人家是怎么实现的吧。

十三章讲国际化(终于知道 i18n 中的 18 是什么意思了,居然 internationalization 在起始的 i 和结束的 n 之间有 18 个字母,汗,老外不知道是怎么想的,还有 l10n 之类的都是这个意思),主要讲 locales 和 C library 的关系, gettext 简单使用,终于搞明白了那么多的 locales 环境变量究竟是做什么用的 (如果作为一个普通用户的话这些恐怕是很难弄清楚的了,当然普通用户需要知道的越少越好,可有时候不知道又不行,这方面 GNU/Linux 对普通用户确实不太友好) 还有一些关于 multibyte character encoding 的信息,内容少了点,不过还是澄清了 character set, character set encoding 和 language 这三个概念。以前就看过关于 Unicode 的文章,所以关于 multibyte character 的内容对我帮助不大。

第十五章 Debugging 很不错,学到了不少技巧。比如用 C99 中的 variadic macro 来定义一些调试打印语句,如

#ifdef MYAPPDEBUG #define DPRINT(mesg, …) fprintf(stderr, mesg, __VA_ARGS__) #else #define DPRINT(mesg, …) #endif

这样是解决了多个参数的问题,不过如果只有一个参数的话这个宏就又不能使用了。另外还介绍了一些调试工具和库,如 gdb, dbug, dmalloc, valgrind 等等。

之前都是把 APUE 当参考,接下来正式看了,不过为了避免重复就挑感兴趣和没有接触过的看了。

我爱 Vim

从去年暑假最后一段时间开始用 Vim 以后就基本上抛弃 Emacs 了。因为看到我的分类中只有 Emacs 而没有 Vim 而写这篇文章。Emacs 分类的文章中都关于遇到问题怎么解决的,Vim 一直都没有遇到什么问题,所以都没有写的需求。不想被人误解我使用 Emacs 而不是 Vim ,也为了提高 Vim 的被人看到的机会,所以特别增加 Vim 分类。

至于为什么选择 Vim 就不多说了,简单说点理由。关于这个问题口水战已经够多了,我就不多添油加醋了。

  1. Vim 默认实现的功能都很好用
  2. 由于 1,Vim 不需要那么多的个性化配置,默认就工作的很好
  3. 有模式的编辑方式非常快,尤其是当你养成习惯后
  4. Vim 对 UTF-8 支持很好,中文输入法也没有遇到什么问题
  5. Vim 速度快(这个不算太重要)
  6. Vim 的插件安装方便
  7. Vim 的帮助非常容易搜索,所以要学习某些功能很容易,这个使我迅速从 Emacs 转向 Vim ……

当然也有些我需要的功能只有在 Emacs 里面有,但 Vim 中没有,但是那些都不是那么至关重要,或者使用频率不高,所以 Emacs 用的越来越少了。(难得试试 Common Lisp 的时候为了 SLIME 会再用一下 Emacs 吧,其他的时候真的是不会再用了)

Arch 已经用 Java 6 了

今天更新时发现有冲突要删除 jdk,看了一下更新软件才注意到 jre 要升级到 6,冲突就是由 Java 引起的。虽然我还不打算升级 Java,但是没有办法,不更新的话冲突没有办法解决。于是就直接升级 jdk 和 jre 了。呵呵,Arch 动作还真是快,Java 6 发布一个月的时间(没有记错的话)就开始用了,而且你还最好要用最新的。

有趣的程序设计语言黑洞理论

最近开始看 Practical Common Lisp,其实自从看了 SICP 以后一直对 Lisp 很感兴趣。(SICP 本身倒是一直没有看完,去年暑假看到第四章就开学了) 从别人哪里看到 James Gosling 是 UNIX 下第一个 Emacs (Gosling Emacs) 的作者,而 Guy Steele 也是 Java 语言标准的指定者之一,Java 跟 Lisp 的渊源开来还真是不浅。在 James Gosling 的 Blog 的这篇文章里他写下了这么一段:

Lisp is a Black Hole: if you try to design something that’s not Lisp, but like Lisp, you’ll find that the gravitational forces on the design will suck it into the Black Hole, and it will become Lisp.

James Gosling 说这是他听是 Guy Steele 说的,Steele 却说他不记得曾经说过,但是这话的调调是像他自己的。

这篇文章还谈到了在 Java 7 中引入 closure,没看 Practical Common Lisp 之前不是很清楚 closure 的真正含义,现在算是明白了。引入 closure 真的是会让 Java 更像 Lisp 了吧,呵呵,不知道 Java 以后会发展成什么样子。(看 closure 的时候觉得编译原理学了以后对语言的了解还是有帮助的,不过感觉学得还不够好)

Practical Common Lisp 里面有这么一句话:现在的语言多数采取 C 的计算模式,但是加入越来越多的 Lisp 中的元素。看过 SICP 以后学 Ruby 的时候就觉得 Ruby 学了 Lisp (Scheme) 里面的一些东西( symbol, closure, 任何函数都有返回值 ),Java 里面引入 closure 的话更是印证了这句话。

在哈根达斯吃冰激凌时的犯罪感

难得写这样的东西。

今天去买小提琴,用哈根达斯为诱饵拉了一个会小提琴的同学一起去。我们两个都没有去过哈根达斯,只知道会很贵,但是不知道会贵到什么程度。一进哈根达斯店门,迎面走来一位穿着洋气的制服、笑容可掬的服务员问我们需要什么,带走还是在店里吃。我们打算在店里,大冬天的,外面刮着风还带走吃简直就是自找罪受。(其实大冬天的在店里吃冰激凌脑筋也好不到哪里去,不过就算是为了尝鲜吧)等坐下来,服务员送来柠檬水,一递上“菜单”就给我们推荐冰激凌“火锅”,等她说完“火锅”多好多好赶紧先问多少钱—280!我们只能笑笑。服务员倒也很好,看我们两个男生不像是会出大价钱的,让我们慢慢选然后就走了。翻到菜单上其他的东西,饮料多数都是30左右,也有更贵的,其他的冰激凌一般都是60-70,“火锅”就贵的离谱了,比280便宜一点的有180多的,其他的没有怎么看,总之价钱都是抢劫的那种。

改句歌词来描述我当时的心理:”其实我想走,一点不想留“。但是已经坐了下来,而且柠檬水已经上来了,想走也不好意思。(开始还以为服务真好,上来就柠檬水,其实是套住你……)既然走不了就豁出去了,奢侈一次吧(买小提琴也蛮奢侈的)。既然是来哈根达斯还是吃冰激凌吧,要饮料的话这边的也太不划算了。2人身上总共也就160多,每人点了一个60多的。服务员的服务还是非常好的,这个要赞一下,不过真正吃到哈根达斯的冰激凌感觉也就这样,是比较好吃,但是不值那个价,即使加上它店里的环境和服务也还是不值那个价。但上了贼船就是下不了的,既然逃不了就好好享受吧!

但是我们错选了靠窗口的位置,而这家店又是在商业街的一楼,里里外外都能很清楚的看到。两个男生在冬天来到哈根达斯确实是会比较引人注意吧,于是在享受被”抢劫“之后得到的冰激凌时经常会看到有人投来异样的目光(也不能叫异样吧,但是如果不是在哈根达斯,我们走在一起是绝对不会这样引人注意的,也或许是在窗口就是容易被人注意?没有多少这样的经历)。尤其是有个女生,我发现她在看我之后与之对视接近10秒,直到她在店外从我们所坐的沙发旁经过为止,其间最近的距离2米不到。(我的相貌让我可以有99%的把握认为她不是因为欣赏美而与我对视,不过我倒是也极少会看女生那么久)一个女生去看电影别人看来很正常,两个三个女生一起去看也没有问题;不过一个男生去看总有点别扭,两个三个恐怕更别扭。看来不光吃看电影如此,吃冰激凌也是这样啊。

虽然是在最繁华的商业街,但是还是看到有衣衫褴褛的老者(会令人想起乞讨者的衣着),背着大包小包吃力的行走,应该是为生活而奔波吧。而我却舒服的躺在沙发里,在开着暖气的房间里,吃着60多人民币一份的冰激凌,看着窗外走过的各色人等,关注穿着入时的摩登女郎,考虑着自己是否会被人认为是从”背背山”来这种无聊而无稽的问题……突然感到心理难受,不平、负罪感随之而来。同样是人,在同一个国家,同一个城市,差别真是太大了!而造就差别的原因往往不是因为他们不曾努力,而是因为他们根本没有努力向社会上层爬的机会。有点矛盾,他们如果爬上社会上层那么还是会有人在下层,社会能不能消除因经济原因带来的不同阶层?我不知道,但是经济上的弱势阶层往往也是政治上的弱势阶层,处在这样阶层的人要向上爬究竟要付出多少才能成功?我也不知道。我只希望即使有阶层,也希望这个阶层的产生是由于某些人不努力而导致他们在社会下层(对于失败者我不知道应该持什么样的态度),而不是由于阶层之间跨越的难度而造成。同学也有同感,由老者聊到了对乞讨者的态度。我曾经受过骗,从此那后就再也不给乞讨者任何帮助。但是现在觉得对老者即使是骗子我也应该给予一定的帮助,毕竟他们已经没有工作的能力。不是为了施舍时能得到的高贵感,我也从来没有过这样的感觉,而是为了让自己的良心平衡一点。这些文字不是做作,正常的人在这种情况下应该都会有这样的想法的吧。

在哈根达斯奢侈消费这是犯罪感一,感觉被人怀疑从“背背山”来是犯罪感二,而那个老者给我带来的负罪感则是今天所有犯罪感中最强烈的,也是能令我有些微变化的一点。