前几天为了测试一个程序,在 SimH 模拟的 DEC VAX-11/780 计算机中安装了 4.3BSD 系统(大概是历史上最伟大的操作系统之一?)。本系统于 1986 年夏天在加州伯克利新鲜出炉,安装磁带绝赞发售中……

# dmesg | head
4.3 BSD UNIX #1: Fri Jun  6 19:55:29 PDT 1986
karels@monet.Berkeley.EDU:/usr/src/sys/GENERIC
real mem  = 8388608

系统的安装过程完全是按照一篇教程进行的。当完成教程后,就可以启动 VAX-11/780 并进入 BSD 系统,这里就不重复了。

登录系统

4.3 BSD UNIX (bsd.my.domain) (console)

login: root
Last login: Mon Jan 27 09:19:47 on console
Jan 27 10:20:58 bsd login: ROOT LOGIN console
4.3 BSD UNIX #1: Fri Jun  6 19:55:29 PDT 1986

Would you like to play a game?

Don't login as root, use su
bsd#

一切仿佛就在昨天,Unix 的 getty 这么多年都没有变化过。另外发现原来连 4.3BSD 都会嘲笑 root 敢死队——小心点,如果误操作,你会引起第三次世界核大战的……(”Would you like to play a game” 显然是 BSD 开发者在玩 1983 年好莱坞科幻《Wargames》的梗)。

系统中甚至有有个名为 /usr/games/wargames 的游戏……

# /usr/games/wargames
Would you like to play a game? yes
Funny, the only way to win is not to play at all

不管你回答什么,它都只会打印 “Funny, the only way to win is not to play at all”,纯粹是为了玩梗而存在。如今技术圈的社交媒体的人们经常玩科幻、电影、动画相关的各种梗,看来一直是历史传统了。

寻找源代码

不玩游戏了,回到测试工作。

众所周知,BSD 操作系统不只是一个内核,而是一套完整的操作系统。因此,所有程序的全套源代码都可以在 /usr/src 中找到。为了进行测试,我需要调试并修改某个系统工具的源代码。于是我使用了 find 快速递归列出文件。

# find /usr/src
/usr/src
...
/usr/src/bin/as
...
/usr/src/bin/awk
...
/usr/src/bin/cat.c
/usr/src/bin/cc.c
/usr/src/bin/chgrp.c
/usr/src/bin/chmod.c
/usr/src/bin/cmp.c
/usr/src/bin/cp.c
/usr/src/bin/csh
...
/usr/src/bin/date.c
/usr/src/bin/dd.c
/usr/src/bin/df.c
/usr/src/bin/diff
/usr/src/bin/diff/diff.c

源代码是应有尽有,一目了然。

见鬼的是这个目录居然不存在?!

# ls /usr/src
/usr/src not found

显然 find 对系统中存在的文件似乎有不同的理解。不过没有什么是看文档解决不了的问题,RTFM 一下。

# man find

SYNOPSIS
find pathname-list expression
find pattern

DESCRIPTION
...
The second form rapidly searches a database for all path-
names which match pattern.  Usually the database is recom-
puted weekly and contains the pathnames of all files which
are publicly accessible.

原来 BSD 的 find(1) 居然这么强大,还包含了文件索引的功能(GNU/Linux 用户可以理解为 updatedb + locate)。换句话说,现在列出的文件都是安装盘建立时的索引,并不实际存在。

磁带

显然,/usr/src 在这台机器上还没有被安装,需要从磁带安装。要使用磁带,必须先将磁带放入磁带机,并根据磁带机的型号在 /dev 下创建设备文件。在 SimH 模拟器的 .ini 配置文件中,我已经配置好了磁带机设备 ts0,它对应的是 DEC TS-11 型磁带机。从名字就可以看出,这台磁带机最初来自 PDP-11 计算机,后来在 VAX-11 时代沿用。

att ts 43.tap

开机时可以在 dmesg 中看到磁带机。

# dmesg | grep ts0
ts0 at zs0 slave 0

但是却找不到相关的设备文件。

# ls /dev/ts0 /dev/zs0
/dev/ts0 not found
/dev/zs0 not found

原来 ts0 和 zs0 都是内核驱动的硬件设备名,并非真正的设备文件。因此,首先创建设备文件。由于 Unix 支持大量不同的设备,创建设备文件是一项十分繁琐的任务。好在 BSD 的同学们为我们准备了一个名为 ./MAKEDEV 的 shell 脚本。

# head /dev/MAKEDEV
#!/bin/sh -
#
# Copyright (c) 1980 Regents of the University of California.
# All rights reserved.  The Berkeley software License Agreement
# specifies the terms and conditions for redistribution.
#
#       @(#)MAKEDEV     4.27 (Berkeley) 4/15/86

创建 ts0 磁带机的设备文件时,只需要输入如下命令(不知为何,./MAKEDEV 没有可执行权限,于是使用 sh ./MAKEDEV)

# cd /dev
# sh ./MAKEDEV ts0

但运行后发现 MAKEDEV 创建的好几个设备文件,包括 /dev/mt0, /dev/mt4, /dev/mt8, /dev/mt12, /dev/rmt0, /dev/rmt4, /dev/rmt8, /dev/rmt12, /dev/nmt0, /dev/mnt8, /dev/nrmt0, /dev/nmrt8,不知应使用哪个文件。

实在不会了,只能上网搜索看看。我首先了解到知道的是,BSD 控制磁带机的工具是 mt,所以先看看本机中 mt 的文档(不能看网络上的,版本都不一样。看来在文档难求的年代,man page 能解决不少问题)。

# man mt
...
Mt is used to give commands to a magnetic tape drive.  If a
tape name is not specified, the environment variable TAPE is
used;  if TAPE does not exist, mt uses the device
/dev/rmt12.

status
Print status information about the tape unit.

原来可以查看磁带机的状态,试一试:

# mt status
ts11 tape drive, residual=0
ds=0
er=152<onl,ies,ped,bot></onl,ies,ped,bot>

确实能识别。

接下来意识到了 Unix 从磁带读取文件的工具是 tar(这显然是废话),也许 tar 的文档里有什么说明,继续 RTFM。

# man tar

t       The names of the specified files are listed each
time they occur on the tape.  If no file argument is
given, all of the names on the tape are listed.

f       Tar uses the next argument as the name of the
archive instead of /dev/rmt?.

原来当 tar 没有指定任何文件时,它会去读取默认的磁带设备文件(不仅如今还有多少人使用过这个功能,反正我没有……)。这就试一试。

# tar t
tar: blocksize = 1
tar: directory checksum error (0 != 217)

tar 提示校验和错误。后来又使用 tar tf /dev/rmtX 把所有的设备文件都试了一遍,没有一个是能正常读取的。

彻底卡在这里了,只能从网络上搜索并重新阅读 SimH 的 4.3BSD 安装教程。原来 tar 不能读取磁带的原因是因为之前没有倒带到开头。

# mt rewind

倒带之后,还需要向后移动三条“空白计数文件”的距离。作为新手,我还并不清楚什么是空白计数文件,也不知道为什么是 3 个。不过先运行一下,日后慢慢了解。

# mt fsf 3

FSF 不是自由软件基金会,而 Forward Space Count Files 的缩写。

再试试 tar,成功!

# tar t
./
./cassette/
./dist/group
./dist/fstab.hp
./dist/motd
./dist/passwd
./dist/rc.local
./conf/touch.c
./h/mount.h
./h/signal.h
./h/quota.h
./netinet/tcp.h
./netinet/udp.h

能看到许多熟悉的文件,但并没有我要找的 /usr 或者 /usr/src。磁带后面还有更多文件,继续倒带。但运行 mt fsf 或者 mt fsf 3 没有效果。后来猜测之前的记录是 mt fsf 3,下一条可能是 mt fsf 6,果然如此。

# tar t
Makefile
...
bin/df.c
bin/hostid.c
bin/mail.c
bin/du.c
bin/strip.c
bin/stty.c
bin/cat.c
bin/ld.c
bin/login.c
bin/time.c
bin/ed.c
bin/nm.c
bin/dd.c
bin/su.c
bin/rm.c
bin/pr.c
bin/cp.c
bin/cmp.c
bin/true.sh
bin/false.sh
bin/ln.c
bin/grep.c
bin/write.c
bin/mv.c
bin/passwd.c
bin/echo.c
bin/hostname.c
bin/ps.c
bin/cc.c
bin/tar.c
bin/kill.c
bin/sync.c
bin/size.c
bin/date.c
bin/tee.c
bin/wall.c
bin/chmod.c
bin/test.c
bin/rmail.c
bin/od.c
bin/chgrp.c
bin/ar.c
bin/expr.y
bin/rcp.c
bin/ls.c
bin/Makefile
bin/mkdir.c
bin/mt.c
bin/nice.c
bin/pagesize.c
bin/pwd.c
bin/rmdir.c
bin/who.c

找到了,这就是 /usr/src。接下来只需要再重新倒带,向前快进并解压磁带上的tar 归档即可。

# mt rewind
# mt fsf 6
# mkdir /usr/src
# cd /usr/src
# tar x

大功告成。

# ls
Makefile  etc/      include/  local/    ucb/      usr.bin/
bin/      games/    lib/      old/      undoc/    usr.lib/

关机

输入 halt。

# halt
Jan 27 11:01:03 bsd halt: halted by root
Jan 27 11:01:04 bsd syslogd: going down on signal 15
syncing disks... done
halting (in tight loop); hit
^P
HALT

由于 Unix 的传统 halt 命令是只关机不断电的(您现在可以安全的关闭计算机了?),因此模拟器此时会报 HALT 指令死循环错误。

HALT
Infinite loop, PC: 8002AFCD (BRB 8002AFCD)

输入 quit 退出 DEC VAX-11/780 模拟器。